Skip to content

Commit

Permalink
Switch to new RunGameAsync API
Browse files Browse the repository at this point in the history
  • Loading branch information
VladimirKhil committed Feb 24, 2024
1 parent eca5453 commit f98e983
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 344 deletions.
161 changes: 2 additions & 159 deletions src/Common/SI.GameServer.Client/GameServerClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,13 @@ namespace SI.GameServer.Client;
/// </summary>
public sealed class GameServerClient : IGameServerClient
{
private const int _BufferSize = 80 * 1024;

private bool _isOpened;

private readonly GameServerClientOptions _options;

private readonly CookieContainer _cookieContainer;
private readonly HttpClientHandler _httpClientHandler;
private readonly HttpClient _client;
private readonly ProgressMessageHandler _progressMessageHandler;

private HubConnection? _connection;

Expand All @@ -56,7 +53,6 @@ private HubConnection Connection
public event Action<string>? Joined;
public event Action<string>? Leaved;
public event Action<string, string>? Receieve;
public event Action<int>? UploadProgress;
public event Action<Message>? IncomingMessage;

public event Func<Exception?, Task>? Closed;
Expand All @@ -73,10 +69,7 @@ public GameServerClient(IOptions<GameServerClientOptions> options, IUIThreadExec
_cookieContainer = new CookieContainer();
_httpClientHandler = new HttpClientHandler { CookieContainer = _cookieContainer };

_progressMessageHandler = new ProgressMessageHandler(_httpClientHandler);
_progressMessageHandler.HttpSendProgress += MessageHandler_HttpSendProgress;

_client = new HttpClient(_progressMessageHandler)
_client = new HttpClient(_httpClientHandler)
{
BaseAddress = new Uri(ServiceUri),
Timeout = _options.Timeout,
Expand All @@ -87,74 +80,6 @@ public GameServerClient(IOptions<GameServerClientOptions> options, IUIThreadExec
public Task<RunGameResponse> RunGameAsync(RunGameRequest runGameRequest, CancellationToken cancellationToken = default) =>
Connection.InvokeAsync<RunGameResponse>("RunGame", runGameRequest, cancellationToken);

public Task<GameCreationResult> CreateGameAsync(
GameSettingsCore<AppSettingsCore> gameSettings,
PackageKey packageKey,
ComputerAccountInfo[] computerAccounts,
CancellationToken cancellationToken = default)
{
gameSettings.AppSettings.Culture = Thread.CurrentThread.CurrentUICulture.Name;

return _connection.InvokeAsync<GameCreationResult>(
"CreateGame",
gameSettings,
packageKey,
computerAccounts.Select(ca => ca.Account).ToArray(),
cancellationToken);
}

public Task<GameCreationResult> CreateGame2Async(
GameSettingsCore<AppSettingsCore> gameSettings,
PackageInfo packageInfo,
ComputerAccountInfo[] computerAccounts,
CancellationToken cancellationToken = default)
{
gameSettings.AppSettings.Culture = Thread.CurrentThread.CurrentUICulture.Name;

return Connection.InvokeAsync<GameCreationResult>(
"CreateGame2",
gameSettings,
packageInfo,
computerAccounts.Select(ca => ca.Account).ToArray(),
cancellationToken);
}

public Task<GameCreationResult> CreateAndJoinGameAsync(
GameSettingsCore<AppSettingsCore> gameSettings,
PackageKey packageKey,
ComputerAccountInfo[] computerAccounts,
bool isMale,
CancellationToken cancellationToken = default)
{
gameSettings.AppSettings.Culture = Thread.CurrentThread.CurrentUICulture.Name;

return _connection.InvokeAsync<GameCreationResult>(
"CreateAndJoinGameNew",
gameSettings,
packageKey,
computerAccounts.Select(ca => ca.Account).ToArray(),
isMale,
cancellationToken);
}

public Task<GameCreationResult> CreateAndJoinGame2Async(
GameSettingsCore<AppSettingsCore> gameSettings,
PackageInfo packageInfo,
ComputerAccountInfo[] computerAccounts,
bool isMale,
CancellationToken cancellationToken = default)
{
gameSettings.AppSettings.Culture = Thread.CurrentThread.CurrentUICulture.Name;

return Connection.InvokeAsync<GameCreationResult>(
"CreateAndJoinGame2",
gameSettings,
packageInfo,
computerAccounts.Select(ca => ca.Account).ToArray(),
isMale,
cancellationToken);
}

public async ValueTask DisposeAsync()
{
if (_connection != null)
Expand All @@ -179,7 +104,7 @@ public Task<Slice<GameInfo>> GetGamesAsync(int fromId, CancellationToken cancell
_connection.InvokeAsync<Slice<GameInfo>>("GetGamesSlice", fromId, cancellationToken);

public Task<HostInfo> GetGamesHostInfoAsync(CancellationToken cancellationToken = default) =>
_connection.InvokeAsync<HostInfo>("GetGamesHostInfo", cancellationToken);
_connection.InvokeAsync<HostInfo>("GetGamesHostInfoNew", Thread.CurrentThread.CurrentUICulture.Name, cancellationToken);

public Task<string> GetNewsAsync(CancellationToken cancellationToken = default) =>
_connection.InvokeAsync<string>("GetNews", cancellationToken);
Expand All @@ -190,12 +115,6 @@ public Task<ChatMessage[]> GetLatestChatMessagesAsync(CancellationToken cancella
public Task<string[]> GetUsersAsync(CancellationToken cancellationToken = default) =>
_connection.InvokeAsync<string[]>("GetUsers", cancellationToken);

public Task<bool> HasPackageAsync(PackageKey packageKey, CancellationToken cancellationToken = default) =>
_connection.InvokeAsync<bool>("HasPackage", packageKey, cancellationToken);

public Task<string> HasImageAsync(FileKey imageKey, CancellationToken cancellationToken = default) =>
_connection.InvokeAsync<string>("HasPicture", imageKey, cancellationToken);

private async Task<string> AuthenticateUserAsync(
string user,
string password,
Expand Down Expand Up @@ -287,80 +206,6 @@ public async Task OpenAsync(string userName, CancellationToken cancellationToken

public Task SayAsync(string message) => _connection.InvokeAsync("Say", message);

public async Task UploadPackageAsync(FileKey packageKey, Stream stream, CancellationToken cancellationToken = default)
{
var url = "api/upload/package";
using var content = new StreamContent(stream, _BufferSize);

try
{
using var formData = new MultipartFormDataContent
{
{ content, "file", packageKey.Name }
};

formData.Headers.ContentMD5 = packageKey.Hash;
using var response = await _client.PostAsync(url, formData, cancellationToken);

if (!response.IsSuccessStatusCode)
{
var errorMessage = await GetErrorMessageAsync(response, cancellationToken);
throw new Exception(errorMessage);
}
}
catch (HttpRequestException exc)
{
throw new Exception(Resources.UploadPackageConnectionError, exc.InnerException ?? exc);
}
catch (TaskCanceledException exc)
{
if (!exc.CancellationToken.IsCancellationRequested)
{
throw new Exception(Resources.UploadPackageTimeout, exc);
}

throw exc;
}
}

public async Task<string> UploadImageAsync(FileKey imageKey, Stream data, CancellationToken cancellationToken = default)
{
var uri = "api/upload/image";

var bytesContent = new StreamContent(data, _BufferSize);

using var formData = new MultipartFormDataContent
{
{ bytesContent, Convert.ToBase64String(imageKey.Hash), imageKey.Name }
};

formData.Headers.ContentMD5 = imageKey.Hash;

var response = await _client.PostAsync(uri, formData, cancellationToken);

if (!response.IsSuccessStatusCode)
{
var errorString = await response.Content.ReadAsStringAsync(cancellationToken);
throw new Exception($"{response.StatusCode}: {errorString}");
}

return await response.Content.ReadAsStringAsync(cancellationToken);
}

public Task<GameCreationResult> JoinGameAsync(
int gameId,
GameRole role,
bool isMale,
string password,
CancellationToken cancellationToken = default) =>
_connection.InvokeAsync<GameCreationResult>("JoinGameNew", gameId, (int)role, isMale, password, cancellationToken);

public Task SendMessageAsync(Message message, CancellationToken cancellationToken = default) =>
_connection.InvokeAsync("SendMessage", message, cancellationToken);

public Task LeaveGameAsync(CancellationToken cancellationToken = default) =>
_connection.InvokeAsync("LeaveGame", cancellationToken);

private static async Task<string> GetErrorMessageAsync(HttpResponseMessage response, CancellationToken cancellationToken)
{
var serverError = await response.Content.ReadAsStringAsync(cancellationToken);
Expand Down Expand Up @@ -392,8 +237,6 @@ private void OnUI(Action action)
action();
}

private void MessageHandler_HttpSendProgress(object? sender, HttpProgressEventArgs e) => UploadProgress?.Invoke(e.ProgressPercentage);

private sealed class ReconnectPolicy : IRetryPolicy
{
public TimeSpan? NextRetryDelay(RetryContext retryContext) => TimeSpan.FromSeconds(5);
Expand Down
78 changes: 17 additions & 61 deletions src/Common/SI.GameServer.Client/IGameServerClient.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
using SI.GameServer.Contract;
using SIData;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

Expand All @@ -10,10 +8,25 @@ namespace SI.GameServer.Client;
/// <summary>
/// Provides a client to SIGame server.
/// </summary>
public interface IGameServerClient : IGameClient
public interface IGameServerClient : IAsyncDisposable
{
string ServiceUri { get; }

/// <summary>
/// Reconnecting event.
/// </summary>
event Func<Exception?, Task> Reconnecting;

/// <summary>
/// Reconnected event.
/// </summary>
event Func<string?, Task> Reconnected;

/// <summary>
/// Connection closed event.
/// </summary>
event Func<Exception?, Task> Closed;

event Action<GameInfo> GameCreated;
event Action<int> GameDeleted;
event Action<GameInfo> GameChanged;
Expand All @@ -22,8 +35,6 @@ public interface IGameServerClient : IGameClient
event Action<string> Leaved;
event Action<string, string> Receieve;

event Action<int> UploadProgress;

Task OpenAsync(string userName, CancellationToken token = default);

/// <summary>
Expand All @@ -50,62 +61,7 @@ public interface IGameServerClient : IGameClient

Task<Slice<GameInfo>> GetGamesAsync(int fromId, CancellationToken cancellationToken = default);

Task<bool> HasPackageAsync(PackageKey packageKey, CancellationToken cancellationToken = default);

Task UploadPackageAsync(FileKey packageHash, Stream stream, CancellationToken cancellationToken = default);

Task<RunGameResponse> RunGameAsync(
RunGameRequest runGameRequest,
CancellationToken cancellationToken = default);

Task<GameCreationResult> CreateGameAsync(
GameSettingsCore<AppSettingsCore> gameSettings,
PackageKey packageKey,
ComputerAccountInfo[] computerAccounts,
CancellationToken cancellationToken = default);

Task<GameCreationResult> CreateGame2Async(
GameSettingsCore<AppSettingsCore> gameSettings,
PackageInfo packageInfo,
ComputerAccountInfo[] computerAccounts,
CancellationToken cancellationToken = default);

Task<string> HasImageAsync(FileKey imageKey, CancellationToken cancellationToken = default);

Task<string> UploadImageAsync(FileKey imageKey, Stream data, CancellationToken cancellationToken = default);
Task<RunGameResponse> RunGameAsync(RunGameRequest runGameRequest, CancellationToken cancellationToken = default);

Task SayAsync(string message);

Task<GameCreationResult> JoinGameAsync(
int gameId,
GameRole role,
bool isMale,
string password,
CancellationToken cancellationToken = default);

Task SendMessageAsync(Message message, CancellationToken cancellationToken = default);

Task<GameCreationResult> CreateAndJoinGameAsync(
GameSettingsCore<AppSettingsCore> gameSettings,
PackageKey packageKey,
ComputerAccountInfo[] computerAccounts,
bool isMale,
CancellationToken cancellationToken = default);

/// <summary>
/// Creates a new game and joins its.
/// </summary>
/// <param name="gameSettings">Game settings.</param>
/// <param name="packageInfo">Package info.</param>
/// <param name="computerAccounts">Custom computer accounts info.</param>
/// <param name="isMale">Male flag.</param>
/// <param name="cancellationToken">Cancellation token.</param>
Task<GameCreationResult> CreateAndJoinGame2Async(
GameSettingsCore<AppSettingsCore> gameSettings,
PackageInfo packageInfo,
ComputerAccountInfo[] computerAccounts,
bool isMale,
CancellationToken cancellationToken = default);

Task LeaveGameAsync(CancellationToken cancellationToken = default);
}
Loading

0 comments on commit f98e983

Please sign in to comment.