Select Git revision
core_purchase.go
-
Simon Esposito authored
Add subscription raw response/notification. Add userID to validated purchases/subscriptions. Add Google refund scheduler. Handle Google IAP refunds by polling their voided purchases API. Invoke custom hooks on refund/subscription notification handling.
Simon Esposito authoredAdd subscription raw response/notification. Add userID to validated purchases/subscriptions. Add Google refund scheduler. Handle Google IAP refunds by polling their voided purchases API. Invoke custom hooks on refund/subscription notification handling.
core_purchase.go 21.47 KiB
// Copyright 2018 The Nakama Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"bytes"
"context"
"database/sql"
"encoding/base64"
"encoding/gob"
"errors"
"fmt"
"net/http"
"strconv"
"strings"
"time"
"github.com/gofrs/uuid"
"github.com/heroiclabs/nakama-common/api"
"github.com/heroiclabs/nakama/v3/iap"
"github.com/jackc/pgtype"
"go.uber.org/zap"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
)
var ErrPurchasesListInvalidCursor = errors.New("purchases list cursor invalid")
var httpc = &http.Client{Timeout: 5 * time.Second}
func ValidatePurchasesApple(ctx context.Context, logger *zap.Logger, db *sql.DB, userID uuid.UUID, password, receipt string, persist bool) (*api.ValidatePurchaseResponse, error) {
validation, raw, err := iap.ValidateReceiptApple(ctx, httpc, receipt, password)
if err != nil {
if err != context.Canceled {
var vErr *iap.ValidationError
if errors.As(err, &vErr) {
logger.Error("Error validating Apple receipt", zap.Error(vErr.Err), zap.Int("status_code", vErr.StatusCode), zap.String("payload", vErr.Payload))
return nil, vErr
} else {
logger.Error("Error validating Apple receipt", zap.Error(err))
}
}
return nil, err
}
if validation.Status != iap.AppleReceiptIsValid {
if validation.IsRetryable == true {
return nil, status.Error(codes.Unavailable, "Apple IAP verification is currently unavailable. Try again later.")
}
return nil, status.Error(codes.FailedPrecondition, fmt.Sprintf("Invalid Receipt. Status: %d", validation.Status))
}
env := api.StoreEnvironment_PRODUCTION
if validation.Environment == iap.AppleSandboxEnvironment {
env = api.StoreEnvironment_SANDBOX
}