Skip to content

Conversation

@jackhellyercw
Copy link

generic purchase provider setup

Copy link
Member

@sesposito sesposito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments, some of the params may still require some thought as we go through the implementation details.

Copy link
Member

@sesposito sesposito left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some more feedback

api/api.proto Outdated

message ValidatePurchaseProviderResponse {
repeated PurchaseProviderValidatedPurchase validated_purchases = 1;
bool persist = 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we need to return this in the response, just in the request, unless you think this could be useful?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe i misunderstood when we spoke the about the previously requested changes, i thought you requested the persist bool to be returned with the response?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I meant that it should be returned as part of the provider implementation functions, not necessarily in the client response, unless you see value in it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah right okay i get you. I will remove this. This also won't need to be return from the provider implementation functions as we now do the upsert outside of those functions as discussed in the call the other week so persist is no longer passed to the validatePurchase func

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The upsert is done outside of the provider implementation but it may still want to skip storing it, so shouldn't it be returned by the provider so that Nakama knows whether to skip the upsert?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the persist bool already exists in Nakama as it comes from a parameter on the api endpoint for purchaseValidate. So Nakama does know whether to skip the upsert

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it's not needed for the enpoints, but we also need to expose the registered adapters through a purchase/subscription validate function in Go/Lua/JS, and whatever these return, also need to be upserted into database, unless persist is false.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that flow also handles the upsert outside of the provider validate implementation with the persist value being passed in from the nk.purchaseValidate function for example

"os"
"time"

"github.com/gofrs/uuid/v5"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be needed as we removed references to uuid.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently being used in the storagePurchase and storageSubscription structs for the userID

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@zyro do you think it's ok to keep this dependency in common or should we move to use strings everywhere?

go.mod Outdated

require google.golang.org/protobuf v1.36.6

require github.com/gofrs/uuid/v5 v5.3.2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't be needed

TransactionId string
RawResponse string
PurchaseTime time.Time
CreateTime time.Time // Set by upsertPurchases
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should remove these fields that are actually set by upsertPurchase/Subscription

Copy link
Author

@jackhellyercw jackhellyercw Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those fields are being used. example from the existing validatepurchaseApple func:

	purchases, err := iap.UpsertPurchases(ctx, db, storagePurchases)
	if err != nil {
		return nil, err
	}

        validatedPurchases := make([]*api.ValidatedPurchase, 0, len(purchases))
	for _, p := range purchases {
		suid := p.UserID.String()
		if p.UserID.IsNil() {
			suid = ""
		}
		validatedPurchases = append(validatedPurchases, &api.ValidatedPurchase{
			UserId:           suid,
			ProductId:        p.ProductId,
			TransactionId:    p.TransactionId,
			Store:            p.Store,
			PurchaseTime:     timestamppb.New(p.PurchaseTime),
			CreateTime:       timestamppb.New(p.CreateTime),
			UpdateTime:       timestamppb.New(p.UpdateTime),
			ProviderResponse: string(raw),
			SeenBefore:       p.SeenBefore,
			Environment:      p.Environment,
		})
	}

Init(purchaseRefundFn PurchaseRefundFn, subscriptionRefundFn SubscriptionRefundFn)
PurchaseValidate(ctx context.Context, in *api.ValidatePurchaseRequest, userID string) ([]*StoragePurchase, error)
SubscriptionValidate(ctx context.Context, in *api.ValidateSubscriptionRequest, userID string) ([]*StorageSubscription, error)
HandleRefund(ctx context.Context) (http.HandlerFunc, error)
Copy link
Member

@sesposito sesposito Aug 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should only return an error instead of http.HandlerFunc

Copy link
Author

@jackhellyercw jackhellyercw Aug 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reason the handlerFunc was returned was so that the apple and google notification handler flow still worked. I can remove this but will need to rethink how that is going to be handled

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleRefund func now only returns error, have added a handleRefundWrapper func to the purchase provider interface to keep backwards compatibility

api/api.proto Outdated

message ValidatePurchaseProviderResponse {
repeated PurchaseProviderValidatedPurchase validated_purchases = 1;
bool persist = 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, it's not needed for the enpoints, but we also need to expose the registered adapters through a purchase/subscription validate function in Go/Lua/JS, and whatever these return, also need to be upserted into database, unless persist is false.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants