mapper class and delete old stuff
This commit is contained in:
@@ -21,15 +21,18 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
private readonly IGameboardManager gameboardManager;
|
||||
private readonly IGameboardRepository gameboardRepository;
|
||||
private readonly ISocketConnectionManager communicationManager;
|
||||
private readonly IModelMapper mapper;
|
||||
|
||||
public GameController(
|
||||
IGameboardRepository repository,
|
||||
IGameboardManager manager,
|
||||
ISocketConnectionManager communicationManager)
|
||||
ISocketConnectionManager communicationManager,
|
||||
IModelMapper mapper)
|
||||
{
|
||||
gameboardManager = manager;
|
||||
gameboardRepository = repository;
|
||||
this.communicationManager = communicationManager;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
[HttpPost("JoinCode")]
|
||||
@@ -75,32 +78,35 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
if (user == null || (session.Player1.Id != user.Id && session.Player2?.Id != user.Id))
|
||||
if (user == null || (session.Player1Name != user.Id && session.Player2Name != user.Id))
|
||||
{
|
||||
return Forbid("User is not seated at this game.");
|
||||
}
|
||||
|
||||
var move = request.Move;
|
||||
var moveModel = move.PieceFromCaptured.HasValue
|
||||
? new Models.Move(move.PieceFromCaptured.Value, move.To, move.IsPromotion)
|
||||
: new Models.Move(move.From!, move.To, move.IsPromotion);
|
||||
var moveSuccess = session.Shogi.Move(moveModel);
|
||||
|
||||
if (moveSuccess)
|
||||
try
|
||||
{
|
||||
var createSuccess = await gameboardRepository.CreateBoardState(session);
|
||||
if (!createSuccess)
|
||||
{
|
||||
throw new ApplicationException("Unable to persist board state.");
|
||||
}
|
||||
await communicationManager.BroadcastToPlayers(new MoveResponse
|
||||
{
|
||||
GameName = session.Name,
|
||||
PlayerName = user.Id
|
||||
}, session.Player1.Id, session.Player2?.Id);
|
||||
var move = request.Move;
|
||||
if (move.PieceFromCaptured.HasValue)
|
||||
session.Move(mapper.Map(move.PieceFromCaptured.Value), move.To);
|
||||
else if (!string.IsNullOrWhiteSpace(move.From))
|
||||
session.Move(move.From, move.To, move.IsPromotion);
|
||||
|
||||
await gameboardRepository.CreateBoardState(session);
|
||||
await communicationManager.BroadcastToPlayers(
|
||||
new MoveResponse
|
||||
{
|
||||
GameName = session.Name,
|
||||
PlayerName = user.Id
|
||||
},
|
||||
session.Player1Name,
|
||||
session.Player2Name);
|
||||
|
||||
return Ok();
|
||||
}
|
||||
return Conflict("Illegal move.");
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return Conflict(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Use JWT tokens for guests so they can authenticate and use API routes, too.
|
||||
@@ -128,28 +134,15 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
public async Task<IActionResult> PostSession([FromBody] PostSession request)
|
||||
{
|
||||
var user = await ReadUserOrThrow();
|
||||
var session = new Models.SessionMetadata(request.Name, request.IsPrivate, user!);
|
||||
var success = await gameboardRepository.CreateSession(session);
|
||||
|
||||
if (success)
|
||||
var session = new Shogi.Domain.SessionMetadata(request.Name, request.IsPrivate, user.Id);
|
||||
await gameboardRepository.CreateSession(session);
|
||||
await communicationManager.BroadcastToAll(new CreateGameResponse
|
||||
{
|
||||
try
|
||||
{
|
||||
Game = mapper.Map(session),
|
||||
PlayerName = user.Id
|
||||
});
|
||||
|
||||
await communicationManager.BroadcastToAll(new CreateGameResponse
|
||||
{
|
||||
Game = session.ToServiceModel(),
|
||||
PlayerName = user.Id
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.Error.WriteLine("Error broadcasting during PostSession");
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
return Conflict();
|
||||
return Ok();
|
||||
|
||||
}
|
||||
|
||||
@@ -174,40 +167,16 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
{
|
||||
BoardState = new BoardState
|
||||
{
|
||||
Board = null,
|
||||
Player1Hand = session.Player1Hand.Select(MapPiece).ToList(),
|
||||
Player2Hand = session.Player2Hand.Select(MapPiece).ToList(),
|
||||
PlayerInCheck = session.InCheck.HasValue ? Map(session.InCheck.Value) : null
|
||||
Board = mapper.Map(session.BoardState),
|
||||
Player1Hand = session.Player1Hand.Select(mapper.Map).ToList(),
|
||||
Player2Hand = session.Player2Hand.Select(mapper.Map).ToList(),
|
||||
PlayerInCheck = mapper.Map(session.InCheck)
|
||||
},
|
||||
GameName = session.Name,
|
||||
Player1 = session.Player1Name,
|
||||
Player2 = session.Player2Name
|
||||
};
|
||||
return this.Ok(response);
|
||||
|
||||
static WhichPlayer Map(Shogi.Domain.WhichPlayer whichPlayer)
|
||||
{
|
||||
return whichPlayer == Shogi.Domain.WhichPlayer.Player1
|
||||
? WhichPlayer.Player1
|
||||
: WhichPlayer.Player2;
|
||||
}
|
||||
static Piece MapPiece(Shogi.Domain.Pieces.Piece piece)
|
||||
{
|
||||
var owner = Map(piece.Owner);
|
||||
var whichPiece = piece.WhichPiece switch
|
||||
{
|
||||
Shogi.Domain.WhichPiece.King => WhichPiece.King,
|
||||
Shogi.Domain.WhichPiece.GoldGeneral => WhichPiece.GoldGeneral,
|
||||
Shogi.Domain.WhichPiece.SilverGeneral => WhichPiece.SilverGeneral,
|
||||
Shogi.Domain.WhichPiece.Bishop => WhichPiece.Bishop,
|
||||
Shogi.Domain.WhichPiece.Rook => WhichPiece.Rook,
|
||||
Shogi.Domain.WhichPiece.Knight => WhichPiece.Knight,
|
||||
Shogi.Domain.WhichPiece.Lance => WhichPiece.Lance,
|
||||
Shogi.Domain.WhichPiece.Pawn => WhichPiece.Pawn,
|
||||
_ => throw new ArgumentException($"Unknown value for {nameof(WhichPiece)}")
|
||||
};
|
||||
return new Piece { IsPromoted = piece.IsPromoted, Owner = owner, WhichPiece = whichPiece };
|
||||
}
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@@ -217,18 +186,18 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
var sessions = await gameboardRepository.ReadSessionMetadatas();
|
||||
|
||||
var sessionsJoinedByUser = sessions
|
||||
.Where(s => s.IsSeated(user))
|
||||
.Select(s => s.ToServiceModel())
|
||||
.Where(s => s.IsSeated(user.Id))
|
||||
.Select(s => mapper.Map(s))
|
||||
.ToList();
|
||||
var sessionsNotJoinedByUser = sessions
|
||||
.Where(s => !s.IsSeated(user))
|
||||
.Select(s => s.ToServiceModel())
|
||||
.Where(s => !s.IsSeated(user.Id))
|
||||
.Select(s => mapper.Map(s))
|
||||
.ToList();
|
||||
|
||||
return new GetSessionsResponse
|
||||
{
|
||||
PlayerHasJoinedSessions = new Collection<Session>(sessionsJoinedByUser),
|
||||
AllOtherSessions = new Collection<Session>(sessionsNotJoinedByUser)
|
||||
PlayerHasJoinedSessions = sessionsJoinedByUser,
|
||||
AllOtherSessions = sessionsNotJoinedByUser
|
||||
};
|
||||
}
|
||||
|
||||
@@ -246,13 +215,12 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
return this.Conflict("This session already has two seated players and is full.");
|
||||
}
|
||||
|
||||
session.SetPlayer2(user);
|
||||
var success = await gameboardRepository.UpdateSession(session);
|
||||
if (!success) return this.Problem(detail: "Unable to update session.");
|
||||
session.SetPlayer2(user.Id);
|
||||
await gameboardRepository.UpdateSession(session);
|
||||
|
||||
var opponentName = user.Id == session.Player1.Id
|
||||
? session.Player2!.Id
|
||||
: session.Player1.Id;
|
||||
var opponentName = user.Id == session.Player1
|
||||
? session.Player2!
|
||||
: session.Player1;
|
||||
await communicationManager.BroadcastToPlayers(new JoinGameResponse
|
||||
{
|
||||
GameName = session.Name,
|
||||
|
||||
@@ -51,13 +51,13 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
public async Task<IActionResult> GuestLogout()
|
||||
{
|
||||
var signoutTask = HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
|
||||
var userId = User?.UserId();
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
connectionManager.Unsubscribe(userId);
|
||||
}
|
||||
|
||||
|
||||
await signoutTask;
|
||||
return Ok();
|
||||
}
|
||||
@@ -68,10 +68,8 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
var user = await gameboardManager.ReadUser(User);
|
||||
if (user == null)
|
||||
{
|
||||
if (await gameboardManager.CreateUser(User))
|
||||
{
|
||||
user = await gameboardManager.ReadUser(User);
|
||||
}
|
||||
await gameboardManager.CreateUser(User);
|
||||
user = await gameboardManager.ReadUser(User);
|
||||
}
|
||||
|
||||
if (user == null)
|
||||
@@ -92,11 +90,7 @@ namespace Gameboard.ShogiUI.Sockets.Controllers
|
||||
{
|
||||
// Create a guest user.
|
||||
var newUser = Models.User.CreateGuestUser(Guid.NewGuid().ToString());
|
||||
var success = await gameboardRepository.CreateUser(newUser);
|
||||
if (!success)
|
||||
{
|
||||
return Conflict();
|
||||
}
|
||||
await gameboardRepository.CreateUser(newUser);
|
||||
|
||||
var identity = newUser.CreateClaimsIdentity();
|
||||
await HttpContext.SignInAsync(
|
||||
|
||||
@@ -7,68 +7,68 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Gameboard.ShogiUI.Sockets.Managers
|
||||
{
|
||||
public interface IGameboardManager
|
||||
{
|
||||
Task<bool> AssignPlayer2ToSession(string sessionName, User user);
|
||||
Task<User?> ReadUser(ClaimsPrincipal user);
|
||||
Task<bool> CreateUser(ClaimsPrincipal user);
|
||||
}
|
||||
public interface IGameboardManager
|
||||
{
|
||||
Task AssignPlayer2ToSession(string sessionName, User user);
|
||||
Task<User?> ReadUser(ClaimsPrincipal user);
|
||||
Task<User?> CreateUser(ClaimsPrincipal user);
|
||||
}
|
||||
|
||||
public class GameboardManager : IGameboardManager
|
||||
{
|
||||
private readonly IGameboardRepository repository;
|
||||
public class GameboardManager : IGameboardManager
|
||||
{
|
||||
private readonly IGameboardRepository repository;
|
||||
|
||||
public GameboardManager(IGameboardRepository repository)
|
||||
{
|
||||
this.repository = repository;
|
||||
}
|
||||
public GameboardManager(IGameboardRepository repository)
|
||||
{
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
public Task<bool> CreateUser(ClaimsPrincipal principal)
|
||||
{
|
||||
var id = principal.UserId();
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
public async Task<User> CreateUser(ClaimsPrincipal principal)
|
||||
{
|
||||
var id = principal.UserId();
|
||||
if (string.IsNullOrEmpty(id))
|
||||
{
|
||||
throw new InvalidOperationException("Cannot create user from given claims.");
|
||||
}
|
||||
|
||||
var user = principal.IsGuest()
|
||||
? User.CreateGuestUser(id)
|
||||
: User.CreateMsalUser(id);
|
||||
var user = principal.IsGuest()
|
||||
? User.CreateGuestUser(id)
|
||||
: User.CreateMsalUser(id);
|
||||
|
||||
return repository.CreateUser(user);
|
||||
}
|
||||
await repository.CreateUser(user);
|
||||
return user;
|
||||
}
|
||||
|
||||
public Task<User?> ReadUser(ClaimsPrincipal principal)
|
||||
{
|
||||
var userId = principal.UserId();
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
return repository.ReadUser(userId);
|
||||
}
|
||||
public Task<User?> ReadUser(ClaimsPrincipal principal)
|
||||
{
|
||||
var userId = principal.UserId();
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
return repository.ReadUser(userId);
|
||||
}
|
||||
|
||||
return Task.FromResult<User?>(null);
|
||||
}
|
||||
return Task.FromResult<User?>(null);
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> CreateJoinCode(string sessionName, string playerName)
|
||||
{
|
||||
//var session = await repository.GetGame(sessionName);
|
||||
//if (playerName == session?.Player1)
|
||||
//{
|
||||
// return await repository.PostJoinCode(sessionName, playerName);
|
||||
//}
|
||||
return string.Empty;
|
||||
}
|
||||
public async Task<string> CreateJoinCode(string sessionName, string playerName)
|
||||
{
|
||||
//var session = await repository.GetGame(sessionName);
|
||||
//if (playerName == session?.Player1)
|
||||
//{
|
||||
// return await repository.PostJoinCode(sessionName, playerName);
|
||||
//}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public async Task<bool> AssignPlayer2ToSession(string sessionName, User user)
|
||||
{
|
||||
var session = await repository.ReadSessionMetaData(sessionName);
|
||||
if (session != null && !session.IsPrivate && session.Player2 == null)
|
||||
{
|
||||
session.SetPlayer2(user);
|
||||
return await repository.UpdateSession(session);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public async Task AssignPlayer2ToSession(string sessionName, User user)
|
||||
{
|
||||
var session = await repository.ReadSessionMetaData(sessionName);
|
||||
if (session != null && !session.IsPrivate && session.Player2 == null)
|
||||
{
|
||||
session.SetPlayer2(user.Id);
|
||||
await repository.UpdateSession(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
100
Gameboard.ShogiUI.Sockets/Managers/ModelMapper.cs
Normal file
100
Gameboard.ShogiUI.Sockets/Managers/ModelMapper.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using Gameboard.ShogiUI.Sockets.ServiceModels.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using DomainWhichPiece = Shogi.Domain.WhichPiece;
|
||||
using DomainWhichPlayer = Shogi.Domain.WhichPlayer;
|
||||
|
||||
namespace Gameboard.ShogiUI.Sockets.Managers
|
||||
{
|
||||
public class ModelMapper : IModelMapper
|
||||
{
|
||||
public WhichPlayer Map(DomainWhichPlayer whichPlayer)
|
||||
{
|
||||
return whichPlayer switch
|
||||
{
|
||||
DomainWhichPlayer.Player1 => WhichPlayer.Player1,
|
||||
DomainWhichPlayer.Player2 => WhichPlayer.Player2,
|
||||
_ => throw new ArgumentException("Unrecognized value for WhichPlayer", nameof(whichPlayer))
|
||||
};
|
||||
}
|
||||
|
||||
public WhichPlayer? Map(DomainWhichPlayer? whichPlayer)
|
||||
{
|
||||
return whichPlayer.HasValue
|
||||
? Map(whichPlayer.Value)
|
||||
: null;
|
||||
}
|
||||
|
||||
public WhichPiece Map(DomainWhichPiece whichPiece)
|
||||
{
|
||||
return whichPiece switch
|
||||
{
|
||||
DomainWhichPiece.King => WhichPiece.King,
|
||||
DomainWhichPiece.GoldGeneral => WhichPiece.GoldGeneral,
|
||||
DomainWhichPiece.SilverGeneral => WhichPiece.SilverGeneral,
|
||||
DomainWhichPiece.Bishop => WhichPiece.Bishop,
|
||||
DomainWhichPiece.Rook => WhichPiece.Rook,
|
||||
DomainWhichPiece.Knight => WhichPiece.Knight,
|
||||
DomainWhichPiece.Lance => WhichPiece.Lance,
|
||||
DomainWhichPiece.Pawn => WhichPiece.Pawn,
|
||||
_ => throw new ArgumentException("Unrecognized value", nameof(whichPiece)),
|
||||
};
|
||||
}
|
||||
|
||||
public DomainWhichPiece Map(WhichPiece whichPiece)
|
||||
{
|
||||
return whichPiece switch
|
||||
{
|
||||
WhichPiece.King => DomainWhichPiece.King,
|
||||
WhichPiece.GoldGeneral => DomainWhichPiece.GoldGeneral,
|
||||
WhichPiece.SilverGeneral => DomainWhichPiece.SilverGeneral,
|
||||
WhichPiece.Bishop => DomainWhichPiece.Bishop,
|
||||
WhichPiece.Rook => DomainWhichPiece.Rook,
|
||||
WhichPiece.Knight => DomainWhichPiece.Knight,
|
||||
WhichPiece.Lance => DomainWhichPiece.Lance,
|
||||
WhichPiece.Pawn => DomainWhichPiece.Pawn,
|
||||
_ => throw new ArgumentException("Unrecognized value", nameof(whichPiece)),
|
||||
};
|
||||
}
|
||||
|
||||
public SessionMetadata Map(Shogi.Domain.SessionMetadata session)
|
||||
{
|
||||
return new SessionMetadata
|
||||
{
|
||||
Name = session.Name,
|
||||
Player1 = session.Player1,
|
||||
Player2 = session.Player2,
|
||||
IsPrivate = session.IsPrivate
|
||||
};
|
||||
}
|
||||
|
||||
public Piece Map(Shogi.Domain.Pieces.Piece piece)
|
||||
{
|
||||
return new Piece { IsPromoted = piece.IsPromoted, Owner = Map(piece.Owner), WhichPiece = Map(piece.WhichPiece) };
|
||||
}
|
||||
|
||||
public Dictionary<string, Piece?> Map(IDictionary<string, Shogi.Domain.Pieces.Piece?> boardState)
|
||||
{
|
||||
return boardState.ToDictionary(kvp => kvp.Key, kvp => MapNullable(kvp.Value));
|
||||
}
|
||||
|
||||
public Piece? MapNullable(Shogi.Domain.Pieces.Piece? piece)
|
||||
{
|
||||
if (piece == null) return null;
|
||||
return Map(piece);
|
||||
}
|
||||
}
|
||||
|
||||
public interface IModelMapper
|
||||
{
|
||||
WhichPlayer Map(DomainWhichPlayer whichPlayer);
|
||||
WhichPlayer? Map(DomainWhichPlayer? whichPlayer);
|
||||
WhichPiece Map(DomainWhichPiece whichPiece);
|
||||
DomainWhichPiece Map(WhichPiece value);
|
||||
SessionMetadata Map(Shogi.Domain.SessionMetadata session);
|
||||
Piece Map(Shogi.Domain.Pieces.Piece p);
|
||||
Piece? MapNullable(Shogi.Domain.Pieces.Piece? p);
|
||||
Dictionary<string, Piece?> Map(IDictionary<string, Shogi.Domain.Pieces.Piece?> boardState);
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,10 @@ namespace Gameboard.ShogiUI.Sockets.Managers
|
||||
{
|
||||
public interface ISocketConnectionManager
|
||||
{
|
||||
Task BroadcastToAll(IResponse response);
|
||||
Task BroadcastToAll(ISocketResponse response);
|
||||
void Subscribe(WebSocket socket, string playerName);
|
||||
void Unsubscribe(string playerName);
|
||||
Task BroadcastToPlayers(IResponse response, params string?[] playerNames);
|
||||
Task BroadcastToPlayers(ISocketResponse response, params string?[] playerNames);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -45,7 +45,7 @@ namespace Gameboard.ShogiUI.Sockets.Managers
|
||||
connections.TryRemove(playerName, out _);
|
||||
}
|
||||
|
||||
public async Task BroadcastToPlayers(IResponse response, params string?[] playerNames)
|
||||
public async Task BroadcastToPlayers(ISocketResponse response, params string?[] playerNames)
|
||||
{
|
||||
var tasks = new List<Task>(playerNames.Length);
|
||||
foreach (var name in playerNames)
|
||||
@@ -59,7 +59,7 @@ namespace Gameboard.ShogiUI.Sockets.Managers
|
||||
}
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
public Task BroadcastToAll(IResponse response)
|
||||
public Task BroadcastToAll(ISocketResponse response)
|
||||
{
|
||||
var message = JsonConvert.SerializeObject(response);
|
||||
logger.LogInformation($"Broadcasting\n{0}", message);
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
using Gameboard.ShogiUI.Sockets.ServiceModels.Types;
|
||||
using Gameboard.ShogiUI.Sockets.Utilities;
|
||||
using System.Diagnostics;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Gameboard.ShogiUI.Sockets.Models
|
||||
{
|
||||
[DebuggerDisplay("{From} - {To}")]
|
||||
public class Move
|
||||
{
|
||||
public Vector2? From { get; } // TODO: Use string notation
|
||||
public bool IsPromotion { get; }
|
||||
public WhichPiece? PieceFromHand { get; }
|
||||
public Vector2 To { get; }
|
||||
|
||||
public Move(Vector2 from, Vector2 to, bool isPromotion = false)
|
||||
{
|
||||
From = from;
|
||||
To = to;
|
||||
IsPromotion = isPromotion;
|
||||
}
|
||||
public Move(WhichPiece pieceFromHand, Vector2 to)
|
||||
{
|
||||
PieceFromHand = pieceFromHand;
|
||||
To = to;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to represent moving a piece on the Board to another position on the Board.
|
||||
/// </summary>
|
||||
/// <param name="fromNotation">Position the piece is being moved from.</param>
|
||||
/// <param name="toNotation">Position the piece is being moved to.</param>
|
||||
/// <param name="isPromotion">If the moving piece should be promoted.</param>
|
||||
public Move(string fromNotation, string toNotation, bool isPromotion = false)
|
||||
{
|
||||
From = NotationHelper.FromBoardNotation(fromNotation);
|
||||
To = NotationHelper.FromBoardNotation(toNotation);
|
||||
IsPromotion = isPromotion;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to represent moving a piece from the Hand to the Board.
|
||||
/// </summary>
|
||||
/// <param name="pieceFromHand">The piece being moved from the Hand to the Board.</param>
|
||||
/// <param name="toNotation">Position the piece is being moved to.</param>
|
||||
/// <param name="isPromotion">If the moving piece should be promoted.</param>
|
||||
public Move(WhichPiece pieceFromHand, string toNotation, bool isPromotion = false)
|
||||
{
|
||||
From = null;
|
||||
PieceFromHand = pieceFromHand;
|
||||
To = NotationHelper.FromBoardNotation(toNotation);
|
||||
IsPromotion = isPromotion;
|
||||
}
|
||||
|
||||
public ServiceModels.Types.Move ToServiceModel() => new()
|
||||
{
|
||||
From = From.HasValue ? NotationHelper.ToBoardNotation(From.Value) : null,
|
||||
IsPromotion = IsPromotion,
|
||||
PieceFromCaptured = PieceFromHand.HasValue ? PieceFromHand : null,
|
||||
To = NotationHelper.ToBoardNotation(To)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
namespace Gameboard.ShogiUI.Sockets.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// A representation of a Session without the board and game-rules.
|
||||
/// </summary>
|
||||
public class SessionMetadata
|
||||
{
|
||||
public string Name { get; }
|
||||
public User Player1 { get; }
|
||||
public User? Player2 { get; private set; }
|
||||
public bool IsPrivate { get; }
|
||||
|
||||
public SessionMetadata(string name, bool isPrivate, User player1, User? player2 = null)
|
||||
{
|
||||
Name = name;
|
||||
IsPrivate = isPrivate;
|
||||
Player1 = player1;
|
||||
Player2 = player2;
|
||||
}
|
||||
public SessionMetadata(Session sessionModel)
|
||||
{
|
||||
Name = sessionModel.Name;
|
||||
IsPrivate = sessionModel.IsPrivate;
|
||||
Player1 = sessionModel.Player1;
|
||||
Player2 = sessionModel.Player2;
|
||||
}
|
||||
|
||||
public void SetPlayer2(User user)
|
||||
{
|
||||
Player2 = user;
|
||||
}
|
||||
|
||||
public bool IsSeated(User user) => user.Id == Player1.Id || user.Id == Player2?.Id;
|
||||
|
||||
public ServiceModels.Types.Session ToServiceModel() => new(Name, Player1.DisplayName, Player2?.DisplayName);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,15 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Kestrel": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "/swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000"
|
||||
}
|
||||
},
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
@@ -7,23 +18,5 @@
|
||||
"applicationUrl": "http://localhost:50728/",
|
||||
"sslPort": 44315
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchUrl": "weatherforecast",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Kestrel": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "/swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
},
|
||||
"applicationUrl": "http://localhost:5100"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Gameboard.ShogiUI.Sockets.Repositories.CouchModels
|
||||
using Shogi.Domain;
|
||||
|
||||
namespace Gameboard.ShogiUI.Sockets.Repositories.CouchModels
|
||||
{
|
||||
public class SessionDocument : CouchDocument
|
||||
{
|
||||
@@ -17,12 +19,12 @@
|
||||
Player2Id = string.Empty;
|
||||
}
|
||||
|
||||
public SessionDocument(Models.SessionMetadata sessionMetaData)
|
||||
public SessionDocument(SessionMetadata sessionMetaData)
|
||||
: base(sessionMetaData.Name, WhichDocumentType.Session)
|
||||
{
|
||||
Name = sessionMetaData.Name;
|
||||
Player1Id = sessionMetaData.Player1.Id;
|
||||
Player2Id = sessionMetaData.Player2?.Id;
|
||||
Player1Id = sessionMetaData.Player1;
|
||||
Player2Id = sessionMetaData.Player2;
|
||||
IsPrivate = sessionMetaData.IsPrivate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
{
|
||||
public interface IGameboardRepository
|
||||
{
|
||||
Task<bool> CreateBoardState(Session session);
|
||||
Task<bool> CreateSession(Models.SessionMetadata session);
|
||||
Task<bool> CreateUser(Models.User user);
|
||||
Task<Collection<Models.SessionMetadata>> ReadSessionMetadatas();
|
||||
Task CreateBoardState(Session session);
|
||||
Task CreateSession(SessionMetadata session);
|
||||
Task CreateUser(Models.User user);
|
||||
Task<Collection<SessionMetadata>> ReadSessionMetadatas();
|
||||
Task<Session?> ReadSession(string name);
|
||||
Task<bool> UpdateSession(Models.SessionMetadata session);
|
||||
Task<Models.SessionMetadata?> ReadSessionMetaData(string name);
|
||||
Task UpdateSession(SessionMetadata session);
|
||||
Task<SessionMetadata?> ReadSessionMetaData(string name);
|
||||
Task<Models.User?> ReadUser(string userName);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task<Collection<Models.SessionMetadata>> ReadSessionMetadatas()
|
||||
public async Task<Collection<SessionMetadata>> ReadSessionMetadatas()
|
||||
{
|
||||
var queryParams = new QueryBuilder { { "include_docs", "true" } }.ToQueryString();
|
||||
var response = await client.GetAsync($"{View_SessionMetadata}{queryParams}");
|
||||
@@ -57,7 +57,7 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
if (result != null)
|
||||
{
|
||||
var groupedBySession = result.rows.GroupBy(row => row.id);
|
||||
var sessions = new List<Models.SessionMetadata>(result.total_rows / 3);
|
||||
var sessions = new List<SessionMetadata>(result.total_rows / 3);
|
||||
foreach (var group in groupedBySession)
|
||||
{
|
||||
/**
|
||||
@@ -72,12 +72,12 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
if (session != null && player1Doc != null)
|
||||
{
|
||||
var player2 = player2Doc == null ? null : new Models.User(player2Doc);
|
||||
sessions.Add(new Models.SessionMetadata(session.Name, session.IsPrivate, new(player1Doc), player2));
|
||||
sessions.Add(new SessionMetadata(session.Name, session.IsPrivate, player1Doc.Id, player2?.Id));
|
||||
}
|
||||
}
|
||||
return new Collection<Models.SessionMetadata>(sessions);
|
||||
return new Collection<SessionMetadata>(sessions);
|
||||
}
|
||||
return new Collection<Models.SessionMetadata>(Array.Empty<Models.SessionMetadata>());
|
||||
return new Collection<SessionMetadata>(Array.Empty<SessionMetadata>());
|
||||
}
|
||||
|
||||
public async Task<Session?> ReadSession(string name)
|
||||
@@ -130,7 +130,7 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<Models.SessionMetadata?> ReadSessionMetaData(string name)
|
||||
public async Task<SessionMetadata?> ReadSessionMetaData(string name)
|
||||
{
|
||||
var queryParams = new QueryBuilder
|
||||
{
|
||||
@@ -159,7 +159,7 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
if (session != null && player1Doc != null)
|
||||
{
|
||||
var player2 = player2Doc == null ? null : new Models.User(player2Doc);
|
||||
return new Models.SessionMetadata(session.Name, session.IsPrivate, new(player1Doc), player2);
|
||||
return new SessionMetadata(session.Name, session.IsPrivate, player1Doc.Id, player2?.Id);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -168,22 +168,15 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
/// <summary>
|
||||
/// Saves a snapshot of board state and the most recent move.
|
||||
/// </summary>
|
||||
public async Task<bool> CreateBoardState(Session session)
|
||||
public async Task CreateBoardState(Session session)
|
||||
{
|
||||
Piece? MapPiece(Shogi.Domain.Pieces.Piece? piece)
|
||||
{
|
||||
return piece == null
|
||||
? null
|
||||
: new Piece { IsPromoted = piece.IsPromoted, Owner = piece.Owner, WhichPiece = piece.WhichPiece };
|
||||
}
|
||||
|
||||
var boardStateDocument = new BoardStateDocument(session.Name, session);
|
||||
var content = new StringContent(JsonConvert.SerializeObject(boardStateDocument), Encoding.UTF8, ApplicationJson);
|
||||
var response = await client.PostAsync(string.Empty, content);
|
||||
return response.IsSuccessStatusCode;
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task<bool> CreateSession(Models.SessionMetadata session)
|
||||
public async Task CreateSession(SessionMetadata session)
|
||||
{
|
||||
var sessionDocument = new SessionDocument(session);
|
||||
var sessionContent = new StringContent(JsonConvert.SerializeObject(sessionDocument), Encoding.UTF8, ApplicationJson);
|
||||
@@ -195,16 +188,15 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
if ((await postSessionDocumentTask).IsSuccessStatusCode)
|
||||
{
|
||||
var response = await client.PostAsync(string.Empty, boardStateContent);
|
||||
return response.IsSuccessStatusCode;
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateSession(Models.SessionMetadata session)
|
||||
public async Task UpdateSession(SessionMetadata session)
|
||||
{
|
||||
// GET existing session to get revisionId.
|
||||
var readResponse = await client.GetAsync(session.Name);
|
||||
if (!readResponse.IsSuccessStatusCode) return false;
|
||||
readResponse.EnsureSuccessStatusCode();
|
||||
var sessionDocument = JsonConvert.DeserializeObject<SessionDocument>(await readResponse.Content.ReadAsStringAsync());
|
||||
|
||||
// PUT the document with the revisionId.
|
||||
@@ -214,7 +206,7 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
};
|
||||
var content = new StringContent(JsonConvert.SerializeObject(couchModel), Encoding.UTF8, ApplicationJson);
|
||||
var response = await client.PutAsync(couchModel.Id, content);
|
||||
return response.IsSuccessStatusCode;
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
//public async Task<bool> PutJoinPublicSession(PutJoinPublicSession request)
|
||||
//{
|
||||
@@ -285,12 +277,12 @@ namespace Gameboard.ShogiUI.Sockets.Repositories
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task<bool> CreateUser(Models.User user)
|
||||
public async Task CreateUser(Models.User user)
|
||||
{
|
||||
var couchModel = new UserDocument(user.Id, user.DisplayName, user.LoginPlatform);
|
||||
var content = new StringContent(JsonConvert.SerializeObject(couchModel), Encoding.UTF8, ApplicationJson);
|
||||
var response = await client.PostAsync(string.Empty, content);
|
||||
return response.IsSuccessStatusCode;
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public void ReadMoveHistory()
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace Gameboard.ShogiUI.Sockets
|
||||
if (user == null)
|
||||
{
|
||||
var newUser = Models.User.CreateMsalUser(nameClaim.Value);
|
||||
var success = await gameboardRepository.CreateUser(newUser);
|
||||
if (success) user = newUser;
|
||||
await gameboardRepository.CreateUser(newUser);
|
||||
user = newUser;
|
||||
}
|
||||
|
||||
if (user != null)
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Gameboard.ShogiUI.Sockets
|
||||
var baseUrl = $"{Configuration["AppSettings:CouchDB:Url"]}/{Configuration["AppSettings:CouchDB:Database"]}/";
|
||||
c.BaseAddress = new Uri(baseUrl);
|
||||
});
|
||||
services.AddTransient<IModelMapper, ModelMapper>();
|
||||
|
||||
services
|
||||
.AddControllers()
|
||||
@@ -128,13 +129,17 @@ namespace Gameboard.ShogiUI.Sockets
|
||||
};
|
||||
});
|
||||
|
||||
// Remove default HttpClient logging.
|
||||
services.RemoveAll<IHttpMessageHandlerBuilderFilter>();
|
||||
services.AddHttpLogging(options =>
|
||||
{
|
||||
options.LoggingFields = Microsoft.AspNetCore.HttpLogging.HttpLoggingFields.Request;
|
||||
});
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISocketService socketConnectionManager)
|
||||
{
|
||||
app.UseHttpLogging();
|
||||
|
||||
var origins = new[] {
|
||||
"http://localhost:3000", "https://localhost:3000",
|
||||
"http://127.0.0.1:3000", "https://127.0.0.1:3000",
|
||||
@@ -147,25 +152,25 @@ namespace Gameboard.ShogiUI.Sockets
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
var client = PublicClientApplicationBuilder
|
||||
.Create(Configuration["AzureAd:ClientId"])
|
||||
.WithLogging(
|
||||
(level, message, pii) =>
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
},
|
||||
LogLevel.Verbose,
|
||||
true,
|
||||
true
|
||||
)
|
||||
.Build();
|
||||
//var client = PublicClientApplicationBuilder
|
||||
// .Create(Configuration["AzureAd:ClientId"])
|
||||
// .WithLogging(
|
||||
// (level, message, pii) =>
|
||||
// {
|
||||
// Console.WriteLine(message);
|
||||
// },
|
||||
// LogLevel.Verbose,
|
||||
// true,
|
||||
// true
|
||||
// )
|
||||
// .Build();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseHsts();
|
||||
}
|
||||
app
|
||||
.UseRequestResponseLogging()
|
||||
//.UseRequestResponseLogging()
|
||||
.UseCors(opt => opt.WithOrigins(origins).AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("Set-Cookie").AllowCredentials())
|
||||
.UseRouting()
|
||||
.UseAuthentication()
|
||||
|
||||
Reference in New Issue
Block a user