diff --git a/Core/Helpers/HttpServerHelper.cs b/Core/Helpers/HttpServerHelper.cs index 0fb865aa..41009714 100644 --- a/Core/Helpers/HttpServerHelper.cs +++ b/Core/Helpers/HttpServerHelper.cs @@ -1,6 +1,72 @@ -namespace Core.Helpers; +using System.Buffers; +using Core.Annotations; +using Core.Models.Enums; +using Core.Models.Spt.Config; +using Core.Servers; +namespace Core.Helpers; + +[Injectable(InjectionType.Singleton)] public class HttpServerHelper { - + protected HttpConfig _httpConfig; + + protected Dictionary mime = new() + { + { "css", "text/css" }, + { "bin", "application/octet-stream" }, + { "html", "text/html" }, + { "jpg", "image/jpeg" }, + { "js", "text/javascript" }, + { "json", "application/json" }, + { "png", "image/png" }, + { "svg", "image/svg+xml" }, + { "txt", "text/plain" } + }; + + public HttpServerHelper(ConfigServer configServer) + { + _httpConfig = configServer.GetConfig(ConfigTypes.HTTP); + } + + public string GetMimeText(string key) + { + return mime[key]; + } + + /** + * Combine ip and port into address + * @returns url + */ + public string BuildUrl() + { + return $"{_httpConfig.BackendIp}:{_httpConfig.BackendPort}"; + } + + /** + * Prepend http to the url:port + * @returns URI + */ + public string GetBackendUrl() + { + return $"http://{BuildUrl()}"; + } + + /** Get websocket url + port */ + public string GetWebsocketUrl() + { + return $"ws://${BuildUrl()}"; + } + + public void SendTextJson(HttpResponse resp, object output) + { + resp.Headers.Add("Content-Type", mime["json"]); + resp.StatusCode = 200; + /* TODO: figure this one out + resp.writeHead(200, "OK", { + "Content-Type": this.mime.json + }); + resp.end(output); + */ + } } diff --git a/Core/Routers/ImageRouter.cs b/Core/Routers/ImageRouter.cs new file mode 100644 index 00000000..c3e3156c --- /dev/null +++ b/Core/Routers/ImageRouter.cs @@ -0,0 +1,46 @@ +using System.Runtime.InteropServices.JavaScript; +using Core.Annotations; +using Core.Services.Mod.Image; +using Core.Utils; + +namespace Core.Routers; + +[Injectable] +public class ImageRouter +{ + protected FileUtil _fileUtil; + protected ImageRouterService _imageRouterService; + protected HttpFileUtil _httpFileUtil; + + public ImageRouter( + FileUtil fileUtil, + ImageRouterService imageRouteService, + HttpFileUtil httpFileUtil + ) + { + _fileUtil = fileUtil; + _imageRouterService = imageRouteService; + _httpFileUtil = httpFileUtil; + } + + public void AddRoute(string key, string valueToAdd) + { + _imageRouterService.addRoute(key, valueToAdd); + } + + public Task SendImage(string sessionID, HttpRequest req, HttpResponse resp, object body) + { + // remove file extension + var url = _fileUtil.StripExtension(req.Path); + + // send image + if (_imageRouterService.ExistsByKey(url)) { + return _httpFileUtil.SendFileAsync(resp, _imageRouterService.getByKey(url)); + } + return Task.CompletedTask; + } + + public string GetImage() { + return "IMAGE"; + } +} diff --git a/Core/Services/Mod/Image/ImageRouterService.cs b/Core/Services/Mod/Image/ImageRouterService.cs new file mode 100644 index 00000000..0a5090aa --- /dev/null +++ b/Core/Services/Mod/Image/ImageRouterService.cs @@ -0,0 +1,24 @@ +using Core.Annotations; + +namespace Core.Services.Mod.Image; + +[Injectable(InjectionType.Singleton)] +public class ImageRouterService +{ + protected Dictionary routes = new(); + + public void addRoute(string urlKey, string route) + { + routes[urlKey] = route; + } + + public string getByKey(string urlKey) + { + return routes[urlKey]; + } + + public bool ExistsByKey(string urlKey) + { + return routes.ContainsKey(urlKey); + } +} diff --git a/Core/Utils/DatabaseImporter.cs b/Core/Utils/DatabaseImporter.cs index 8e126ebc..8d639619 100644 --- a/Core/Utils/DatabaseImporter.cs +++ b/Core/Utils/DatabaseImporter.cs @@ -3,6 +3,7 @@ using Core.DI; using Core.Models.Enums; using Core.Models.Spt.Config; using Core.Models.Spt.Server; +using Core.Routers; using Core.Servers; using Core.Services; using ILogger = Core.Models.Utils.ILogger; @@ -22,18 +23,20 @@ public class DatabaseImporter : OnLoad protected readonly DatabaseServer _databaseServer; - //protected readonly ImageRouter _imageRouter; + protected readonly ImageRouter _imageRouter; protected readonly EncodingUtil _encodingUtil; protected readonly HashUtil _hashUtil; protected readonly ImporterUtil _importerUtil; protected readonly ConfigServer _configServer; + protected readonly FileUtil _fileUtil; public DatabaseImporter( ILogger logger, // TODO: are we gonna use this? @inject("JsonUtil") protected jsonUtil: JsonUtil, + FileUtil fileUtil, LocalisationService localisationService, DatabaseServer databaseServer, - //ImageRouter imageRouter, + ImageRouter imageRouter, EncodingUtil encodingUtil, HashUtil hashUtil, ImporterUtil importerUtil, @@ -47,6 +50,7 @@ public class DatabaseImporter : OnLoad _hashUtil = hashUtil; _importerUtil = importerUtil; _configServer = configServer; + _fileUtil = fileUtil; httpConfig = _configServer.GetConfig(ConfigTypes.HTTP); } @@ -88,9 +92,8 @@ public class DatabaseImporter : OnLoad await HydrateDatabase(filepath); var imageFilePath = $"${filepath}images/"; - /* - var directories = this.vfs.getDirs(imageFilePath); - this.loadImages(imageFilePath, directories, [ + //var directories = this.vfs.getDirs(imageFilePath); + LoadImages(imageFilePath, _fileUtil.GetDirectories(imageFilePath), [ "/files/achievement/", "/files/CONTENT/banners/", "/files/handbook/", @@ -100,7 +103,6 @@ public class DatabaseImporter : OnLoad "/files/quest/icon/", "/files/trader/avatar/", ]); - */ } /** @@ -167,18 +169,18 @@ public class DatabaseImporter : OnLoad * Find and map files with image router inside a designated path * @param filepath Path to find files in */ - public void LoadImages(string filepath, List directories, List routes) + public void LoadImages(string filepath, string[] directories, List routes) { - /* - for (const directoryIndex in directories) { + for (var i = 0; i < directories.Length; i++) + { // Get all files in directory - const filesInDirectory = this.vfs.getFiles(`${filepath}${directories[directoryIndex]}`); - for (const file of filesInDirectory) { + var filesInDirectory = _fileUtil.GetFiles(directories[i]); + foreach (var file in filesInDirectory) { // Register each file in image router - const filename = this.vfs.stripExtension(file); - const routeKey = `${routes[directoryIndex]}${filename}`; - let imagePath = `${filepath}${directories[directoryIndex]}/${file}`; - + var filename = _fileUtil.StripExtension(file); + var routeKey = $"{routes[i]}{filename}"; + var imagePath = $"{filepath}{directories[i]}/{file}"; +/* const pathOverride = this.getImagePathOverride(imagePath); if (pathOverride) { this.logger.debug(`overrode route: ${routeKey} endpoint: ${imagePath} with ${pathOverride}`); @@ -186,12 +188,12 @@ public class DatabaseImporter : OnLoad } this.imageRouter.addRoute(routeKey, imagePath); + */ } } // Map icon file separately - this.imageRouter.addRoute("/favicon.ico", `${filepath}icon.ico`); - */ + //this.imageRouter.addRoute("/favicon.ico", `${filepath}icon.ico`); } /** @@ -211,4 +213,4 @@ internal enum ValidationResult FAILED = 1, NOT_FOUND = 2, UNDEFINED = 3 -} \ No newline at end of file +} diff --git a/Core/Utils/FileUtil.cs b/Core/Utils/FileUtil.cs index 5fc396f4..cde04efe 100644 --- a/Core/Utils/FileUtil.cs +++ b/Core/Utils/FileUtil.cs @@ -24,4 +24,9 @@ public class FileUtil { return Path.GetExtension(path).Replace(".", ""); } -} \ No newline at end of file + + public string StripExtension(string path) + { + return Path.GetFileNameWithoutExtension(path); + } +} diff --git a/Core/Utils/HttpFileUtil.cs b/Core/Utils/HttpFileUtil.cs new file mode 100644 index 00000000..027f6d30 --- /dev/null +++ b/Core/Utils/HttpFileUtil.cs @@ -0,0 +1,25 @@ +using Core.Annotations; +using Core.Helpers; + +namespace Core.Utils; + +[Injectable] +public class HttpFileUtil +{ + protected HttpServerHelper _httpServerHelper; + + public HttpFileUtil(HttpServerHelper httpServerHelper) + { + _httpServerHelper = httpServerHelper; + } + + public Task SendFileAsync(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.Add("Content-Type", type); + return resp.SendFileAsync(filePath, CancellationToken.None); + // maybe the above is correct? + // await pipeline(fs.createReadStream(filePath), resp); + } +}