New: Use ASP.NET Core instead of Nancy

(cherry picked from commit 58ddbcd77e17ef95ecfad4b746084ee9326116f3)
This commit is contained in:
ta264
2021-03-15 21:32:12 +00:00
parent 7d494f9743
commit dbdc527f2e
122 changed files with 2177 additions and 2838 deletions

View File

@@ -1,74 +0,0 @@
using System;
using Nancy;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Extensions;
namespace Prowlarr.Http.Frontend
{
public interface ICacheableSpecification
{
bool IsCacheable(NancyContext context);
}
public class CacheableSpecification : ICacheableSpecification
{
public bool IsCacheable(NancyContext context)
{
if (!RuntimeInfo.IsProduction)
{
return false;
}
if (((DynamicDictionary)context.Request.Query).ContainsKey("h"))
{
return true;
}
if (context.Request.Path.StartsWith("/api", StringComparison.CurrentCultureIgnoreCase))
{
if (context.Request.Path.ContainsIgnoreCase("/MediaCover"))
{
return true;
}
return false;
}
if (context.Request.Path.StartsWith("/signalr", StringComparison.CurrentCultureIgnoreCase))
{
return false;
}
if (context.Request.Path.EndsWith("index.js"))
{
return false;
}
if (context.Request.Path.EndsWith("initialize.js"))
{
return false;
}
if (context.Request.Path.StartsWith("/feed", StringComparison.CurrentCultureIgnoreCase))
{
return false;
}
if (context.Request.Path.StartsWith("/log", StringComparison.CurrentCultureIgnoreCase) &&
context.Request.Path.EndsWith(".txt", StringComparison.CurrentCultureIgnoreCase))
{
return false;
}
if (context.Response != null)
{
if (context.Response.ContentType.Contains("text/html"))
{
return false;
}
}
return true;
}
}
}

View File

@@ -1,7 +1,6 @@
using System.IO;
using System.Text;
using Nancy;
using Nancy.Responses;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using NzbDrone.Common;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Analytics;
@@ -9,7 +8,9 @@ using NzbDrone.Core.Configuration;
namespace Prowlarr.Http.Frontend
{
public class InitializeJsModule : NancyModule
[Authorize(Policy = "UI")]
[ApiController]
public class InitializeJsController : Controller
{
private readonly IConfigFileProvider _configFileProvider;
private readonly IAnalyticsService _analyticsService;
@@ -18,35 +19,21 @@ namespace Prowlarr.Http.Frontend
private static string _urlBase;
private string _generatedContent;
public InitializeJsModule(IConfigFileProvider configFileProvider,
IAnalyticsService analyticsService)
public InitializeJsController(IConfigFileProvider configFileProvider,
IAnalyticsService analyticsService)
{
_configFileProvider = configFileProvider;
_analyticsService = analyticsService;
_apiKey = configFileProvider.ApiKey;
_urlBase = configFileProvider.UrlBase;
Get("/initialize.js", x => Index());
}
private Response Index()
[HttpGet("/initialize.js")]
public IActionResult Index()
{
// TODO: Move away from window.Sonarr and prefetch the information returned here when starting the UI
return new StreamResponse(GetContentStream, "application/javascript");
}
private Stream GetContentStream()
{
var text = GetContent();
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(text);
writer.Flush();
stream.Position = 0;
return stream;
// TODO: Move away from window.Prowlarr and prefetch the information returned here when starting the UI
return Content(GetContent(), "application/javascript");
}
private string GetContent()

View File

@@ -1,7 +1,6 @@
using System;
using System.IO;
using System.Text.RegularExpressions;
using Nancy;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
@@ -40,13 +39,14 @@ namespace Prowlarr.Http.Frontend.Mappers
return stream;
}
public override Response GetResponse(string resourceUrl)
/*
public override IActionResult GetResponse(string resourceUrl)
{
var response = base.GetResponse(resourceUrl);
response.Headers["X-UA-Compatible"] = "IE=edge";
return response;
}
}*/
protected string GetHtmlText()
{

View File

@@ -1,4 +1,4 @@
using Nancy;
using Microsoft.AspNetCore.Mvc;
namespace Prowlarr.Http.Frontend.Mappers
{
@@ -6,6 +6,6 @@ namespace Prowlarr.Http.Frontend.Mappers
{
string Map(string resourceUrl);
bool CanHandle(string resourceUrl);
Response GetResponse(string resourceUrl);
IActionResult GetResponse(string resourceUrl);
}
}

View File

@@ -1,7 +1,7 @@
using System;
using System.IO;
using Nancy;
using Nancy.Responses;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.StaticFiles;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
@@ -13,14 +13,14 @@ namespace Prowlarr.Http.Frontend.Mappers
private readonly IDiskProvider _diskProvider;
private readonly Logger _logger;
private readonly StringComparison _caseSensitive;
private static readonly NotFoundResponse NotFoundResponse = new NotFoundResponse();
private readonly IContentTypeProvider _mimeTypeProvider;
protected StaticResourceMapperBase(IDiskProvider diskProvider, Logger logger)
{
_diskProvider = diskProvider;
_logger = logger;
_mimeTypeProvider = new FileExtensionContentTypeProvider();
_caseSensitive = RuntimeInfo.IsProduction ? DiskProviderBase.PathStringComparison : StringComparison.OrdinalIgnoreCase;
}
@@ -28,19 +28,23 @@ namespace Prowlarr.Http.Frontend.Mappers
public abstract bool CanHandle(string resourceUrl);
public virtual Response GetResponse(string resourceUrl)
public virtual IActionResult GetResponse(string resourceUrl)
{
var filePath = Map(resourceUrl);
if (_diskProvider.FileExists(filePath, _caseSensitive))
{
var response = new StreamResponse(() => GetContentStream(filePath), MimeTypes.GetMimeType(filePath));
return new MaterialisingResponse(response);
if (!_mimeTypeProvider.TryGetContentType(filePath, out var contentType))
{
contentType = "application/octet-stream";
}
return new FileStreamResult(GetContentStream(filePath), contentType);
}
_logger.Warn("File {0} not found", filePath);
return NotFoundResponse;
return null;
}
protected virtual Stream GetContentStream(string filePath)

View File

@@ -0,0 +1,73 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using NLog;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
using Prowlarr.Http.Frontend.Mappers;
namespace Prowlarr.Http.Frontend
{
[Authorize(Policy="UI")]
[ApiController]
public class StaticResourceController : Controller
{
private readonly string _urlBase;
private readonly string _loginPath;
private readonly IEnumerable<IMapHttpRequestsToDisk> _requestMappers;
private readonly Logger _logger;
public StaticResourceController(IConfigFileProvider configFileProvider,
IAppFolderInfo appFolderInfo,
IEnumerable<IMapHttpRequestsToDisk> requestMappers,
Logger logger)
{
_urlBase = configFileProvider.UrlBase.Trim('/');
_requestMappers = requestMappers;
_logger = logger;
_loginPath = Path.Combine(appFolderInfo.StartUpFolder, configFileProvider.UiFolder, "login.html");
}
[AllowAnonymous]
[HttpGet("login")]
public IActionResult LoginPage()
{
return PhysicalFile(_loginPath, "text/html");
}
[EnableCors("AllowGet")]
[AllowAnonymous]
[HttpGet("/content/{**path:regex(^(?!api/).*)}")]
public IActionResult IndexContent([FromRoute] string path)
{
return MapResource("Content/" + path);
}
[HttpGet("")]
[HttpGet("/{**path:regex(^(?!api/).*)}")]
public IActionResult Index([FromRoute] string path)
{
return MapResource(path);
}
private IActionResult MapResource(string path)
{
path = "/" + (path ?? "");
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
if (mapper != null)
{
return mapper.GetResponse(path) ?? NotFound();
}
_logger.Warn("Couldn't find handler for {0}", path);
return NotFound();
}
}
}

View File

@@ -1,48 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Nancy;
using NLog;
using Prowlarr.Http.Frontend.Mappers;
namespace Prowlarr.Http.Frontend
{
public class StaticResourceModule : NancyModule
{
private readonly IEnumerable<IMapHttpRequestsToDisk> _requestMappers;
private readonly Logger _logger;
public StaticResourceModule(IEnumerable<IMapHttpRequestsToDisk> requestMappers, Logger logger)
{
_requestMappers = requestMappers;
_logger = logger;
Get("/{resource*}", x => Index());
Get("/", x => Index());
}
private Response Index()
{
var path = Request.Url.Path;
if (
string.IsNullOrWhiteSpace(path) ||
path.StartsWith("/api", StringComparison.CurrentCultureIgnoreCase) ||
path.StartsWith("/signalr", StringComparison.CurrentCultureIgnoreCase))
{
return new NotFoundResponse();
}
var mapper = _requestMappers.SingleOrDefault(m => m.CanHandle(path));
if (mapper != null)
{
return mapper.GetResponse(path);
}
_logger.Warn("Couldn't find handler for {0}", path);
return new NotFoundResponse();
}
}
}