I don't know what I'm doing anymore

This commit is contained in:
Michele 2020-11-16 00:03:42 +00:00
parent ea9cc32534
commit 8fdee0cb67
17 changed files with 342 additions and 116 deletions

View file

@ -0,0 +1,19 @@
using MediatR;
using System;
namespace Sledgemapper.Api.Commands
{
public abstract class BaseCommand<T> : IRequest<T>
{
public double Timestamp { get; private set; }
public string SessionName { get; private set; }
public int UserId { get; set; }
public BaseCommand(string sessionName, int userId)
{
Timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
SessionName = sessionName;
UserId=userId;
}
}
}

View file

@ -2,14 +2,10 @@ using MediatR;
namespace Sledgemapper.Api.Commands namespace Sledgemapper.Api.Commands
{ {
public class NewSessionCommand : IRequest<bool> public class NewSessionCommand : BaseCommand<bool>
{ {
public string SessionName { get; set; } public NewSessionCommand(string sessionName, int userId):base(sessionName, userId)
public int UserId { get; }
public NewSessionCommand(string sessionName, int userId)
{ {
SessionName = sessionName;
UserId = userId;
} }
} }
} }

View file

@ -0,0 +1,47 @@
using System.Transactions;
using System.Net.Mail;
using MediatR;
using Sledgemapper.Api.Data;
using Sledgemapper.Shared.Entities;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Sledgemapper.Api.Handlers;
namespace Sledgemapper.Api.Commands
{
public class SaveNewTileCommand:BaseCommand<bool>
{
public Tile Tile {get;set;}
public SaveNewTileCommand(string sessionName, Tile tile, int userId):base(sessionName, userId){
Tile=tile;
}
}
public class SaveNewTileCommandHandler : IRequestHandler<SaveNewTileCommand, bool>
{
private readonly MyDbContext _dbcontext;
private readonly IMediator _mediator;
public SaveNewTileCommandHandler(IMediator mediator, MyDbContext dbcontext){ _dbcontext = dbcontext; _mediator= mediator;}
public async Task<bool> Handle(SaveNewTileCommand notification, CancellationToken cancellationToken)
{
var jsonString = JsonSerializer.Serialize<Tile>(notification.Tile);
_dbcontext.MapLogs.Add(new Sledgemapper.Api.Models.MapLog
{
Operation = "N",
SessionName = notification.SessionName,
Type = "T",
Timestamp = notification.Timestamp,
Object = jsonString
});
await _dbcontext.SaveChangesAsync();
await _mediator.Publish(new NewTileNotification(notification.SessionName, notification.Tile));
return true;
}
}
}

View file

@ -1,3 +1,4 @@
using System.Net;
using MediatR; using MediatR;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@ -17,48 +18,50 @@ namespace Sledgemapper.Api.Controllers
public SessionController(IMediator mediator) { _mediator = mediator; } public SessionController(IMediator mediator) { _mediator = mediator; }
[HttpPost] [HttpPost]
public async Task Post(string sessionName) public async Task<bool> Post(string sessionName)
{ {
var userId = int.Parse(HttpContext.User.Identity.Name); var userId = int.Parse(HttpContext.User.Identity.Name);
var result = await _mediator.Send(new NewSessionCommand(sessionName, userId)); var result = await _mediator.Send(new NewSessionCommand(sessionName, userId));
return result;
} }
[HttpPost("tile")] [HttpPost("tile")]
public async Task Post(string sessionName, [FromBody]Tile tile) public async Task Post(string sessionName, [FromBody] Tile tile)
{ {
await _mediator.Publish(new NewTileNotification(sessionName, tile)); var userId = int.Parse(HttpContext.User.Identity.Name);
await _mediator.Send(new SaveNewTileCommand(sessionName, tile, userId));
} }
[HttpPost("overlay")] [HttpPost("overlay")]
public async Task Post(string sessionName, [FromBody]Overlay overlay) public async Task Post(string sessionName, [FromBody] Overlay overlay)
{ {
await _mediator.Publish(new NewOverlayNotification(sessionName, overlay)); await _mediator.Publish(new NewOverlayNotification(sessionName, overlay));
} }
[HttpPost("wall")] [HttpPost("wall")]
public async Task Post(string sessionName, [FromBody]Wall wall) public async Task Post(string sessionName, [FromBody] Wall wall)
{ {
await _mediator.Publish(new NewWallNotification(sessionName, wall)); await _mediator.Publish(new NewWallNotification(sessionName, wall));
} }
[HttpDelete("tile")] [HttpDelete("tile")]
public async Task Delete(string sessionName, [FromBody]Tile tile) public async Task Delete(string sessionName, [FromBody] Tile tile)
{ {
await _mediator.Publish(new DeleteTileNotification(sessionName, tile)); await _mediator.Publish(new DeleteTileNotification(sessionName, tile));
} }
[HttpDelete("overlay")] [HttpDelete("overlay")]
public async Task Delete(string sessionName, [FromBody]Overlay overlay) public async Task Delete(string sessionName, [FromBody] Overlay overlay)
{ {
await _mediator.Publish(new DeleteOverlayNotification(sessionName, overlay)); await _mediator.Publish(new DeleteOverlayNotification(sessionName, overlay));
} }
[HttpDelete("wall")] [HttpDelete("wall")]
public async Task Delete(string sessionName, [FromBody]Wall wall) public async Task Delete(string sessionName, [FromBody] Wall wall)
{ {
await _mediator.Publish(new DeleteWallNotification(sessionName, wall)); await _mediator.Publish(new DeleteWallNotification(sessionName, wall));
} }
} }
} }

View file

@ -13,30 +13,30 @@ namespace Sledgemapper.Api.Data
} }
} }
public class MyDbContext : DbContext public class MyDbContext : DbContext
{ {
public DbSet<MapLog> MapLogs { get; set; } public DbSet<MapLog> MapLogs { get; set; }
public DbSet<Session> Sessions { get; set; }
public DbSet<UserConnection> UserConnections { get; set; }
public DbSet<SessionUser> SessionUsers { get; set; }
public MyDbContext(DbContextOptions options) : base(options) public MyDbContext(DbContextOptions options) : base(options)
{ {
} }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) // protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ // {
// optionsBuilder. // // optionsBuilder.
// options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName); // // options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName);
// optionsBuilder.UseSqlite("Filename=SledgemapperDatabase.db", options => // // optionsBuilder.UseSqlite("Filename=SledgemapperDatabase.db", options =>
// { // // {
// options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName); // // options.MigrationsAssembly(Assembly.GetExecutingAssembly().FullName);
// }); // // });
optionsBuilder.UseSqlite("Filename=MyDatabase.db").UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); // optionsBuilder.UseSqlite("Filename=MyDatabase.db").UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
base.OnConfiguring(optionsBuilder); // base.OnConfiguring(optionsBuilder);
} // }
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
@ -45,8 +45,28 @@ namespace Sledgemapper.Api.Data
modelBuilder.Entity<MapLog>(entity => modelBuilder.Entity<MapLog>(entity =>
{ {
entity.HasKey(e => e.MapLogId); entity.HasKey(e => e.MapLogId);
//entity.HasIndex(e => {e.SessionName, e.Timestamp}); });
});
modelBuilder.Entity<Session>().ToTable("Session", "dbo");
modelBuilder.Entity<Session>(entity =>
{
entity.HasKey(e => e.SessionId);
entity.HasIndex(e => e.SessionName).IsUnique();
});
modelBuilder.Entity<UserConnection>().ToTable("UserConnection", "dbo");
modelBuilder.Entity<UserConnection>(entity =>
{
entity.HasKey(e => e.UserConnectionId);
});
modelBuilder.Entity<SessionUser>().ToTable("SessionUser", "dbo");
modelBuilder.Entity<SessionUser>(entity =>
{
entity.HasKey(e => e.SessionUserId);
});
base.OnModelCreating(modelBuilder); base.OnModelCreating(modelBuilder);
} }
} }

View file

@ -20,11 +20,11 @@ namespace Sledgemapper.Api.Handlers
public async Task<bool> Handle(NewSessionCommand notification, CancellationToken cancellationToken) public async Task<bool> Handle(NewSessionCommand notification, CancellationToken cancellationToken)
{ {
// _dbcontext.MapLogs.Add(new Session _dbcontext.Sessions.Add(new Session
// { {
// SessionName = notification.SessionName, SessionName = notification.SessionName,
// OwnerUserId = notification.UserId OwnerUserId = notification.UserId
// }); });
await _dbcontext.SaveChangesAsync(); await _dbcontext.SaveChangesAsync();
return true; return true;
} }

View file

@ -12,6 +12,8 @@ using Sledgemapper.Api.Data;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Sledgemapper.Api.Models;
using Sledgemapper.Helpers;
namespace SignalRChat.Hubs namespace SignalRChat.Hubs
{ {
@ -20,11 +22,15 @@ namespace SignalRChat.Hubs
[Authorize] [Authorize]
public class SledgemapperHub : Hub<ISledgemapperClient> public class SledgemapperHub : Hub<ISledgemapperClient>
{ {
public SledgemapperHub() private readonly MyDbContext _dbContext;
{ private readonly DataContext _datacontext;
public SledgemapperHub(MyDbContext dbContext, DataContext datacontext)
{
_dbContext = dbContext;
_datacontext = datacontext;
} }
private static Dictionary<string, Session> _sessions = new Dictionary<string, Session>(); // private static Dictionary<string, Session> _sessions = new Dictionary<string, Session>();
public List<string> Colors = new List<string>{"CC0000", public List<string> Colors = new List<string>{"CC0000",
"CC3300", "CC3300",
"FFCC00", "FFCC00",
@ -114,60 +120,116 @@ namespace SignalRChat.Hubs
await Clients.Group(sessionName).DeleteOverlay(tile); await Clients.Group(sessionName).DeleteOverlay(tile);
} }
public async Task<Session> NewSession(string sessionName, string initials) // public async Task<Session> NewSession(string sessionName, string initials)
{ // {
// var userId = int.Parse(Context.User.Identity.Name);
// // var user = this.Context.GetHttpContext().;
// var session = new Session();
// session.Colors = new List<string>(Colors);
// session.Colors.Shuffle();
// var player = new Player { Position = new Tile { X = 0, Y = 0 }, ConnectionId = Context.ConnectionId, Color = session.Colors[0], Initials = initials };
// session.Players.Add(player);
// _sessions.Add(sessionName, session);
// await Groups.AddToGroupAsync(Context.ConnectionId, sessionName);
// return session;
// }
public async Task<Sledgemapper.Shared.Entities.Session> JoinSession(string sessionName, string initials)
{
var session = _dbContext.Sessions.FirstOrDefault(s => s.SessionName == sessionName);
var userId = int.Parse(Context.User.Identity.Name); var userId = int.Parse(Context.User.Identity.Name);
// var user = this.Context.GetHttpContext().; if (session != null)
var session = new Session();
session.Colors = new List<string>(Colors);
session.Colors.Shuffle();
var player = new Player { Position = new Tile { X = 0, Y = 0 }, ConnectionId = Context.ConnectionId, Color = session.Colors[0], Initials = initials };
session.Players.Add(player);
_sessions.Add(sessionName, session);
await Groups.AddToGroupAsync(Context.ConnectionId, sessionName);
return session;
}
public async Task<Session> JoinSession(string sessionName, string initials)
{
if (_sessions.ContainsKey(sessionName))
{ {
var session = _sessions[sessionName]; // var newSession = new Session();
var player = new Player { Position = new Tile { X = 0, Y = 0 }, ConnectionId = Context.ConnectionId, Color = session.Colors[session.Players.Count], Initials = initials }; var userSession = new SessionUser { SessionId = session.SessionId, UserId = userId };
session.Players.Add(player); _dbContext.SessionUsers.Add(userSession);
await Clients.Group(sessionName).NewPlayer(player); await _dbContext.SaveChangesAsync();
var usersSession = _dbContext.SessionUsers.Where(m => m.SessionId == session.SessionId).Select(m => m.UserId).ToList();
var players = _datacontext.
Users.
Where(m => usersSession.Contains(m.Id)).
Select(p => new Player
{
Initials = p.Initials,
UserId = userId,
Position = new Tile { X = 0, Y = 0 }
}).ToList();
await _dbContext.SaveChangesAsync();
await Groups.AddToGroupAsync(Context.ConnectionId, sessionName); await Groups.AddToGroupAsync(Context.ConnectionId, sessionName);
return session; var newSession = new Sledgemapper.Shared.Entities.Session
{
Players = players,
SessionName = sessionName
};
return newSession;
} }
else else
{ {
return null; return null;
} }
// if (_sessions.ContainsKey(sessionName))
// {
// var session = _sessions[sessionName];
// var player = new Player { Position = new Tile { X = 0, Y = 0 }, ConnectionId = Context.ConnectionId, Color = session.Colors[session.Players.Count], Initials = initials };
// session.Players.Add(player);
// await Clients.Group(sessionName).NewPlayer(player);
// return session;
// }
// else
// {
// return null;
// }
} }
public async Task UpdatePosition(string sessionName, Tile tile) public async Task UpdatePosition(string sessionName, Tile tile)
{ {
var player = _sessions[sessionName].Players.First(m => m.ConnectionId == Context.ConnectionId); // var userId = int.Parse(Context.User.Identity.Name);
player.Position = tile; // var session = _dbContext.Sessions.FirstOrDefault(m => m.SessionName == sessionName);
await Clients.Group(sessionName).PlayerUpdate(player);
// var player = _sessions[sessionName].Players.First(m => m.ConnectionId == Context.ConnectionId);
// player.Position = tile;
// await Clients.Group(sessionName).PlayerUpdate(player);
} }
public async Task<Session> Refresh(string sessionName) // public async Task<Session> Refresh(string sessionName)
// {
// return _sessions[sessionName];
// }
// public async Task Sync(string sessionName, Session map)
// {
// _sessions[sessionName].Map = map.Map;
// _sessions[sessionName].Overlays = map.Overlays;
// _sessions[sessionName].Walls = map.Walls;
// await Clients.Group(sessionName).UpdateMap(_sessions[sessionName]);
// }
public override async Task OnConnectedAsync()
{ {
return _sessions[sessionName]; var userId = int.Parse(Context.User.Identity.Name);
//var result = _connectedPlayers.AddOrUpdate(Context.ConnectionId, userId,(key, oldValue) => userId);
var userConnection = new UserConnection { ConnectionId = Context.ConnectionId, UserId = userId };
_dbContext.UserConnections.Add(userConnection);
await _dbContext.SaveChangesAsync();
await base.OnConnectedAsync();
} }
public async Task Sync(string sessionName, Session map) public override Task OnDisconnectedAsync(Exception exception)
{ {
_sessions[sessionName].Map = map.Map; _connectedPlayers.TryRemove(Context.ConnectionId, out var userId);
_sessions[sessionName].Overlays = map.Overlays; return base.OnDisconnectedAsync(exception);
_sessions[sessionName].Walls = map.Walls;
await Clients.Group(sessionName).UpdateMap(_sessions[sessionName]);
} }
ConcurrentDictionary<string, int> _connectedPlayers = new ConcurrentDictionary<string, int>();
} }
} }

Binary file not shown.

View file

@ -1,3 +1,4 @@
using System.Data;
using System; using System;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;

View file

@ -0,0 +1,18 @@
using System.Data;
using System;
using System.ComponentModel.DataAnnotations;
namespace Sledgemapper.Api.Models
{
public class SessionUser
{
[Key]
public int SessionUserId { get; set; }
[Required]
public int SessionId { get; set; }
[Required]
public int UserId { get; set; }
}
}

View file

@ -0,0 +1,17 @@
using System.Data;
using System;
using System.ComponentModel.DataAnnotations;
namespace Sledgemapper.Api.Models
{
public class UserConnection
{
[Key]
public int UserConnectionId { get; set; }
[Required]
public int UserId { get; set; }
[Required]
public string ConnectionId{get;set;}
}
}

View file

@ -15,7 +15,9 @@ namespace SignalRChat
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
CreateHostBuilder(args).Build().Run(); var host= CreateHostBuilder(args).Build();
CreateDbIfNotExists(host);
host.Run();
} }
public static IHostBuilder CreateHostBuilder(string[] args) => public static IHostBuilder CreateHostBuilder(string[] args) =>
@ -32,22 +34,22 @@ namespace SignalRChat
// webBuilder.UseStartup<Startup>(); // webBuilder.UseStartup<Startup>();
// }); // });
// private static void CreateDbIfNotExists(IHost host) private static void CreateDbIfNotExists(IHost host)
// { {
// using (var scope = host.Services.CreateScope()) using (var scope = host.Services.CreateScope())
// { {
// var services = scope.ServiceProvider; var services = scope.ServiceProvider;
// try try
// { {
// var context = services.GetRequiredService<MyDbContext>(); var context = services.GetRequiredService<MyDbContext>();
// DbInitializer.Initialize(context); DbInitializer.Initialize(context);
// } }
// catch (Exception ex) catch (Exception ex)
// { {
// var logger = services.GetRequiredService<ILogger<Program>>(); var logger = services.GetRequiredService<ILogger<Program>>();
// logger.LogError(ex, "An error occurred creating the DB."); logger.LogError(ex, "An error occurred creating the DB.");
// } }
// } }
// } }
} }
} }

Binary file not shown.

View file

@ -2,7 +2,7 @@ namespace Sledgemapper.Shared.Entities
{ {
public class Player public class Player
{ {
public string ConnectionId { get; set; } public int UserId { get; set; }
public string Color { get; set; } public string Color { get; set; }
public string Initials { get; set; } public string Initials { get; set; }

View file

@ -7,6 +7,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Sledgemapper namespace Sledgemapper
@ -35,16 +37,8 @@ namespace Sledgemapper
var httpClientHandler = new HttpClientHandler();
//if (myConfigurationService.VerifySslCertificate == false)
//{
httpClientHandler.ServerCertificateCustomValidationCallback =
(message, certificate, chain, sslPolicyErrors) => true;
//}
Api = RestService.For<IMapApi>( Api = RestService.For<IMapApi>(
new HttpClient(httpClientHandler) new HttpClient(new AuthenticatedHttpClientHandler(GetToken))
{ {
BaseAddress = new Uri("http://localhost:5000") BaseAddress = new Uri("http://localhost:5000")
} }
@ -59,7 +53,7 @@ namespace Sledgemapper
Connection.On<Player>("PlayerUpdate", (player) => Connection.On<Player>("PlayerUpdate", (player) =>
{ {
var p = SessionData.Players.FirstOrDefault(m => m.ConnectionId == player.ConnectionId); var p = SessionData.Players.FirstOrDefault(m => m.UserId == player.UserId);
if (p != null) if (p != null)
{ {
p.Position = player.Position; p.Position = player.Position;
@ -101,7 +95,7 @@ namespace Sledgemapper
Connection.On<Player>("NewPlayer", (player) => Connection.On<Player>("NewPlayer", (player) =>
{ {
var p = SessionData.Players.FirstOrDefault(m => m.ConnectionId == player.ConnectionId); var p = SessionData.Players.FirstOrDefault(m => m.UserId == player.UserId);
if (p is null) if (p is null)
{ {
SessionData.Players.Add(player); SessionData.Players.Add(player);
@ -114,6 +108,11 @@ namespace Sledgemapper
}); });
} }
private Task<string> GetToken()
{
return Task.FromResult(_authenticateResponse.Token);
}
public async Task<bool> Register(RegisterModel registerModel) public async Task<bool> Register(RegisterModel registerModel)
{ {
var result = await Api.Register(registerModel); var result = await Api.Register(registerModel);
@ -173,4 +172,34 @@ namespace Sledgemapper
} }
} }
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);
}
}
} }

View file

@ -9,8 +9,12 @@ using System.Threading.Tasks;
namespace Sledgemapper namespace Sledgemapper
{ {
[Headers("Authorization: Bearer")]
public interface IMapApi public interface IMapApi
{ {
[Post("/session/{sessionName}")]
Task<bool> NewSession(string sessionName);
[Post("/session/{sessionName}/tile")] [Post("/session/{sessionName}/tile")]
Task NewTile([Body] Tile tile, string sessionName); Task NewTile([Body] Tile tile, string sessionName);
@ -29,9 +33,12 @@ namespace Sledgemapper
[Delete("/session/{sessionName}/overlay")] [Delete("/session/{sessionName}/overlay")]
Task DeleteOverlay([Body] Overlay overlay, string sessionName); Task DeleteOverlay([Body] Overlay overlay, string sessionName);
[Headers("Authorization")]
[Post("/users/register")] [Post("/users/register")]
Task<HttpResponseMessage> Register([Body] RegisterModel registerModel); Task<HttpResponseMessage> Register([Body] RegisterModel registerModel);
[Headers("Authorization")]
[Post("/users/authenticate")] [Post("/users/authenticate")]
Task<AuthenticateResponse> Authenticate([Body] AuthenticateModel registerModel); Task<AuthenticateResponse> Authenticate([Body] AuthenticateModel registerModel);
} }

View file

@ -473,16 +473,21 @@ namespace Sledgemapper
var successful = false; var successful = false;
try try
{ {
var session = await _communicationManager.Connection?.InvokeAsync<Session>("NewSession", localContent.TxtSession.Text, _authResponse.Initials); var result = await _communicationManager.Api.NewSession(localContent.TxtSession.Text);
if (session != null)
// var session = await _communicationManager.Connection?.InvokeAsync<Session>("NewSession", localContent.TxtSession.Text, _authResponse.Initials);
if (result)
{ {
_sessionData = session; //_sessionData;
_sessionData.SessionName = localContent.TxtSession.Text; _sessionData.SessionName = localContent.TxtSession.Text;
_sessionData.MapEntityAdded -= OnMapEntityAdded;
_sessionData.MapEntityAdded += OnMapEntityAdded; _sessionData.MapEntityAdded += OnMapEntityAdded;
_sessionData.Players = session.Players; // _sessionData.Players = session.Players;
} }
successful = session != null; successful = result;
var result2 = await _communicationManager.Connection?.InvokeAsync<Session>("JoinSession", localContent.TxtSession.Text, _authResponse.Initials);
} }
catch (Exception ex) catch (Exception ex)
{ {