party migrate to Pilz.Net
This commit is contained in:
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
namespace OwnChar.Server.Api.Endpoint;
|
|
||||||
|
|
||||||
public record struct ApiMapInfo(string Pattern, string Method);
|
|
||||||
@@ -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";
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
namespace OwnChar.Server.Api.Endpoint;
|
|
||||||
|
|
||||||
public interface IApiBuilder
|
|
||||||
{
|
|
||||||
public IReadOnlyDictionary<ApiMapInfo, Delegate> Handlers { get; }
|
|
||||||
|
|
||||||
void Map(string path, Delegate action);
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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)
|
protected override bool CheckAuthentication(string authKey)
|
||||||
{
|
{
|
||||||
var context = httpListener.GetContext();
|
return base.CheckAuthentication(authKey) || IsLoggedIn(authKey);
|
||||||
|
|
||||||
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
|
|
||||||
var path = context.Request.Url?.PathAndQuery.Replace(apiUrl, string.Empty);
|
|
||||||
if (string.IsNullOrWhiteSpace(path) || context.Request.ContentLength64 <= 0)
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user