280 lines
10 KiB
C#
280 lines
10 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)
|
|
{
|
|
|
|
#if DEBUG
|
|
var baseAddress = "http://localhost:5000";
|
|
#else
|
|
var baseAddress = "http://hub.michelescandura.com:5000";
|
|
#endif
|
|
|
|
SessionData = sessionData;
|
|
Connection = new HubConnectionBuilder()
|
|
.WithAutomaticReconnect()
|
|
|
|
.WithUrl($"{baseAddress}/SledgemapperHub", options =>
|
|
{
|
|
options.AccessTokenProvider = () => Task.FromResult(_authenticateResponse.Token);
|
|
})
|
|
.Build();
|
|
|
|
Api = RestService.For<IMapApi>(
|
|
new HttpClient(new AuthenticatedHttpClientHandler(GetToken))
|
|
{
|
|
BaseAddress = new Uri(baseAddress)
|
|
}
|
|
);
|
|
|
|
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<Note>("DeleteNote", (tile) =>
|
|
{
|
|
SessionData.Notes.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<Room>("NewRoom", (room) =>
|
|
{
|
|
SessionData.Rooms.Remove(room.ToString(), out var _);
|
|
SessionData.Rooms.TryAdd(room.ToString(), room);
|
|
});
|
|
|
|
Connection.On<Line>("NewLine", (line) =>
|
|
{
|
|
SessionData.Lines.Remove(line.ToString(), out var _);
|
|
SessionData.Lines.TryAdd(line.ToString(), line);
|
|
});
|
|
|
|
Connection.On("RefreshPlayers", () =>
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(SessionData.SessionName))
|
|
{
|
|
Connection?.SendAsync("UpdatePosition", SessionData.SessionName, SessionData.SessionId, SessionData.Players.First(p => p.UserId == int.Parse(_authenticateResponse.Id)));
|
|
}
|
|
});
|
|
|
|
Connection.On<Player>("RemovePlayer", (player) =>
|
|
{
|
|
var p = SessionData.Players.FirstOrDefault(m => m.UserId == player.UserId);
|
|
if (p != null)
|
|
{
|
|
SessionData.Players.Remove(p);
|
|
}
|
|
});
|
|
|
|
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<Note>("NewNote", (note) =>
|
|
{
|
|
//SessionData.Notes.Remove(note.ToString(), out var _);
|
|
SessionData.Notes.AddOrUpdate(note.ToString(), note, (key, oldnote) => note);
|
|
});
|
|
|
|
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;
|
|
}
|
|
});
|
|
|
|
Connection.On<Ping>("Ping", (ping) =>
|
|
{
|
|
SessionData.Pings.TryAdd(Guid.NewGuid(), ping);
|
|
});
|
|
}
|
|
|
|
private Task<string> GetToken()
|
|
{
|
|
return Task.FromResult(_authenticateResponse.Token);
|
|
}
|
|
|
|
public async Task<IMapApi.AuthResult> 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;
|
|
case Note note:
|
|
Queue.Enqueue(async () => await Execute(async () => await Api.NewNote(note, SessionData.SessionName).ConfigureAwait(false)));
|
|
break;
|
|
case Room room:
|
|
Queue.Enqueue(async () => await Execute(async () => await Api.NewRoom(room, SessionData.SessionName).ConfigureAwait(false)));
|
|
break;
|
|
case Line line:
|
|
Queue.Enqueue(async () => await Execute(async () => await Api.NewLine(line, 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;
|
|
case Note note:
|
|
Queue.Enqueue(async () => await Execute(async () => await Api.DeleteNote(note, SessionData.SessionName).ConfigureAwait(false)));
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
internal async Task Ping(Tile location)
|
|
{
|
|
if (Connection!=null && Connection.State == HubConnectionState.Connected)
|
|
{
|
|
await Connection.InvokeAsync("Ping",SessionData.SessionName, location);
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
}
|
|
}
|