update server to implement felica polling

This commit is contained in:
ppc
2025-01-14 15:46:35 +00:00
parent b33670d849
commit 31c56d2449
5 changed files with 93 additions and 56 deletions
+32 -23
View File
@@ -1,5 +1,6 @@
using System;
using System.Globalization;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
@@ -21,11 +22,14 @@ internal static partial class WebServer
[property: JsonPropertyName("gameId")] string GameId,
[property: JsonPropertyName("serverName")] string ServerName,
[property: JsonPropertyName("sessionUptime")] long SessionUptime,
[property: JsonPropertyName("timeSinceLastPoll")] long? TimeSinceLastPoll,
[property: JsonPropertyName("physicalCardIdentifierPreference")] string PhysicalCardIdentifierPreference);
[property: JsonPropertyName("timeSinceLastPoll")] long? TimeSinceLastPoll);
public record CardReadRequest(
[property: JsonPropertyName("cardId")] string MatrixCode);
[property: JsonPropertyName("cardId")] string AccessCode,
[property: JsonPropertyName("physicalCardIDm")] string PhysicalCardIDm);
public record ServerErrorMessage(
[property: JsonPropertyName("message")] string Message);
public static WebApplication BuildServer(params string[] listenAddresses)
{
@@ -83,8 +87,7 @@ internal static partial class WebServer
Config.GameId,
Config.ServerName,
Environment.TickCount64 - startedAt,
lastPollAt < 0 ? null : Environment.TickCount64 - lastPollAt,
Config.PhysicalCardIdentifierPreference);
lastPollAt < 0 ? null : Environment.TickCount64 - lastPollAt);
return Results.Ok(state);
}
@@ -99,23 +102,25 @@ internal static partial class WebServer
}
catch (JsonException e)
{
ctx.Response.StatusCode = 400;
await ctx.Response.WriteAsync(e.Message);
await WriteErrorResponse(ctx, StatusCodes.Status400BadRequest, e.Message);
return;
}
if (string.IsNullOrEmpty(request?.MatrixCode))
if (string.IsNullOrEmpty(request?.AccessCode))
{
ctx.Response.StatusCode = 400;
await ctx.Response.WriteAsync("Card id not provided.");
await WriteErrorResponse(ctx, StatusCodes.Status400BadRequest, "Access Code not provided.");
return;
}
if (request.MatrixCode.Length is 0 or < 20)
if (request.AccessCode.Length is 0 or < 20 || !request.AccessCode.Any(char.IsAsciiDigit))
{
ctx.Response.StatusCode = 422;
await ctx.Response.WriteAsync("Invalid card id length.");
await WriteErrorResponse(ctx, StatusCodes.Status422UnprocessableEntity, "Invalid Access Code.");
return;
}
if (request.AccessCode.All(x => x == '0'))
{
await WriteErrorResponse(ctx, StatusCodes.Status403Forbidden, "All-zero access codes are forbidden.");
return;
}
@@ -124,26 +129,30 @@ internal static partial class WebServer
if (currentCard?.Expired == false)
{
var timeLeft = Math.Ceiling(TimeSpan.FromMilliseconds(currentCard.ExpiresAt - Environment.TickCount64).TotalSeconds);
ctx.Response.StatusCode = 429;
ctx.Response.Headers.RetryAfter = timeLeft.ToString(CultureInfo.InvariantCulture);
ctx.Response.StatusCode = StatusCodes.Status429TooManyRequests;
ctx.Response.Headers.RetryAfter = Math.Ceiling(TimeSpan.FromMilliseconds(currentCard.ExpiresAt - Environment.TickCount64).TotalSeconds).ToString(CultureInfo.InvariantCulture);
return;
}
if (cardPresenter.SetCard(request.MatrixCode) != null)
if (cardPresenter.SetCard(request.AccessCode, request.PhysicalCardIDm) != null)
{
ctx.Response.StatusCode = 202;
ctx.Response.StatusCode = StatusCodes.Status202Accepted;
}
else
{
ctx.Response.StatusCode = 422;
await ctx.Response.WriteAsync("Invalid card id format.");
await WriteErrorResponse(ctx, StatusCodes.Status422UnprocessableEntity, "Invalid card id format.");
}
}
private static Task WriteErrorResponse(HttpContext ctx, int code, string message)
{
ctx.Response.StatusCode = code;
return ctx.Response.WriteAsJsonAsync(new ServerErrorMessage(message), SerializerContext.Default.ServerErrorMessage);
}
[JsonSerializable(typeof(SystemState))]
[JsonSerializable(typeof(CardReadRequest))]
[JsonSerializable(typeof(ServerErrorMessage))]
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.Never)]
private partial class SerializerContext : JsonSerializerContext;
}