sledgemapper/Sledgemapper/CommunicationManager.cs
2020-11-20 00:05:23 +00:00

214 lines
7.9 KiB
C#

using Microsoft.AspNetCore.SignalR.Client;
using Polly;
using Refit;
using Sledgemapper.Shared.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace Sledgemapper
{
public class CommunicationManager
{
public IMapApi Api { get; private set; }
public HubConnection Connection { get; private set; }
public readonly Session SessionData;
private readonly ChannelsQueue Queue = new();
private AuthenticateResponse _authenticateResponse;
public CommunicationManager(Session sessionData)
{
SessionData = sessionData;
Connection = new HubConnectionBuilder()
.WithAutomaticReconnect()
.WithUrl("http://localhost:5000/SledgemapperHub", options =>
{
options.AccessTokenProvider = () => Task.FromResult(_authenticateResponse.Token);
})
// .WithUrl("http://hub.michelescandura.com:5000/SledgemapperHub")
.Build();
Api = RestService.For<IMapApi>(
new HttpClient(new AuthenticatedHttpClientHandler(GetToken))
{
BaseAddress = new Uri("http://localhost:5000")
}
);
Connection.On<Session>("UpdateMap", (map) =>
{
SessionData.Map = map.Map;
SessionData.Walls = map.Walls;
SessionData.Overlays = map.Overlays;
});
Connection.On<Player>("PlayerUpdate", (player) =>
{
var p = SessionData.Players.FirstOrDefault(m => m.UserId == player.UserId);
if (p != null)
{
p.Position = player.Position;
}
else
{
SessionData.Players.Add(player);
}
});
Connection.On<Tile>("DeleteTile", (tile) =>
{
SessionData.Map.Remove(tile.ToString(), out var _);
});
Connection.On<Wall>("DeleteWall", (tile) =>
{
SessionData.Walls.Remove(tile.ToString(), out var _);
});
Connection.On<Overlay>("DeleteOverlay", (tile) =>
{
SessionData.Overlays.Remove(tile.ToString(), out var _);
});
Connection.On<Tile>("NewTile", (tile) =>
{
SessionData.Map.Remove(tile.ToString(), out var _);
SessionData.Map.TryAdd(tile.ToString(), tile);
});
Connection.On("RefreshPlayers", () =>
{
Connection?.SendAsync("UpdatePosition", SessionData.SessionName, SessionData.SessionId, SessionData.Players.First(p=>p.UserId==int.Parse(_authenticateResponse.Id)));
});
Connection.On<Wall>("NewWall", (tile) =>
{
SessionData.Walls.Remove(tile.ToString(), out var _);
SessionData.Walls.TryAdd(tile.ToString(), tile);
});
Connection.On<Overlay>("NewOverlay", (tile) =>
{
SessionData.Overlays.Remove(tile.ToString(), out var _);
SessionData.Overlays.TryAdd(tile.ToString(), tile);
});
Connection.On<Player>("NewPlayer", (player) =>
{
var p = SessionData.Players.FirstOrDefault(m => m.UserId == player.UserId);
if (p is null)
{
SessionData.Players.Add(player);
}
else
{
p.Color = player.Color;
p.Position = player.Position;
}
});
}
private Task<string> GetToken()
{
return Task.FromResult(_authenticateResponse.Token);
}
public async Task<HttpResponseMessage> Register(RegisterModel registerModel)
{
var result = await Api.Register(registerModel).ConfigureAwait(false);
return result;
}
public async Task<AuthenticateResponse> Login(AuthenticateModel authenticateModel)
{
_authenticateResponse = await Api.Authenticate(authenticateModel).ConfigureAwait(false);
return _authenticateResponse;
}
private async Task Execute(Func<Task> call)
{
await Policy
.Handle<ApiException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
.RetryForeverAsync()
//.RetryAsync(Polly.RetrySyntax., async (exception, retryCount) => await Task.Delay(500))
.ExecuteAsync(async () => await call().ConfigureAwait(false))
.ConfigureAwait(false);
}
public void Enqueue(BaseMapEntity entity, TileAction action)
{
switch (action)
{
case TileAction.Add:
switch (entity)
{
case Tile tile:
Queue.Enqueue(async () => await Execute(async () => await Api.NewTile(tile, SessionData.SessionName).ConfigureAwait(false)));
break;
case Overlay overlay:
Queue.Enqueue(async () => await Execute(async () => await Api.NewOverlay(overlay, SessionData.SessionName).ConfigureAwait(false)));
break;
case Wall wall:
Queue.Enqueue(async () => await Execute(async () => await Api.NewWall(wall, SessionData.SessionName).ConfigureAwait(false)));
break;
}
break;
case TileAction.Delete:
switch (entity)
{
case Tile tile:
Queue.Enqueue(async () => await Execute(async () => await Api.DeleteTile(tile, SessionData.SessionName).ConfigureAwait(false)));
break;
case Overlay overlay:
Queue.Enqueue(async () => await Execute(async () => await Api.DeleteOverlay(overlay, SessionData.SessionName).ConfigureAwait(false)));
break;
case Wall wall:
Queue.Enqueue(async () => await Execute(async () => await Api.DeleteWall(wall, SessionData.SessionName).ConfigureAwait(false)));
break;
}
break;
}
}
}
class AuthenticatedHttpClientHandler : HttpClientHandler
{
private readonly Func<Task<string>> getToken;
public AuthenticatedHttpClientHandler(Func<Task<string>> getToken)
{
if (getToken == null) throw new ArgumentNullException(nameof(getToken));
this.getToken = getToken;
//if (myConfigurationService.VerifySslCertificate == false)
//{
ServerCertificateCustomValidationCallback =
(message, certificate, chain, sslPolicyErrors) => true;
//}
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
// See if the request has an authorize header
var auth = request.Headers.Authorization;
if (auth != null)
{
var token = await getToken().ConfigureAwait(false);
request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, token);
}
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
}