From c41f04d92d810f701947f1348ff05c32d3b60946 Mon Sep 17 00:00:00 2001 From: Glax Date: Sat, 20 Apr 2024 18:34:20 +0200 Subject: [PATCH] All Valid Request Paths return "Not Implemented". Ping returns Pong. --- Tranga/Server/RequestPath.cs | 19 +++++ Tranga/Server/Server.cs | 94 ++++++++++++++++------- Tranga/Server/v2Connector.cs | 19 +++++ Tranga/Server/v2Jobs.cs | 73 ++++++++++++++++++ Tranga/Server/v2LibraryConnectors.cs | 37 +++++++++ Tranga/Server/v2Manga.cs | 27 +++++++ Tranga/Server/v2Miscellaneous.cs | 22 ++++++ Tranga/Server/v2NotificationConnectors.cs | 37 +++++++++ Tranga/Server/v2Settings.cs | 62 +++++++++++++++ Tranga/Tranga.cs | 4 +- 10 files changed, 366 insertions(+), 28 deletions(-) create mode 100644 Tranga/Server/RequestPath.cs create mode 100644 Tranga/Server/v2Connector.cs create mode 100644 Tranga/Server/v2Jobs.cs create mode 100644 Tranga/Server/v2LibraryConnectors.cs create mode 100644 Tranga/Server/v2Manga.cs create mode 100644 Tranga/Server/v2Miscellaneous.cs create mode 100644 Tranga/Server/v2NotificationConnectors.cs create mode 100644 Tranga/Server/v2Settings.cs diff --git a/Tranga/Server/RequestPath.cs b/Tranga/Server/RequestPath.cs new file mode 100644 index 0000000..c8db596 --- /dev/null +++ b/Tranga/Server/RequestPath.cs @@ -0,0 +1,19 @@ +using System.Net; +using System.Text.RegularExpressions; + +namespace Tranga.Server; + +internal struct RequestPath +{ + internal readonly string HttpMethod; + internal readonly string RegexStr; + internal readonly Func, ValueTuple> Method; + + public RequestPath(string httpHttpMethod, string regexStr, + Func, ValueTuple> method) + { + this.HttpMethod = httpHttpMethod; + this.RegexStr = regexStr; + this.Method = method; + } +} \ No newline at end of file diff --git a/Tranga/Server/Server.cs b/Tranga/Server/Server.cs index d090aff..8f35f86 100644 --- a/Tranga/Server/Server.cs +++ b/Tranga/Server/Server.cs @@ -6,14 +6,68 @@ using Newtonsoft.Json; namespace Tranga.Server; -public class Server : GlobalBase, IDisposable +public partial class Server : GlobalBase, IDisposable { private readonly HttpListener _listener = new(); private readonly Tranga _parent; private bool _running = true; + private readonly List _apiRequestPaths; + public Server(Tranga parent) : base(parent) { + /* + * Contains all valid Request Methods, Paths (with Regex Group Matching for specific Parameters) and Handling Methods + */ + _apiRequestPaths = new List + { + new ("GET", @"/v2/Connector/Types", GetV2ConnectorTypes), + new ("GET", @"/v2/Connector/([a-zA-Z]+)/GetManga", GetV2ConnectorConnectorNameGetManga), + new ("GET", @"/v2/Manga/([-A-Za-z0-9+/]*={0,3})", GetV2MangaInternalId), + new ("DELETE", @"/v2/Manga/([-A-Za-z0-9+/]*={0,3})", DeleteV2MangaInternalId), + new ("GET", @"/v2/Manga/([-A-Za-z0-9+/]*={0,3})/Cover", GetV2MangaInternalIdCover), + new ("GET", @"/v2/Manga/([-A-Za-z0-9+/]*={0,3})/Chapters", GetV2MangaInternalIdChapters), + new ("GET", @"/v2/Jobs", GetV2Jobs), + new ("GET", @"/v2/Jobs/Running", GetV2JobsRunning), + new ("GET", @"/v2/Jobs/Waiting", GetV2JobsWaiting), + new ("GET", @"/v2/Jobs/Monitoring", GetV2JobsMonitoring), + new ("POST", @"/v2/Jobs/Create/Monitor/(^[-A-Za-z0-9+/]*={0,3}$)", PostV2JobsCreateMonitorInternalId), + new ("POST", @"/v2/Jobs/Create/DownloadNewChapters/(^[-A-Za-z0-9+/]*={0,3}$)", PostV2JobsCreateDownloadNewChaptersInternalId), + new ("POST", @"/v2/Jobs/Create/UpdateMetadata", PostV2JobsCreateUpdateMetadata), + new ("POST", @"/v2/Jobs/Create/UpdateMetadata/(^[-A-Za-z0-9+/]*={0,3}$)", PostV2JobsCreateUpdateMetadataInternalId), + new ("GET", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)", GetV2JobJobId), + new ("DELETE", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)", DeleteV2JobJobId), + new ("GET", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)/Progress", GetV2JobJobIdProgress), + new ("POST", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)/StartNow", PostV2JobJobIdStartNow), + new ("POST", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)/Cancel", PostV2JobJobIdCancel), + new ("GET", @"/v2/Settings", GetV2Settings), + new ("GET", @"/v2/Settings/UserAgent", GetV2SettingsUserAgent), + new ("POST", @"/v2/Settings/UserAgent", PostV2SettingsUserAgent), + new ("GET", @"/v2/Settings/RateLimit/Types", GetV2SettingsRateLimitTypes), + new ("GET", @"/v2/Settings/RateLimit", GetV2SettingsRateLimit), + new ("POST", @"/v2/Settings/RateLimit", PostV2SettingsRateLimit), + new ("GET", @"/v2/Settings/RateLimit/([a-zA-Z]+)", GetV2SettingsRateLimitType), + new ("POST", @"/v2/Settings/RateLimit/([a-zA-Z]+)", PostV2SettingsRateLimitType), + new ("GET", @"/v2/Settings/AprilFoolsMode", GetV2SettingsAprilFoolsMode), + new ("POST", @"/v2/Settings/AprilFoolsMode", PostV2SettingsAprilFoolsMode), + new ("POST", @"/v2/Settings/DownloadLocation", PostV2SettingsDownloadLocation), + new ("GET", @"/v2/LibraryConnector", GetV2LibraryConnector), + new ("GET", @"/v2/LibraryConnector/Types", GetV2LibraryConnectorTypes), + new ("GET", @"/v2/LibraryConnector/([a-zA-Z]+)", GetV2LibraryConnectorType), + new ("POST", @"/v2/LibraryConnector/([a-zA-Z]+)", PostV2LibraryConnectorType), + new ("POST", @"/v2/LibraryConnector/([a-zA-Z]+)/Test", PostV2LibraryConnectorTypeTest), + new ("DELETE", @"/v2/LibraryConnector/([a-zA-Z]+)", DeleteV2LibraryConnectorType), + new ("GET", @"/v2/NotificationConnector", GetV2NotificationConnector), + new ("GET", @"/v2/NotificationConnector/Types", GetV2NotificationConnectorTypes), + new ("GET", @"/v2/NotificationConnector/([a-zA-Z]+)", GetV2NotificationConnectorType), + new ("POST", @"/v2/NotificationConnector/([a-zA-Z]+)", PostV2NotificationConnectorType), + new ("POST", @"/v2/NotificationConnector/([a-zA-Z]+)/Test", PostV2NotificationConnectorTypeTest), + new ("DELETE", @"/v2/NotificationConnector/([a-zA-Z]+)", DeleteV2NotificationConnectorType), + new ("GET", @"/v2/LogFile", GetV2LogFile), + new ("GET", @"/v2/Ping", GetV2Ping), + new ("POST", @"/v2/Ping", PostV2Ping) + }; + this._parent = parent; if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) this._listener.Prefixes.Add($"http://*:{settings.apiPortNumber}/"); @@ -55,14 +109,14 @@ public class Server : GlobalBase, IDisposable HttpListenerRequest request = context.Request; HttpListenerResponse response = context.Response; if (request.HttpMethod == "OPTIONS") - SendResponse(HttpStatusCode.OK, context.Response); + SendResponse(HttpStatusCode.OK, context.Response); //Response always contains all valid Request-Methods if (request.Url!.LocalPath.Contains("favicon")) SendResponse(HttpStatusCode.NoContent, response); - string path = Regex.Match(request.Url!.LocalPath, @"[A-z0-9]+(\/[A-z0-9]+)*").Value; + string path = Regex.Match(request.Url.LocalPath, @"\/[A-z0-9]+(\/[A-z0-9]+)*").Value; //Local Path - if (!Regex.IsMatch(request.Url.LocalPath, "/v2(/.*)?")) + if (!Regex.IsMatch(path, "/v2(/.*)?")) //Use only v2 API { - SendResponse(HttpStatusCode.NotFound, response); + SendResponse(HttpStatusCode.NotFound, response, "Use Version 2 API"); return; } @@ -71,13 +125,16 @@ public class Server : GlobalBase, IDisposable Dictionary requestParams = requestVariables.UnionBy(requestBody, v => v.Key) .ToDictionary(kv => kv.Key, kv => kv.Value); //The actual variable used for the API - ValueTuple responseMessage = request.HttpMethod switch + ValueTuple responseMessage; //Used to respond to the HttpRequest + if (_apiRequestPaths.Any(p => p.HttpMethod == request.HttpMethod && Regex.IsMatch(path, p.RegexStr))) //Check if Request-Path is valid { - "GET" => HandleGet(path, requestParams), - "POST" => HandlePost(path, requestParams), - "DELETE" => HandleDelete(path, requestParams), - _ => new ValueTuple(HttpStatusCode.MethodNotAllowed, null) - }; + RequestPath requestPath = + _apiRequestPaths.First(p => p.HttpMethod == request.HttpMethod && Regex.IsMatch(path, p.RegexStr)); + responseMessage = + requestPath.Method.Invoke(Regex.Match(path, requestPath.RegexStr).Groups, requestParams); //Get HttpResponse content + } + else + responseMessage = new ValueTuple(HttpStatusCode.MethodNotAllowed, "Unknown Request Path"); SendResponse(responseMessage.Item1, response, responseMessage.Item2); } @@ -171,21 +228,6 @@ public class Server : GlobalBase, IDisposable stream.Close(); } } - - private ValueTuple HandleGet(string path, Dictionary requestParameters) - { - return new ValueTuple(HttpStatusCode.NotImplemented, "Not implemented."); - } - - private ValueTuple HandlePost(string path, Dictionary requestParameters) - { - return new ValueTuple(HttpStatusCode.NotImplemented, "Not implemented."); - } - - private ValueTuple HandleDelete(string path, Dictionary requestParameters) - { - return new ValueTuple(HttpStatusCode.NotImplemented, "Not implemented."); - } public void Dispose() diff --git a/Tranga/Server/v2Connector.cs b/Tranga/Server/v2Connector.cs new file mode 100644 index 0000000..ac3b38a --- /dev/null +++ b/Tranga/Server/v2Connector.cs @@ -0,0 +1,19 @@ +using System.Net; +using System.Text.RegularExpressions; + +namespace Tranga.Server; + +public partial class Server +{ + private ValueTuple GetV2ConnectorTypes(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.Accepted, _parent.GetConnectors()); + } + + private ValueTuple GetV2ConnectorConnectorNameGetManga(GroupCollection groups, Dictionary requestParameters) + { + if(groups.Count < 1 || !_parent.GetConnectors().Contains(groups[1].Value)) + return new ValueTuple(HttpStatusCode.BadRequest, $"Connector '{groups[1].Value}' does not exist."); + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } +} \ No newline at end of file diff --git a/Tranga/Server/v2Jobs.cs b/Tranga/Server/v2Jobs.cs new file mode 100644 index 0000000..5a6813f --- /dev/null +++ b/Tranga/Server/v2Jobs.cs @@ -0,0 +1,73 @@ +using System.Net; +using System.Text.RegularExpressions; + +namespace Tranga.Server; + +public partial class Server +{ + private ValueTuple GetV2Jobs(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2JobsRunning(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2JobsWaiting(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2JobsMonitoring(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2JobsCreateMonitorInternalId(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2JobsCreateDownloadNewChaptersInternalId(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2JobsCreateUpdateMetadata(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2JobsCreateUpdateMetadataInternalId(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2JobJobId(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple DeleteV2JobJobId(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2JobJobIdProgress(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2JobJobIdStartNow(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2JobJobIdCancel(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + +} \ No newline at end of file diff --git a/Tranga/Server/v2LibraryConnectors.cs b/Tranga/Server/v2LibraryConnectors.cs new file mode 100644 index 0000000..5ee6287 --- /dev/null +++ b/Tranga/Server/v2LibraryConnectors.cs @@ -0,0 +1,37 @@ +using System.Net; +using System.Text.RegularExpressions; + +namespace Tranga.Server; + +public partial class Server +{ + private ValueTuple GetV2LibraryConnector(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2LibraryConnectorTypes(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2LibraryConnectorType(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2LibraryConnectorType(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2LibraryConnectorTypeTest(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple DeleteV2LibraryConnectorType(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } +} \ No newline at end of file diff --git a/Tranga/Server/v2Manga.cs b/Tranga/Server/v2Manga.cs new file mode 100644 index 0000000..834cb4f --- /dev/null +++ b/Tranga/Server/v2Manga.cs @@ -0,0 +1,27 @@ +using System.Net; +using System.Text.RegularExpressions; + +namespace Tranga.Server; + +public partial class Server +{ + private ValueTuple GetV2MangaInternalId(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple DeleteV2MangaInternalId(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2MangaInternalIdCover(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2MangaInternalIdChapters(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } +} \ No newline at end of file diff --git a/Tranga/Server/v2Miscellaneous.cs b/Tranga/Server/v2Miscellaneous.cs new file mode 100644 index 0000000..e0ce1a8 --- /dev/null +++ b/Tranga/Server/v2Miscellaneous.cs @@ -0,0 +1,22 @@ +using System.Net; +using System.Text.RegularExpressions; + +namespace Tranga.Server; + +public partial class Server +{ + private ValueTuple GetV2LogFile(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2Ping(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.Accepted, "Pong!"); + } + + private ValueTuple PostV2Ping(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.Accepted, "Pong!"); + } +} \ No newline at end of file diff --git a/Tranga/Server/v2NotificationConnectors.cs b/Tranga/Server/v2NotificationConnectors.cs new file mode 100644 index 0000000..7d7cb73 --- /dev/null +++ b/Tranga/Server/v2NotificationConnectors.cs @@ -0,0 +1,37 @@ +using System.Net; +using System.Text.RegularExpressions; + +namespace Tranga.Server; + +public partial class Server +{ + private ValueTuple GetV2NotificationConnector(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2NotificationConnectorTypes(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2NotificationConnectorType(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2NotificationConnectorType(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2NotificationConnectorTypeTest(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple DeleteV2NotificationConnectorType(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } +} \ No newline at end of file diff --git a/Tranga/Server/v2Settings.cs b/Tranga/Server/v2Settings.cs new file mode 100644 index 0000000..6615726 --- /dev/null +++ b/Tranga/Server/v2Settings.cs @@ -0,0 +1,62 @@ +using System.Net; +using System.Text.RegularExpressions; + +namespace Tranga.Server; + +public partial class Server +{ + private ValueTuple GetV2Settings(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2SettingsUserAgent(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2SettingsUserAgent(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2SettingsRateLimitTypes(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2SettingsRateLimit(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2SettingsRateLimit(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2SettingsRateLimitType(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2SettingsRateLimitType(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple GetV2SettingsAprilFoolsMode(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2SettingsAprilFoolsMode(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } + + private ValueTuple PostV2SettingsDownloadLocation(GroupCollection groups, Dictionary requestParameters) + { + return new ValueTuple(HttpStatusCode.NotImplemented, "Not Implemented"); + } +} \ No newline at end of file diff --git a/Tranga/Tranga.cs b/Tranga/Tranga.cs index 91b1f19..4f28670 100644 --- a/Tranga/Tranga.cs +++ b/Tranga/Tranga.cs @@ -49,9 +49,9 @@ public partial class Tranga : GlobalBase return connector is not null; } - public IEnumerable GetConnectors() + public IEnumerable GetConnectors() { - return _connectors; + return _connectors.Select(c => c.name); } public Manga? GetPublicationById(string internalId)