Separating runtime from application code to improve building. Upgraded mooncore packages. Started switching to flyonui. Added PluginFramework plugin loading via mooncore

This commit is contained in:
2025-07-11 17:13:37 +02:00
parent 7e158d48c6
commit eaece9e334
67 changed files with 448 additions and 234 deletions

View File

@@ -16,14 +16,14 @@ namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys;
[Authorize(Policy = "permissions:admin.system.files")]
public class FilesController : Controller
{
private readonly string BaseDirectory = PathBuilder.Dir("storage");
private readonly string BaseDirectory = "storage";
private readonly long ChunkSize = ByteConverter.FromMegaBytes(20).Bytes;
[HttpGet("list")]
public Task<FileSystemEntryResponse[]> List([FromQuery] string path)
{
var safePath = SanitizePath(path);
var physicalPath = PathBuilder.Dir(BaseDirectory, safePath);
var physicalPath = Path.Combine(BaseDirectory, safePath);
var entries = new List<FileSystemEntryResponse>();
@@ -84,7 +84,7 @@ public class FilesController : Controller
var positionToSkipTo = ChunkSize * chunkId;
var safePath = SanitizePath(path);
var physicalPath = PathBuilder.File(BaseDirectory, safePath);
var physicalPath = Path.Combine(BaseDirectory, safePath);
var baseDir = Path.GetDirectoryName(physicalPath);
if (!string.IsNullOrEmpty(baseDir))
@@ -113,11 +113,11 @@ public class FilesController : Controller
var oldSafePath = SanitizePath(oldPath);
var newSafePath = SanitizePath(newPath);
var oldPhysicalDirPath = PathBuilder.Dir(BaseDirectory, oldSafePath);
var oldPhysicalDirPath = Path.Combine(BaseDirectory, oldSafePath);
if (Directory.Exists(oldPhysicalDirPath))
{
var newPhysicalDirPath = PathBuilder.Dir(BaseDirectory, newSafePath);
var newPhysicalDirPath = Path.Combine(BaseDirectory, newSafePath);
Directory.Move(
oldPhysicalDirPath,
@@ -126,8 +126,8 @@ public class FilesController : Controller
}
else
{
var oldPhysicalFilePath = PathBuilder.File(BaseDirectory, oldSafePath);
var newPhysicalFilePath = PathBuilder.File(BaseDirectory, newSafePath);
var oldPhysicalFilePath = Path.Combine(BaseDirectory, oldSafePath);
var newPhysicalFilePath = Path.Combine(BaseDirectory, newSafePath);
System.IO.File.Move(
oldPhysicalFilePath,
@@ -142,13 +142,13 @@ public class FilesController : Controller
public Task Delete([FromQuery] string path)
{
var safePath = SanitizePath(path);
var physicalDirPath = PathBuilder.Dir(BaseDirectory, safePath);
var physicalDirPath = Path.Combine(BaseDirectory, safePath);
if (Directory.Exists(physicalDirPath))
Directory.Delete(physicalDirPath, true);
else
{
var physicalFilePath = PathBuilder.File(BaseDirectory, safePath);
var physicalFilePath = Path.Combine(BaseDirectory, safePath);
System.IO.File.Delete(physicalFilePath);
}
@@ -160,7 +160,7 @@ public class FilesController : Controller
public Task CreateDirectory([FromQuery] string path)
{
var safePath = SanitizePath(path);
var physicalPath = PathBuilder.Dir(BaseDirectory, safePath);
var physicalPath = Path.Combine(BaseDirectory, safePath);
Directory.CreateDirectory(physicalPath);
return Task.CompletedTask;
@@ -170,7 +170,7 @@ public class FilesController : Controller
public async Task Download([FromQuery] string path)
{
var safePath = SanitizePath(path);
var physicalPath = PathBuilder.File(BaseDirectory, safePath);
var physicalPath = Path.Combine(BaseDirectory, safePath);
await using var fs = System.IO.File.Open(physicalPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
await fs.CopyToAsync(Response.Body);
@@ -192,7 +192,7 @@ public class FilesController : Controller
private async Task CompressTarGz(string path, string[] itemsToCompress)
{
var safePath = SanitizePath(path);
var destination = PathBuilder.File(BaseDirectory, safePath);
var destination = Path.Combine(BaseDirectory, safePath);
await using var outStream = System.IO.File.Create(destination);
await using var gzoStream = new GZipOutputStream(outStream);
@@ -201,7 +201,7 @@ public class FilesController : Controller
foreach (var itemName in itemsToCompress)
{
var safeFilePath = SanitizePath(itemName);
var filePath = PathBuilder.File(BaseDirectory, safeFilePath);
var filePath = Path.Combine(BaseDirectory, safeFilePath);
var fi = new FileInfo(filePath);
@@ -210,7 +210,7 @@ public class FilesController : Controller
else
{
var safeDirePath = SanitizePath(itemName);
var dirPath = PathBuilder.Dir(BaseDirectory, safeDirePath);
var dirPath = Path.Combine(BaseDirectory, safeDirePath);
await AddDirectoryToTarGz(tarStream, dirPath);
}
@@ -267,7 +267,7 @@ public class FilesController : Controller
private async Task CompressZip(string path, string[] itemsToCompress)
{
var safePath = SanitizePath(path);
var destination = PathBuilder.File(BaseDirectory, safePath);
var destination = Path.Combine(BaseDirectory, safePath);
await using var outStream = System.IO.File.Create(destination);
await using var zipOutputStream = new ZipOutputStream(outStream);
@@ -275,7 +275,7 @@ public class FilesController : Controller
foreach (var itemName in itemsToCompress)
{
var safeFilePath = SanitizePath(itemName);
var filePath = PathBuilder.File(BaseDirectory, safeFilePath);
var filePath = Path.Combine(BaseDirectory, safeFilePath);
var fi = new FileInfo(filePath);
@@ -284,7 +284,7 @@ public class FilesController : Controller
else
{
var safeDirePath = SanitizePath(itemName);
var dirPath = PathBuilder.Dir(BaseDirectory, safeDirePath);
var dirPath = Path.Combine(BaseDirectory, safeDirePath);
await AddDirectoryToZip(zipOutputStream, dirPath);
}
@@ -350,7 +350,7 @@ public class FilesController : Controller
var safeDestination = SanitizePath(destination);
var safeArchivePath = SanitizePath(path);
var archivePath = PathBuilder.File(BaseDirectory, safeArchivePath);
var archivePath = Path.Combine(BaseDirectory, safeArchivePath);
await using var fs = System.IO.File.Open(archivePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
await using var gzipInputStream = new GZipInputStream(fs);
@@ -364,7 +364,7 @@ public class FilesController : Controller
break;
var safeFilePath = SanitizePath(entry.Name);
var fileDestination = PathBuilder.File(BaseDirectory, safeDestination, safeFilePath);
var fileDestination = Path.Combine(BaseDirectory, safeDestination, safeFilePath);
var parentFolder = Path.GetDirectoryName(fileDestination);
// Ensure parent directory exists, if it's not the base directory
@@ -393,7 +393,7 @@ public class FilesController : Controller
var safeDestination = SanitizePath(destination);
var safeArchivePath = SanitizePath(path);
var archivePath = PathBuilder.File(BaseDirectory, safeArchivePath);
var archivePath = Path.Combine(BaseDirectory, safeArchivePath);
await using var fs = System.IO.File.Open(archivePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
await using var zipInputStream = new ZipInputStream(fs);
@@ -409,7 +409,7 @@ public class FilesController : Controller
continue;
var safeFilePath = SanitizePath(entry.Name);
var fileDestination = PathBuilder.File(BaseDirectory, safeDestination, safeFilePath);
var fileDestination = Path.Combine(BaseDirectory, safeDestination, safeFilePath);
var parentFolder = Path.GetDirectoryName(fileDestination);
// Ensure parent directory exists, if it's not the base directory

View File

@@ -14,7 +14,7 @@ public class ThemeController : Controller
[Authorize(Policy = "permissions:admin.system.theme.update")]
public async Task Patch([FromBody] UpdateThemeRequest request)
{
var themePath = PathBuilder.File("storage", "theme.json");
var themePath = Path.Combine("storage", "theme.json");
await System.IO.File.WriteAllTextAsync(
themePath,

View File

@@ -1,14 +1,12 @@
using System.Text.Json;
using System.Text;
using Microsoft.AspNetCore.Mvc;
using MoonCore.Exceptions;
using MoonCore.Helpers;
using Moonlight.ApiServer.Configuration;
using Moonlight.ApiServer.Services;
using Moonlight.Shared.Misc;
namespace Moonlight.ApiServer.Http.Controllers;
namespace Moonlight.ApiServer.Http.Controllers.Frontend;
[ApiController]
[Route("/")]
public class FrontendController : Controller
{
private readonly FrontendService FrontendService;
@@ -21,4 +19,12 @@ public class FrontendController : Controller
[HttpGet("frontend.json")]
public async Task<FrontendConfiguration> GetConfiguration()
=> await FrontendService.GetConfiguration();
[HttpGet]
public async Task<IResult> Index()
{
var content = await FrontendService.GenerateIndexHtml();
return Results.Text(content, "text/html", Encoding.UTF8);
}
}

View File

@@ -0,0 +1,51 @@
@using Moonlight.Shared.Misc
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@Configuration.Title</title>
<base href="/" />
@foreach (var style in Configuration.Styles)
{
<link rel="stylesheet" href="@style" />
}
<link href="manifest.webmanifest" rel="manifest" />
<link rel="apple-touch-icon" sizes="512x512" href="/img/icon-512.png" />
<link rel="apple-touch-icon" sizes="192x192" href="/img/icon-192.png" />
</head>
<body class="bg-gray-950 text-white font-inter h-full">
<div id="app">
<div class="flex h-screen justify-center items-center">
<div class="sm:max-w-lg">
<div id="blazor-loader-label" class="text-center mb-2 text-lg font-semibold"></div>
<div class="flex flex-col gap-1">
<div class="progress min-w-sm md:min-w-md" role="progressbar">
<div id="blazor-loader-progress" class="progress-bar"></div>
</div>
</div>
</div>
</div>
</div>
@foreach (var script in Configuration.Scripts)
{
<script src="@script"></script>
}
<script src="/_framework/blazor.webassembly.js"></script>
<script>navigator.serviceWorker.register('service-worker.js');</script>
</body>
</html>
@code
{
[Parameter] public FrontendConfiguration Configuration { get; set; }
}

View File

@@ -2,13 +2,11 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MoonCore.Helpers;
using MoonCore.Services;
using Moonlight.ApiServer.Configuration;
using Moonlight.ApiServer.Models;
namespace Moonlight.ApiServer.Http.Controllers.Swagger;
[AllowAnonymous]
[Route("api/swagger")]
public class SwaggerController : Controller
{