diff options
Diffstat (limited to 'src/SMAPI.Web/Startup.cs')
-rw-r--r-- | src/SMAPI.Web/Startup.cs | 168 |
1 files changed, 87 insertions, 81 deletions
diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index 56ef9a79..586b0c3c 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -1,8 +1,7 @@ -using System; using System.Collections.Generic; +using System.Net; using Hangfire; using Hangfire.MemoryStorage; -using Hangfire.Mongo; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Rewrite; @@ -10,13 +9,9 @@ using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; -using Mongo2Go; -using MongoDB.Bson.Serialization; -using MongoDB.Driver; using Newtonsoft.Json; using StardewModdingAPI.Toolkit.Serialization; using StardewModdingAPI.Web.Framework; -using StardewModdingAPI.Web.Framework.Caching; using StardewModdingAPI.Web.Framework.Caching.Mods; using StardewModdingAPI.Web.Framework.Caching.Wiki; using StardewModdingAPI.Web.Framework.Clients.Chucklefish; @@ -27,7 +22,7 @@ using StardewModdingAPI.Web.Framework.Clients.Nexus; using StardewModdingAPI.Web.Framework.Clients.Pastebin; using StardewModdingAPI.Web.Framework.Compression; using StardewModdingAPI.Web.Framework.ConfigModels; -using StardewModdingAPI.Web.Framework.RewriteRules; +using StardewModdingAPI.Web.Framework.RedirectRules; using StardewModdingAPI.Web.Framework.Storage; namespace StardewModdingAPI.Web @@ -47,7 +42,7 @@ namespace StardewModdingAPI.Web *********/ /// <summary>Construct an instance.</summary> /// <param name="env">The hosting environment.</param> - public Startup(IHostingEnvironment env) + public Startup(IWebHostEnvironment env) { this.Configuration = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) @@ -67,70 +62,41 @@ namespace StardewModdingAPI.Web .Configure<BackgroundServicesConfig>(this.Configuration.GetSection("BackgroundServices")) .Configure<ModCompatibilityListConfig>(this.Configuration.GetSection("ModCompatibilityList")) .Configure<ModUpdateCheckConfig>(this.Configuration.GetSection("ModUpdateCheck")) - .Configure<MongoDbConfig>(this.Configuration.GetSection("MongoDB")) .Configure<SiteConfig>(this.Configuration.GetSection("Site")) .Configure<RouteOptions>(options => options.ConstraintMap.Add("semanticVersion", typeof(VersionConstraint))) .AddLogging() - .AddMemoryCache() - .AddMvc() - .ConfigureApplicationPartManager(manager => manager.FeatureProviders.Add(new InternalControllerFeatureProvider())) - .AddJsonOptions(options => - { - foreach (JsonConverter converter in new JsonHelper().JsonSettings.Converters) - options.SerializerSettings.Converters.Add(converter); - - options.SerializerSettings.Formatting = Formatting.Indented; - options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; - }); - MongoDbConfig mongoConfig = this.Configuration.GetSection("MongoDB").Get<MongoDbConfig>(); - - // init background service - { - BackgroundServicesConfig config = this.Configuration.GetSection("BackgroundServices").Get<BackgroundServicesConfig>(); - if (config.Enabled) - services.AddHostedService<BackgroundService>(); - } + .AddMemoryCache(); - // init MongoDB - services.AddSingleton<MongoDbRunner>(serv => !mongoConfig.IsConfigured() - ? MongoDbRunner.Start() - : throw new InvalidOperationException("The MongoDB connection is configured, so the local development version should not be used.") - ); - services.AddSingleton<IMongoDatabase>(serv => - { - // get connection string - string connectionString = mongoConfig.IsConfigured() - ? mongoConfig.ConnectionString - : serv.GetRequiredService<MongoDbRunner>().ConnectionString; + // init MVC + services + .AddControllers() + .AddNewtonsoftJson(options => this.ConfigureJsonNet(options.SerializerSettings)) + .ConfigureApplicationPartManager(manager => manager.FeatureProviders.Add(new InternalControllerFeatureProvider())); + services + .AddRazorPages(); - // get client - BsonSerializer.RegisterSerializer(new UtcDateTimeOffsetSerializer()); - return new MongoClient(connectionString).GetDatabase(mongoConfig.Database); - }); - services.AddSingleton<IModCacheRepository>(serv => new ModCacheRepository(serv.GetRequiredService<IMongoDatabase>())); - services.AddSingleton<IWikiCacheRepository>(serv => new WikiCacheRepository(serv.GetRequiredService<IMongoDatabase>())); + // init storage + services.AddSingleton<IModCacheRepository>(new ModCacheMemoryRepository()); + services.AddSingleton<IWikiCacheRepository>(new WikiCacheMemoryRepository()); // init Hangfire services - .AddHangfire(config => + .AddHangfire((serv, config) => { config .SetDataCompatibilityLevel(CompatibilityLevel.Version_170) .UseSimpleAssemblyNameTypeSerializer() - .UseRecommendedSerializerSettings(); - - if (mongoConfig.IsConfigured()) - { - config.UseMongoStorage(mongoConfig.ConnectionString, $"{mongoConfig.Database}-hangfire", new MongoStorageOptions - { - MigrationOptions = new MongoMigrationOptions(MongoMigrationStrategy.Drop), - CheckConnection = false // error on startup takes down entire process - }); - } - else - config.UseMemoryStorage(); + .UseRecommendedSerializerSettings() + .UseMemoryStorage(); }); + // init background service + { + BackgroundServicesConfig config = this.Configuration.GetSection("BackgroundServices").Get<BackgroundServicesConfig>(); + if (config.Enabled) + services.AddHostedService<BackgroundService>(); + } + // init API clients { ApiClientsConfig api = this.Configuration.GetSection("ApiClients").Get<ApiClientsConfig>(); @@ -142,6 +108,7 @@ namespace StardewModdingAPI.Web baseUrl: api.ChucklefishBaseUrl, modPageUrlFormat: api.ChucklefishModPageUrlFormat )); + services.AddSingleton<ICurseForgeClient>(new CurseForgeClient( userAgent: userAgent, apiUrl: api.CurseForgeBaseUrl @@ -188,8 +155,7 @@ namespace StardewModdingAPI.Web /// <summary>The method called by the runtime to configure the HTTP request pipeline.</summary> /// <param name="app">The application builder.</param> - /// <param name="env">The hosting environment.</param> - public void Configure(IApplicationBuilder app, IHostingEnvironment env) + public void Configure(IApplicationBuilder app) { // basic config app.UseDeveloperExceptionPage(); @@ -201,7 +167,13 @@ namespace StardewModdingAPI.Web ) .UseRewriter(this.GetRedirectRules()) .UseStaticFiles() // wwwroot folder - .UseMvc(); + .UseRouting() + .UseAuthorization() + .UseEndpoints(p => + { + p.MapControllers(); + p.MapRazorPages(); + }); // enable Hangfire dashboard app.UseHangfireDashboard("/tasks", new DashboardOptions @@ -215,29 +187,63 @@ namespace StardewModdingAPI.Web /********* ** Private methods *********/ + /// <summary>Configure a Json.NET serializer.</summary> + /// <param name="settings">The serializer settings to edit.</param> + private void ConfigureJsonNet(JsonSerializerSettings settings) + { + foreach (JsonConverter converter in new JsonHelper().JsonSettings.Converters) + settings.Converters.Add(converter); + + settings.Formatting = Formatting.Indented; + settings.NullValueHandling = NullValueHandling.Ignore; + } + /// <summary>Get the redirect rules to apply.</summary> private RewriteOptions GetRedirectRules() { - var redirects = new RewriteOptions(); + var redirects = new RewriteOptions() + // shortcut paths + .Add(new RedirectPathsToUrlsRule(new Dictionary<string, string> + { + [@"^/3\.0\.?$"] = "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0", + [@"^/(?:buildmsg|package)(?:/?(.*))$"] = "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1", // buildmsg deprecated, remove when SDV 1.4 is released + [@"^/community\.?$"] = "https://stardewvalleywiki.com/Modding:Community", + [@"^/compat\.?$"] = "https://smapi.io/mods", + [@"^/docs\.?$"] = "https://stardewvalleywiki.com/Modding:Index", + [@"^/install\.?$"] = "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI", + [@"^/troubleshoot(.*)$"] = "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1", + [@"^/xnb\.?$"] = "https://stardewvalleywiki.com/Modding:Using_XNB_mods" + })) + + // legacy paths + .Add(new RedirectPathsToUrlsRule(this.GetLegacyPathRedirects())) + + // subdomains + .Add(new RedirectHostsToUrlsRule(HttpStatusCode.PermanentRedirect, host => host switch + { + "api.smapi.io" => "smapi.io/api", + "json.smapi.io" => "smapi.io/json", + "log.smapi.io" => "smapi.io/log", + "mods.smapi.io" => "smapi.io/mods", + _ => host.EndsWith(".smapi.io") + ? "smapi.io" + : null + })) - // redirect to HTTPS (except API for Linux/Mac Mono compatibility) - redirects.Add(new ConditionalRedirectToHttpsRule( - shouldRewrite: req => - req.Host.Host != "localhost" - && !req.Path.StartsWithSegments("/api") - )); + // redirect to HTTPS (except API for Linux/Mac Mono compatibility) + .Add( + new RedirectToHttpsRule(except: req => req.Host.Host == "localhost" || req.Path.StartsWithSegments("/api")) + ); - // shortcut redirects - redirects.Add(new RedirectToUrlRule(@"^/3\.0\.?$", "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0")); - redirects.Add(new RedirectToUrlRule(@"^/(?:buildmsg|package)(?:/?(.*))$", "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1")); // buildmsg deprecated, remove when SDV 1.4 is released - redirects.Add(new RedirectToUrlRule(@"^/community\.?$", "https://stardewvalleywiki.com/Modding:Community")); - redirects.Add(new RedirectToUrlRule(@"^/compat\.?$", "https://smapi.io/mods")); - redirects.Add(new RedirectToUrlRule(@"^/docs\.?$", "https://stardewvalleywiki.com/Modding:Index")); - redirects.Add(new RedirectToUrlRule(@"^/install\.?$", "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI")); - redirects.Add(new RedirectToUrlRule(@"^/troubleshoot(.*)$", "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1")); - redirects.Add(new RedirectToUrlRule(@"^/xnb\.?$", "https://stardewvalleywiki.com/Modding:Using_XNB_mods")); + return redirects; + } + + /// <summary>Get the redirects for legacy paths that have been moved elsewhere.</summary> + private IDictionary<string, string> GetLegacyPathRedirects() + { + var redirects = new Dictionary<string, string>(); - // redirect legacy canimod.com URLs + // canimod.com => wiki var wikiRedirects = new Dictionary<string, string[]> { ["Modding:Index#Migration_guides"] = new[] { "^/for-devs/updating-a-smapi-mod", "^/guides/updating-a-smapi-mod" }, @@ -251,10 +257,10 @@ namespace StardewModdingAPI.Web ["Modding:Object_data"] = new[] { "^/for-devs/object-data", "^/guides/object-data" }, ["Modding:Weather_data"] = new[] { "^/for-devs/weather", "^/guides/weather" } }; - foreach (KeyValuePair<string, string[]> pair in wikiRedirects) + foreach ((string page, string[] patterns) in wikiRedirects) { - foreach (string pattern in pair.Value) - redirects.Add(new RedirectToUrlRule(pattern, "https://stardewvalleywiki.com/" + pair.Key)); + foreach (string pattern in patterns) + redirects.Add(pattern, "https://stardewvalleywiki.com/" + page); } return redirects; |