party migrate to Pilz.Net

This commit is contained in:
2024-08-22 15:12:57 +02:00
parent 1efc4fd77a
commit 255ba2348d
12 changed files with 30 additions and 137 deletions

View File

@@ -1,13 +0,0 @@
namespace OwnChar.Server.Api.Endpoint;
internal class ApiBuilder : IApiBuilder
{
private readonly Dictionary<ApiMapInfo, Delegate> handlers = [];
public IReadOnlyDictionary<ApiMapInfo, Delegate> Handlers => handlers;
public void Map(string pattern, Delegate action)
{
handlers.Add(new(pattern, "POST"), action);
}
}

View File

@@ -1,3 +0,0 @@
namespace OwnChar.Server.Api.Endpoint;
public record struct ApiMapInfo(string Pattern, string Method);

View File

@@ -1,12 +0,0 @@
using System.Net;
namespace OwnChar.Server.Api.Endpoint;
public static class ApiRequestMethods
{
public static string Get => WebRequestMethods.Http.Get;
public static string Put => WebRequestMethods.Http.Put;
public static string Post => WebRequestMethods.Http.Post;
public static string Patch => "PATCH";
public static string Delete => "DELETE";
}

View File

@@ -1,7 +1,4 @@
using OwnChar.Server.Api; namespace OwnChar.Server.Api.Endpoint;
using OwnChar.Server.Api.Endpoint;
namespace OwnChar.Server.Api.Endpoint.Implementations;
internal class CharactersApi(IServer server) : IApiEndpoint internal class CharactersApi(IServer server) : IApiEndpoint
{ {

View File

@@ -7,7 +7,7 @@ using OwnChar.Data.Model.Client;
using OwnChar.Server.Data.Model; using OwnChar.Server.Data.Model;
using OwnChar.Server.Extensions; using OwnChar.Server.Extensions;
namespace OwnChar.Server.Api.Endpoint.Implementations; namespace OwnChar.Server.Api.Endpoint;
internal class GroupsApi(IServer server) : IApiEndpoint internal class GroupsApi(IServer server) : IApiEndpoint
{ {

View File

@@ -1,8 +0,0 @@
namespace OwnChar.Server.Api.Endpoint;
public interface IApiBuilder
{
public IReadOnlyDictionary<ApiMapInfo, Delegate> Handlers { get; }
void Map(string path, Delegate action);
}

View File

@@ -3,7 +3,7 @@ using OwnChar.Api.Packets.General;
using OwnChar.Server.Data.Model; using OwnChar.Server.Data.Model;
using OwnChar.Server.Extensions; using OwnChar.Server.Extensions;
namespace OwnChar.Server.Api.Endpoint.Implementations; namespace OwnChar.Server.Api.Endpoint;
internal class LoginApi(ServerContext server) : IApiEndpoint internal class LoginApi(ServerContext server) : IApiEndpoint
{ {

View File

@@ -1,6 +1,4 @@
using OwnChar.Server.Api; namespace OwnChar.Server.Api.Endpoint;
namespace OwnChar.Server.Api.Endpoint.Implementations;
internal class UsersApi(IServer server) : IApiEndpoint internal class UsersApi(IServer server) : IApiEndpoint
{ {

View File

@@ -1,16 +1,15 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using OwnChar.Data.Model.Base; using OwnChar.Data.Model.Base;
using Pilz.Configuration; using Pilz.Configuration;
using Pilz.Net.Api;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using ILogger = Castle.Core.Logging.ILogger;
namespace OwnChar.Server.Api; namespace OwnChar.Server.Api;
public interface IServer public interface IServer : IApiServer
{ {
ISettings Settings { get; } ISettings Settings { get; }
DbContext? Data { get; } DbContext? Data { get; }
ILogger Log { get; }
[MemberNotNull(nameof(Data))] [MemberNotNull(nameof(Data))]
void CheckLogin(string secret); void CheckLogin(string secret);

View File

@@ -3,9 +3,9 @@ using Pilz.Plugins.Advanced;
namespace OwnChar.Server.Api.Plugins; namespace OwnChar.Server.Api.Plugins;
public abstract class ApiEndpointFeature(string identifier) : PluginFeature(FeatureType, identifier), IApiEndpoint public abstract class ApiEndpointFeature(string identifier) : PluginFeature(FeatureType, identifier)
{ {
public static string FeatureType => "ownchar.server.apiep"; public static string FeatureType => "ownchar.server.apiep";
public abstract void Initialize(IApiBuilder builder); public abstract void OnServerInit(IServer init);
} }

View File

@@ -8,8 +8,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Castle.Core" Version="5.1.1" /> <PackageReference Include="Castle.Core" Version="5.1.1" />
<PackageReference Include="Pilz.Configuration" Version="3.1.2" /> <PackageReference Include="Pilz.Configuration" Version="3.1.3" />
<PackageReference Include="Pilz.Cryptography" Version="2.0.1" /> <PackageReference Include="Pilz.Cryptography" Version="2.1.1" />
<PackageReference Include="Pilz.Net" Version="2.0.4" />
<PackageReference Include="Pilz.Plugins" Version="2.1.9" /> <PackageReference Include="Pilz.Plugins" Version="2.1.9" />
<PackageReference Include="Pilz.Plugins.Advanced" Version="2.10.1" /> <PackageReference Include="Pilz.Plugins.Advanced" Version="2.10.1" />
</ItemGroup> </ItemGroup>

View File

@@ -1,124 +1,58 @@
using Castle.Core.Logging; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using OwnChar.Data.Model.Base; using OwnChar.Data.Model.Base;
using OwnChar.Server.Api; using OwnChar.Server.Api;
using OwnChar.Server.Api.Endpoint; using OwnChar.Server.Api.Endpoint;
using OwnChar.Server.Api.Endpoint.Implementations;
using OwnChar.Server.Api.Plugins; using OwnChar.Server.Api.Plugins;
using OwnChar.Server.Data; using OwnChar.Server.Data;
using Pilz.Configuration; using Pilz.Configuration;
using Pilz.Cryptography; using Pilz.Cryptography;
using Pilz.Extensions.Collections;
using Pilz.Net.Api;
using Pilz.Plugins.Advanced; using Pilz.Plugins.Advanced;
using System.Net;
namespace OwnChar.Server; namespace OwnChar.Server;
internal class ServerContext(ISettings settings) : IServer internal class ServerContext(ISettings settings) : ApiServer(settings.Get<ServerSettings>().ApiUrl!), IServer
{ {
private readonly Dictionary<string, UserAccountBase> users = []; private readonly Dictionary<string, UserAccountBase> users = [];
private readonly HttpListener httpListener = new();
private readonly ApiBuilder apiBuilder = new();
public DbContext? Data { get; private set; } public DbContext? Data { get; private set; }
public ISettings Settings { get; } = settings; public ISettings Settings { get; } = settings;
public ILogger Log { get; set; } = NullLogger.Instance; public override void Start()
public void Start(string[] args)
{ {
Log.Info("Prepairing server"); Log.Info("Prepairing server");
// Load database // Load database
Log.Debug("Loading database");
var settings = Settings.Get<ServerSettings>(); var settings = Settings.Get<ServerSettings>();
Log.Debug("Loading database");
Data = new DatabaseContext(settings.DbServer, settings.DbUser, settings.DbPassword); Data = new DatabaseContext(settings.DbServer, settings.DbUser, settings.DbPassword);
// Built-in endpoints // Built-in endpoints
Log.Debug("Loading internal api endpoints"); Log.Debug("Loading internal api endpoints");
var apibuilder = new ApiBuilder(); RegisterHandler(new LoginApi(this));
new LoginApi(this).Initialize(apibuilder); RegisterHandler(new UsersApi(this));
new UsersApi(this).Initialize(apibuilder); RegisterHandler(new GroupsApi(this));
new GroupsApi(this).Initialize(apibuilder); RegisterHandler(new CharactersApi(this));
new CharactersApi(this).Initialize(apibuilder);
// Plugin endpoints // Plugin endpoints
Log.Debug("Loading plugin api endpoints"); Log.Debug("Loading plugin api endpoints");
var endpoints = PluginFeatureController.Instance.Features.Get(ApiEndpointFeature.FeatureType).OfType<IApiEndpoint>(); PluginFeatureController.Instance.Features.Get(ApiEndpointFeature.FeatureType).OfType<ApiEndpointFeature>().ForEach(n => n.OnServerInit(this));
if (endpoints.Any())
{
foreach (var endpoint in endpoints)
endpoint.Initialize(apibuilder);
}
// Run server // Run server
Log.Info("Starting webserver"); Log.Info("Starting webserver");
httpListener.Start(); base.Start();
Listen();
} }
private void Listen() protected override string? DecodeAuthKey(string authKey)
{ {
var apiUrl = Settings.Get<ServerSettings>().ApiUrl; return base.DecodeAuthKey(new SecureString(authKey, true));
if (string.IsNullOrWhiteSpace(apiUrl))
throw new NullReferenceException("ApiUrl is empty!");
while (httpListener.IsListening)
{
var context = httpListener.GetContext();
if (context.Request.HttpMethod != HttpMethod.Post.Method
|| context.Request.ContentType is not string contentType
|| contentType.Contains("application/json")
|| context.Request.AcceptTypes is null
|| context.Request.AcceptTypes.Contains("application/json"))
{
close();
continue;
} }
// Parse url protected override bool CheckAuthentication(string authKey)
var path = context.Request.Url?.PathAndQuery.Replace(apiUrl, string.Empty);
if (string.IsNullOrWhiteSpace(path) || context.Request.ContentLength64 <= 0)
{ {
close(); return base.CheckAuthentication(authKey) || IsLoggedIn(authKey);
continue;
}
// Find mapped function and get target type
if (!apiBuilder.Handlers.TryGetValue(new(path, context.Request.HttpMethod), out var postAction))
{
close();
return;
}
// ...
// Read input content
using StreamReader input = new(context.Request.InputStream);
var contentJson = input.ReadToEnd();
// Deserialize request
if (JsonHelpers.DeserializeRequest<T>(contentJson) is not T request)
{
close();
continue;
}
// Set response parameters
context.Response.StatusCode = (int)args.ResponseStatusCode;
context.Response.StatusDescription = args.ResponseStatusDescription;
// Write response content
if (args.ResponseContent != null)
{
context.Response.ContentType = ContentTypes.CONTENT_TYPE_JSON;
using StreamWriter output = new(context.Response.OutputStream);
output.Write(args.ResponseContent);
}
close();
void close() => context.Response.OutputStream.Close();
}
} }
public string Login(UserAccountBase account) public string Login(UserAccountBase account)