diff --git a/Libraries/SPTarkov.Server.Core/DI/ISerializer.cs b/Libraries/SPTarkov.Server.Core/DI/ISerializer.cs index b566c16e..b4593842 100644 --- a/Libraries/SPTarkov.Server.Core/DI/ISerializer.cs +++ b/Libraries/SPTarkov.Server.Core/DI/ISerializer.cs @@ -2,6 +2,6 @@ namespace SPTarkov.Server.Core.DI; public interface ISerializer { - public void Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body); + public Task Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body); public bool CanHandle(string route); } diff --git a/Libraries/SPTarkov.Server.Core/Loaders/PostDBModLoader.cs b/Libraries/SPTarkov.Server.Core/Loaders/PostDBModLoader.cs index 017d450a..7898e0e0 100644 --- a/Libraries/SPTarkov.Server.Core/Loaders/PostDBModLoader.cs +++ b/Libraries/SPTarkov.Server.Core/Loaders/PostDBModLoader.cs @@ -9,7 +9,7 @@ namespace SPTarkov.Server.Core.Loaders; [Injectable(TypePriority = OnLoadOrder.PostDBModLoader)] public class PostDBModLoader( ISptLogger _logger, - IEnumerable _postDbLoadMods + IEnumerable _postDbLoadMods ) : IOnLoad { public async Task OnLoad() @@ -19,7 +19,7 @@ public class PostDBModLoader( _logger.Info("Loading PostDBMods..."); foreach (var postDbLoadMod in _postDbLoadMods) { - postDbLoadMod.PostDBLoad(); + await postDbLoadMod.PostSptLoadAsync(); } _logger.Info("Finished loading PostDBMods..."); diff --git a/Libraries/SPTarkov.Server.Core/Loaders/PostSptModLoader.cs b/Libraries/SPTarkov.Server.Core/Loaders/PostSptModLoader.cs index 35684c93..bbc7fc6e 100644 --- a/Libraries/SPTarkov.Server.Core/Loaders/PostSptModLoader.cs +++ b/Libraries/SPTarkov.Server.Core/Loaders/PostSptModLoader.cs @@ -9,7 +9,7 @@ namespace SPTarkov.Server.Core.Loaders; [Injectable(TypePriority = OnLoadOrder.PostSptModLoader)] public class PostSptModLoader( ISptLogger _logger, - IEnumerable _postSptLoadMods + IEnumerable _postSptLoadMods ) : IOnLoad { public async Task OnLoad() @@ -19,7 +19,7 @@ public class PostSptModLoader( _logger.Info("Loading PostSptMods..."); foreach (var postSptLoadMod in _postSptLoadMods) { - postSptLoadMod.PostSptLoad(); + await postSptLoadMod.PostSptLoadAsync(); } _logger.Info("Finished loading PostSptMods..."); diff --git a/Libraries/SPTarkov.Server.Core/Models/External/IPostDBLoadMod.cs b/Libraries/SPTarkov.Server.Core/Models/External/IPostDBLoadMod.cs deleted file mode 100644 index fed88749..00000000 --- a/Libraries/SPTarkov.Server.Core/Models/External/IPostDBLoadMod.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace SPTarkov.Server.Core.Models.External; - -public interface IPostDBLoadMod -{ - void PostDBLoad(); -} diff --git a/Libraries/SPTarkov.Server.Core/Models/External/IPostDBLoadModAsync.cs b/Libraries/SPTarkov.Server.Core/Models/External/IPostDBLoadModAsync.cs new file mode 100644 index 00000000..64db0b60 --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Models/External/IPostDBLoadModAsync.cs @@ -0,0 +1,6 @@ +namespace SPTarkov.Server.Core.Models.External; + +public interface IPostDBLoadModAsync +{ + Task PostDBLoadAsync(); +} diff --git a/Libraries/SPTarkov.Server.Core/Models/External/IPostSptLoadMod.cs b/Libraries/SPTarkov.Server.Core/Models/External/IPostSptLoadMod.cs deleted file mode 100644 index 69371f41..00000000 --- a/Libraries/SPTarkov.Server.Core/Models/External/IPostSptLoadMod.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace SPTarkov.Server.Core.Models.External; - -public interface IPostSptLoadMod -{ - void PostSptLoad(); -} diff --git a/Libraries/SPTarkov.Server.Core/Models/External/IPostSptLoadModAsync.cs b/Libraries/SPTarkov.Server.Core/Models/External/IPostSptLoadModAsync.cs new file mode 100644 index 00000000..e82cdda5 --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Models/External/IPostSptLoadModAsync.cs @@ -0,0 +1,6 @@ +namespace SPTarkov.Server.Core.Models.External; + +public interface IPostSptLoadModAsync +{ + Task PostSptLoadAsync(); +} diff --git a/Libraries/SPTarkov.Server.Core/Models/External/IPreSptLoadMod.cs b/Libraries/SPTarkov.Server.Core/Models/External/IPreSptLoadMod.cs deleted file mode 100644 index 75781ffa..00000000 --- a/Libraries/SPTarkov.Server.Core/Models/External/IPreSptLoadMod.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace SPTarkov.Server.Core.Models.External; - -public interface IPreSptLoadMod -{ - void PreSptLoad(); -} diff --git a/Libraries/SPTarkov.Server.Core/Models/External/IPreSptLoadModAsync.cs b/Libraries/SPTarkov.Server.Core/Models/External/IPreSptLoadModAsync.cs new file mode 100644 index 00000000..241bca30 --- /dev/null +++ b/Libraries/SPTarkov.Server.Core/Models/External/IPreSptLoadModAsync.cs @@ -0,0 +1,6 @@ +namespace SPTarkov.Server.Core.Models.External; + +public interface IPreSptLoadModAsync +{ + Task PreSptLoadAsync(); +} diff --git a/Libraries/SPTarkov.Server.Core/Routers/ImageRouter.cs b/Libraries/SPTarkov.Server.Core/Routers/ImageRouter.cs index 6863b725..d52f5e56 100644 --- a/Libraries/SPTarkov.Server.Core/Routers/ImageRouter.cs +++ b/Libraries/SPTarkov.Server.Core/Routers/ImageRouter.cs @@ -31,7 +31,7 @@ public class ImageRouter _imageRouterService.AddRoute(key.ToLower(), valueToAdd); } - public void SendImage(string sessionId, HttpRequest req, HttpResponse resp, object body) + public async Task SendImage(string sessionId, HttpRequest req, HttpResponse resp, object body) { // remove file extension var url = _fileUtil.StripExtension(req.Path, true); @@ -40,7 +40,7 @@ public class ImageRouter var urlKeyLower = url.ToLower(); if (_imageRouterService.ExistsByKey(urlKeyLower)) { - _httpFileUtil.SendFile(resp, _imageRouterService.GetByKey(urlKeyLower)); + await _httpFileUtil.SendFile(resp, _imageRouterService.GetByKey(urlKeyLower)); return; } diff --git a/Libraries/SPTarkov.Server.Core/Routers/Serializers/BundleSerializer.cs b/Libraries/SPTarkov.Server.Core/Routers/Serializers/BundleSerializer.cs index 2d020d41..c4034517 100644 --- a/Libraries/SPTarkov.Server.Core/Routers/Serializers/BundleSerializer.cs +++ b/Libraries/SPTarkov.Server.Core/Routers/Serializers/BundleSerializer.cs @@ -13,7 +13,7 @@ public class BundleSerializer( HttpFileUtil httpFileUtil ) : ISerializer { - public void Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body) + public async Task Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body) { var key = req.Path.Value.Split("/bundle/")[1]; var bundle = bundleLoader.GetBundle(key); @@ -30,7 +30,7 @@ public class BundleSerializer( } var bundlePath = Path.Join(bundle.ModPath, "/bundles/", bundle.FileName); - httpFileUtil.SendFile(resp, bundlePath); + await httpFileUtil.SendFile(resp, bundlePath); } public bool CanHandle(string route) diff --git a/Libraries/SPTarkov.Server.Core/Routers/Serializers/ImageSerializer.cs b/Libraries/SPTarkov.Server.Core/Routers/Serializers/ImageSerializer.cs index 8dfcd085..a8fac549 100644 --- a/Libraries/SPTarkov.Server.Core/Routers/Serializers/ImageSerializer.cs +++ b/Libraries/SPTarkov.Server.Core/Routers/Serializers/ImageSerializer.cs @@ -13,9 +13,9 @@ public class ImageSerializer : ISerializer _imageRouter = imageRouter; } - public void Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body) + public async Task Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body) { - _imageRouter.SendImage(sessionID, req, resp, body); + await _imageRouter.SendImage(sessionID, req, resp, body); } public bool CanHandle(string route) diff --git a/Libraries/SPTarkov.Server.Core/Routers/Serializers/NotifySerializer.cs b/Libraries/SPTarkov.Server.Core/Routers/Serializers/NotifySerializer.cs index 870bec25..5cd58b27 100644 --- a/Libraries/SPTarkov.Server.Core/Routers/Serializers/NotifySerializer.cs +++ b/Libraries/SPTarkov.Server.Core/Routers/Serializers/NotifySerializer.cs @@ -13,7 +13,7 @@ public class NotifySerializer( HttpServerHelper httpServerHelper ) : ISerializer { - public void Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body) + public async Task Serialize(string sessionID, HttpRequest req, HttpResponse resp, object? body) { var splittedUrl = req.Path.Value.Split("/"); var tmpSessionID = splittedUrl[^1].Split("?last_id")[0]; @@ -22,7 +22,7 @@ public class NotifySerializer( * Take our array of JSON message objects and cast them to JSON strings, so that they can then * be sent to client as NEWLINE separated strings... yup. */ - notifierController.NotifyAsync(tmpSessionID) + await notifierController.NotifyAsync(tmpSessionID) .ContinueWith(messages => messages.Result.Select(message => string.Join("\n", jsonUtil.Serialize(message)))) .ContinueWith(text => httpServerHelper.SendTextJson(resp, text)); } diff --git a/Libraries/SPTarkov.Server.Core/Servers/Http/IHttpListener.cs b/Libraries/SPTarkov.Server.Core/Servers/Http/IHttpListener.cs index 6e1586d2..af794c01 100644 --- a/Libraries/SPTarkov.Server.Core/Servers/Http/IHttpListener.cs +++ b/Libraries/SPTarkov.Server.Core/Servers/Http/IHttpListener.cs @@ -3,5 +3,5 @@ public interface IHttpListener { bool CanHandle(string sessionId, HttpRequest req); - void Handle(string sessionId, HttpRequest req, HttpResponse resp); + Task Handle(string sessionId, HttpRequest req, HttpResponse resp); } diff --git a/Libraries/SPTarkov.Server.Core/Servers/Http/SptHttpListener.cs b/Libraries/SPTarkov.Server.Core/Servers/Http/SptHttpListener.cs index 268d0712..c7a79696 100644 --- a/Libraries/SPTarkov.Server.Core/Servers/Http/SptHttpListener.cs +++ b/Libraries/SPTarkov.Server.Core/Servers/Http/SptHttpListener.cs @@ -13,57 +13,43 @@ using LogLevel = SPTarkov.Server.Core.Models.Spt.Logging.LogLevel; namespace SPTarkov.Server.Core.Servers.Http; [Injectable] -public class SptHttpListener : IHttpListener +public class SptHttpListener( + HttpRouter httpRouter, + IEnumerable serializers, + ISptLogger logger, + ISptLogger requestsLogger, + JsonUtil jsonUtil, + HttpResponseUtil httpHttpResponseUtil, + LocalisationService localisationService + ) : IHttpListener { - // we want to reserve on the list 512KB capacity before it needs to expand, should be enough for most requests - private const int InitialCapacityForListBuffer = 1024 * 512; - // We want to read 1KB at a time, for most request this is already big enough private const int BodyReadBufferSize = 1024 * 1; private static readonly ImmutableHashSet SupportedMethods = ["GET", "PUT", "POST"]; - protected readonly HttpResponseUtil _httpResponseUtil; - protected readonly JsonUtil _jsonUtil; - protected readonly LocalisationService _localisationService; - protected readonly ISptLogger _logger; - protected readonly ISptLogger _requestLogger; + protected readonly HttpResponseUtil _httpResponseUtil = httpHttpResponseUtil; + protected readonly JsonUtil _jsonUtil = jsonUtil; + protected readonly LocalisationService _localisationService = localisationService; + protected readonly ISptLogger _logger = logger; + protected readonly ISptLogger _requestLogger = requestsLogger; - protected readonly HttpRouter _router; - protected readonly IEnumerable _serializers; - - public SptHttpListener( - HttpRouter httpRouter, - IEnumerable serializers, - ISptLogger logger, - ISptLogger requestsLogger, - JsonUtil jsonUtil, - HttpResponseUtil httpHttpResponseUtil, - LocalisationService localisationService - ) - { - _router = httpRouter; - _serializers = serializers; - _logger = logger; - _requestLogger = requestsLogger; - _httpResponseUtil = httpHttpResponseUtil; - _localisationService = localisationService; - _jsonUtil = jsonUtil; - } + protected readonly HttpRouter _router = httpRouter; + protected readonly IEnumerable _serializers = serializers; public bool CanHandle(string _, HttpRequest req) { return SupportedMethods.Contains(req.Method); } - public void Handle(string sessionId, HttpRequest req, HttpResponse resp) + public async Task Handle(string sessionId, HttpRequest req, HttpResponse resp) { switch (req.Method) { case "GET": { var response = GetResponse(sessionId, req, null); - SendResponse(sessionId, req, resp, null, response); + await SendResponse(sessionId, req, resp, null, response); break; } // these are handled almost identically. @@ -75,49 +61,50 @@ public class SptHttpListener : IHttpListener // debug = 1 are as well. This should be fixed. // let compressed = req.headers["content-encoding"] === "deflate"; var requestIsCompressed = !req.Headers.TryGetValue("requestcompressed", out var compressHeader) || - compressHeader != "0"; + compressHeader != "0"; var requestCompressed = req.Method == "PUT" || requestIsCompressed; - // reserve some capacity to avoid having the list to resize - var totalRead = new List(InitialCapacityForListBuffer); - // read 1KB at a time - var memory = new Memory(new byte[BodyReadBufferSize]); - var readTask = req.Body.ReadAsync(memory).AsTask(); - readTask.Wait(); - var readBytes = 0; - while (readTask.Result != 0) + var body = string.Empty; + using MemoryStream bufferStream = new(); + + var buffer = new byte[BodyReadBufferSize]; + int bytesRead; + + while ((bytesRead = await req.Body.ReadAsync(buffer)) > 0) { - readBytes += readTask.Result; - totalRead.AddRange(memory[..readTask.Result].ToArray()); - memory = new Memory(new byte[BodyReadBufferSize]); - readTask = req.Body.ReadAsync(memory).AsTask(); - readTask.Wait(); + await bufferStream.WriteAsync(buffer.AsMemory(0, bytesRead)); } - string value; + bufferStream.Position = 0; + if (requestCompressed) { - using var uncompressedDataStream = new MemoryStream(); - using var compressedDataStream = new MemoryStream(totalRead[..readBytes].ToArray()); - using var deflateStream = new ZLibStream(compressedDataStream, CompressionMode.Decompress, true); - deflateStream.CopyTo(uncompressedDataStream); - value = Encoding.UTF8.GetString(uncompressedDataStream.ToArray()); + using var deflateStream = new ZLibStream(bufferStream, CompressionMode.Decompress); + using var decompressedStream = new MemoryStream(); + await deflateStream.CopyToAsync(decompressedStream); + decompressedStream.Position = 0; + + using var reader = new StreamReader(decompressedStream, Encoding.UTF8); + body = await reader.ReadToEndAsync(); } else { - value = Encoding.UTF8.GetString(totalRead[..readBytes].ToArray()); + // No decompression needed, decode directly from the bufferStream's buffer + bufferStream.Position = 0; + using var reader = new StreamReader(bufferStream, Encoding.UTF8); + body = await reader.ReadToEndAsync(); } if (!requestIsCompressed) { if (_logger.IsLogEnabled(LogLevel.Debug)) { - _logger.Debug(value); + _logger.Debug(body); } } - var response = GetResponse(sessionId, req, value); - SendResponse(sessionId, req, resp, value, response); + var response = GetResponse(sessionId, req, body); + await SendResponse(sessionId, req, resp, body, response); break; } @@ -137,7 +124,7 @@ public class SptHttpListener : IHttpListener /// Outgoing response /// Buffer /// Server generated response data - public void SendResponse( + public async Task SendResponse( string sessionID, HttpRequest req, HttpResponse resp, @@ -155,7 +142,7 @@ public class SptHttpListener : IHttpListener if (IsDebugRequest(req)) { // Send only raw response without transformation - SendJson(resp, output, sessionID); + await SendJson(resp, output, sessionID); if (_logger.IsLogEnabled(LogLevel.Debug)) { _logger.Debug($"Response: {output}"); @@ -169,12 +156,12 @@ public class SptHttpListener : IHttpListener var serialiser = _serializers.FirstOrDefault(x => x.CanHandle(output)); if (serialiser != null) { - serialiser.Serialize(sessionID, req, resp, bodyInfo); + await serialiser.Serialize(sessionID, req, resp, bodyInfo); } else // No serializer can handle the request (majority of requests dont), zlib the output and send response back { - SendZlibJson(resp, output, sessionID); + await SendZlibJson(resp, output, sessionID); } LogRequest(req, output); @@ -225,35 +212,35 @@ public class SptHttpListener : IHttpListener return output; } - public void SendJson(HttpResponse resp, string? output, string sessionID) + public async Task SendJson(HttpResponse resp, string? output, string sessionID) { resp.StatusCode = 200; resp.ContentType = "application/json"; resp.Headers.Append("Set-Cookie", $"PHPSESSID={sessionID}"); if (!string.IsNullOrEmpty(output)) { - resp.Body.WriteAsync(Encoding.UTF8.GetBytes(output)).AsTask().Wait(); + await resp.Body.WriteAsync(Encoding.UTF8.GetBytes(output)); } - resp.StartAsync().Wait(); - resp.CompleteAsync().Wait(); + await resp.StartAsync(); + await resp.CompleteAsync(); } - public void SendZlibJson(HttpResponse resp, string? output, string sessionID) + public async Task SendZlibJson(HttpResponse resp, string? output, string sessionID) { using (var ms = new MemoryStream()) { using (var deflateStream = new ZLibStream(ms, CompressionLevel.SmallestSize)) { - deflateStream.WriteAsync(Encoding.UTF8.GetBytes(output)).AsTask().Wait(); + await deflateStream.WriteAsync(Encoding.UTF8.GetBytes(output)); } var bytes = ms.ToArray(); - resp.Body.WriteAsync(bytes, 0, bytes.Length).Wait(); + await resp.Body.WriteAsync(bytes); } - resp.StartAsync().Wait(); - resp.CompleteAsync().Wait(); + await resp.StartAsync(); + await resp.CompleteAsync(); } private record Response(string Method, string jsonData); diff --git a/Libraries/SPTarkov.Server.Core/Servers/HttpServer.cs b/Libraries/SPTarkov.Server.Core/Servers/HttpServer.cs index 1faaa838..88c1d316 100644 --- a/Libraries/SPTarkov.Server.Core/Servers/HttpServer.cs +++ b/Libraries/SPTarkov.Server.Core/Servers/HttpServer.cs @@ -15,11 +15,11 @@ namespace SPTarkov.Server.Core.Servers; [Injectable(InjectionType.Singleton)] public class HttpServer( + WebApplicationBuilder _builder, ISptLogger _logger, LocalisationService _localisationService, ConfigServer _configServer, CertificateHelper _certificateHelper, - ApplicationContext _applicationContext, WebSocketServer _webSocketServer, ProfileActivityService _profileActivityService, IEnumerable _httpListeners @@ -27,20 +27,21 @@ public class HttpServer( { private readonly HttpConfig _httpConfig = _configServer.GetConfig(); private bool _started; + private WebApplication? _webApplication; /// /// Handle server loading event /// /// Server builder /// Throws Exception when WebApplicationBuiler or WebApplication are null - public void Load(WebApplicationBuilder? builder) + public void Load() { - if (builder is null) + if (_builder is null) { throw new Exception("WebApplicationBuilder is null in HttpServer.Load()"); } - builder.WebHost.ConfigureKestrel(options => + _builder.WebHost.ConfigureKestrel(options => { options.Listen(IPAddress.Parse(_httpConfig.Ip), _httpConfig.Port, listenOptions => { @@ -53,29 +54,35 @@ public class HttpServer( }); }); - var app = builder.Build(); + _webApplication = _builder.Build(); - if (app is null) + if (_webApplication is null) { throw new Exception("WebApplication is null in HttpServer.Load()"); } // Enable web socket - app.UseWebSockets(new WebSocketOptions + _webApplication.UseWebSockets(new WebSocketOptions { // Every minute a heartbeat is sent to keep the connection alive. KeepAliveInterval = TimeSpan.FromSeconds(60) }); - app?.Use((HttpContext req, RequestDelegate _) => + _webApplication.Use(async (HttpContext req, RequestDelegate _) => { - return Task.Factory.StartNew(async () => await HandleFallback(req)); + await HandleFallback(req); } ); + } - _started = true; + public async Task StartAsync() + { + if (_webApplication != null && !_started) + { + _started = true; + await _webApplication.RunAsync(); + } - _applicationContext.AddValue(ContextVariableType.WEB_APPLICATION, app); } private async Task HandleFallback(HttpContext context) @@ -103,7 +110,12 @@ public class HttpServer( try { - _httpListeners.SingleOrDefault(l => l.CanHandle(sessionId, context.Request))?.Handle(sessionId, context.Request, context.Response); + var listener = _httpListeners.FirstOrDefault(l => l.CanHandle(sessionId, context.Request)); + + if (listener != null) + { + await listener.Handle(sessionId, context.Request, context.Response); + } } catch (Exception ex) { diff --git a/Libraries/SPTarkov.Server.Core/Utils/App.cs b/Libraries/SPTarkov.Server.Core/Utils/App.cs index c0686642..d610524e 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/App.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/App.cs @@ -57,7 +57,7 @@ public class App _coreConfig = configServer.GetConfig(); } - public async Task Run() + public async Task InitializeAsync() { // execute onLoad callbacks _logger.Info(_localisationService.GetText("executing_startup_callbacks")); @@ -96,14 +96,19 @@ public class App } _timer = new Timer(_ => Update(_onUpdate), null, TimeSpan.Zero, TimeSpan.FromMilliseconds(5000)); + } - if (_httpServer.IsStarted()) + public async Task StartAsync() + { + if(!_httpServer.IsStarted()) { _logger.Success(_localisationService.GetText("started_webserver_success", _httpServer.ListeningUrl())); _logger.Success(_localisationService.GetText("websocket-started", _httpServer.ListeningUrl().Replace("https://", "wss://"))); } _logger.Success(GetRandomisedStartMessage()); + + await _httpServer.StartAsync(); } protected string GetRandomisedStartMessage() diff --git a/Libraries/SPTarkov.Server.Core/Utils/HttpFileUtil.cs b/Libraries/SPTarkov.Server.Core/Utils/HttpFileUtil.cs index a4128d9f..ee777d4f 100644 --- a/Libraries/SPTarkov.Server.Core/Utils/HttpFileUtil.cs +++ b/Libraries/SPTarkov.Server.Core/Utils/HttpFileUtil.cs @@ -4,21 +4,16 @@ using SPTarkov.Server.Core.Helpers; namespace SPTarkov.Server.Core.Utils; [Injectable] -public class HttpFileUtil +public class HttpFileUtil(HttpServerHelper httpServerHelper) { - protected HttpServerHelper _httpServerHelper; + protected HttpServerHelper _httpServerHelper = httpServerHelper; - public HttpFileUtil(HttpServerHelper httpServerHelper) - { - _httpServerHelper = httpServerHelper; - } - - public void SendFile(HttpResponse resp, string filePath) + public async Task SendFile(HttpResponse resp, string filePath) { var pathSlice = filePath.Split("/"); var mimePath = _httpServerHelper.GetMimeText(pathSlice[^1].Split(".")[^1]); var type = string.IsNullOrWhiteSpace(mimePath) ? _httpServerHelper.GetMimeText("txt") : mimePath; resp.Headers.Append("Content-Type", type); - resp.SendFileAsync(filePath, CancellationToken.None).Wait(); + await resp.SendFileAsync(filePath, CancellationToken.None); } } diff --git a/SPTarkov.Server/Program.cs b/SPTarkov.Server/Program.cs index 5c7455db..98fbe1a4 100644 --- a/SPTarkov.Server/Program.cs +++ b/SPTarkov.Server/Program.cs @@ -8,6 +8,7 @@ using SPTarkov.Server.Core.Helpers; using SPTarkov.Server.Core.Models.External; using SPTarkov.Server.Core.Models.Spt.Mod; using SPTarkov.Server.Core.Models.Utils; +using SPTarkov.Server.Core.Servers; using SPTarkov.Server.Core.Utils; using SPTarkov.Server.Core.Utils.Logger; using SPTarkov.Server.Logger; @@ -17,7 +18,7 @@ namespace SPTarkov.Server; public static class Program { - public static void Main(string[] args) + public static async Task Main(string[] args) { // Initialize the program variables ProgramStatics.Initialize(); @@ -30,7 +31,7 @@ public static class Program diHandler.AddInjectableTypesFromTypeAssembly(typeof(Program)); diHandler.AddInjectableTypesFromTypeAssembly(typeof(App)); - List loadedMods = null; + List loadedMods = []; if (ProgramStatics.MODS()) { // Search for mod dlls @@ -61,28 +62,25 @@ public static class Program if (ProgramStatics.MODS()) { // Initialize PreSptMods - var preSptLoadMods = serviceProvider.GetServices(); + var preSptLoadMods = serviceProvider.GetServices(); foreach (var preSptLoadMod in preSptLoadMods) { - preSptLoadMod.PreSptLoad(); + await preSptLoadMod.PreSptLoadAsync(); } } // Get the Built app and run it var app = serviceProvider.GetService(); - app?.Run().Wait(); - // Run garbage collection now the server is ready to start - GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; - GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true); - - - var httpServerHelper = serviceProvider.GetService(); - // When the application is started by the HttpServer it will be added into the AppContext of the WebApplication - // object, which we can use here to start the webapp. - if (httpServerHelper != null) + if (app != null) { - appContext?.GetLatestValue(ContextVariableType.WEB_APPLICATION)?.GetValue().Run(); + await app.InitializeAsync(); + + // Run garbage collection now the server is ready to start + GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce; + GC.Collect(GC.MaxGeneration, GCCollectionMode.Aggressive, true, true); + + await app.StartAsync(); } } catch (Exception ex)