From fea7b7812646e1f1a7e5d39a680e0ea3704a3a43 Mon Sep 17 00:00:00 2001 From: rfi Date: Mon, 19 Feb 2024 18:11:00 +0700 Subject: [PATCH] accounts db & http sdk db impl --- BLHX.Server.Common/BLHX.Server.Common.csproj | 1 + BLHX.Server.Common/Database/Account.cs | 34 ++++++++++++ BLHX.Server.Common/Database/DBManager.cs | 36 +++++++++++++ .../Controllers/AccountController.cs | 40 +++++++++++++- BLHX.Server.SDK/Models/Base.cs | 10 ++++ BLHX.Server.SDK/Models/User.cs | 43 +++++++++++++++ BLHX.Server.SDK/SDKServer.cs | 52 ++++++++++++++++++- BLHX.Server/Program.cs | 3 +- 8 files changed, 216 insertions(+), 3 deletions(-) create mode 100644 BLHX.Server.Common/Database/Account.cs create mode 100644 BLHX.Server.Common/Database/DBManager.cs create mode 100644 BLHX.Server.SDK/Models/Base.cs create mode 100644 BLHX.Server.SDK/Models/User.cs diff --git a/BLHX.Server.Common/BLHX.Server.Common.csproj b/BLHX.Server.Common/BLHX.Server.Common.csproj index 51069f8..7eaa8da 100644 --- a/BLHX.Server.Common/BLHX.Server.Common.csproj +++ b/BLHX.Server.Common/BLHX.Server.Common.csproj @@ -7,6 +7,7 @@ + diff --git a/BLHX.Server.Common/Database/Account.cs b/BLHX.Server.Common/Database/Account.cs new file mode 100644 index 0000000..cd83db6 --- /dev/null +++ b/BLHX.Server.Common/Database/Account.cs @@ -0,0 +1,34 @@ +using Microsoft.EntityFrameworkCore; +using System.ComponentModel.DataAnnotations.Schema; + +namespace BLHX.Server.Common.Database +{ + public sealed class AccountContext : DbContext, IBLHXDBContext + { + public static string DbPath => "Databases/accounts.db"; + public DbSet Accounts { get; set; } + + public AccountContext() + { + Database.EnsureCreated(); + } + + protected override void OnConfiguring(DbContextOptionsBuilder options) + => options.UseSqlite($"Data Source={((IBLHXDBContext)this).GetFullDbPath()}"); + } + + [PrimaryKey(nameof(Uid))] + public class Account + { + [DatabaseGenerated(DatabaseGeneratedOption.Identity)] + public uint Uid { get; set; } + public string DeviceId { get; set; } + public string Token { get; set; } + + public Account(string deviceId, string token) + { + DeviceId = deviceId; + Token = token; + } + } +} diff --git a/BLHX.Server.Common/Database/DBManager.cs b/BLHX.Server.Common/Database/DBManager.cs new file mode 100644 index 0000000..be69dfc --- /dev/null +++ b/BLHX.Server.Common/Database/DBManager.cs @@ -0,0 +1,36 @@ +using BLHX.Server.Common.Utils; +using Microsoft.EntityFrameworkCore; +using System.Reflection; + +namespace BLHX.Server.Common.Database +{ + public static class DBManager + { + public static readonly Logger c = new(nameof(DBManager), ConsoleColor.DarkCyan); + public static AccountContext AccountContext { get; } + + static DBManager() + { + foreach (var dbCtx in Assembly.GetExecutingAssembly().GetTypes().Where(p => typeof(IBLHXDBContext).IsAssignableFrom(p) && !p.IsInterface)) + { + var dbPath = (string)dbCtx.GetProperty(nameof(AccountContext.DbPath))!.GetValue(null)!; + var saveDir = Path.GetDirectoryName(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, dbPath))!; + if (!Directory.Exists(saveDir)) + Directory.CreateDirectory(saveDir); + } + + AccountContext = new AccountContext(); + } + } + + public interface IBLHXDBContext + { + public static abstract string DbPath { get; } + public string GetFullDbPath(); + } + + public interface IBLHXDBContext : IBLHXDBContext where TSelf : DbContext + { + string IBLHXDBContext.GetFullDbPath() => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, (string)typeof(TSelf).GetProperty(nameof(DbPath))!.GetValue(null)!); + } +} diff --git a/BLHX.Server.SDK/Controllers/AccountController.cs b/BLHX.Server.SDK/Controllers/AccountController.cs index 05b9a55..c740c18 100644 --- a/BLHX.Server.SDK/Controllers/AccountController.cs +++ b/BLHX.Server.SDK/Controllers/AccountController.cs @@ -1,4 +1,6 @@ -using BLHX.Server.Sdk; +using BLHX.Server.Common.Database; +using BLHX.Server.Sdk; +using BLHX.Server.SDK.Models; namespace BLHX.Server.SDK.Controllers { @@ -6,7 +8,43 @@ namespace BLHX.Server.SDK.Controllers { public static void Register(WebApplication app) { + app.MapPost("user/create", (HttpContext ctx, UserCreateRequest req) => + { + var account = DBManager.AccountContext.Accounts.SingleOrDefault(x => x.DeviceId == req.DeviceId); + UserCreateResponse rsp = new() { Result = 0, IsNew = 0 }; + if (account is null) + { + account = new(req.DeviceId, Guid.NewGuid().ToString()); + DBManager.AccountContext.Add(account); + DBManager.AccountContext.SaveChanges(); + rsp.IsNew = 1; + } + rsp.Uid = account.Uid; + rsp.Token = account.Token; + + return ctx.Response.WriteAsJsonAsync(rsp); + }); + + app.MapPost("user/login", (HttpContext ctx, UserLoginRequest req) => + { + var account = DBManager.AccountContext.Accounts.SingleOrDefault(x => x.Uid == req.Uid); + + if (account is not null && account.Token == req.Token) + { + return ctx.Response.WriteAsJsonAsync(new UserLoginResponse() + { + AccessToken = account.Token, + Birth = null, + ChannelId = req.StoreId, + CurrentTimestampMs = DateTimeOffset.Now.ToUnixTimeMilliseconds(), + KrKmcStatus = 2, + Result = 0, + TransCode = "NULL" + }); + } + return ctx.Response.WriteAsJsonAsync(new BaseResponse() { Result = 1 }); + }); } } } diff --git a/BLHX.Server.SDK/Models/Base.cs b/BLHX.Server.SDK/Models/Base.cs new file mode 100644 index 0000000..8ae0899 --- /dev/null +++ b/BLHX.Server.SDK/Models/Base.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; + +namespace BLHX.Server.SDK.Models +{ + class BaseResponse + { + [JsonPropertyName("result")] + public int Result { get; set; } + } +} diff --git a/BLHX.Server.SDK/Models/User.cs b/BLHX.Server.SDK/Models/User.cs new file mode 100644 index 0000000..a71a4a0 --- /dev/null +++ b/BLHX.Server.SDK/Models/User.cs @@ -0,0 +1,43 @@ +using BLHX.Server.Sdk; +using System.Text.Json.Serialization; + +namespace BLHX.Server.SDK.Models +{ + record UserCreateRequest(string ChannelId, string DeviceId) : BindableFormRequest; + record UserLoginRequest(uint Uid, string StoreId, string DeviceId, string Platform, string Token) : BindableFormRequest; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + class UserLoginResponse : BaseResponse + { + [JsonPropertyName("accessToken")] + public string AccessToken { get; set; } + + [JsonPropertyName("birth")] + public dynamic? Birth { get; set; } + + [JsonPropertyName("channelId")] + public string ChannelId { get; set; } + + [JsonPropertyName("current_timestamp_ms")] + public long CurrentTimestampMs { get; set; } + + [JsonPropertyName("kr_kmc_status")] + public int KrKmcStatus { get; set; } + + [JsonPropertyName("transcode")] + public string TransCode { get; set; } + } + + class UserCreateResponse : BaseResponse + { + [JsonPropertyName("uid")] + public uint Uid { get; set; } + + [JsonPropertyName("token")] + public string Token { get; set; } + + [JsonPropertyName("isNew")] + public int IsNew { get; set; } + } +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +} diff --git a/BLHX.Server.SDK/SDKServer.cs b/BLHX.Server.SDK/SDKServer.cs index 256de82..ef73891 100644 --- a/BLHX.Server.SDK/SDKServer.cs +++ b/BLHX.Server.SDK/SDKServer.cs @@ -1,11 +1,15 @@ using BLHX.Server.Common.Utils; +using Microsoft.AspNetCore.Mvc.Abstractions; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc; +using System.Globalization; using System.Reflection; namespace BLHX.Server.Sdk { public class SDKServer { - static readonly Logger c = new(nameof(SDKServer), ConsoleColor.Green); + public static readonly Logger c = new(nameof(SDKServer), ConsoleColor.Green); static Task? runTask = null; public static void Main(string[] args) @@ -13,11 +17,15 @@ namespace BLHX.Server.Sdk var builder = WebApplication.CreateBuilder(args); // Disables default logger builder.Logging.ClearProviders(); + builder.Services.AddMvcCore(); + builder.Services.AddAntiforgery(); var app = builder.Build(); app.Urls.Add("http://*:80"); app.Urls.Add("https://*:443"); + app.UseStatusCodePages(); + app.UseAntiforgery(); app.UseMiddleware(); foreach (Type controller in Assembly.GetExecutingAssembly().GetTypes().Where(p => typeof(IRegisterable).IsAssignableFrom(p) && !p.IsInterface)) @@ -63,4 +71,46 @@ namespace BLHX.Server.Sdk { public abstract static void Register(WebApplication app); } + + public static class BindingExtensions + { + public static async Task BindFromForm(this HttpContext httpContext) + { + var serviceProvider = httpContext.RequestServices; + var factory = serviceProvider.GetRequiredService(); + var metadataProvider = serviceProvider.GetRequiredService(); + + var metadata = metadataProvider.GetMetadataForType(typeof(T)); + var modelBinder = factory.CreateBinder(new() + { + Metadata = metadata + }); + + var context = new DefaultModelBindingContext + { + ModelMetadata = metadata, + ModelName = string.Empty, + ValueProvider = new FormValueProvider( + BindingSource.Form, + httpContext.Request.Form, + CultureInfo.InvariantCulture + ), + ActionContext = new ActionContext( + httpContext, + new RouteData(), + new ActionDescriptor()), + ModelState = new ModelStateDictionary() + }; + await modelBinder.BindModelAsync(context); + return (T?)context.Result.Model; + } + } + + public abstract record BindableFormRequest + { + public static async ValueTask BindAsync(HttpContext httpContext, ParameterInfo parameter) + { + return await httpContext.BindFromForm(); + } + } } diff --git a/BLHX.Server/Program.cs b/BLHX.Server/Program.cs index 12a7f19..4bca586 100644 --- a/BLHX.Server/Program.cs +++ b/BLHX.Server/Program.cs @@ -1,4 +1,5 @@ -using BLHX.Server.Common.Utils; +using BLHX.Server.Common.Database; +using BLHX.Server.Common.Utils; using BLHX.Server.Game; using BLHX.Server.Sdk; using System.Net.NetworkInformation;