mirror of
https://github.com/BililiveRecorder/BililiveRecorder.git
synced 2024-11-16 11:42:22 +08:00
feat(web): make webui work at any base path
This commit is contained in:
parent
8428ca286a
commit
ca755d5ec5
|
@ -11,12 +11,12 @@ namespace BililiveRecorder.Web
|
|||
public class BasicAuthMiddleware
|
||||
{
|
||||
private readonly RequestDelegate next;
|
||||
private readonly ManifestEmbeddedFileProvider fileProvider;
|
||||
private readonly CompositeFileProvider fileProvider;
|
||||
private const string BasicAndSpace = "Basic ";
|
||||
|
||||
private static string? Html401Page;
|
||||
|
||||
public BasicAuthMiddleware(RequestDelegate next, ManifestEmbeddedFileProvider fileProvider)
|
||||
public BasicAuthMiddleware(RequestDelegate next, CompositeFileProvider fileProvider)
|
||||
{
|
||||
this.next = next ?? throw new ArgumentNullException(nameof(next));
|
||||
this.fileProvider = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp" Version="0.17.1" />
|
||||
<PackageReference Include="AutoMapper" Version="11.0.1" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="11.0.0" />
|
||||
<PackageReference Include="GraphQL.MicrosoftDI" Version="4.8.0" />
|
||||
|
@ -23,6 +24,7 @@
|
|||
<PackageReference Include="GraphQL.SystemReactive" Version="4.8.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="6.0.8" />
|
||||
<PackageReference Include="NUglify" Version="1.20.2" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
92
BililiveRecorder.Web/DynamicHtmlController.cs
Normal file
92
BililiveRecorder.Web/DynamicHtmlController.cs
Normal file
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AngleSharp.Html;
|
||||
using AngleSharp.Html.Parser;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using NUglify;
|
||||
|
||||
namespace BililiveRecorder.Web
|
||||
{
|
||||
[Controller]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public sealed class DynamicHtmlController : Controller
|
||||
{
|
||||
private static string? cachedIndexHtml;
|
||||
private readonly CompositeFileProvider fileProvider;
|
||||
|
||||
public DynamicHtmlController(CompositeFileProvider fileProvider)
|
||||
{
|
||||
this.fileProvider = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
|
||||
}
|
||||
|
||||
[Route("/", Name = "Home Page"), HttpGet]
|
||||
public ActionResult GetHomePage()
|
||||
{
|
||||
if (cachedIndexHtml is null)
|
||||
{
|
||||
using var file = this.fileProvider.GetFileInfo("/index.html").CreateReadStream();
|
||||
using var reader = new StreamReader(file, Encoding.UTF8);
|
||||
var html = reader.ReadToEnd();
|
||||
cachedIndexHtml = html
|
||||
.Replace("__VERSION__", GitVersionInformation.FullSemVer)
|
||||
.Replace("__FULL_VERSION__", GitVersionInformation.InformationalVersion)
|
||||
;
|
||||
}
|
||||
|
||||
return this.Content(cachedIndexHtml, "text/html", Encoding.UTF8);
|
||||
}
|
||||
|
||||
[Route("/ui/", Name = "WebUI Html"), HttpGet]
|
||||
public async Task GetWebUIAsync()
|
||||
{
|
||||
var parser = new HtmlParser();
|
||||
var fileInfo = this.fileProvider.GetFileInfo("/ui/index.html");
|
||||
|
||||
using var injectionScriptStream = new StreamReader(this.fileProvider.GetFileInfo(".webui_injection.js").CreateReadStream());
|
||||
var scriptContent = await injectionScriptStream.ReadToEndAsync();
|
||||
|
||||
using var stream = fileInfo.CreateReadStream();
|
||||
using var document = await parser.ParseDocumentAsync(stream).ConfigureAwait(false);
|
||||
|
||||
var spaPath = this.HttpContext.Items.ContainsKey("webui-spa-path") ? ((PathString)this.HttpContext.Items["webui-spa-path"]!) : this.Request.Path;
|
||||
|
||||
spaPath.StartsWithSegments("/ui", out var remaining);
|
||||
|
||||
var head = document.Head!;
|
||||
var template = document.CreateElement("template");
|
||||
template.Id = "delayed-init";
|
||||
head.AppendChild(template);
|
||||
|
||||
var scripts = document.QuerySelectorAll("script[type='module']");
|
||||
var css = document.QuerySelectorAll("link[rel='stylesheet']");
|
||||
|
||||
foreach (var script in scripts)
|
||||
{
|
||||
script.Remove();
|
||||
template.AppendChild(script);
|
||||
}
|
||||
|
||||
foreach (var node in css)
|
||||
{
|
||||
node.Remove();
|
||||
template.AppendChild(node);
|
||||
}
|
||||
|
||||
var initScript = document.CreateElement("script");
|
||||
initScript.TextContent = Uglify.Js(scriptContent).Code;
|
||||
initScript.SetAttribute("data-href", remaining);
|
||||
|
||||
head.AppendChild(initScript);
|
||||
|
||||
this.Response.StatusCode = 200;
|
||||
this.Response.ContentType = "text/html; encoding=utf-8";
|
||||
|
||||
using var writer = new StreamWriter(this.Response.Body);
|
||||
document.ToHtml(writer, new MinifyMarkupFormatter());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
namespace BililiveRecorder.Web
|
||||
{
|
||||
[Controller, Route("/", Name = "Home Page")]
|
||||
[ApiExplorerSettings(IgnoreApi = true)]
|
||||
public sealed class IndexController : Controller
|
||||
{
|
||||
private static string? result;
|
||||
private readonly ManifestEmbeddedFileProvider fileProvider;
|
||||
|
||||
public IndexController(ManifestEmbeddedFileProvider fileProvider)
|
||||
{
|
||||
this.fileProvider = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public ActionResult Get()
|
||||
{
|
||||
if (result is null)
|
||||
{
|
||||
using var file = this.fileProvider.GetFileInfo("/index.html").CreateReadStream();
|
||||
using var reader = new StreamReader(file, Encoding.UTF8);
|
||||
var html = reader.ReadToEnd();
|
||||
result = html
|
||||
.Replace("__VERSION__", GitVersionInformation.FullSemVer)
|
||||
.Replace("__FULL_VERSION__", GitVersionInformation.InformationalVersion)
|
||||
;
|
||||
}
|
||||
|
||||
return this.Content(result, "text/html", Encoding.UTF8);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,7 +74,9 @@ namespace BililiveRecorder.Web
|
|||
;
|
||||
}));
|
||||
|
||||
services.AddSingleton(new ManifestEmbeddedFileProvider(typeof(Startup).Assembly));
|
||||
services
|
||||
.AddSingleton(new ManifestEmbeddedFileProvider(typeof(Startup).Assembly))
|
||||
.AddSingleton(sp => new CompositeFileProvider(sp.GetRequiredService<IWebHostEnvironment>().WebRootFileProvider, sp.GetRequiredService<ManifestEmbeddedFileProvider>()));
|
||||
|
||||
// Graphql API
|
||||
GraphQL.MicrosoftDI.GraphQLBuilderExtensions.AddGraphQL(services)
|
||||
|
@ -152,6 +154,7 @@ namespace BililiveRecorder.Web
|
|||
{
|
||||
if (originalPath.StartsWithSegments("/ui"))
|
||||
{
|
||||
context.Items["webui-spa-path"] = originalPath;
|
||||
context.Request.Path = "/ui/";
|
||||
}
|
||||
else
|
||||
|
@ -193,11 +196,11 @@ namespace BililiveRecorder.Web
|
|||
ctp.Mappings[".mjs"] = "text/javascript; charset=utf-8";
|
||||
ctp.Mappings[".json"] = "application/json; charset=utf-8";
|
||||
|
||||
var manifestEmbeddedFileProvider = app.ApplicationServices.GetRequiredService<ManifestEmbeddedFileProvider>();
|
||||
var compositeFileProvider = app.ApplicationServices.GetRequiredService<CompositeFileProvider>();
|
||||
var sharedStaticFiles = new SharedOptions()
|
||||
{
|
||||
// 在运行的 exe 旁边新建一个 wwwroot 文件夹,会优先使用里面的内容,然后 fallback 到打包的资源文件
|
||||
FileProvider = new CompositeFileProvider(env.WebRootFileProvider, manifestEmbeddedFileProvider),
|
||||
FileProvider = compositeFileProvider,
|
||||
RedirectToAppendTrailingSlash = true,
|
||||
};
|
||||
|
||||
|
|
28
BililiveRecorder.Web/embeded/.webui_injection.js
Normal file
28
BililiveRecorder.Web/embeded/.webui_injection.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
(function () {
|
||||
const currentScript = document.currentScript;
|
||||
if (currentScript && "string" === typeof currentScript.dataset.href) {
|
||||
const SERVER_PATH = currentScript.dataset.href;
|
||||
const baseTag = document.getElementsByTagName('base')[0];
|
||||
console.log("SERVER_PATH: " + SERVER_PATH);
|
||||
const pathname = location.pathname;
|
||||
console.log("location.pathname: " + pathname);
|
||||
if (SERVER_PATH.length === 0) {
|
||||
let BASE = pathname + '/';
|
||||
baseTag.href = BASE;
|
||||
console.log("base path: " + BASE);
|
||||
} else if (pathname.endsWith(SERVER_PATH)) {
|
||||
var i = pathname.lastIndexOf(SERVER_PATH);
|
||||
if (i > -1) {
|
||||
let BASE = pathname.slice(0, i) + '/';
|
||||
baseTag.href = BASE;
|
||||
console.log("base path: " + BASE);
|
||||
}
|
||||
} else {
|
||||
console.log('????');
|
||||
}
|
||||
}
|
||||
const init = document.getElementById('delayed-init');
|
||||
document.head.append(init.content.cloneNode(true));
|
||||
init.remove();
|
||||
currentScript.remove();
|
||||
})()
|
|
@ -1 +1 @@
|
|||
Subproject commit 08eeaf6789ba1e0825c7e5027c2fb8d3c9108207
|
||||
Subproject commit 517c2a659f26f4fea088036650de502aa7f8621f
|
Loading…
Reference in New Issue
Block a user