diff --git a/main.c b/main.c index 218a7e0..2fee619 100644 --- a/main.c +++ b/main.c @@ -658,8 +658,6 @@ void end_text_input(char *what_player_said) return; } player->state = CHARACTER_IDLE; -#ifdef WEB // hacky -#endif size_t player_said_len = strlen(what_player_said); int actual_len = 0; diff --git a/server/main.go b/server/main.go index e76cb0c..8df5668 100644 --- a/server/main.go +++ b/server/main.go @@ -14,6 +14,7 @@ import ( "math/rand" gogpt "github.com/sashabaranov/go-gpt3" "github.com/stripe/stripe-go/v74" + "github.com/stripe/stripe-go/v74/event" "github.com/stripe/stripe-go/v74/webhook" "github.com/stripe/stripe-go/v74/checkout/session" @@ -97,33 +98,12 @@ func clearOld(db *gorm.DB) { } } -func webhookResponse(w http.ResponseWriter, req *http.Request) { - const MaxBodyBytes = int64(65536) - req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes) - - body, err := ioutil.ReadAll(req.Body) - if err != nil { - log.Printf("Error reading request body: %v\n", err) - w.WriteHeader(http.StatusServiceUnavailable) - return - } - - endpointSecret := webhookSecret - event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret) - - if err != nil { - log.Printf("Error verifying webhook signature %s\n", err) - w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature - return - } - +func handleEvent(event stripe.Event) error { if event.Type == "checkout.session.completed" { var session stripe.CheckoutSession err := json.Unmarshal(event.Data.Raw, &session) if err != nil { - log.Printf("Error parsing webhook JSON %s", err) - w.WriteHeader(http.StatusBadRequest) - return + return fmt.Errorf("Error parsing webhook JSON %s", err) } params := &stripe.CheckoutSessionParams{} @@ -132,7 +112,6 @@ func webhookResponse(w http.ResponseWriter, req *http.Request) { // Retrieve the session. If you require line items in the response, you may include them by expanding line_items. // Fulfill the purchase... - var toFulfill User found := false for trial := 0; trial < 5; trial++ { @@ -144,18 +123,51 @@ func webhookResponse(w http.ResponseWriter, req *http.Request) { } } if !found { - log.Println("Error Failed to find user in database to fulfill: very bad! ID: " + session.ID) + return fmt.Errorf("Error Failed to find user in database to fulfill: very bad! ID: " + session.ID) } else { userString, err := codes.CodeToString(toFulfill.Code) if err != nil { - log.Printf("Error strange thing, saved user's code was unable to be converted to a string %s", err) + return fmt.Errorf("Error strange thing, saved user's code was unable to be converted to a string %s", err) } log.Printf("Fulfilling user with code %s number %d\n", userString, toFulfill.Code) + if(toFulfill.IsFulfilled) { + log.Printf("User with code %s is already fulfilled, strange\n", userString) + } toFulfill.IsFulfilled = true - db.Save(&toFulfill) + err = db.Save(&toFulfill).Error + if err != nil { + return fmt.Errorf("Failed to save fulfilled flag status to database: %s", err) + } } } + return nil +} +func webhookResponse(w http.ResponseWriter, req *http.Request) { + const MaxBodyBytes = int64(65536) + req.Body = http.MaxBytesReader(w, req.Body, MaxBodyBytes) + + body, err := ioutil.ReadAll(req.Body) + if err != nil { + log.Printf("Error reading request body: %v\n", err) + w.WriteHeader(http.StatusServiceUnavailable) + return + } + + endpointSecret := webhookSecret + event, err := webhook.ConstructEvent(body, req.Header.Get("Stripe-Signature"), endpointSecret) + + if err != nil { + log.Printf("Error verifying webhook signature %s\n", err) + w.WriteHeader(http.StatusBadRequest) // Return a 400 error on a bad signature + return + } + + err = handleEvent(event) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + } + w.WriteHeader(http.StatusOK) } @@ -285,12 +297,30 @@ func index(w http.ResponseWriter, req *http.Request) { } else { // now have valid user, in the database, to be rate limit checked // rate limiting based on user token - _, exists := daypassTimedOut[thisUserCode] - if exists { - rejected = true + if !thisUser.IsFulfilled { + log.Println("Unfulfilled user trying to play, might've been unresponded to event. Retrieving backlog of unfulfilled events...\n") + params := &stripe.EventListParams{} + params.Filters.AddFilter("delivery_success", "", "false") + i := event.List(params) + for i.Next() { + e := i.Event() + log.Println("Unfulfilled event! Of type %s. Handling...\n", e.Type) + err := handleEvent(*e) + if err != nil { + log.Println("Failed to fulfill unfulfilled event: %s\n", err) + } + } + } + if thisUser.IsFulfilled { + _, exists := daypassTimedOut[thisUserCode] + if exists { + rejected = true + } else { + rejected = false + daypassTimedOut[thisUserCode] = currentTime() + } } else { - rejected = false - daypassTimedOut[thisUserCode] = currentTime() + log.Println("User with code and existing entry in database was not fulfilled, and wanted to play... Very bad. Usercode: %s\n", thisUserCode) } } }