Files
Shogi/Gameboard.ShogiUI.Sockets/Controllers/GameController.cs
2022-06-22 18:29:19 -05:00

254 lines
7.1 KiB
C#

using Gameboard.ShogiUI.Sockets.Managers;
using Gameboard.ShogiUI.Sockets.Repositories;
using Gameboard.ShogiUI.Sockets.ServiceModels.Api;
using Gameboard.ShogiUI.Sockets.ServiceModels.Socket;
using Gameboard.ShogiUI.Sockets.ServiceModels.Types;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Gameboard.ShogiUI.Sockets.Controllers
{
[ApiController]
[Route("[controller]")]
[Authorize]
public class GameController : ControllerBase
{
private readonly IGameboardManager gameboardManager;
private readonly IGameboardRepository gameboardRepository;
private readonly ISocketConnectionManager communicationManager;
private readonly IModelMapper mapper;
public GameController(
IGameboardRepository repository,
IGameboardManager manager,
ISocketConnectionManager communicationManager,
IModelMapper mapper)
{
gameboardManager = manager;
gameboardRepository = repository;
this.communicationManager = communicationManager;
this.mapper = mapper;
}
[HttpPost("JoinCode")]
public async Task<IActionResult> PostGameInvitation([FromBody] PostGameInvitation request)
{
//var isPlayer1 = await gameboardManager.IsPlayer1(request.SessionName, userName);
//if (isPlayer1)
//{
// var code = await gameboardRepository.PostJoinCode(request.SessionName, userName);
// return new CreatedResult("", new PostGameInvitationResponse(code));
//}
//else
//{
return new UnauthorizedResult();
//}
}
[AllowAnonymous]
[HttpPost("GuestJoinCode")]
public async Task<IActionResult> PostGuestGameInvitation([FromBody] PostGuestGameInvitation request)
{
//var isGuest = gameboardManager.IsGuest(request.GuestId);
//var isPlayer1 = gameboardManager.IsPlayer1(request.SessionName, request.GuestId);
//if (isGuest && await isPlayer1)
//{
// var code = await gameboardRepository.PostJoinCode(request.SessionName, request.GuestId);
// return new CreatedResult("", new PostGameInvitationResponse(code));
//}
//else
//{
return new UnauthorizedResult();
//}
}
[HttpPost("{gameName}/Move")]
public async Task<IActionResult> PostMove([FromRoute] string gameName, [FromBody] PostMove request)
{
var user = await gameboardManager.ReadUser(User);
var session = await gameboardRepository.ReadSession(gameName);
if (session == null)
{
return NotFound();
}
if (user == null || (session.Player1Name != user.Id && session.Player2Name != user.Id))
{
return Forbid("User is not seated at this game.");
}
try
{
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();
}
catch (InvalidOperationException ex)
{
return Conflict(ex.Message);
}
}
// TODO: Use JWT tokens for guests so they can authenticate and use API routes, too.
//[Route("")]
//public async Task<IActionResult> PostSession([FromBody] PostSession request)
//{
// var model = new Models.Session(request.Name, request.IsPrivate, request.Player1, request.Player2);
// var success = await repository.CreateSession(model);
// if (success)
// {
// var message = new ServiceModels.Socket.Messages.CreateGameResponse(ServiceModels.Types.ClientAction.CreateGame)
// {
// Game = model.ToServiceModel(),
// PlayerName =
// }
// var task = request.IsPrivate
// ? communicationManager.BroadcastToPlayers(response, userName)
// : communicationManager.BroadcastToAll(response);
// return new CreatedResult("", null);
// }
// return new ConflictResult();
//}
[HttpPost]
public async Task<IActionResult> PostSession([FromBody] PostSession request)
{
var user = await ReadUserOrThrow();
var session = new Shogi.Domain.SessionMetadata(request.Name, request.IsPrivate, user.Id);
await gameboardRepository.CreateSession(session);
await communicationManager.BroadcastToAll(new CreateGameResponse
{
Game = mapper.Map(session),
PlayerName = user.Id
});
return Ok();
}
/// <summary>
/// Reads the board session and subscribes the caller to socket events for that session.
/// </summary>
[HttpGet("{gameName}")]
public async Task<IActionResult> GetSession([FromRoute] string gameName)
{
var user = await ReadUserOrThrow();
var session = await gameboardRepository.ReadSession(gameName);
if (session == null)
{
return NotFound();
}
var playerPerspective = session.Player2Name == user.Id
? WhichPlayer.Player2
: WhichPlayer.Player1;
var response = new Session
{
BoardState = new BoardState
{
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 Ok(response);
}
[HttpGet]
public async Task<ActionResult<GetSessionsResponse>> GetSessions()
{
var user = await ReadUserOrThrow();
var sessions = await gameboardRepository.ReadSessionMetadatas();
var sessionsJoinedByUser = sessions
.Where(s => s.IsSeated(user.Id))
.Select(s => mapper.Map(s))
.ToList();
var sessionsNotJoinedByUser = sessions
.Where(s => !s.IsSeated(user.Id))
.Select(s => mapper.Map(s))
.ToList();
return Ok(new GetSessionsResponse
{
PlayerHasJoinedSessions = sessionsJoinedByUser,
AllOtherSessions = sessionsNotJoinedByUser
});
}
[HttpPut("{gameName}")]
public async Task<IActionResult> PutJoinSession([FromRoute] string gameName)
{
var user = await ReadUserOrThrow();
var session = await gameboardRepository.ReadSessionMetaData(gameName);
if (session == null)
{
return NotFound();
}
if (session.Player2 != null)
{
return this.Conflict("This session already has two seated players and is full.");
}
session.SetPlayer2(user.Id);
await gameboardRepository.UpdateSession(session);
var opponentName = user.Id == session.Player1
? session.Player2!
: session.Player1;
await communicationManager.BroadcastToPlayers(new JoinGameResponse
{
GameName = session.Name,
PlayerName = user.Id
}, opponentName);
return Ok();
}
[Authorize(Roles = "Admin, Shogi")]
[HttpDelete("{gameName}")]
public async Task<IActionResult> DeleteSession([FromRoute] string gameName)
{
var user = await ReadUserOrThrow();
if (user.IsAdmin)
{
return Ok();
}
else
{
return Unauthorized();
}
}
private async Task<Models.User> ReadUserOrThrow()
{
var user = await gameboardManager.ReadUser(User);
if (user == null)
{
throw new UnauthorizedAccessException("Unknown user claims.");
}
return user;
}
}
}