using System; using System.Text.Json.Serialization; using System.Threading.Tasks; using GenHTTP.Api.Protocol; using GenHTTP.Modules.IO; using StringContent = GenHTTP.Modules.IO.Strings.StringContent; namespace Artemis.Core.Services; /// /// Represents a base type for plugin end points to be targeted by the /// public abstract class PluginEndPoint { private readonly PluginsHandler _pluginsHandler; internal PluginEndPoint(PluginFeature pluginFeature, string name, PluginsHandler pluginsHandler) { _pluginsHandler = pluginsHandler; PluginFeature = pluginFeature; Name = name; PluginFeature.Disabled += OnDisabled; } /// /// Gets the name of the end point /// public string Name { get; } /// /// Gets the full URL of the end point /// public string Url => $"/{_pluginsHandler.BaseRoute}/{PluginFeature.Plugin.Guid}/{Name}"; /// /// Gets the plugin the end point is associated with /// [JsonIgnore] public PluginFeature PluginFeature { get; } /// /// Gets the plugin info of the plugin the end point is associated with /// public PluginInfo PluginInfo => PluginFeature.Plugin.Info; /// /// Gets the mime type of the input this end point accepts /// public FlexibleContentType Accepts { get; protected set; } /// /// Gets the mime type of the output this end point returns /// public FlexibleContentType Returns { get; protected set; } /// /// Occurs whenever a request threw an unhandled exception /// public event EventHandler? RequestException; /// /// Occurs whenever a request is about to be processed /// public event EventHandler? ProcessingRequest; /// /// Occurs whenever a request was processed /// public event EventHandler? ProcessedRequest; /// /// Called whenever the end point has to process a request /// /// The HTTP context of the request protected abstract Task ProcessRequest(IRequest request); /// /// Invokes the event /// /// The exception that occurred during the request protected virtual void OnRequestException(Exception e) { RequestException?.Invoke(this, new EndpointExceptionEventArgs(e)); } /// /// Invokes the event /// protected virtual void OnProcessingRequest(IRequest request) { ProcessingRequest?.Invoke(this, new EndpointRequestEventArgs(request)); } /// /// Invokes the event /// protected virtual void OnProcessedRequest(IRequest request) { ProcessedRequest?.Invoke(this, new EndpointRequestEventArgs(request)); } internal async Task InternalProcessRequest(IRequest context) { try { OnProcessingRequest(context); if (!Equals(context.ContentType, Accepts)) { OnRequestException(new Exception("Unsupported media type")); return context.Respond().Status(ResponseStatus.UnsupportedMediaType).Build(); } IResponse response = await ProcessRequest(context); OnProcessedRequest(context); return response; } catch (Exception e) { OnRequestException(e); return context.Respond() .Status(ResponseStatus.InternalServerError) .Content(new StringContent(e.ToString())) .Type(ContentType.TextPlain) .Build(); } } private void OnDisabled(object? sender, EventArgs e) { PluginFeature.Disabled -= OnDisabled; _pluginsHandler.RemovePluginEndPoint(this); } }