stability improvements
This commit is contained in:
parent
79edfcc4d3
commit
333c6c4046
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Sledgemapper.Api.Models;
|
||||
using Sledgemapper.Entities;
|
||||
|
||||
namespace Sledgemapper.Api.Core.Entities
|
||||
{
|
||||
|
@ -7,6 +7,8 @@ using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using Sledgemapper.Api.Models;
|
||||
using Sledgemapper.Api.Commands;
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
using Session = Sledgemapper.Shared.Entities.Session;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
@ -104,8 +106,8 @@ namespace Sledgemapper.Api.Handlers
|
||||
Timestamp = mapUpdates.Max(mapSession => mapSession.Timestamp),
|
||||
Object = JsonSerializer.Serialize(mapSession)
|
||||
};
|
||||
await _dbcontext.Snapshots.AddAsync(newSnapshot);
|
||||
await _dbcontext.SaveChangesAsync();
|
||||
await _dbcontext.Snapshots.AddAsync(newSnapshot, cancellationToken);
|
||||
await _dbcontext.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
return mapSession;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ using Sledgemapper.Api.Infrastructure.Data;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
@ -22,18 +23,18 @@ namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
try
|
||||
{
|
||||
var user = await _dbcontext.Users.FindAsync(notification.UserId);
|
||||
var user = await _dbcontext.Users.FindAsync(notification.UserId, cancellationToken);
|
||||
_dbcontext.Attach(user);
|
||||
var campaign = new Core.Entities.Campaign
|
||||
{
|
||||
CampaignName = notification.CampaignName,
|
||||
OwnerId = user.Id,
|
||||
InvitedUsers = new System.Collections.Generic.List<Entities.User> { user }
|
||||
InvitedUsers = new System.Collections.Generic.List<User> { user }
|
||||
};
|
||||
|
||||
_dbcontext.Campaigns.Add(campaign);
|
||||
|
||||
await _dbcontext.SaveChangesAsync();
|
||||
await _dbcontext.SaveChangesAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -6,6 +6,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
using Sledgemapper.Api.Commands;
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
@ -21,15 +22,15 @@ namespace Sledgemapper.Api.Handlers
|
||||
|
||||
var session = _dbcontext.Sessions.First(m => m.SessionName == notification.SessionName);
|
||||
|
||||
var newSnapshot = new Models.Snapshot
|
||||
var newSnapshot = new Snapshot
|
||||
{
|
||||
SessionId = session.SessionId,
|
||||
Timestamp = notification.Timestamp,
|
||||
Object = JsonSerializer.Serialize(notification.Session)
|
||||
|
||||
};
|
||||
await _dbcontext.Snapshots.AddAsync(newSnapshot);
|
||||
await _dbcontext.SaveChangesAsync();
|
||||
await _dbcontext.Snapshots.AddAsync(newSnapshot, cancellationToken);
|
||||
await _dbcontext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -2,9 +2,9 @@ using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Sledgemapper.Api.Hubs;
|
||||
using Sledgemapper.Api.Notifications;
|
||||
using Sledgemapper.Clients;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Shared.Clients;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
|
@ -2,9 +2,9 @@ using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Sledgemapper.Api.Hubs;
|
||||
using Sledgemapper.Api.Notifications;
|
||||
using Sledgemapper.Clients;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Shared.Clients;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Sledgemapper.Api.Notifications;
|
||||
using Sledgemapper.Clients;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Api.Hubs;
|
||||
using Sledgemapper.Shared.Clients;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Sledgemapper.Api.Notifications;
|
||||
using Sledgemapper.Clients;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Api.Hubs;
|
||||
using Sledgemapper.Shared.Clients;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Sledgemapper.Api.Notifications;
|
||||
using Sledgemapper.Clients;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Api.Hubs;
|
||||
using Sledgemapper.Shared.Clients;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Sledgemapper.Api.Notifications;
|
||||
using Sledgemapper.Clients;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Api.Hubs;
|
||||
using Sledgemapper.Shared.Clients;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
|
@ -1,10 +1,10 @@
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Sledgemapper.Api.Notifications;
|
||||
using Sledgemapper.Clients;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Api.Hubs;
|
||||
using Sledgemapper.Shared.Clients;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using Sledgemapper.Api.Models;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
|
||||
namespace Sledgemapper.Api.Handlers
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
using AutoMapper;
|
||||
using Sledgemapper.Entities;
|
||||
using Sledgemapper.Models.Users;
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
using Sledgemapper.Api.Models;
|
||||
|
||||
namespace Sledgemapper.Api.Helpers
|
||||
{
|
||||
|
@ -1,8 +1,6 @@
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
using Sledgemapper.Api.Models;
|
||||
using Sledgemapper.Entities;
|
||||
|
||||
namespace Sledgemapper.Api.Infrastructure.Data
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
using MediatR;
|
||||
using System;
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
@ -6,7 +7,7 @@ namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public Note Note { get; private set; }
|
||||
|
||||
public DeleteNoteNotification(Models.Session session, Note note, string userId) : base(session, userId)
|
||||
public DeleteNoteNotification(Session session, Note note, string userId) : base(session, userId)
|
||||
{
|
||||
Note = note;
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
@ -6,7 +8,7 @@ namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public Overlay Overlay { get; private set; }
|
||||
|
||||
public DeleteOverlayNotification(Models.Session session, Overlay overlay, string userId) : base(session, userId)
|
||||
public DeleteOverlayNotification(Session session, Overlay overlay, string userId) : base(session, userId)
|
||||
{
|
||||
Overlay = overlay;
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
@ -6,7 +8,7 @@ namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public Tile Tile { get; private set; }
|
||||
|
||||
public DeleteTileNotification(Models.Session session, Tile tile, string userId) : base(session, userId)
|
||||
public DeleteTileNotification(Session session, Tile tile, string userId) : base(session, userId)
|
||||
{
|
||||
Tile = tile;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
@ -6,7 +7,7 @@ namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public Wall Wall { get; private set; }
|
||||
|
||||
public DeleteWallNotification(Models.Session session, Wall wall, string userId) : base(session, userId)
|
||||
public DeleteWallNotification(Session session, Wall wall, string userId) : base(session, userId)
|
||||
{
|
||||
Wall = wall;
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
@ -6,7 +8,7 @@ namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public Line Line { get; private set; }
|
||||
|
||||
public NewLineNotification(Models.Session session, Line line, string userId) : base(session, userId)
|
||||
public NewLineNotification(Session session, Line line, string userId) : base(session, userId)
|
||||
{
|
||||
Line = line;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
@ -6,7 +7,7 @@ namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public Overlay Overlay { get; private set; }
|
||||
|
||||
public NewOverlayNotification(Models.Session session, Overlay overlay, string userId) : base(session, userId)
|
||||
public NewOverlayNotification(Session session, Overlay overlay, string userId) : base(session, userId)
|
||||
{
|
||||
Overlay = overlay;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
@ -6,7 +7,7 @@ namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public Room Room { get; private set; }
|
||||
|
||||
public NewRoomNotification(Models.Session session, Room room, string userId) : base(session, userId)
|
||||
public NewRoomNotification(Session session, Room room, string userId) : base(session, userId)
|
||||
{
|
||||
Room = room;
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public class NewSessionNotification : BaseNotification
|
||||
{
|
||||
public NewSessionNotification(string sessionName, string userId) : base(new Models.Session { SessionName = sessionName }, userId)
|
||||
public NewSessionNotification(string sessionName, string userId) : base(new Session { SessionName = sessionName }, userId)
|
||||
{ }
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
@ -6,7 +8,7 @@ namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
public Tile Tile { get; private set; }
|
||||
|
||||
public NewTileNotification(Models.Session session, Tile tile, string userId) : base(session, userId)
|
||||
public NewTileNotification(Session session, Tile tile, string userId) : base(session, userId)
|
||||
{
|
||||
Tile = tile;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using Session = Sledgemapper.Api.Core.Entities.Session;
|
||||
|
||||
namespace Sledgemapper.Api.Notifications
|
||||
{
|
||||
|
@ -12,6 +12,7 @@ using System.Text;
|
||||
using Sledgemapper.Api.Hubs;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Sledgemapper.Api.Core.Entities;
|
||||
|
||||
namespace Sledgemapper.Api
|
||||
{
|
||||
@ -69,7 +70,7 @@ namespace Sledgemapper.Api
|
||||
};
|
||||
});
|
||||
|
||||
services.AddDefaultIdentity<Entities.User>(options => options.SignIn.RequireConfirmedAccount = false)
|
||||
services.AddDefaultIdentity<User>(options => options.SignIn.RequireConfirmedAccount = false)
|
||||
.AddEntityFrameworkStores<SledgemapperDbContext>();
|
||||
|
||||
services.AddSwaggerGen(c =>
|
||||
@ -95,7 +96,7 @@ namespace Sledgemapper.Api
|
||||
Id = "Bearer"
|
||||
}
|
||||
},
|
||||
new string[] { }
|
||||
Array.Empty<string>()
|
||||
}
|
||||
});
|
||||
});
|
||||
|
38
Sledgemapper/AuthenticatedHttpClientHandler.cs
Normal file
38
Sledgemapper/AuthenticatedHttpClientHandler.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sledgemapper
|
||||
{
|
||||
internal class AuthenticatedHttpClientHandler : HttpClientHandler
|
||||
{
|
||||
private readonly Func<Task<string>> _getToken;
|
||||
|
||||
public AuthenticatedHttpClientHandler(Func<Task<string>> getToken)
|
||||
{
|
||||
_getToken = getToken ?? throw new ArgumentNullException(nameof(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);
|
||||
}
|
||||
}
|
||||
}
|
@ -2,15 +2,19 @@ using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Channels;
|
||||
using Sentry;
|
||||
using Sledgemapper.Messages;
|
||||
using TinyMessenger;
|
||||
|
||||
namespace Sledgemapper
|
||||
{
|
||||
public class ChannelsQueue
|
||||
{
|
||||
public TinyMessengerHub Messenger { get; }
|
||||
private readonly ChannelWriter<Action> _writer;
|
||||
|
||||
public ChannelsQueue()
|
||||
public ChannelsQueue(TinyMessenger.TinyMessengerHub messenger)
|
||||
{
|
||||
Messenger = messenger;
|
||||
var channel = Channel.CreateUnbounded<Action>(new UnboundedChannelOptions() { SingleReader = true });
|
||||
var reader = channel.Reader;
|
||||
_writer = channel.Writer;
|
||||
@ -19,8 +23,8 @@ namespace Sledgemapper
|
||||
{
|
||||
while (await reader.WaitToReadAsync())
|
||||
{
|
||||
// Fast loop around available jobs
|
||||
while (reader.TryRead(out var job))
|
||||
// Fast loop around available jobs
|
||||
while (reader.TryRead(out var job))
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -29,7 +33,7 @@ namespace Sledgemapper
|
||||
catch (Exception ex)
|
||||
{
|
||||
SentrySdk.CaptureException(ex);
|
||||
throw;
|
||||
messenger.Publish(new ErrorMessage(this, ex.Message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,50 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
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;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using Polly;
|
||||
using Polly.Retry;
|
||||
using Refit;
|
||||
using SharpFontInternal;
|
||||
using Sledgemapper.Messages;
|
||||
using Sledgemapper.Shared.Entities;
|
||||
using TinyMessenger;
|
||||
|
||||
namespace Sledgemapper
|
||||
{
|
||||
public class CommunicationManager
|
||||
{
|
||||
private readonly ChannelsQueue _queue = new();
|
||||
public TinyMessengerHub Messenger { get; }
|
||||
public IMapApi Api { get; }
|
||||
public HubConnection Connection { get; }
|
||||
|
||||
private readonly ChannelsQueue _queue;
|
||||
private readonly AsyncRetryPolicy _retryPolicy;
|
||||
public readonly Session SessionData;
|
||||
private AuthenticateResponse _authenticateResponse;
|
||||
|
||||
public CommunicationManager(Session sessionData)
|
||||
public CommunicationManager(Session sessionData, TinyMessengerHub messenger)
|
||||
{
|
||||
Messenger = messenger;
|
||||
_queue = new ChannelsQueue(Messenger);
|
||||
#if DEBUG
|
||||
var baseAddress = "http://localhost:5000";
|
||||
#else
|
||||
var baseAddress = "http://hub.michelescandura.com:5000";
|
||||
#endif
|
||||
|
||||
_retryPolicy = Policy
|
||||
.Handle<ApiException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
|
||||
.Or<HttpRequestException>()
|
||||
.RetryAsync(3);
|
||||
|
||||
//.RetryAsync(Polly.RetrySyntax., async (exception, retryCount) => await Task.Delay(500))
|
||||
|
||||
|
||||
SessionData = sessionData;
|
||||
Connection = new HubConnectionBuilder()
|
||||
.WithAutomaticReconnect()
|
||||
@ -132,9 +150,6 @@ namespace Sledgemapper
|
||||
Connection.On<Ping>("Ping", ping => { SessionData.Pings.TryAdd(Guid.NewGuid(), ping); });
|
||||
}
|
||||
|
||||
public IMapApi Api { get; }
|
||||
public HubConnection Connection { get; }
|
||||
|
||||
public void Enqueue(BaseMapEntity entity, TileAction action)
|
||||
{
|
||||
switch (action)
|
||||
@ -209,30 +224,81 @@ namespace Sledgemapper
|
||||
{
|
||||
await Policy
|
||||
.Handle<ApiException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
|
||||
.Or<HttpRequestException>()
|
||||
.RetryForeverAsync()
|
||||
//.RetryAsync(Polly.RetrySyntax., async (exception, retryCount) => await Task.Delay(500))
|
||||
.ExecuteAsync(async () => await call().ConfigureAwait(false))
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
|
||||
private Task<string> GetToken()
|
||||
{
|
||||
return Task.FromResult(_authenticateResponse.Token);
|
||||
return Task.FromResult(_authenticateResponse?.Token ?? "");
|
||||
}
|
||||
|
||||
public async Task<List<Campaign>> GetCampaigns()
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _retryPolicy.ExecuteAsync(Api.GetCampaigns);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Sentry.SentrySdk.CaptureException(e);
|
||||
Messenger.Publish(new ErrorMessage(this, "Error loading campaigns"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<List<Session>> GetMaps(Guid campaignId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _retryPolicy.ExecuteAsync(() => Api.GetMaps(campaignId));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Sentry.SentrySdk.CaptureException(e);
|
||||
Messenger.Publish(new ErrorMessage(this, "Error loading maps"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<List<Player>> GetPlayers(Guid campaignId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _retryPolicy.ExecuteAsync(() => Api.GetPlayers(campaignId));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Sentry.SentrySdk.CaptureException(e);
|
||||
Messenger.Publish(new ErrorMessage(this, "Error loading players"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<AuthenticateResponse> Login(AuthenticateModel authenticateModel)
|
||||
{
|
||||
_authenticateResponse = await Api.Authenticate(authenticateModel).ConfigureAwait(false);
|
||||
_authenticateResponse = await Policy
|
||||
.Handle<ApiException>(ex => ex.StatusCode == HttpStatusCode.RequestTimeout)
|
||||
.Or<HttpRequestException>()
|
||||
.RetryAsync(3)
|
||||
//.RetryAsync(Polly.RetrySyntax., async (exception, retryCount) => await Task.Delay(500))
|
||||
.ExecuteAsync(async () => await Api.Authenticate(authenticateModel))
|
||||
.ConfigureAwait(false);
|
||||
|
||||
//_authenticateResponse = await Api.Authenticate(authenticateModel).ConfigureAwait(false);
|
||||
return _authenticateResponse;
|
||||
}
|
||||
|
||||
internal async Task Ping(Tile location)
|
||||
{
|
||||
if (Connection is { State: HubConnectionState.Connected })
|
||||
{
|
||||
await Connection.InvokeAsync("Ping", SessionData.SessionName, location);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IMapApi.AuthResult> Register(RegisterModel registerModel)
|
||||
@ -241,34 +307,4 @@ namespace Sledgemapper
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
internal class AuthenticatedHttpClientHandler : HttpClientHandler
|
||||
{
|
||||
private readonly Func<Task<string>> _getToken;
|
||||
|
||||
public AuthenticatedHttpClientHandler(Func<Task<string>> getToken)
|
||||
{
|
||||
_getToken = getToken ?? throw new ArgumentNullException(nameof(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);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,77 +1,60 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AsyncAwaitBestPractices;
|
||||
using Myra.Graphics2D.UI;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Myra.Graphics2D.Brushes;
|
||||
using Myra.Graphics2D.UI;
|
||||
|
||||
namespace Sledgemapper
|
||||
{
|
||||
public static class ExtensionMethods
|
||||
{
|
||||
public static Dictionary<string, T> LoadContentFolder<T>(this ContentManager contentManager, string contentFolder)
|
||||
{
|
||||
DirectoryInfo dir = new(contentManager.RootDirectory + "/" + contentFolder);
|
||||
if (!dir.Exists)
|
||||
throw new DirectoryNotFoundException();
|
||||
Dictionary<string, T> result = new();
|
||||
|
||||
FileInfo[] files = dir.GetFiles("*.*");
|
||||
foreach (FileInfo file in files.Where(f => f.Extension != ".ttf" && f.Extension != ".otf"))
|
||||
{
|
||||
result.Add(file.Name.Split('.')[0], contentManager.Load<T>(contentFolder + "/" + file.Name.Split('.')[0]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static IEnumerable<string> Split(this string str, int chunkSize) => Enumerable.Range(0, str.Length / chunkSize)
|
||||
.Select(i => str.Substring(i * chunkSize, chunkSize));
|
||||
|
||||
public static Point AbsPoint(this Point point)
|
||||
{
|
||||
return new Point(System.Math.Abs(point.X), System.Math.Abs(point.Y));
|
||||
}
|
||||
|
||||
public static (Window Window, C Content) GetParentContentInWindow<C>(this Widget widget) where C : Widget
|
||||
{
|
||||
Container container = widget.Parent;
|
||||
while (!(container is Window))
|
||||
{
|
||||
container = container.Parent;
|
||||
}
|
||||
|
||||
var localWindow = (Window)container;
|
||||
var localContent = localWindow.Content as C;
|
||||
return (localWindow, localContent);
|
||||
return new Point(Math.Abs(point.X), Math.Abs(point.Y));
|
||||
}
|
||||
|
||||
public static Window GetContainingWindow(this Widget widget)
|
||||
{
|
||||
var container = widget.Parent;
|
||||
while (!(container is Window) || container is null)
|
||||
{
|
||||
container = container.Parent;
|
||||
}
|
||||
while (container is not Window or null) container = container.Parent;
|
||||
|
||||
return container as Window;
|
||||
}
|
||||
|
||||
public static bool ValidateTextbox(this TextBox textBox)
|
||||
public static (Window Window, TC Content) GetParentContentInWindow<TC>(this Widget widget) where TC : Widget
|
||||
{
|
||||
var valid = !string.IsNullOrWhiteSpace(textBox.Text);
|
||||
if (!valid)
|
||||
var container = widget.Parent;
|
||||
while (container is not Window) container = container.Parent;
|
||||
|
||||
var localWindow = (Window)container;
|
||||
var localContent = localWindow.Content as TC;
|
||||
return (localWindow, localContent);
|
||||
}
|
||||
|
||||
public static Dictionary<string, T> LoadContentFolder<T>(this ContentManager contentManager, string contentFolder)
|
||||
{
|
||||
DirectoryInfo dir = new(contentManager.RootDirectory + "/" + contentFolder);
|
||||
if (!dir.Exists)
|
||||
{
|
||||
textBox.Background = new SolidBrush(Color.Red);
|
||||
throw new DirectoryNotFoundException();
|
||||
}
|
||||
else
|
||||
|
||||
Dictionary<string, T> result = new();
|
||||
|
||||
var files = dir.GetFiles("*.*");
|
||||
|
||||
foreach (var file in files.Where(f => f.Extension != ".ttf" && f.Extension != ".otf"))
|
||||
{
|
||||
textBox.Background = new SolidBrush(new Color(51, 51, 51)); ;
|
||||
result.Add(file.Name.Split('.')[0], contentManager.Load<T>(contentFolder + "/" + file.Name.Split('.')[0]));
|
||||
|
||||
}
|
||||
return valid;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void ShowInModalWindow(this Widget widget, Desktop desktop, string title)
|
||||
@ -79,29 +62,35 @@ namespace Sledgemapper
|
||||
Window window = new()
|
||||
{
|
||||
Title = title,
|
||||
Content=widget
|
||||
Content = widget
|
||||
};
|
||||
|
||||
window.ShowModal(desktop);
|
||||
}
|
||||
|
||||
public static void Toast(this Widget widget, Desktop desktop, string title)
|
||||
public static IEnumerable<string> Split(this string str, int chunkSize)
|
||||
{
|
||||
|
||||
|
||||
Window window = new()
|
||||
{
|
||||
Content = widget
|
||||
};
|
||||
window.Show(desktop, new Point(desktop.BoundsFetcher().X-200, desktop.BoundsFetcher().Y - 200));
|
||||
Task.Delay(500).ContinueWith(_=>window.Close()).SafeFireAndForget();
|
||||
return Enumerable.Range(0, str.Length / chunkSize)
|
||||
.Select(i => str.Substring(i * chunkSize, chunkSize));
|
||||
}
|
||||
|
||||
public static void Toast(this Widget widget, Desktop desktop)
|
||||
{
|
||||
widget.Left = desktop.BoundsFetcher().Center.X - widget.Width.Value / 2;
|
||||
widget.Top = desktop.BoundsFetcher().Height - 90;
|
||||
widget.ZIndex = 1000;
|
||||
desktop.Widgets.Add(widget);
|
||||
|
||||
Task.Delay(2000).ContinueWith(_ => { desktop.Widgets.Remove(widget); }
|
||||
).SafeFireAndForget();
|
||||
}
|
||||
|
||||
public static bool ValidateTextbox(this TextBox textBox)
|
||||
{
|
||||
var valid = !string.IsNullOrWhiteSpace(textBox.Text);
|
||||
textBox.Background = valid ? new SolidBrush(new Color(51, 51, 51)) : new SolidBrush(Color.Red);
|
||||
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
//public interface IExtendedWidget
|
||||
//{
|
||||
// void ShowInModalWindow(this Widget widget, string title)
|
||||
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
@ -39,7 +39,7 @@ namespace Sledgemapper
|
||||
Task<List<Campaign>> GetCampaigns();
|
||||
|
||||
[Get("/campaign/{campaignName}/players")]
|
||||
Task<List<Player>> GetPlayers(string campaignName);
|
||||
Task<List<Player>> GetPlayers(Guid campaignName);
|
||||
|
||||
|
||||
[Get("/campaign/{campaignName}/maps")]
|
||||
|
@ -60,13 +60,12 @@ namespace Sledgemapper
|
||||
_sessionData = new Session();
|
||||
IsFixedTimeStep = true;
|
||||
TargetElapsedTime = TimeSpan.FromSeconds(1d / 30d);
|
||||
_communicationManager = new CommunicationManager(_sessionData);
|
||||
_messenger = new TinyMessengerHub();
|
||||
_communicationManager = new CommunicationManager(_sessionData,_messenger);
|
||||
_communicationManager.Connection.Reconnected += OnHubReconnected;
|
||||
_communicationManager.Connection.Reconnecting += OnHubReconnecting;
|
||||
_communicationManager.Connection.Closed += OnHubDisconnected;
|
||||
_state = State.Instance;
|
||||
|
||||
_messenger = new TinyMessengerHub();
|
||||
}
|
||||
|
||||
protected override void Draw(GameTime gameTime)
|
||||
|
@ -44,7 +44,7 @@ namespace Sledgemapper.UI
|
||||
|
||||
private void OnMenuCampaignNew(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is MenuItem && !((MenuItem)sender).Enabled)
|
||||
if (sender is MenuItem { Enabled: false })
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -61,24 +61,37 @@ namespace Sledgemapper.UI
|
||||
var list = item.Parent as Grid;
|
||||
for (var i = 0; i < list.ChildrenCount; i++)
|
||||
{
|
||||
var currentItem = list.GetChild(i) as HorizontalStackPanel;// UI.ListItem;
|
||||
currentItem.Background = new SolidBrush("#D9D9D9FF");
|
||||
if (list.GetChild(i) is HorizontalStackPanel currentItem) currentItem.Background = new SolidBrush("#D9D9D9FF");
|
||||
}
|
||||
item.Background = new SolidBrush(Settings.Instance.OverlayTintColor);
|
||||
_campaignSelected = true;
|
||||
}
|
||||
|
||||
public async Task LoadCampaigns()
|
||||
public async Task<bool> LoadCampaigns()
|
||||
{
|
||||
var campaigns = await CommunicationManager.Api.GetCampaigns();
|
||||
var campaigns = await CommunicationManager.GetCampaigns();
|
||||
|
||||
if (campaigns is null)
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var campaign in campaigns)
|
||||
{
|
||||
var item = new ListItem();
|
||||
item.ItemName.Text = campaign.Name;
|
||||
item.Tag = campaign.Id;
|
||||
var item = new ListItem
|
||||
{
|
||||
ItemName =
|
||||
{
|
||||
Text = campaign.Name
|
||||
},
|
||||
Tag = campaign.Id
|
||||
};
|
||||
item.TouchUp += OnCampaignSelected;
|
||||
StackCampaignsList.AddChild(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
@ -111,7 +111,7 @@ namespace Sledgemapper.UI
|
||||
|
||||
private void OnBtnToolbarDeleteClicked(object sender, EventArgs e)
|
||||
{
|
||||
Messenger.Publish(new ErrorMessage(this,"test"));
|
||||
Messenger.Publish(new ErrorMessage(this, "test"));
|
||||
State.Instance.InsertMode = InsertMode.NewDelete;
|
||||
|
||||
ClearSelection();
|
||||
@ -201,7 +201,7 @@ namespace Sledgemapper.UI
|
||||
|
||||
private void OnErrorMessage(ErrorMessage obj)
|
||||
{
|
||||
new ErrorWindow(obj.Message).Toast(Desktop,null);
|
||||
new ErrorWindow(obj.Message).Toast(Desktop);
|
||||
}
|
||||
|
||||
private void OneMenuFileSettingsSelected(object sender, EventArgs e)
|
||||
@ -273,7 +273,7 @@ namespace Sledgemapper.UI
|
||||
|
||||
private void OnMenuCampaignNew(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is MenuItem && !((MenuItem)sender).Enabled) return;
|
||||
if (sender is MenuItem { Enabled: false }) return;
|
||||
|
||||
new CampaignWindow(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "New campaign");
|
||||
;
|
||||
@ -284,8 +284,10 @@ namespace Sledgemapper.UI
|
||||
if (!((MenuItem)sender).Enabled) return;
|
||||
|
||||
var content = new CampaignList(CommunicationManager, Messenger);
|
||||
await content.LoadCampaigns();
|
||||
content.ShowInModalWindow(Desktop, "Campaigns");
|
||||
if (await content.LoadCampaigns())
|
||||
{
|
||||
content.ShowInModalWindow(Desktop, "Campaigns");
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnMenuCampaignPlayersSelected(object sender, EventArgs e)
|
||||
@ -293,8 +295,10 @@ namespace Sledgemapper.UI
|
||||
if (!((MenuItem)sender).Enabled) return;
|
||||
|
||||
var content = new PlayerList(CommunicationManager);
|
||||
await content.LoadPlayers();
|
||||
content.ShowInModalWindow(Desktop, "Players");
|
||||
if (await content.LoadPlayers())
|
||||
{
|
||||
content.ShowInModalWindow(Desktop, "Players");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMenuConnectLoginSelected(object sender, EventArgs e)
|
||||
@ -373,7 +377,7 @@ namespace Sledgemapper.UI
|
||||
|
||||
private void OnMenuMapNew(object sender, EventArgs e)
|
||||
{
|
||||
if (sender is MenuItem && !((MenuItem)sender).Enabled) return;
|
||||
if (sender is MenuItem { Enabled: false }) return;
|
||||
|
||||
new MapWindow(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "New map");
|
||||
}
|
||||
@ -383,8 +387,10 @@ namespace Sledgemapper.UI
|
||||
if (!((MenuItem)sender).Enabled) return;
|
||||
|
||||
var content = new MapList(CommunicationManager, Messenger);
|
||||
await content.LoadMaps();
|
||||
content.ShowInModalWindow(Desktop, "Maps");
|
||||
if (await content.LoadMaps())
|
||||
{
|
||||
content.ShowInModalWindow(Desktop, "Maps");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMenuViewCenterOnSelectionSelected(object sender, EventArgs e)
|
||||
@ -394,11 +400,6 @@ namespace Sledgemapper.UI
|
||||
|
||||
private void OnMenuViewNotesSelected(object sender, EventArgs e)
|
||||
{
|
||||
Window window = new()
|
||||
{
|
||||
Title = "Notes"
|
||||
};
|
||||
|
||||
new NoteList(CommunicationManager, Messenger).ShowInModalWindow(Desktop, "Notes");
|
||||
}
|
||||
|
||||
|
@ -39,9 +39,14 @@ namespace Sledgemapper.UI
|
||||
this.GetContainingWindow().Close();
|
||||
}
|
||||
|
||||
public async Task LoadMaps()
|
||||
public async Task<bool> LoadMaps()
|
||||
{
|
||||
var campaigns = await CommunicationManager.Api.GetMaps(State.Instance.CampaignId);
|
||||
var campaigns = await CommunicationManager.GetMaps(State.Instance.CampaignId);
|
||||
if (campaigns is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var campaign in campaigns)
|
||||
{
|
||||
var item = new ListItem();
|
||||
@ -50,6 +55,8 @@ namespace Sledgemapper.UI
|
||||
item.TouchUp += OnMapSelected;
|
||||
StackCampaignsList.AddChild(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnMapSelected(object sender, EventArgs e)
|
||||
|
@ -19,15 +19,21 @@ namespace Sledgemapper.UI
|
||||
};
|
||||
}
|
||||
|
||||
public async Task LoadPlayers()
|
||||
public async Task<bool> LoadPlayers()
|
||||
{
|
||||
var players = await CommunicationManager.Api.GetPlayers(State.Instance.CampaignName);
|
||||
var players = await CommunicationManager.GetPlayers(State.Instance.CampaignId);
|
||||
if (players is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (var player in players)
|
||||
{
|
||||
var item = new ListItem();
|
||||
item.ItemName.Text = player.UserName;
|
||||
StackCampaignsList.AddChild(item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ShowAddPLayerWindow()
|
||||
|
Loading…
Reference in New Issue
Block a user