254 lines
7.1 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|