/** * 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. */ using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Threading.Tasks; namespace Nakama { /// public class Client : IClient { private readonly ApiClient _apiClient; private readonly ClientOptions _options; public Client(string serverKey = ClientOptions.DefaultServerKey, string host = ClientOptions.DefaultHost, int port = ClientOptions.DefaultPort, bool secure = false) : this(new ClientOptions { EnableSsl = secure, Host = host, Port = port, ServerKey = serverKey }) { } public Client(ClientOptions options) { // FIXME move into ClientOptions object. Logger = NullLogger.Instance; // don't log by default. Retries = 3; Trace = false; Timeout = 5000; options.ValidateOptions(); _options = options.Clone(); ServicePointManager.ServerCertificateValidationCallback = _options.ServerCertificateValidationCallback; // Use GZip compression with request/responses. var handler = new HttpClientHandler(); if (handler.SupportsAutomaticDecompression && _options.AutomaticDecompression) handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; var httpClient = new HttpClient(handler); if (_options.AutomaticCompression) httpClient = new HttpClient(new GZipHttpClientHandler(handler)); var scheme = _options.EnableSsl ? Uri.UriSchemeHttps : Uri.UriSchemeHttp; _apiClient = new ApiClient(new UriBuilder(scheme, _options.Host, _options.Port).Uri, httpClient); } /// public string Host => _options.Host; /// public ILogger Logger { get; set; } /// public int Port => _options.Port; /// public int Retries { get; set; } /// public string ServerKey => _options.ServerKey; /// public bool Secure => _options.EnableSsl; /// public bool Trace { get; set; } /// public int Timeout { get; set; } /// public async Task AddFriendsAsync(ISession session, IEnumerable ids, IEnumerable usernames = null) { await _apiClient.AddFriendsAsync(session.AuthToken, ids, usernames); } /// public async Task AddGroupUsersAsync(ISession session, string groupId, IEnumerable ids) { await _apiClient.AddGroupUsersAsync(session.AuthToken, groupId, ids); } /// public async Task AuthenticateCustomAsync(string id, string username = null, bool create = true) { var request = new ApiAccountCustom {Id = id}; var resp = await _apiClient.AuthenticateCustomAsync(ServerKey, string.Empty, request, create, username); return Session.Restore(resp.Token, resp.Created); } /// public async Task AuthenticateDeviceAsync(string id, string username = null, bool create = true) { var request = new ApiAccountDevice {Id = id}; var resp = await _apiClient.AuthenticateDeviceAsync(ServerKey, string.Empty, request, create, username); return Session.Restore(resp.Token, resp.Created); } /// public async Task AuthenticateEmailAsync(string email, string password, string username = null, bool create = true) { var request = new ApiAccountEmail {Email = email, Password = password}; var resp = await _apiClient.AuthenticateEmailAsync(ServerKey, string.Empty, request, create, username); return Session.Restore(resp.Token, resp.Created); } /// public async Task AuthenticateFacebookAsync(string token, string username = null, bool create = true, bool import = true) { var request = new ApiAccountFacebook {Token = token}; var resp = await _apiClient.AuthenticateFacebookAsync(ServerKey, string.Empty, request, create, username, import); return Session.Restore(resp.Token, resp.Created); } /// public async Task AuthenticateGameCenterAsync(string bundleId, string playerId, string publicKeyUrl, string salt, string signature, string timestampSeconds, string username = null, bool create = true) { var request = new ApiAccountGameCenter { BundleId = bundleId, PlayerId = playerId, PublicKeyUrl = publicKeyUrl, Salt = salt, Signature = signature, TimestampSeconds = timestampSeconds }; var resp = await _apiClient.AuthenticateGameCenterAsync(ServerKey, string.Empty, request, create, username); return Session.Restore(resp.Token, resp.Created); } /// public async Task AuthenticateGoogleAsync(string token, string username = null, bool create = true) { var request = new ApiAccountGoogle {Token = token}; var resp = await _apiClient.AuthenticateGoogleAsync(ServerKey, string.Empty, request, create, username); return Session.Restore(resp.Token, resp.Created); } /// public async Task AuthenticateSteamAsync(string token, string username = null, bool create = true) { var request = new ApiAccountSteam {Token = token}; var resp = await _apiClient.AuthenticateSteamAsync(ServerKey, string.Empty, request, create, username); return Session.Restore(resp.Token, resp.Created); } /// public async Task BlockFriendsAsync(ISession session, IEnumerable ids, IEnumerable usernames = null) { await _apiClient.BlockFriendsAsync(session.AuthToken, ids, usernames); } /// public async Task CreateGroupAsync(ISession session, string name, string description = "", string avatarUrl = null, string langTag = null, bool open = true) { var request = new ApiCreateGroupRequest { Name = name, Description = description, AvatarUrl = avatarUrl, LangTag = langTag, Open = open }; return await _apiClient.CreateGroupAsync(session.AuthToken, request); } /// public async Task DeleteFriendsAsync(ISession session, IEnumerable ids, IEnumerable usernames = null) { await _apiClient.DeleteFriendsAsync(session.AuthToken, ids, usernames); } /// public async Task DeleteGroupAsync(ISession session, string groupId) { await _apiClient.DeleteGroupAsync(session.AuthToken, groupId); } /// public async Task DeleteLeaderboardRecordAsync(ISession session, string leaderboardId) { await _apiClient.DeleteLeaderboardRecordAsync(session.AuthToken, leaderboardId); } /// public async Task DeleteNotificationsAsync(ISession session, IEnumerable ids) { await _apiClient.DeleteNotificationsAsync(session.AuthToken, ids); } /// public async Task DeleteStorageObjectsAsync(ISession session, params StorageObjectId[] ids) { var objects = new List(ids.Length); foreach (var id in ids) objects.Add(new ApiDeleteStorageObjectId { Collection = id.Collection, Key = id.Key, Version = id.Version }); var request = new ApiDeleteStorageObjectsRequest {_objectIds = objects}; await _apiClient.DeleteStorageObjectsAsync(session.AuthToken, request); } /// public async Task GetAccountAsync(ISession session) { return await _apiClient.GetAccountAsync(session.AuthToken); } /// public async Task GetUsersAsync(ISession session, IEnumerable ids, IEnumerable usernames = null, IEnumerable facebookIds = null) { return await _apiClient.GetUsersAsync(session.AuthToken, ids, usernames, facebookIds); } /// public async Task ImportFacebookFriendsAsync(ISession session, string token, bool reset = false) { var request = new ApiAccountFacebook {Token = token}; await _apiClient.ImportFacebookFriendsAsync(session.AuthToken, request, reset); } /// public async Task JoinGroupAsync(ISession session, string groupId) { await _apiClient.JoinGroupAsync(session.AuthToken, groupId); } /// public async Task JoinTournamentAsync(ISession session, string tournamentId) { await _apiClient.JoinTournamentAsync(session.AuthToken, tournamentId); } /// public async Task KickGroupUsersAsync(ISession session, string groupId, IEnumerable ids) { await _apiClient.KickGroupUsersAsync(session.AuthToken, groupId, ids); } /// public async Task LeaveGroupAsync(ISession session, string groupId) { await _apiClient.LeaveGroupAsync(session.AuthToken, groupId); } /// public async Task LinkCustomAsync(ISession session, string id) { var request = new ApiAccountCustom {Id = id}; await _apiClient.LinkCustomAsync(session.AuthToken, request); } /// public async Task LinkDeviceAsync(ISession session, string id) { var request = new ApiAccountDevice {Id = id}; await _apiClient.LinkDeviceAsync(session.AuthToken, request); } /// public async Task LinkEmailAsync(ISession session, string email, string password) { var request = new ApiAccountEmail {Email = email, Password = password}; await _apiClient.LinkEmailAsync(session.AuthToken, request); } /// public async Task LinkFacebookAsync(ISession session, string token, bool import = true) { var request = new ApiAccountFacebook {Token = token}; await _apiClient.LinkFacebookAsync(session.AuthToken, request, import); } /// public async Task LinkGameCenterAsync(ISession session, string bundleId, string playerId, string publicKeyUrl, string salt, string signature, string timestampSeconds) { var request = new ApiAccountGameCenter { BundleId = bundleId, PlayerId = playerId, PublicKeyUrl = publicKeyUrl, Salt = salt, Signature = signature, TimestampSeconds = timestampSeconds }; await _apiClient.LinkGameCenterAsync(session.AuthToken, request); } /// public async Task LinkGoogleAsync(ISession session, string token) { var request = new ApiAccountGoogle {Token = token}; await _apiClient.LinkGoogleAsync(session.AuthToken, request); } /// public async Task LinkSteamAsync(ISession session, string token) { var request = new ApiAccountSteam {Token = token}; await _apiClient.LinkSteamAsync(session.AuthToken, request); } /// public async Task ListChannelMessagesAsync(ISession session, string channelId, int limit = 1, bool forward = true, string cursor = null) { return await _apiClient.ListChannelMessagesAsync(session.AuthToken, channelId, limit, forward, cursor); } /// public async Task ListFriendsAsync(ISession session) { return await _apiClient.ListFriendsAsync(session.AuthToken); } /// public async Task ListGroupUsersAsync(ISession session, string groupId) { return await _apiClient.ListGroupUsersAsync(session.AuthToken, groupId); } /// public async Task ListGroupsAsync(ISession session, string name = null, int limit = 1, string cursor = null) { return await _apiClient.ListGroupsAsync(session.AuthToken, name, cursor, limit); } /// public async Task ListLeaderboardRecordsAsync(ISession session, string leaderboardId, IEnumerable ownerIds = null, int limit = 1, string cursor = null) { return await _apiClient.ListLeaderboardRecordsAsync(session.AuthToken, leaderboardId, ownerIds, limit, cursor); } /// public async Task ListLeaderboardRecordsAroundOwnerAsync(ISession session, string leaderboardId, string ownerId, int limit = 1) { return await _apiClient.ListLeaderboardRecordsAroundOwnerAsync(session.AuthToken, leaderboardId, ownerId, limit); } /// public async Task ListMatchesAsync(ISession session, int min, int max, int limit, bool authoritative, string label, string query = null) { // Arguments are re-ordered for more natural usage than is code generated. return await _apiClient.ListMatchesAsync(session.AuthToken, limit, authoritative, label, min, max, query); } /// public async Task ListNotificationsAsync(ISession session, int limit = 1, string cacheableCursor = null) { return await _apiClient.ListNotificationsAsync(session.AuthToken, limit, cacheableCursor); } /// public async Task ListStorageObjects(ISession session, string collection, int limit, string cursor) { return await _apiClient.ListStorageObjectsAsync(session.AuthToken, collection, "", limit, cursor); } /// public async Task ListTournamentRecordsAroundOwnerAsync(ISession session, string tournamentId, string ownerId, int limit = 1) { return await _apiClient.ListTournamentRecordsAroundOwnerAsync(session.AuthToken, tournamentId, ownerId, limit); } /// public async Task ListTournamentRecordsAsync(ISession session, string tournamentId, IEnumerable ownerIds = null, int limit = 1, string cursor = null) { return await _apiClient.ListTournamentRecordsAsync(session.AuthToken, tournamentId, ownerIds, limit, cursor); } /// public async Task ListTournamentsAsync(ISession session, int categoryStart, int categoryEnd, int startTime, int endTime, int limit = 1, string cursor = null) { return await _apiClient.ListTournamentsAsync(session.AuthToken, categoryStart, categoryEnd, startTime, endTime, limit, cursor); } /// public async Task ListUserGroupsAsync(ISession session) { return await ListUserGroupsAsync(session, session.UserId); } /// public async Task ListUserGroupsAsync(ISession session, string userId) { return await _apiClient.ListUserGroupsAsync(session.AuthToken, userId); } /// public async Task ListUsersStorageObjectsAsync(ISession session, string collection, string userId, int limit, string cursor) { return await _apiClient.ListStorageObjects2Async(session.AuthToken, collection, userId, limit, cursor); } /// public async Task PromoteGroupUsersAsync(ISession session, string groupId, IEnumerable ids) { await _apiClient.PromoteGroupUsersAsync(session.AuthToken, groupId, ids); } /// public async Task ReadStorageObjectsAsync(ISession session, params IApiReadStorageObjectId[] ids) { var wrapper = new List(ids.Length); foreach (var id in ids) wrapper.Add(new ApiReadStorageObjectId { Collection = id.Collection, Key = id.Key, UserId = id.UserId }); var request = new ApiReadStorageObjectsRequest {_objectIds = wrapper}; return await _apiClient.ReadStorageObjectsAsync(session.AuthToken, request); } /// public async Task RpcAsync(ISession session, string id, string payload) { return await _apiClient.RpcFuncAsync(session.AuthToken, id, payload); } /// public async Task RpcAsync(ISession session, string id) { return await _apiClient.RpcFunc2Async(session.AuthToken, id, null, null); } /// public async Task RpcAsync(string httpKey, string id, string payload = null) { return await _apiClient.RpcFunc2Async(null, id, payload, httpKey); } /// public async Task UnlinkCustomAsync(ISession session, string id) { var request = new ApiAccountCustom {Id = id}; await _apiClient.UnlinkCustomAsync(session.AuthToken, request); } /// public async Task UnlinkDeviceAsync(ISession session, string id) { var request = new ApiAccountDevice {Id = id}; await _apiClient.UnlinkDeviceAsync(session.AuthToken, request); } /// public async Task UnlinkEmailAsync(ISession session, string email, string password) { var request = new ApiAccountEmail {Email = email, Password = password}; await _apiClient.UnlinkEmailAsync(session.AuthToken, request); } /// public async Task UnlinkFacebookAsync(ISession session, string token) { var request = new ApiAccountFacebook {Token = token}; await _apiClient.UnlinkFacebookAsync(session.AuthToken, request); } /// public async Task UnlinkGameCenterAsync(ISession session, string bundleId, string playerId, string publicKeyUrl, string salt, string signature, string timestampSeconds) { var request = new ApiAccountGameCenter { BundleId = bundleId, PlayerId = playerId, PublicKeyUrl = publicKeyUrl, Salt = salt, Signature = signature, TimestampSeconds = timestampSeconds }; await _apiClient.UnlinkGameCenterAsync(session.AuthToken, request); } /// public async Task UnlinkGoogleAsync(ISession session, string token) { var request = new ApiAccountGoogle {Token = token}; await _apiClient.UnlinkGoogleAsync(session.AuthToken, request); } /// public async Task UnlinkSteamAsync(ISession session, string token) { var request = new ApiAccountSteam {Token = token}; await _apiClient.UnlinkSteamAsync(session.AuthToken, request); } /// public async Task UpdateAccountAsync(ISession session, string username, string displayName = null, string avatarUrl = null, string langTag = null, string location = null, string timezone = null) { var request = new ApiUpdateAccountRequest { AvatarUrl = avatarUrl, DisplayName = displayName, LangTag = langTag, Location = location, Timezone = timezone, Username = username }; await _apiClient.UpdateAccountAsync(session.AuthToken, request); } /// public async Task UpdateGroupAsync(ISession session, string groupId, string name, string description = null, string avatarUrl = null, string langTag = null, bool open = false) { var request = new ApiUpdateGroupRequest { AvatarUrl = avatarUrl, Description = description, LangTag = langTag, Name = name, Open = open }; await _apiClient.UpdateGroupAsync(session.AuthToken, groupId, request); } /// public async Task WriteLeaderboardRecordAsync(ISession session, string leaderboardId, long score, long subscore = 0L, string metadata = null) { var request = new WriteLeaderboardRecordRequestLeaderboardRecordWrite { Metadata = metadata, Score = score.ToString(), Subscore = subscore.ToString() }; return await _apiClient.WriteLeaderboardRecordAsync(session.AuthToken, leaderboardId, request); } /// public async Task WriteStorageObjectsAsync(ISession session, params IApiWriteStorageObject[] objects) { var wrapper = new List(objects.Length); foreach (var o in objects) wrapper.Add(new ApiWriteStorageObject { Collection = o.Collection, Key = o.Key, PermissionRead = o.PermissionRead, PermissionWrite = o.PermissionWrite, Value = o.Value, Version = o.Version }); var request = new ApiWriteStorageObjectsRequest {_objects = wrapper}; return await _apiClient.WriteStorageObjectsAsync(session.AuthToken, request); } /// public async Task WriteTournamentRecordAsync(ISession session, string tournamentId, long score, long subscore = 0L, string metadata = null) { var request = new WriteTournamentRecordRequestTournamentRecordWrite { Metadata = metadata, Score = score.ToString(), Subscore = subscore.ToString() }; return await _apiClient.WriteTournamentRecordAsync(session.AuthToken, tournamentId, request); } /// public ISocket CreateWebSocket(int reconnect = 3) { var scheme = _options.EnableSsl ? "wss" : "ws"; var baseUri = new UriBuilder(scheme, Host, Port); // FIXME implement reconnect events? return new WebSocketWrapper(baseUri.Uri, Logger, Timeout); } } }