using Gameboard.ShogiUI.Sockets.Repositories.CouchModels; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; namespace Gameboard.ShogiUI.Sockets.Repositories { public interface IGameboardRepository { Task CreateGuestUser(string userName); Task CreateSession(Models.SessionMetadata session); Task> ReadSessionMetadatas(); Task IsGuestUser(string userName); Task PostJoinCode(string gameName, string userName); Task ReadSession(string name); Task ReadShogi(string name); Task UpdateSession(Models.Session session); } public class GameboardRepository : IGameboardRepository { private const string ApplicationJson = "application/json"; private readonly HttpClient client; private readonly ILogger logger; public GameboardRepository(IHttpClientFactory clientFactory, ILogger logger) { client = clientFactory.CreateClient("couchdb"); this.logger = logger; } public async Task> ReadSessionMetadatas() { var selector = new Dictionary(2) { [nameof(SessionDocument.DocumentType)] = WhichDocumentType.Session }; var q = new { Selector = selector }; var content = new StringContent(JsonConvert.SerializeObject(q), Encoding.UTF8, ApplicationJson); var response = await client.PostAsync("_find", content); var responseContent = await response.Content.ReadAsStringAsync(); var sessions = JsonConvert.DeserializeObject>(responseContent).docs; return sessions .Select(s => new Models.SessionMetadata(s.Name, s.IsPrivate, s.Player1, s.Player2)) .ToList(); } public async Task ReadSession(string name) { var readShogiTask = ReadShogi(name); var response = await client.GetAsync(name); var responseContent = await response.Content.ReadAsStringAsync(); var couchModel = JsonConvert.DeserializeObject(responseContent); var shogi = await readShogiTask; if (shogi == null) { return null; } return couchModel.ToDomainModel(shogi); } public async Task ReadShogi(string name) { var selector = new Dictionary(2) { [nameof(BoardStateDocument.DocumentType)] = WhichDocumentType.BoardState, [nameof(BoardStateDocument.Name)] = name }; var sort = new Dictionary(1) { [nameof(BoardStateDocument.CreatedDate)] = "desc" }; var query = JsonConvert.SerializeObject(new { selector, sort = new[] { sort } }); var content = new StringContent(query, Encoding.UTF8, ApplicationJson); var response = await client.PostAsync("_find", content); var responseContent = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { logger.LogError("Couch error during _find in {func}: {error}.\n\nQuery: {query}", nameof(ReadShogi), responseContent, query); return null; } var boardStates = JsonConvert .DeserializeObject>(responseContent) .docs; if (boardStates.Length == 0) return null; // Skip(1) because the first BoardState has no move; it represents the initial board state of a new Session. var moves = boardStates.Skip(1).Select(couchModel => { var move = couchModel.Move; Models.Move model = move!.PieceFromHand.HasValue ? new Models.Move(move.PieceFromHand.Value, move.To) : new Models.Move(move.From!, move.To, move.IsPromotion); return model; }).ToList(); return new Models.Shogi(moves); } public async Task CreateSession(Models.SessionMetadata session) { var sessionDocument = new SessionDocument(session); var sessionContent = new StringContent(JsonConvert.SerializeObject(sessionDocument), Encoding.UTF8, ApplicationJson); var postSessionDocumentTask = client.PostAsync(string.Empty, sessionContent); var boardStateDocument = new BoardStateDocument(session.Name, new Models.Shogi()); var boardStateContent = new StringContent(JsonConvert.SerializeObject(boardStateDocument), Encoding.UTF8, ApplicationJson); if ((await postSessionDocumentTask).IsSuccessStatusCode) { var response = await client.PostAsync(string.Empty, boardStateContent); return response.IsSuccessStatusCode; } return false; } public async Task UpdateSession(Models.Session session) { var couchModel = new SessionDocument(session); var content = new StringContent(JsonConvert.SerializeObject(couchModel), Encoding.UTF8, ApplicationJson); var response = await client.PutAsync(couchModel.Id, content); return response.IsSuccessStatusCode; } //public async Task PutJoinPublicSession(PutJoinPublicSession request) //{ // var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, MediaType); // var response = await client.PutAsync(JoinSessionRoute, content); // var json = await response.Content.ReadAsStringAsync(); // return JsonConvert.DeserializeObject(json).JoinSucceeded; //} //public async Task PostJoinPrivateSession(PostJoinPrivateSession request) //{ // var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, MediaType); // var response = await client.PostAsync(JoinSessionRoute, content); // var json = await response.Content.ReadAsStringAsync(); // var deserialized = JsonConvert.DeserializeObject(json); // if (deserialized.JoinSucceeded) // { // return deserialized.SessionName; // } // return null; //} //public async Task> GetMoves(string gameName) //{ // var uri = $"Session/{gameName}/Moves"; // var get = await client.GetAsync(Uri.EscapeUriString(uri)); // var json = await get.Content.ReadAsStringAsync(); // if (string.IsNullOrWhiteSpace(json)) // { // return new List(); // } // var response = JsonConvert.DeserializeObject(json); // return response.Moves.Select(m => new Move(m)).ToList(); //} //public async Task PostMove(string gameName, PostMove request) //{ // var uri = $"Session/{gameName}/Move"; // var content = new StringContent(JsonConvert.SerializeObject(request), Encoding.UTF8, MediaType); // await client.PostAsync(Uri.EscapeUriString(uri), content); //} public async Task PostJoinCode(string gameName, string userName) { // var uri = $"JoinCode/{gameName}"; // var serialized = JsonConvert.SerializeObject(new PostJoinCode { PlayerName = userName }); // var content = new StringContent(serialized, Encoding.UTF8, MediaType); // var json = await (await client.PostAsync(Uri.EscapeUriString(uri), content)).Content.ReadAsStringAsync(); // return JsonConvert.DeserializeObject(json).JoinCode; return string.Empty; } //public async Task GetPlayer(string playerName) //{ // var uri = $"Player/{playerName}"; // var get = await client.GetAsync(Uri.EscapeUriString(uri)); // var content = await get.Content.ReadAsStringAsync(); // if (!string.IsNullOrWhiteSpace(content)) // { // var response = JsonConvert.DeserializeObject(content); // return new Player(response.Player.Name); // } // return null; //} public async Task CreateGuestUser(string userName) { var couchModel = new UserDocument(userName, UserDocument.LoginPlatform.Guest); var content = new StringContent(JsonConvert.SerializeObject(couchModel), Encoding.UTF8, ApplicationJson); var response = await client.PostAsync(string.Empty, content); return response.IsSuccessStatusCode; } public async Task IsGuestUser(string userName) { var req = new HttpRequestMessage(HttpMethod.Head, new Uri($"{client.BaseAddress}/{UserDocument.GetDocumentId(userName)}")); var response = await client.SendAsync(req); return response.IsSuccessStatusCode; } } }