diff --git a/CHANGELOG.md b/CHANGELOG.md index e4fe9c89..452e8bd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,9 +4,20 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [3.8.0] +### Added +- Nakama: Added `Authoritative` flag to tournaments returned from the server. +- Nakama: Added `RefundTime` and `UserId` to purchases and subscriptions returned from the server. +- Nakama: Added raw subscription provider information. +- Nakama: Added `DeleteAccountAsync` for deleting user accounts. +- Satori: Added `DeleteIdentityAsync` for deleting user identities. + ### Changed -- Nakama: Use `session.Username` wherever outdated state might be returned. +- Nakama: Used `session.Username` wherever outdated state might be returned. + +### Fixed +- Nakama: Fixed issue where outgoing payloads could include unnecessary JSON. + ## [3.7.0] ### Added diff --git a/Nakama/ApiClient.gen.cs b/Nakama/ApiClient.gen.cs index 37e586ca..ad1c921c 100644 --- a/Nakama/ApiClient.gen.cs +++ b/Nakama/ApiClient.gen.cs @@ -7,7 +7,7 @@ namespace Nakama using System.Text; using System.Threading; using System.Threading.Tasks; - using Nakama.TinyJson; + using TinyJson; /// /// An exception generated for HttpResponse objects don't return a success status. @@ -134,6 +134,7 @@ internal class GroupUserListGroupUser : IGroupUserListGroupUser public int State { get; set; } /// + [IgnoreDataMember] public IApiUser User => _user; [DataMember(Name="user"), Preserve] public ApiUser _user { get; set; } @@ -169,6 +170,7 @@ internal class UserGroupListUserGroup : IUserGroupListUserGroup { /// + [IgnoreDataMember] public IApiGroup Group => _group; [DataMember(Name="group"), Preserve] public ApiGroup _group { get; set; } @@ -222,6 +224,7 @@ internal class WriteLeaderboardRecordRequestLeaderboardRecordWrite : IWriteLeade public string Metadata { get; set; } /// + [IgnoreDataMember] public ApiOperator Operator => _operator; [DataMember(Name="operator"), Preserve] public ApiOperator _operator { get; set; } @@ -281,6 +284,7 @@ internal class WriteTournamentRecordRequestTournamentRecordWrite : IWriteTournam public string Metadata { get; set; } /// + [IgnoreDataMember] public ApiOperator Operator => _operator; [DataMember(Name="operator"), Preserve] public ApiOperator _operator { get; set; } @@ -355,6 +359,7 @@ internal class ApiAccount : IApiAccount public string CustomId { get; set; } /// + [IgnoreDataMember] public IEnumerable Devices => _devices ?? new List(0); [DataMember(Name="devices"), Preserve] public List _devices { get; set; } @@ -368,6 +373,7 @@ internal class ApiAccount : IApiAccount public string Email { get; set; } /// + [IgnoreDataMember] public IApiUser User => _user; [DataMember(Name="user"), Preserve] public ApiUser _user { get; set; } @@ -420,6 +426,7 @@ internal class ApiAccountApple : IApiAccountApple public string Token { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -465,6 +472,7 @@ internal class ApiAccountCustom : IApiAccountCustom public string Id { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -510,6 +518,7 @@ internal class ApiAccountDevice : IApiAccountDevice public string Id { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -564,6 +573,7 @@ internal class ApiAccountEmail : IApiAccountEmail public string Password { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -610,6 +620,7 @@ internal class ApiAccountFacebook : IApiAccountFacebook public string Token { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -655,6 +666,7 @@ internal class ApiAccountFacebookInstantGame : IApiAccountFacebookInstantGame public string SignedPlayerInfo { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -745,6 +757,7 @@ internal class ApiAccountGameCenter : IApiAccountGameCenter public string TimestampSeconds { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -795,6 +808,7 @@ internal class ApiAccountGoogle : IApiAccountGoogle public string Token { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -840,6 +854,7 @@ internal class ApiAccountSteam : IApiAccountSteam public string Token { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -1043,6 +1058,7 @@ internal class ApiChannelMessageList : IApiChannelMessageList public string CacheableCursor { get; set; } /// + [IgnoreDataMember] public IEnumerable Messages => _messages ?? new List(0); [DataMember(Name="messages"), Preserve] public List _messages { get; set; } @@ -1209,6 +1225,7 @@ internal class ApiDeleteStorageObjectsRequest : IApiDeleteStorageObjectsRequest { /// + [IgnoreDataMember] public IEnumerable ObjectIds => _objectIds ?? new List(0); [DataMember(Name="object_ids"), Preserve] public List _objectIds { get; set; } @@ -1261,6 +1278,7 @@ internal class ApiEvent : IApiEvent public string Name { get; set; } /// + [IgnoreDataMember] public IDictionary Properties => _properties ?? new Dictionary(); [DataMember(Name="properties"), Preserve] public Dictionary _properties { get; set; } @@ -1321,6 +1339,7 @@ internal class ApiFriend : IApiFriend public string UpdateTime { get; set; } /// + [IgnoreDataMember] public IApiUser User => _user; [DataMember(Name="user"), Preserve] public ApiUser _user { get; set; } @@ -1361,6 +1380,7 @@ internal class ApiFriendList : IApiFriendList public string Cursor { get; set; } /// + [IgnoreDataMember] public IEnumerable Friends => _friends ?? new List(0); [DataMember(Name="friends"), Preserve] public List _friends { get; set; } @@ -1538,6 +1558,7 @@ internal class ApiGroupList : IApiGroupList public string Cursor { get; set; } /// + [IgnoreDataMember] public IEnumerable Groups => _groups ?? new List(0); [DataMember(Name="groups"), Preserve] public List _groups { get; set; } @@ -1577,6 +1598,7 @@ internal class ApiGroupUserList : IApiGroupUserList public string Cursor { get; set; } /// + [IgnoreDataMember] public IEnumerable GroupUsers => _groupUsers ?? new List(0); [DataMember(Name="group_users"), Preserve] public List _groupUsers { get; set; } @@ -1764,6 +1786,7 @@ internal class ApiLeaderboardRecordList : IApiLeaderboardRecordList public string NextCursor { get; set; } /// + [IgnoreDataMember] public IEnumerable OwnerRecords => _ownerRecords ?? new List(0); [DataMember(Name="owner_records"), Preserve] public List _ownerRecords { get; set; } @@ -1773,6 +1796,7 @@ internal class ApiLeaderboardRecordList : IApiLeaderboardRecordList public string PrevCursor { get; set; } /// + [IgnoreDataMember] public IEnumerable Records => _records ?? new List(0); [DataMember(Name="records"), Preserve] public List _records { get; set; } @@ -1810,6 +1834,7 @@ internal class ApiLinkSteamRequest : IApiLinkSteamRequest { /// + [IgnoreDataMember] public IApiAccountSteam Account => _account; [DataMember(Name="account"), Preserve] public ApiAccountSteam _account { get; set; } @@ -1960,6 +1985,7 @@ internal class ApiMatchList : IApiMatchList { /// + [IgnoreDataMember] public IEnumerable Matches => _matches ?? new List(0); [DataMember(Name="matches"), Preserve] public List _matches { get; set; } @@ -2086,6 +2112,7 @@ internal class ApiNotificationList : IApiNotificationList public string CacheableCursor { get; set; } /// + [IgnoreDataMember] public IEnumerable Notifications => _notifications ?? new List(0); [DataMember(Name="notifications"), Preserve] public List _notifications { get; set; } @@ -2191,6 +2218,7 @@ internal class ApiReadStorageObjectsRequest : IApiReadStorageObjectsRequest { /// + [IgnoreDataMember] public IEnumerable ObjectIds => _objectIds ?? new List(0); [DataMember(Name="object_ids"), Preserve] public List _objectIds { get; set; } @@ -2363,6 +2391,7 @@ internal class ApiSessionRefreshRequest : IApiSessionRefreshRequest public string Token { get; set; } /// + [IgnoreDataMember] public IDictionary Vars => _vars ?? new Dictionary(); [DataMember(Name="vars"), Preserve] public Dictionary _vars { get; set; } @@ -2565,6 +2594,7 @@ internal class ApiStorageObjectAcks : IApiStorageObjectAcks { /// + [IgnoreDataMember] public IEnumerable Acks => _acks ?? new List(0); [DataMember(Name="acks"), Preserve] public List _acks { get; set; } @@ -2603,6 +2633,7 @@ internal class ApiStorageObjectList : IApiStorageObjectList public string Cursor { get; set; } /// + [IgnoreDataMember] public IEnumerable Objects => _objects ?? new List(0); [DataMember(Name="objects"), Preserve] public List _objects { get; set; } @@ -2633,6 +2664,7 @@ internal class ApiStorageObjects : IApiStorageObjects { /// + [IgnoreDataMember] public IEnumerable Objects => _objects ?? new List(0); [DataMember(Name="objects"), Preserve] public List _objects { get; set; } @@ -2718,6 +2750,7 @@ internal class ApiSubscriptionList : IApiSubscriptionList public string PrevCursor { get; set; } /// + [IgnoreDataMember] public IEnumerable ValidatedSubscriptions => _validatedSubscriptions ?? new List(0); [DataMember(Name="validated_subscriptions"), Preserve] public List _validatedSubscriptions { get; set; } @@ -2738,6 +2771,11 @@ public override string ToString() public interface IApiTournament { + /// + /// Whether the leaderboard was created authoritatively or not. + /// + bool Authoritative { get; } + /// /// True if the tournament is active and can enter. A computed value. /// @@ -2838,6 +2876,10 @@ public interface IApiTournament internal class ApiTournament : IApiTournament { + /// + [DataMember(Name="authoritative"), Preserve] + public bool Authoritative { get; set; } + /// [DataMember(Name="can_enter"), Preserve] public bool CanEnter { get; set; } @@ -2887,6 +2929,7 @@ internal class ApiTournament : IApiTournament public int NextReset { get; set; } /// + [IgnoreDataMember] public ApiOperator Operator => _operator; [DataMember(Name="operator"), Preserve] public ApiOperator _operator { get; set; } @@ -2918,6 +2961,7 @@ internal class ApiTournament : IApiTournament public override string ToString() { var output = ""; + output = string.Concat(output, "Authoritative: ", Authoritative, ", "); output = string.Concat(output, "CanEnter: ", CanEnter, ", "); output = string.Concat(output, "Category: ", Category, ", "); output = string.Concat(output, "CreateTime: ", CreateTime, ", "); @@ -2967,6 +3011,7 @@ internal class ApiTournamentList : IApiTournamentList public string Cursor { get; set; } /// + [IgnoreDataMember] public IEnumerable Tournaments => _tournaments ?? new List(0); [DataMember(Name="tournaments"), Preserve] public List _tournaments { get; set; } @@ -3016,6 +3061,7 @@ internal class ApiTournamentRecordList : IApiTournamentRecordList public string NextCursor { get; set; } /// + [IgnoreDataMember] public IEnumerable OwnerRecords => _ownerRecords ?? new List(0); [DataMember(Name="owner_records"), Preserve] public List _ownerRecords { get; set; } @@ -3025,6 +3071,7 @@ internal class ApiTournamentRecordList : IApiTournamentRecordList public string PrevCursor { get; set; } /// + [IgnoreDataMember] public IEnumerable Records => _records ?? new List(0); [DataMember(Name="records"), Preserve] public List _records { get; set; } @@ -3342,6 +3389,7 @@ internal class ApiUserGroupList : IApiUserGroupList public string Cursor { get; set; } /// + [IgnoreDataMember] public IEnumerable UserGroups => _userGroups ?? new List(0); [DataMember(Name="user_groups"), Preserve] public List _userGroups { get; set; } @@ -3372,6 +3420,7 @@ internal class ApiUsers : IApiUsers { /// + [IgnoreDataMember] public IEnumerable Users => _users ?? new List(0); [DataMember(Name="users"), Preserve] public List _users { get; set; } @@ -3525,6 +3574,7 @@ internal class ApiValidatePurchaseResponse : IApiValidatePurchaseResponse { /// + [IgnoreDataMember] public IEnumerable ValidatedPurchases => _validatedPurchases ?? new List(0); [DataMember(Name="validated_purchases"), Preserve] public List _validatedPurchases { get; set; } @@ -3630,6 +3680,7 @@ internal class ApiValidateSubscriptionResponse : IApiValidateSubscriptionRespons { /// + [IgnoreDataMember] public IApiValidatedSubscription ValidatedSubscription => _validatedSubscription; [DataMember(Name="validated_subscription"), Preserve] public ApiValidatedSubscription _validatedSubscription { get; set; } @@ -3649,7 +3700,7 @@ public interface IApiValidatedPurchase { /// - /// UNIX Timestamp when the receipt validation was stored in DB. + /// Timestamp when the receipt validation was stored in DB. /// string CreateTime { get; } @@ -3669,10 +3720,15 @@ public interface IApiValidatedPurchase string ProviderResponse { get; } /// - /// UNIX Timestamp when the purchase was done. + /// Timestamp when the purchase was done. /// string PurchaseTime { get; } + /// + /// Timestamp when the purchase was refunded. Set to UNIX + /// + string RefundTime { get; } + /// /// Whether the purchase had already been validated by Nakama before. /// @@ -3689,9 +3745,14 @@ public interface IApiValidatedPurchase string TransactionId { get; } /// - /// UNIX Timestamp when the receipt validation was updated in DB. + /// Timestamp when the receipt validation was updated in DB. /// string UpdateTime { get; } + + /// + /// Purchase User ID. + /// + string UserId { get; } } /// @@ -3703,6 +3764,7 @@ internal class ApiValidatedPurchase : IApiValidatedPurchase public string CreateTime { get; set; } /// + [IgnoreDataMember] public ApiStoreEnvironment Environment => _environment; [DataMember(Name="environment"), Preserve] public ApiStoreEnvironment _environment { get; set; } @@ -3719,11 +3781,16 @@ internal class ApiValidatedPurchase : IApiValidatedPurchase [DataMember(Name="purchase_time"), Preserve] public string PurchaseTime { get; set; } + /// + [DataMember(Name="refund_time"), Preserve] + public string RefundTime { get; set; } + /// [DataMember(Name="seen_before"), Preserve] public bool SeenBefore { get; set; } /// + [IgnoreDataMember] public ApiStoreProvider Store => _store; [DataMember(Name="store"), Preserve] public ApiStoreProvider _store { get; set; } @@ -3736,6 +3803,10 @@ internal class ApiValidatedPurchase : IApiValidatedPurchase [DataMember(Name="update_time"), Preserve] public string UpdateTime { get; set; } + /// + [DataMember(Name="user_id"), Preserve] + public string UserId { get; set; } + public override string ToString() { var output = ""; @@ -3744,10 +3815,12 @@ public override string ToString() output = string.Concat(output, "ProductId: ", ProductId, ", "); output = string.Concat(output, "ProviderResponse: ", ProviderResponse, ", "); output = string.Concat(output, "PurchaseTime: ", PurchaseTime, ", "); + output = string.Concat(output, "RefundTime: ", RefundTime, ", "); output = string.Concat(output, "SeenBefore: ", SeenBefore, ", "); output = string.Concat(output, "Store: ", Store, ", "); output = string.Concat(output, "TransactionId: ", TransactionId, ", "); output = string.Concat(output, "UpdateTime: ", UpdateTime, ", "); + output = string.Concat(output, "UserId: ", UserId, ", "); return output; } } @@ -3788,11 +3861,26 @@ public interface IApiValidatedSubscription /// string ProductId { get; } + /// + /// Raw provider notification body. + /// + string ProviderNotification { get; } + + /// + /// Raw provider validation response body. + /// + string ProviderResponse { get; } + /// /// UNIX Timestamp when the purchase was done. /// string PurchaseTime { get; } + /// + /// Subscription refund time. If this time is set, the subscription was refunded. + /// + string RefundTime { get; } + /// /// Store identifier /// @@ -3802,6 +3890,11 @@ public interface IApiValidatedSubscription /// UNIX Timestamp when the receipt validation was updated in DB. /// string UpdateTime { get; } + + /// + /// Subscription User ID. + /// + string UserId { get; } } /// @@ -3817,6 +3910,7 @@ internal class ApiValidatedSubscription : IApiValidatedSubscription public string CreateTime { get; set; } /// + [IgnoreDataMember] public ApiStoreEnvironment Environment => _environment; [DataMember(Name="environment"), Preserve] public ApiStoreEnvironment _environment { get; set; } @@ -3833,11 +3927,24 @@ internal class ApiValidatedSubscription : IApiValidatedSubscription [DataMember(Name="product_id"), Preserve] public string ProductId { get; set; } + /// + [DataMember(Name="provider_notification"), Preserve] + public string ProviderNotification { get; set; } + + /// + [DataMember(Name="provider_response"), Preserve] + public string ProviderResponse { get; set; } + /// [DataMember(Name="purchase_time"), Preserve] public string PurchaseTime { get; set; } /// + [DataMember(Name="refund_time"), Preserve] + public string RefundTime { get; set; } + + /// + [IgnoreDataMember] public ApiStoreProvider Store => _store; [DataMember(Name="store"), Preserve] public ApiStoreProvider _store { get; set; } @@ -3846,6 +3953,10 @@ internal class ApiValidatedSubscription : IApiValidatedSubscription [DataMember(Name="update_time"), Preserve] public string UpdateTime { get; set; } + /// + [DataMember(Name="user_id"), Preserve] + public string UserId { get; set; } + public override string ToString() { var output = ""; @@ -3855,9 +3966,13 @@ public override string ToString() output = string.Concat(output, "ExpiryTime: ", ExpiryTime, ", "); output = string.Concat(output, "OriginalTransactionId: ", OriginalTransactionId, ", "); output = string.Concat(output, "ProductId: ", ProductId, ", "); + output = string.Concat(output, "ProviderNotification: ", ProviderNotification, ", "); + output = string.Concat(output, "ProviderResponse: ", ProviderResponse, ", "); output = string.Concat(output, "PurchaseTime: ", PurchaseTime, ", "); + output = string.Concat(output, "RefundTime: ", RefundTime, ", "); output = string.Concat(output, "Store: ", Store, ", "); output = string.Concat(output, "UpdateTime: ", UpdateTime, ", "); + output = string.Concat(output, "UserId: ", UserId, ", "); return output; } } @@ -3957,6 +4072,7 @@ internal class ApiWriteStorageObjectsRequest : IApiWriteStorageObjectsRequest { /// + [IgnoreDataMember] public IEnumerable Objects => _objects ?? new List(0); [DataMember(Name="objects"), Preserve] public List _objects { get; set; } @@ -4028,6 +4144,7 @@ internal class RpcStatus : IRpcStatus public int Code { get; set; } /// + [IgnoreDataMember] public IEnumerable Details => _details ?? new List(0); [DataMember(Name="details"), Preserve] public List _details { get; set; } @@ -4090,6 +4207,33 @@ public async Task HealthcheckAsync( await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); } + /// + /// Delete the current user's account. + /// + public async Task DeleteAccountAsync( + string bearerToken, + CancellationToken? cancellationToken) + { + + var urlpath = "/v2/account"; + + var queryParams = ""; + + var uri = new UriBuilder(_baseUri) + { + Path = urlpath, + Query = queryParams + }.Uri; + + var method = "DELETE"; + var headers = new Dictionary(); + var header = string.Concat("Bearer ", bearerToken); + headers.Add("Authorization", header); + + byte[] content = null; + await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); + } + /// /// Fetch the current user's account. /// @@ -4158,14 +4302,14 @@ public async Task UpdateAccountAsync( public async Task AuthenticateAppleAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountApple body, + ApiAccountApple account, bool? create, string username, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/apple"; @@ -4194,7 +4338,7 @@ public async Task AuthenticateAppleAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4206,14 +4350,14 @@ public async Task AuthenticateAppleAsync( public async Task AuthenticateCustomAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountCustom body, + ApiAccountCustom account, bool? create, string username, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/custom"; @@ -4242,7 +4386,7 @@ public async Task AuthenticateCustomAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4254,14 +4398,14 @@ public async Task AuthenticateCustomAsync( public async Task AuthenticateDeviceAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountDevice body, + ApiAccountDevice account, bool? create, string username, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/device"; @@ -4290,7 +4434,7 @@ public async Task AuthenticateDeviceAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4302,14 +4446,14 @@ public async Task AuthenticateDeviceAsync( public async Task AuthenticateEmailAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountEmail body, + ApiAccountEmail account, bool? create, string username, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/email"; @@ -4338,7 +4482,7 @@ public async Task AuthenticateEmailAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4350,15 +4494,15 @@ public async Task AuthenticateEmailAsync( public async Task AuthenticateFacebookAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountFacebook body, + ApiAccountFacebook account, bool? create, string username, bool? sync, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/facebook"; @@ -4390,7 +4534,7 @@ public async Task AuthenticateFacebookAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4402,14 +4546,14 @@ public async Task AuthenticateFacebookAsync( public async Task AuthenticateFacebookInstantGameAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountFacebookInstantGame body, + ApiAccountFacebookInstantGame account, bool? create, string username, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/facebookinstantgame"; @@ -4438,7 +4582,7 @@ public async Task AuthenticateFacebookInstantGameAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4450,14 +4594,14 @@ public async Task AuthenticateFacebookInstantGameAsync( public async Task AuthenticateGameCenterAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountGameCenter body, + ApiAccountGameCenter account, bool? create, string username, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/gamecenter"; @@ -4486,7 +4630,7 @@ public async Task AuthenticateGameCenterAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4498,14 +4642,14 @@ public async Task AuthenticateGameCenterAsync( public async Task AuthenticateGoogleAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountGoogle body, + ApiAccountGoogle account, bool? create, string username, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/google"; @@ -4534,7 +4678,7 @@ public async Task AuthenticateGoogleAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4546,15 +4690,15 @@ public async Task AuthenticateGoogleAsync( public async Task AuthenticateSteamAsync( string basicAuthUsername, string basicAuthPassword, - ApiAccountSteam body, + ApiAccountSteam account, bool? create, string username, bool? sync, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/authenticate/steam"; @@ -4586,7 +4730,7 @@ public async Task AuthenticateSteamAsync( } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -4733,13 +4877,13 @@ public async Task LinkEmailAsync( /// public async Task LinkFacebookAsync( string bearerToken, - ApiAccountFacebook body, + ApiAccountFacebook account, bool? sync, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/account/link/facebook"; @@ -4761,7 +4905,7 @@ public async Task LinkFacebookAsync( headers.Add("Authorization", header); byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); } @@ -5484,13 +5628,13 @@ public async Task BlockFriendsAsync( /// public async Task ImportFacebookFriendsAsync( string bearerToken, - ApiAccountFacebook body, + ApiAccountFacebook account, bool? reset, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/friend/facebook"; @@ -5512,7 +5656,7 @@ public async Task ImportFacebookFriendsAsync( headers.Add("Authorization", header); byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); } @@ -5522,13 +5666,13 @@ public async Task ImportFacebookFriendsAsync( /// public async Task ImportSteamFriendsAsync( string bearerToken, - ApiAccountSteam body, + ApiAccountSteam account, bool? reset, CancellationToken? cancellationToken) { - if (body == null) + if (account == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'account' is required but was null."); } var urlpath = "/v2/friend/steam"; @@ -5550,7 +5694,7 @@ public async Task ImportSteamFriendsAsync( headers.Add("Authorization", header); byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = account.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); } @@ -6351,16 +6495,16 @@ public async Task ListLeaderboardRecordsAsync( public async Task WriteLeaderboardRecordAsync( string bearerToken, string leaderboardId, - WriteLeaderboardRecordRequestLeaderboardRecordWrite body, + WriteLeaderboardRecordRequestLeaderboardRecordWrite record, CancellationToken? cancellationToken) { if (leaderboardId == null) { throw new ArgumentException("'leaderboardId' is required but was null."); } - if (body == null) + if (record == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'record' is required but was null."); } var urlpath = "/v2/leaderboard/{leaderboardId}"; @@ -6380,7 +6524,7 @@ public async Task WriteLeaderboardRecordAsync( headers.Add("Authorization", header); byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = record.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -6563,6 +6707,8 @@ public async Task ListNotificationsAsync( /// public async Task RpcFunc2Async( string bearerToken, + string basicAuthUsername, + string basicAuthPassword, string id, string payload, string httpKey, @@ -6597,6 +6743,12 @@ public async Task RpcFunc2Async( var header = string.Concat("Bearer ", bearerToken); headers.Add("Authorization", header); } + if (!string.IsNullOrEmpty(basicAuthUsername)) + { + var credentials = Encoding.UTF8.GetBytes(basicAuthUsername + ":" + basicAuthPassword); + var header = string.Concat("Basic ", Convert.ToBase64String(credentials)); + headers.Add("Authorization", header); + } byte[] content = null; var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); @@ -6608,8 +6760,10 @@ public async Task RpcFunc2Async( /// public async Task RpcFuncAsync( string bearerToken, + string basicAuthUsername, + string basicAuthPassword, string id, - string body, + string payload, string httpKey, CancellationToken? cancellationToken) { @@ -6617,9 +6771,9 @@ public async Task RpcFuncAsync( { throw new ArgumentException("'id' is required but was null."); } - if (body == null) + if (payload == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'payload' is required but was null."); } var urlpath = "/v2/rpc/{id}"; @@ -6643,9 +6797,15 @@ public async Task RpcFuncAsync( var header = string.Concat("Bearer ", bearerToken); headers.Add("Authorization", header); } + if (!string.IsNullOrEmpty(basicAuthUsername)) + { + var credentials = Encoding.UTF8.GetBytes(basicAuthUsername + ":" + basicAuthPassword); + var header = string.Concat("Basic ", Convert.ToBase64String(credentials)); + headers.Add("Authorization", header); + } byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = payload.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -6992,16 +7152,16 @@ public async Task ListTournamentRecordsAsync( public async Task WriteTournamentRecord2Async( string bearerToken, string tournamentId, - WriteTournamentRecordRequestTournamentRecordWrite body, + WriteTournamentRecordRequestTournamentRecordWrite record, CancellationToken? cancellationToken) { if (tournamentId == null) { throw new ArgumentException("'tournamentId' is required but was null."); } - if (body == null) + if (record == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'record' is required but was null."); } var urlpath = "/v2/tournament/{tournamentId}"; @@ -7021,7 +7181,7 @@ public async Task WriteTournamentRecord2Async( headers.Add("Authorization", header); byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = record.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); @@ -7033,16 +7193,16 @@ public async Task WriteTournamentRecord2Async( public async Task WriteTournamentRecordAsync( string bearerToken, string tournamentId, - WriteTournamentRecordRequestTournamentRecordWrite body, + WriteTournamentRecordRequestTournamentRecordWrite record, CancellationToken? cancellationToken) { if (tournamentId == null) { throw new ArgumentException("'tournamentId' is required but was null."); } - if (body == null) + if (record == null) { - throw new ArgumentException("'body' is required but was null."); + throw new ArgumentException("'record' is required but was null."); } var urlpath = "/v2/tournament/{tournamentId}"; @@ -7062,7 +7222,7 @@ public async Task WriteTournamentRecordAsync( headers.Add("Authorization", header); byte[] content = null; - var jsonBody = body.ToJson(); + var jsonBody = record.ToJson(); content = Encoding.UTF8.GetBytes(jsonBody); var contents = await HttpAdapter.SendAsync(method, uri, headers, content, Timeout, cancellationToken); return contents.FromJson(); diff --git a/Nakama/Client.cs b/Nakama/Client.cs index 2cdb02f2..47668296 100644 --- a/Nakama/Client.cs +++ b/Nakama/Client.cs @@ -331,6 +331,21 @@ public async Task CreateGroupAsync(ISession session, string name, str }, canceller), new RetryHistory(session, retryConfiguration ?? GlobalRetryConfiguration, canceller)); } + /// + public async Task DeleteAccountAsync(ISession session, RetryConfiguration retryConfiguration = null, + CancellationToken canceller = default) + { + if (AutoRefreshSession && !string.IsNullOrEmpty(session.RefreshToken) && + session.HasExpired(DateTime.UtcNow.Add(DefaultExpiredTimeSpan))) + { + await SessionRefreshAsync(session, null, retryConfiguration, canceller); + } + + await _retryInvoker.InvokeWithRetry( + () => _apiClient.DeleteAccountAsync(session.AuthToken, canceller), + new RetryHistory(session, retryConfiguration ?? GlobalRetryConfiguration, canceller)); + } + /// public async Task DeleteFriendsAsync(ISession session, IEnumerable ids, IEnumerable usernames = null, RetryConfiguration retryConfiguration = null, @@ -1155,7 +1170,7 @@ public async Task RpcAsync(ISession session, string id, string payload, } return await _retryInvoker.InvokeWithRetry( - () => _apiClient.RpcFuncAsync(session.AuthToken, id, payload, null, canceller), + () => _apiClient.RpcFuncAsync(session.AuthToken, string.Empty, string.Empty, id, payload, null, canceller), new RetryHistory(session, retryConfiguration ?? GlobalRetryConfiguration, canceller)); } @@ -1170,20 +1185,20 @@ public async Task RpcAsync(ISession session, string id, RetryConfigurat } return await _retryInvoker.InvokeWithRetry( - () => _apiClient.RpcFunc2Async(session.AuthToken, id, null, null, canceller), + () => _apiClient.RpcFunc2Async(session.AuthToken, string.Empty, string.Empty, id, null, null, canceller), new RetryHistory(session, retryConfiguration ?? GlobalRetryConfiguration, canceller)); } /// public Task RpcAsync(string httpkey, string id, string payload, RetryConfiguration retryConfiguration = null, CancellationToken canceller = default) => - _retryInvoker.InvokeWithRetry(() => _apiClient.RpcFuncAsync(null, id, payload, httpkey, canceller), + _retryInvoker.InvokeWithRetry(() => _apiClient.RpcFuncAsync(null, string.Empty, string.Empty, id, payload, httpkey, canceller), new RetryHistory(id, retryConfiguration ?? GlobalRetryConfiguration, canceller)); /// public Task RpcAsync(string httpkey, string id, RetryConfiguration retryConfiguration = null, CancellationToken canceller = default) => - _retryInvoker.InvokeWithRetry(() => _apiClient.RpcFunc2Async(null, id, null, httpkey, canceller), + _retryInvoker.InvokeWithRetry(() => _apiClient.RpcFunc2Async(null, string.Empty, string.Empty, id, null, httpkey, canceller), new RetryHistory(id, retryConfiguration ?? GlobalRetryConfiguration, canceller)); /// diff --git a/Nakama/IClient.cs b/Nakama/IClient.cs index f94990d8..23eb5031 100644 --- a/Nakama/IClient.cs +++ b/Nakama/IClient.cs @@ -236,6 +236,15 @@ Task AuthenticateSteamAsync(string token, string username = null, bool Task CreateGroupAsync(ISession session, string name, string description = "", string avatarUrl = null, string langTag = null, bool open = true, int maxCount = 100, RetryConfiguration retryConfiguration = null, CancellationToken canceller = default); + /// + /// Delete the current user's account. Note that this will invalidate your session, requiring you to reauthenticate. + /// + /// The session of the user. + /// The retry configuration. See + /// The that can be used to cancel the request while mid-flight. + /// A task which represents the asynchronous operation. + Task DeleteAccountAsync(ISession session, RetryConfiguration retryConfiguration = null, CancellationToken canceller = default); + /// /// Delete one more or users by id or username from friends. /// @@ -796,7 +805,7 @@ Task ListUsersStorageObjectsAsync(ISession session, strin /// The that can be used to cancel the request while mid-flight. /// A task to resolve an RPC response. Task RpcAsync(string httpKey, string id, string payload, RetryConfiguration retryConfiguration = null, CancellationToken canceller = default); - + /// /// Execute a function on the server without a session. /// diff --git a/codegen/main.go b/codegen/main.go index 0b8ec4e2..491089c6 100755 --- a/codegen/main.go +++ b/codegen/main.go @@ -178,6 +178,7 @@ namespace {{.Namespace}} [DataMember(Name="{{ $attrDataName }}"), Preserve] public List {{ $fieldname }} { get; set; } {{- else}} + [IgnoreDataMember] public IEnumerable {{ $fieldname }} => _{{ $propname | snakeToCamel }} ?? new List<{{ $property.Items.Ref | cleanRef }}>(0); [DataMember(Name="{{ $attrDataName }}"), Preserve] public List<{{ $property.Items.Ref | cleanRef }}> _{{ $propname | snakeToCamel }} { get; set; } @@ -185,35 +186,43 @@ namespace {{.Namespace}} {{- else if eq $property.Type "object"}} {{- if eq $property.AdditionalProperties.Type "string"}} {{- if eq $property.AdditionalProperties.Format "int64" }} + [IgnoreDataMember] public IDictionary {{ $fieldname }} => ApiClient.DeserializeIntProperties(_{{ $propname | snakeToCamel }}) ?? new Dictionary(); [DataMember(Name="{{ $attrDataName }}"), Preserve] public Dictionary _{{ $propname | snakeToCamel }} { get; set; } {{- else }} + [IgnoreDataMember] public IDictionary {{ $fieldname }} => _{{ $propname | snakeToCamel }} ?? new Dictionary(); [DataMember(Name="{{ $attrDataName }}"), Preserve] public Dictionary _{{ $propname | snakeToCamel }} { get; set; } {{- end }} {{- else if eq $property.AdditionalProperties.Type "integer"}} + [IgnoreDataMember] public IDictionary {{ $fieldname }} => _{{ $propname | snakeToCamel }} ?? new Dictionary(); [DataMember(Name="{{ $attrDataName }}"), Preserve] {{- else if eq $property.AdditionalProperties.Type "number"}} + [IgnoreDataMember] public IDictionary {{ $fieldname }} => _{{ $propname | snakeToCamel }} ?? new Dictionary(); [DataMember(Name="{{ $attrDataName }}"), Preserve] public Dictionary _{{ $propname | snakeToCamel }} { get; set; } {{- else if eq $property.AdditionalProperties.Type "boolean"}} + [IgnoreDataMember] public IDictionary {{ $fieldname }} => _{{ $propname | snakeToCamel }} ?? new Dictionary(); [DataMember(Name="{{ $attrDataName }}"), Preserve] public Dictionary _{{ $propname | snakeToCamel }} { get; set; } {{- else}} + [IgnoreDataMember] public IDictionary {{ $fieldname }} => _{{ $propname | snakeToCamel }} ?? new Dictionary(); [DataMember(Name="{{ $attrDataName }}"), Preserve] public Dictionary _{{ $propname | snakeToCamel }} { get; set; } {{- end}} {{- else if isRefToEnum (cleanRef $property.Ref) }} + [IgnoreDataMember] public {{ $property.Ref | cleanRef }} {{ $fieldname }} => _{{ $propname | snakeToCamel }}; [DataMember(Name="{{ $attrDataName }}"), Preserve] public {{ $property.Ref | cleanRef }} _{{ $propname | snakeToCamel }} { get; set; } {{- else }} + [IgnoreDataMember] public I{{ $property.Ref | cleanRef }} {{ $fieldname }} => _{{ $propname | snakeToCamel }}; [DataMember(Name="{{ $attrDataName }}"), Preserve] public {{ $property.Ref | cleanRef }} _{{ $propname | snakeToCamel }} { get; set; }