159 lines
5.1 KiB
C#
159 lines
5.1 KiB
C#
using Castle.Core.Logging;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using OwnChar.Data.Model.Base;
|
|
using OwnChar.Server.Api;
|
|
using OwnChar.Server.Api.Endpoint;
|
|
using OwnChar.Server.Api.Endpoint.Implementations;
|
|
using OwnChar.Server.Api.Plugins;
|
|
using OwnChar.Server.Data;
|
|
using Pilz.Configuration;
|
|
using Pilz.Cryptography;
|
|
using Pilz.Plugins.Advanced;
|
|
using System.Net;
|
|
|
|
namespace OwnChar.Server;
|
|
|
|
internal class ServerContext(ISettings settings) : IServer
|
|
{
|
|
private readonly Dictionary<string, UserAccountBase> users = [];
|
|
private readonly HttpListener httpListener = new();
|
|
private readonly ApiBuilder apiBuilder = new();
|
|
|
|
public DbContext? Data { get; private set; }
|
|
|
|
public ISettings Settings { get; } = settings;
|
|
|
|
public ILogger Log { get; set; } = NullLogger.Instance;
|
|
|
|
public void Start(string[] args)
|
|
{
|
|
Log.Info("Prepairing server");
|
|
|
|
// Load database
|
|
Log.Debug("Loading database");
|
|
var settings = Settings.Get<ServerSettings>();
|
|
Data = new DatabaseContext(settings.DbServer, settings.DbUser, settings.DbPassword);
|
|
|
|
// Built-in endpoints
|
|
Log.Debug("Loading internal api endpoints");
|
|
var apibuilder = new ApiBuilder();
|
|
new LoginApi(this).Initialize(apibuilder);
|
|
new UsersApi(this).Initialize(apibuilder);
|
|
new GroupsApi(this).Initialize(apibuilder);
|
|
new CharactersApi(this).Initialize(apibuilder);
|
|
|
|
// Plugin endpoints
|
|
Log.Debug("Loading plugin api endpoints");
|
|
var endpoints = PluginFeatureController.Instance.Features.Get(ApiEndpointFeature.FeatureType).OfType<IApiEndpoint>();
|
|
if (endpoints.Any())
|
|
{
|
|
foreach (var endpoint in endpoints)
|
|
endpoint.Initialize(apibuilder);
|
|
}
|
|
|
|
// Run server
|
|
Log.Info("Starting webserver");
|
|
httpListener.Start();
|
|
Listen();
|
|
}
|
|
|
|
private void Listen()
|
|
{
|
|
var apiUrl = Settings.Get<ServerSettings>().ApiUrl;
|
|
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
|
|
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)
|
|
{
|
|
var secret = new UniquieID(UniquieIDGenerationMode.GenerateOnInit).ID;
|
|
users.Add(secret, account);
|
|
Log.DebugFormat("Logged-in out user with secret {0}", secret);
|
|
return secret;
|
|
}
|
|
|
|
public void Logout(string secret)
|
|
{
|
|
users.Remove(secret);
|
|
Log.DebugFormat("Logged-out user with secret {0}", secret);
|
|
}
|
|
|
|
public bool IsLoggedIn(string secret)
|
|
{
|
|
Log.DebugFormat("Deleting user with secret {0}", secret);
|
|
return users.ContainsKey(secret);
|
|
}
|
|
|
|
public void CheckLogin(string secret)
|
|
{
|
|
Log.DebugFormat("Checking login for user with secret {0}", secret);
|
|
if (!IsLoggedIn(secret))
|
|
throw new UnauthorizedAccessException();
|
|
}
|
|
|
|
public UserAccountBase? GetUser(string secret)
|
|
{
|
|
Log.DebugFormat("Getting user with secret {0}", secret);
|
|
if (users.TryGetValue(secret, out UserAccountBase? value))
|
|
return value;
|
|
return null;
|
|
}
|
|
}
|