diff --git a/PluralKit.API/Errors.cs b/PluralKit.API/Errors.cs new file mode 100644 index 00000000..de0779f2 --- /dev/null +++ b/PluralKit.API/Errors.cs @@ -0,0 +1,51 @@ +using System; + +using Newtonsoft.Json.Linq; + +namespace PluralKit.API +{ + public class PKError: Exception + { + public int ResponseCode { get; init; } + public int JsonCode { get; init; } + public PKError(int code, int json_code, string message) : base(message) + { + ResponseCode = code; + JsonCode = json_code; + } + + public JObject ToJson() + { + var j = new JObject(); + j.Add("message", this.Message); + j.Add("code", this.JsonCode); + return j; + } + } + + public class ModelParseError: PKError + { + public ModelParseError() : base(400, 0, "Error parsing JSON model") + { + // todo + } + + public new JObject ToJson() + { + var j = base.ToJson(); + + return j; + } + } + + public static class APIErrors + { + public static PKError GenericBadRequest = new(400, 0, "400: Bad Request"); + public static PKError SystemNotFound = new(404, 20001, "System not found."); + public static PKError MemberNotFound = new(404, 20002, "Member not found."); + public static PKError GroupNotFound = new(404, 20003, "Group not found."); + public static PKError UnauthorizedMemberList = new(403, 30001, "Unauthorized to view member list"); + public static PKError UnauthorizedGroupList = new(403, 30002, "Unauthorized to view group list"); + public static PKError Unimplemented = new(501, 50001, "Unimplemented"); + } +} \ No newline at end of file diff --git a/PluralKit.API/Startup.cs b/PluralKit.API/Startup.cs index a19b67de..f14dafba 100644 --- a/PluralKit.API/Startup.cs +++ b/PluralKit.API/Startup.cs @@ -7,7 +7,9 @@ using Autofac; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.Extensions.Configuration; @@ -15,6 +17,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.OpenApi.Models; +using Newtonsoft.Json; + +using Serilog; + using PluralKit.Core; namespace PluralKit.API @@ -91,7 +97,7 @@ namespace PluralKit.API builder.RegisterInstance(InitUtils.BuildConfiguration(Environment.GetCommandLineArgs()).Build()) .As(); builder.RegisterModule(new ConfigModule("API")); - builder.RegisterModule(new LoggingModule("api")); + builder.RegisterModule(new LoggingModule("api", cfg: new LoggerConfiguration().Filter.ByExcluding(exc => exc.Exception is PKError))); builder.RegisterModule(new MetricsModule("API")); builder.RegisterModule(); builder.RegisterModule(); @@ -124,6 +130,23 @@ namespace PluralKit.API return next(); }); + app.UseExceptionHandler(handler => handler.Run(async ctx => + { + var exc = ctx.Features.Get(); + if (exc.Error is not PKError) + { + ctx.Response.StatusCode = 500; + await ctx.Response.WriteAsync("{\"message\":\"500: Internal Server Error\",\"code\":0}"); + return; + } + + var err = (PKError)exc.Error; + ctx.Response.StatusCode = err.ResponseCode; + + var json = JsonConvert.SerializeObject(err.ToJson()); + await ctx.Response.WriteAsync(json); + })); + app.UseMiddleware(); //app.UseHttpsRedirection(); diff --git a/PluralKit.Core/Modules/LoggingModule.cs b/PluralKit.Core/Modules/LoggingModule.cs index adab7624..7c13689d 100644 --- a/PluralKit.Core/Modules/LoggingModule.cs +++ b/PluralKit.Core/Modules/LoggingModule.cs @@ -17,11 +17,13 @@ namespace PluralKit.Core { private readonly string _component; private readonly Action _fn; + private LoggerConfiguration _cfg { get; init; } - public LoggingModule(string component, Action fn = null) + public LoggingModule(string component, Action fn = null, LoggerConfiguration cfg = null) { _component = component; _fn = fn ?? (_ => { }); + _cfg = cfg ?? new LoggerConfiguration(); } protected override void Load(ContainerBuilder builder) @@ -44,7 +46,7 @@ namespace PluralKit.Core var consoleTemplate = "[{Timestamp:HH:mm:ss.fff}] {Level:u3} {Message:lj}{NewLine}{Exception}"; var outputTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss.ffffff}] {Level:u3} {Message:lj}{NewLine}{Exception}"; - var logCfg = new LoggerConfiguration() + var logCfg = _cfg .Enrich.FromLogContext() .ConfigureForNodaTime(DateTimeZoneProviders.Tzdb) .Enrich.WithProperty("Component", _component) @@ -53,6 +55,9 @@ namespace PluralKit.Core // Don't want App.Metrics/D#+ spam .MinimumLevel.Override("App.Metrics", LogEventLevel.Information) + // nor ASP.NET spam + .MinimumLevel.Override("Microsoft", LogEventLevel.Information) + // Actual formatting for these is handled in ScalarFormatting .Destructure.AsScalar() .Destructure.AsScalar()