Separating runtime from application code to improve building. Upgraded mooncore packages. Started switching to flyonui. Added PluginFramework plugin loading via mooncore
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoDefaultLaunchSettingsFile>True</NoDefaultLaunchSettingsFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Moonlight.ApiServer\Moonlight.ApiServer.csproj" />
|
||||
<ProjectReference Include="..\Moonlight.Client.Runtime\Moonlight.Client.Runtime.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
|
||||
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.7" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
10
Moonlight.ApiServer.Runtime/PluginLoader.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using MoonCore.PluginFramework;
|
||||
using Moonlight.ApiServer.Plugins;
|
||||
|
||||
namespace Moonlight.ApiServer.Runtime;
|
||||
|
||||
[PluginLoader]
|
||||
public partial class PluginLoader : IPluginStartup
|
||||
{
|
||||
|
||||
}
|
||||
9
Moonlight.ApiServer.Runtime/Program.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Moonlight.ApiServer;
|
||||
using Moonlight.ApiServer.Runtime;
|
||||
|
||||
var startup = new Startup();
|
||||
|
||||
var pluginLoader = new PluginLoader();
|
||||
pluginLoader.Initialize();
|
||||
|
||||
await startup.Run(args, pluginLoader.Instances);
|
||||
29
Moonlight.ApiServer.Runtime/Properties/launchSettings.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5165",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"HTTP_PROXY": "",
|
||||
"HTTPS_PROXY": ""
|
||||
},
|
||||
"hotReloadEnabled": true
|
||||
},
|
||||
"WASM Debug": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:5165",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"HTTP_PROXY": "",
|
||||
"HTTPS_PROXY": ""
|
||||
},
|
||||
"hotReloadEnabled": true,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using Moonlight.ApiServer.Database;
|
||||
using Moonlight.ApiServer.Implementations.Diagnose;
|
||||
using Moonlight.ApiServer.Implementations.Metrics;
|
||||
using Moonlight.ApiServer.Interfaces;
|
||||
using Moonlight.ApiServer.Models;
|
||||
using Moonlight.ApiServer.Plugins;
|
||||
using Moonlight.ApiServer.Services;
|
||||
using OpenTelemetry.Metrics;
|
||||
@@ -11,7 +12,6 @@ using OpenTelemetry.Trace;
|
||||
|
||||
namespace Moonlight.ApiServer.Implementations.Startup;
|
||||
|
||||
[PluginStartup]
|
||||
public class CoreStartup : IPluginStartup
|
||||
{
|
||||
public Task BuildApplication(IServiceProvider serviceProvider, IHostApplicationBuilder builder)
|
||||
@@ -81,6 +81,23 @@ public class CoreStartup : IPluginStartup
|
||||
|
||||
#endregion
|
||||
|
||||
#region Client / Frontend
|
||||
|
||||
if (configuration.Client.Enable)
|
||||
{
|
||||
builder.Services.AddSingleton(new FrontendConfigurationOption()
|
||||
{
|
||||
Scripts =
|
||||
[
|
||||
"/_content/Moonlight.Client/js/moonlight.js", "/_content/Moonlight.Client/js/moonCore.js",
|
||||
"/_content/Moonlight.Client/ace/ace.js"
|
||||
],
|
||||
Styles = ["/css/style.min.css"]
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -90,7 +107,7 @@ public class CoreStartup : IPluginStartup
|
||||
|
||||
#region Prometheus
|
||||
|
||||
if(configuration.Metrics.Enable)
|
||||
if (configuration.Metrics.Enable)
|
||||
app.UseOpenTelemetryPrometheusScrapingEndpoint();
|
||||
|
||||
#endregion
|
||||
|
||||
62
Moonlight.ApiServer/Implementations/UserAuthInvalidation.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.Security.Claims;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MoonCore.Extended.Abstractions;
|
||||
using MoonCore.Extended.JwtInvalidation;
|
||||
using Moonlight.ApiServer.Database.Entities;
|
||||
|
||||
namespace Moonlight.ApiServer.Implementations;
|
||||
|
||||
public class UserAuthInvalidation : IJwtInvalidateHandler
|
||||
{
|
||||
private readonly DatabaseRepository<User> UserRepository;
|
||||
private readonly DatabaseRepository<ApiKey> ApiKeyRepository;
|
||||
|
||||
public UserAuthInvalidation(
|
||||
DatabaseRepository<User> userRepository,
|
||||
DatabaseRepository<ApiKey> apiKeyRepository
|
||||
)
|
||||
{
|
||||
UserRepository = userRepository;
|
||||
ApiKeyRepository = apiKeyRepository;
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(ClaimsPrincipal principal)
|
||||
{
|
||||
var userIdClaim = principal.FindFirstValue("userId");
|
||||
|
||||
if (!string.IsNullOrEmpty(userIdClaim))
|
||||
{
|
||||
var userId = int.Parse(userIdClaim);
|
||||
|
||||
var user = await UserRepository
|
||||
.Get()
|
||||
.FirstOrDefaultAsync(x => x.Id == userId);
|
||||
|
||||
if (user == null)
|
||||
return true; // User is deleted, invalidate session
|
||||
|
||||
var iatStr = principal.FindFirstValue("iat")!;
|
||||
var iat = DateTimeOffset.FromUnixTimeSeconds(long.Parse(iatStr));
|
||||
|
||||
// If the token has been issued before the token valid time, its expired, and we want to invalidate it
|
||||
return user.TokenValidTimestamp > iat;
|
||||
}
|
||||
|
||||
var apiKeyIdClaim = principal.FindFirstValue("apiKeyId");
|
||||
|
||||
if (!string.IsNullOrEmpty(apiKeyIdClaim))
|
||||
{
|
||||
var apiKeyId = int.Parse(apiKeyIdClaim);
|
||||
|
||||
var apiKey = await ApiKeyRepository
|
||||
.Get()
|
||||
.FirstOrDefaultAsync(x => x.Id == apiKeyId);
|
||||
|
||||
// If the api key exists, we don't want to invalidate the request.
|
||||
// If it doesn't exist we want to invalidate the request
|
||||
return apiKey == null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Moonlight.Client\Moonlight.Client.csproj" />
|
||||
<ProjectReference Include="..\Moonlight.Shared\Moonlight.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -30,13 +29,14 @@
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.18" />
|
||||
<PackageReference Include="Hangfire.Core" Version="1.8.18" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
||||
<PackageReference Include="Hangfire.Core" Version="1.8.20" />
|
||||
<PackageReference Include="Hangfire.EntityFrameworkCore" Version="0.7.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5" />
|
||||
<PackageReference Include="MoonCore" Version="1.8.8" />
|
||||
<PackageReference Include="MoonCore.Extended" Version="1.3.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.7" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
|
||||
<PackageReference Include="MoonCore" Version="1.9.1" />
|
||||
<PackageReference Include="MoonCore.Extended" Version="1.3.5" />
|
||||
<PackageReference Include="MoonCore.PluginFramework.Generator" Version="1.0.1" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.12.0-beta.1" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.12.0" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.12.0" />
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Moonlight.ApiServer.Plugins;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class PluginStartupAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using MoonCore.Attributes;
|
||||
using MoonCore.Exceptions;
|
||||
using MoonCore.Helpers;
|
||||
using Moonlight.ApiServer.Configuration;
|
||||
using Moonlight.ApiServer.Http.Controllers.Frontend;
|
||||
using Moonlight.ApiServer.Models;
|
||||
using Moonlight.Shared.Misc;
|
||||
|
||||
@@ -17,23 +18,26 @@ public class FrontendService
|
||||
private readonly AppConfiguration Configuration;
|
||||
private readonly IWebHostEnvironment WebHostEnvironment;
|
||||
private readonly IEnumerable<FrontendConfigurationOption> ConfigurationOptions;
|
||||
private readonly IServiceProvider ServiceProvider;
|
||||
|
||||
public FrontendService(
|
||||
AppConfiguration configuration,
|
||||
IWebHostEnvironment webHostEnvironment,
|
||||
IEnumerable<FrontendConfigurationOption> configurationOptions
|
||||
IEnumerable<FrontendConfigurationOption> configurationOptions,
|
||||
IServiceProvider serviceProvider
|
||||
)
|
||||
{
|
||||
Configuration = configuration;
|
||||
WebHostEnvironment = webHostEnvironment;
|
||||
ConfigurationOptions = configurationOptions;
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task<FrontendConfiguration> GetConfiguration()
|
||||
{
|
||||
var configuration = new FrontendConfiguration()
|
||||
{
|
||||
Title = "Moonlight",
|
||||
Title = "Moonlight", // TODO: CONFIG
|
||||
ApiUrl = Configuration.PublicUrl,
|
||||
HostEnvironment = "ApiServer"
|
||||
};
|
||||
@@ -62,7 +66,20 @@ public class FrontendService
|
||||
return configuration;
|
||||
}
|
||||
|
||||
public async Task<Stream> GenerateZip()
|
||||
public async Task<string> GenerateIndexHtml() // TODO: Cache
|
||||
{
|
||||
var configuration = await GetConfiguration();
|
||||
|
||||
return await ComponentHelper.RenderComponent<FrontendPage>(
|
||||
ServiceProvider,
|
||||
parameters =>
|
||||
{
|
||||
parameters["Configuration"] = configuration;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<Stream> GenerateZip() // TODO: Rework to be able to extract everything successfully
|
||||
{
|
||||
// We only allow the access to this function when we are actually hosting the frontend
|
||||
if (!Configuration.Client.Enable)
|
||||
|
||||
@@ -12,6 +12,7 @@ using MoonCore.Extended.Helpers;
|
||||
using MoonCore.Extended.JwtInvalidation;
|
||||
using MoonCore.Extensions;
|
||||
using MoonCore.Helpers;
|
||||
using MoonCore.Logging;
|
||||
using MoonCore.Permissions;
|
||||
using Moonlight.ApiServer.Configuration;
|
||||
using Moonlight.ApiServer.Database;
|
||||
@@ -111,8 +112,7 @@ public class Startup
|
||||
private Task CreateStorage()
|
||||
{
|
||||
Directory.CreateDirectory("storage");
|
||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "logs"));
|
||||
Directory.CreateDirectory(PathBuilder.Dir("storage", "plugins"));
|
||||
Directory.CreateDirectory(Path.Combine("storage", "logs"));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -142,7 +142,7 @@ public class Startup
|
||||
private Task UseBase()
|
||||
{
|
||||
WebApplication.UseRouting();
|
||||
WebApplication.UseApiExceptionHandler();
|
||||
WebApplication.UseExceptionHandler();
|
||||
|
||||
if (Configuration.Client.Enable)
|
||||
{
|
||||
@@ -161,7 +161,7 @@ public class Startup
|
||||
WebApplication.MapControllers();
|
||||
|
||||
if (Configuration.Client.Enable)
|
||||
WebApplication.MapFallbackToFile("index.html");
|
||||
WebApplication.MapFallbackToController("Index", "Frontend");
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ public class Startup
|
||||
serviceCollection.AddLogging(builder =>
|
||||
{
|
||||
builder.ClearProviders();
|
||||
builder.AddProviders(LoggerProviders);
|
||||
builder.AddAnsiConsole();
|
||||
});
|
||||
|
||||
PluginLoadServiceProvider = serviceCollection.BuildServiceProvider();
|
||||
@@ -202,8 +202,6 @@ public class Startup
|
||||
// Collect startups
|
||||
var pluginStartups = new List<IPluginStartup>();
|
||||
|
||||
pluginStartups.Add(new CoreStartup());
|
||||
|
||||
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
||||
|
||||
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
||||
@@ -291,7 +289,7 @@ public class Startup
|
||||
var configurationBuilder = new ConfigurationBuilder();
|
||||
|
||||
// Ensure configuration file exists
|
||||
var jsonFilePath = PathBuilder.File(Directory.GetCurrentDirectory(), "storage", "app.json");
|
||||
var jsonFilePath = Path.Combine(Directory.GetCurrentDirectory(), "storage", "app.json");
|
||||
|
||||
if (!File.Exists(jsonFilePath))
|
||||
await File.WriteAllTextAsync(jsonFilePath, JsonSerializer.Serialize(new AppConfiguration()));
|
||||
@@ -336,18 +334,8 @@ public class Startup
|
||||
|
||||
private Task SetupLogging()
|
||||
{
|
||||
LoggerProviders = LoggerBuildHelper.BuildFromConfiguration(configuration =>
|
||||
{
|
||||
configuration.Console.Enable = true;
|
||||
configuration.Console.EnableAnsiMode = true;
|
||||
configuration.FileLogging.Enable = true;
|
||||
configuration.FileLogging.Path = PathBuilder.File("storage", "logs", "latest.log");
|
||||
configuration.FileLogging.EnableLogRotation = true;
|
||||
configuration.FileLogging.RotateLogNameTemplate = PathBuilder.File("storage", "logs", "apiserver.{0}.log");
|
||||
});
|
||||
|
||||
LoggerFactory = new LoggerFactory();
|
||||
LoggerFactory.AddProviders(LoggerProviders);
|
||||
LoggerFactory.AddAnsiConsole();
|
||||
|
||||
Logger = LoggerFactory.CreateLogger<Startup>();
|
||||
|
||||
@@ -358,30 +346,33 @@ public class Startup
|
||||
{
|
||||
// Configure application logging
|
||||
WebApplicationBuilder.Logging.ClearProviders();
|
||||
WebApplicationBuilder.Logging.AddProviders(LoggerProviders);
|
||||
WebApplicationBuilder.Logging.AddAnsiConsole();
|
||||
WebApplicationBuilder.Logging.AddFile(Path.Combine("storage", "logs", "moonlight.log"));
|
||||
|
||||
// Logging levels
|
||||
var logConfigPath = PathBuilder.File("storage", "logConfig.json");
|
||||
var logConfigPath = Path.Combine("storage", "logConfig.json");
|
||||
|
||||
// Ensure logging config, add a default one is missing
|
||||
if (!File.Exists(logConfigPath))
|
||||
{
|
||||
var logLevels = new Dictionary<string, string>
|
||||
var defaultLogLevels = new Dictionary<string, string>
|
||||
{
|
||||
{ "Default", "Information" },
|
||||
{ "Microsoft.AspNetCore", "Warning" },
|
||||
{ "System.Net.Http.HttpClient", "Warning" }
|
||||
};
|
||||
|
||||
var logLevelsJson = JsonSerializer.Serialize(logLevels);
|
||||
var logConfig = "{\"LogLevel\":" + logLevelsJson + "}";
|
||||
await File.WriteAllTextAsync(logConfigPath, logConfig);
|
||||
var logLevelsJson = JsonSerializer.Serialize(defaultLogLevels);
|
||||
await File.WriteAllTextAsync(logConfigPath, logLevelsJson);
|
||||
}
|
||||
|
||||
// Add logging configuration
|
||||
WebApplicationBuilder.Logging.AddConfiguration(
|
||||
var logLevels = JsonSerializer.Deserialize<Dictionary<string, string>>(
|
||||
await File.ReadAllTextAsync(logConfigPath)
|
||||
);
|
||||
)!;
|
||||
|
||||
foreach (var level in logLevels)
|
||||
WebApplicationBuilder.Logging.AddFilter(level.Key, Enum.Parse<LogLevel>(level.Value));
|
||||
|
||||
// Mute exception handler middleware
|
||||
// https://github.com/dotnet/aspnetcore/issues/19740
|
||||
@@ -406,7 +397,6 @@ public class Startup
|
||||
WebApplicationBuilder.Services.AddServiceCollectionAccessor();
|
||||
|
||||
WebApplicationBuilder.Services.AddScoped(typeof(DatabaseRepository<>));
|
||||
WebApplicationBuilder.Services.AddScoped(typeof(CrudHelper<,>));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -443,42 +433,8 @@ public class Startup
|
||||
};
|
||||
});
|
||||
|
||||
WebApplicationBuilder.Services.AddJwtInvalidation("coreAuthentication", options =>
|
||||
{
|
||||
options.InvalidateTimeProvider = async (provider, principal) =>
|
||||
{
|
||||
var userIdClaim = principal.Claims.FirstOrDefault(x => x.Type == "userId");
|
||||
|
||||
if (userIdClaim != null)
|
||||
{
|
||||
var userId = int.Parse(userIdClaim.Value);
|
||||
|
||||
var userRepository = provider.GetRequiredService<DatabaseRepository<User>>();
|
||||
var user = await userRepository.Get().FirstOrDefaultAsync(x => x.Id == userId);
|
||||
|
||||
if (user == null)
|
||||
return DateTime.MaxValue;
|
||||
|
||||
return user.TokenValidTimestamp;
|
||||
}
|
||||
|
||||
var apiKeyIdClaim = principal.Claims.FirstOrDefault(x => x.Type == "apiKeyId");
|
||||
|
||||
if (apiKeyIdClaim != null)
|
||||
{
|
||||
var apiKeyId = int.Parse(apiKeyIdClaim.Value);
|
||||
|
||||
var apiKeyRepository = provider.GetRequiredService<DatabaseRepository<ApiKey>>();
|
||||
var apiKey = await apiKeyRepository.Get().FirstOrDefaultAsync(x => x.Id == apiKeyId);
|
||||
|
||||
// If the api key exists, we don't want to invalidate the request.
|
||||
// If it doesn't exist we want to invalidate the request
|
||||
return apiKey == null ? DateTime.MaxValue : DateTime.MinValue;
|
||||
}
|
||||
|
||||
return DateTime.MaxValue;
|
||||
};
|
||||
});
|
||||
WebApplicationBuilder.Services.AddJwtBearerInvalidation("coreAuthentication");
|
||||
WebApplicationBuilder.Services.AddScoped<IJwtInvalidateHandler, UserAuthInvalidation>();
|
||||
|
||||
WebApplicationBuilder.Services.AddAuthorization();
|
||||
|
||||
@@ -499,8 +455,6 @@ public class Startup
|
||||
{
|
||||
WebApplication.UseAuthentication();
|
||||
|
||||
WebApplication.UseJwtInvalidation();
|
||||
|
||||
WebApplication.UseAuthorization();
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
||||
64
Moonlight.Client.Runtime/Moonlight.Client.Runtime.csproj
Normal file
@@ -0,0 +1,64 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoDefaultLaunchSettingsFile>True</NoDefaultLaunchSettingsFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Moonlight.Client\Moonlight.Client.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.7"/>
|
||||
<PackageReference Include="MoonCore.PluginFramework.Generator" Version="1.0.1"/>
|
||||
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.5" PrivateAssets="all"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Styles\exports.css">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>styles</PackagePath>
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Styles\package-lock.json">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>styles</PackagePath>
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="Styles\package.json">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>styles</PackagePath>
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Styles\preTailwind.css">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>styles</PackagePath>
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Styles\resolveNuget.js">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>styles</PackagePath>
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Styles\style.css">
|
||||
<Pack>true</Pack>
|
||||
<PackagePath>styles</PackagePath>
|
||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="wwwroot\css\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<_ContentIncludedByDefault Remove="wwwroot\js\moonCore.js" />
|
||||
<_ContentIncludedByDefault Remove="wwwroot\js\moonlight.js" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
10
Moonlight.Client.Runtime/PluginLoader.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using MoonCore.PluginFramework;
|
||||
using Moonlight.Client.Plugins;
|
||||
|
||||
namespace Moonlight.Client.Runtime;
|
||||
|
||||
[PluginLoader]
|
||||
public partial class PluginLoader : IPluginStartup
|
||||
{
|
||||
|
||||
}
|
||||
9
Moonlight.Client.Runtime/Program.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using Moonlight.Client;
|
||||
using Moonlight.Client.Runtime;
|
||||
|
||||
var startup = new Startup();
|
||||
|
||||
var pluginLoader = new PluginLoader();
|
||||
pluginLoader.Initialize();
|
||||
|
||||
await startup.Run(args, pluginLoader.Instances);
|
||||
14
Moonlight.Client.Runtime/Properties/launchSettings.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
|
||||
"applicationUrl": "http://localhost:5165",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=fallback') layer;
|
||||
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap') layer;
|
||||
@import url("https://cdn.jsdelivr.net/npm/lucide-static/font/lucide.css") layer;
|
||||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=fallback') layer(base);
|
||||
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap') layer(base);
|
||||
@import url("https://cdn.jsdelivr.net/npm/lucide-static/font/lucide.css") layer(base);
|
||||
|
||||
@theme {
|
||||
--font-inter: "Inter", var(--font-sans);
|
||||
0
Moonlight.Client/Styles/mappings/mooncore.map → Moonlight.Client.Runtime/Styles/mappings/mooncore.map
Executable file → Normal file
@@ -6,9 +6,9 @@
|
||||
"xml2js": "^0.6.2"
|
||||
},
|
||||
"scripts": {
|
||||
"pretailwind-build": "node resolveNuget.js ../Moonlight.Client.csproj",
|
||||
"pretailwind-build": "node resolveNuget.js ../Moonlight.Client.Runtime.csproj",
|
||||
"tailwind-build": "npx tailwindcss -i style.css -o ../wwwroot/css/style.min.css",
|
||||
"pretailwind": "node resolveNuget.js ../Moonlight.Client.csproj",
|
||||
"pretailwind": "node resolveNuget.js ../Moonlight.Client.Runtime.csproj",
|
||||
"tailwind": "npx tailwindcss -i style.css -o ../wwwroot/css/style.min.css --watch"
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,9 @@
|
||||
@source "../**/*.razor";
|
||||
@source "../**/*.cs";
|
||||
@source "../**/*.html";
|
||||
|
||||
@source "../../Moonlight.Client/**/*.razor";
|
||||
@source "../../Moonlight.Client/**/*.cs";
|
||||
@source "../../Moonlight.Client/**/*.html";
|
||||
|
||||
@source "./mappings/*.map";
|
||||
BIN
Moonlight.Client.Runtime/wwwroot/img/icon-192.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
Moonlight.Client.Runtime/wwwroot/img/icon-512.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
Moonlight.Client.Runtime/wwwroot/img/pfp_placeholder.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
6
Moonlight.Client/GlobalUsings.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
// Global using directives
|
||||
|
||||
global using Microsoft.AspNetCore.Components.Web;
|
||||
global using Microsoft.JSInterop;
|
||||
global using Microsoft.Extensions.Logging;
|
||||
global using MoonCore.Blazor.FlyonUi.Components;
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moonlight.Client.Interfaces;
|
||||
using Moonlight.Client.Plugins;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using MoonCore.Blazor.Services;
|
||||
using MoonCore.Blazor.Tailwind.Fm;
|
||||
using MoonCore.Blazor.Tailwind.Fm.Models;
|
||||
using MoonCore.Blazor.Tailwind.Services;
|
||||
using MoonCore.Helpers;
|
||||
using Moonlight.Shared.Http.Requests.Admin.Sys.Files;
|
||||
using Moonlight.Shared.Http.Responses.Admin.Sys;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
@@ -22,11 +22,9 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Blazor-ApexCharts" Version="6.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.5" PrivateAssets="all" />
|
||||
<PackageReference Include="MoonCore" Version="1.8.8" />
|
||||
<PackageReference Include="MoonCore.Blazor" Version="1.3.0" />
|
||||
<PackageReference Include="MoonCore.Blazor.Tailwind" Version="1.4.7" />
|
||||
<PackageReference Include="MoonCore" Version="1.9.1" />
|
||||
<PackageReference Include="MoonCore.Blazor" Version="1.3.1" />
|
||||
<PackageReference Include="MoonCore.Blazor.FlyonUi" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="**\*.cs" Exclude="storage\**\*;bin\**\*;obj\**\*">
|
||||
@@ -56,4 +54,10 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Moonlight.Shared\Moonlight.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Styles\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<_ContentIncludedByDefault Remove="wwwroot\css\style.min.css" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,7 +0,0 @@
|
||||
namespace Moonlight.Client.Plugins;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class PluginStartupAttribute : Attribute
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
using Moonlight.Client;
|
||||
|
||||
var startup = new Startup();
|
||||
|
||||
try
|
||||
{
|
||||
await startup.Run(args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
using System.Web;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using MoonCore.Blazor.FlyonUi.Auth;
|
||||
using MoonCore.Blazor.Services;
|
||||
using MoonCore.Blazor.Tailwind.Auth;
|
||||
using MoonCore.Exceptions;
|
||||
using MoonCore.Helpers;
|
||||
using Moonlight.Shared.Http.Requests.Auth;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
namespace Moonlight.Client.Services;
|
||||
|
||||
public class WindowService
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.JSInterop;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MoonCore.Blazor.FlyonUi;
|
||||
using MoonCore.Blazor.FlyonUi.Auth;
|
||||
using MoonCore.Blazor.Services;
|
||||
using MoonCore.Blazor.Tailwind.Extensions;
|
||||
using MoonCore.Blazor.Tailwind.Auth;
|
||||
using MoonCore.Extensions;
|
||||
using MoonCore.Helpers;
|
||||
using MoonCore.Logging;
|
||||
using MoonCore.Permissions;
|
||||
using Moonlight.Client.Implementations;
|
||||
using Moonlight.Client.Interfaces;
|
||||
using Moonlight.Client.Plugins;
|
||||
using Moonlight.Client.Services;
|
||||
using Moonlight.Shared.Misc;
|
||||
using Moonlight.Client.UI;
|
||||
using WindowService = Moonlight.Client.Services.WindowService;
|
||||
|
||||
namespace Moonlight.Client;
|
||||
|
||||
@@ -27,7 +24,6 @@ public class Startup
|
||||
private FrontendConfiguration Configuration;
|
||||
|
||||
// Logging
|
||||
private ILoggerProvider[] LoggerProviders;
|
||||
private ILoggerFactory LoggerFactory;
|
||||
private ILogger<Startup> Logger;
|
||||
|
||||
@@ -143,12 +139,13 @@ public class Startup
|
||||
});
|
||||
|
||||
WebAssemblyHostBuilder.Services.AddScoped<WindowService>();
|
||||
WebAssemblyHostBuilder.Services.AddMoonCoreBlazorTailwind();
|
||||
WebAssemblyHostBuilder.Services.AddFileManagerOperations();
|
||||
WebAssemblyHostBuilder.Services.AddFlyonUiServices();
|
||||
WebAssemblyHostBuilder.Services.AddScoped<LocalStorageService>();
|
||||
|
||||
WebAssemblyHostBuilder.Services.AddScoped<ThemeService>();
|
||||
|
||||
WebAssemblyHostBuilder.Services.AutoAddServices<Program>();
|
||||
WebAssemblyHostBuilder.Services.AutoAddServices<Startup>();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -179,7 +176,7 @@ public class Startup
|
||||
startupSc.AddLogging(builder =>
|
||||
{
|
||||
builder.ClearProviders();
|
||||
builder.AddProviders(LoggerProviders);
|
||||
builder.AddAnsiConsole();
|
||||
});
|
||||
|
||||
PluginLoadServiceProvider = startupSc.BuildServiceProvider();
|
||||
@@ -187,8 +184,6 @@ public class Startup
|
||||
// Collect startups
|
||||
var pluginStartups = new List<IPluginStartup>();
|
||||
|
||||
pluginStartups.Add(new CoreStartup());
|
||||
|
||||
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
||||
|
||||
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
||||
@@ -259,15 +254,8 @@ public class Startup
|
||||
|
||||
private Task SetupLogging()
|
||||
{
|
||||
LoggerProviders = LoggerBuildHelper.BuildFromConfiguration(configuration =>
|
||||
{
|
||||
configuration.Console.Enable = true;
|
||||
configuration.Console.EnableAnsiMode = true;
|
||||
configuration.FileLogging.Enable = false;
|
||||
});
|
||||
|
||||
LoggerFactory = new LoggerFactory();
|
||||
LoggerFactory.AddProviders(LoggerProviders);
|
||||
LoggerFactory.AddAnsiConsole();
|
||||
|
||||
Logger = LoggerFactory.CreateLogger<Startup>();
|
||||
|
||||
@@ -277,7 +265,7 @@ public class Startup
|
||||
private Task RegisterLogging()
|
||||
{
|
||||
WebAssemblyHostBuilder.Logging.ClearProviders();
|
||||
WebAssemblyHostBuilder.Logging.AddProviders(LoggerProviders);
|
||||
WebAssemblyHostBuilder.Logging.AddAnsiConsole();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<ModalLauncher/>
|
||||
|
||||
<div id="blazor-error-ui" class="fixed bottom-0 left-0 w-full z-50">
|
||||
<div class="bg-danger-600 text-white p-4 flex flex-row justify-between items-center">
|
||||
<div class="bg-error text-white p-4 flex flex-row justify-between items-center">
|
||||
<div class="flex items-center">
|
||||
<i class="icon-bomb text-lg text-white me-2"></i>
|
||||
<span>An unhandled error has occurred.</span>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
@using System.Security.Claims
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using MoonCore.Blazor.Tailwind.Auth
|
||||
@using MoonCore.Blazor.FlyonUi.Auth
|
||||
@using Moonlight.Client.Interfaces
|
||||
@using Moonlight.Client.Models
|
||||
@using Moonlight.Client.UI.Layouts
|
||||
|
||||
@inject ToastService ToastService
|
||||
@inject NavigationManager Navigation
|
||||
@inject AuthenticationStateManager AuthStateManager
|
||||
@inject IEnumerable<ISidebarItemProvider> SidebarItemProviders
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
@inject FrontendConfiguration FrontendConfiguration
|
||||
@inject ThemeService ThemeService
|
||||
@inject ToastService ToastService
|
||||
@inject DownloadService DownloadService
|
||||
|
||||
@* @inject DownloadService DownloadService *@
|
||||
|
||||
<div class="card card-body p-2">
|
||||
<div class="flex flex-row items-center justify-end gap-x-2">
|
||||
@@ -108,7 +109,7 @@
|
||||
AddSetting("danger", "danger-300", 252, 165, 165);
|
||||
AddSetting("danger", "danger-400", 248, 113, 113);
|
||||
AddSetting("danger", "danger", 239, 68, 68);
|
||||
AddSetting("danger", "danger-600", 220, 38, 38);
|
||||
AddSetting("danger", "error", 220, 38, 38);
|
||||
AddSetting("danger", "danger-700", 185, 28, 28);
|
||||
AddSetting("danger", "danger-800", 153, 27, 27);
|
||||
AddSetting("danger", "danger-900", 127, 29, 29);
|
||||
@@ -192,7 +193,7 @@
|
||||
{
|
||||
if (FrontendConfiguration.HostEnvironment != "ApiServer")
|
||||
{
|
||||
await ToastService.Danger(
|
||||
await ToastService.Error(
|
||||
"Theme Settings",
|
||||
"Unable to save the theme settings. If you are using a static host, you need to configure the colors in the frontend.json file"
|
||||
);
|
||||
@@ -215,7 +216,7 @@
|
||||
var json = JsonSerializer.Serialize(ThemeService.Variables);
|
||||
|
||||
// Download the theme configuration
|
||||
await DownloadService.DownloadString("theme.json", json);
|
||||
//await DownloadService.DownloadString("theme.json", json);
|
||||
|
||||
await ToastService.Success("Successfully exported theme configuration");
|
||||
}
|
||||
@@ -224,7 +225,7 @@
|
||||
{
|
||||
if (!eventArgs.File.Name.EndsWith(".json"))
|
||||
{
|
||||
await ToastService.Danger("Only .json files are allowed");
|
||||
await ToastService.Error("Only .json files are allowed");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
@inject NavigationManager Navigation
|
||||
@inject ToastService ToastService
|
||||
@inject AlertService AlertService
|
||||
@inject DownloadService DownloadService
|
||||
|
||||
@* @inject DownloadService DownloadService *@
|
||||
|
||||
<PageHeader Title="Create API Key">
|
||||
<a href="/admin/api" class="btn btn-secondary">
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
@using MoonCore.Helpers
|
||||
@using MoonCore.Models
|
||||
@using MoonCore.Blazor.Tailwind.Dt
|
||||
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
||||
@using MoonCore.Blazor.FlyonUi.DataTables
|
||||
|
||||
@inject HttpApiClient ApiClient
|
||||
@inject AlertService AlertService
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
@using System.Text.Json
|
||||
@using MoonCore.Helpers
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||
@using MoonCore.Blazor.Tailwind.Input2
|
||||
|
||||
@inject HttpApiClient ApiClient
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
@using MoonCore.Helpers
|
||||
@using MoonCore.Models
|
||||
@using MoonCore.Blazor.Tailwind.Dt
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||
@using MoonCore.Blazor.FlyonUi.DataTables
|
||||
|
||||
@inject HttpApiClient ApiClient
|
||||
@inject AlertService AlertService
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
@using MoonCore.Helpers
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||
@using MoonCore.Blazor.Tailwind.Input2
|
||||
|
||||
@inject HttpApiClient ApiClient
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
@using Microsoft.JSInterop
|
||||
@using Moonlight.Client
|
||||
|
||||
@using MoonCore.Blazor.Tailwind.Components
|
||||
@using MoonCore.Blazor.Tailwind.Alerts
|
||||
@using MoonCore.Blazor.Tailwind.Helpers
|
||||
@using MoonCore.Blazor.Tailwind.Modals
|
||||
@using MoonCore.Blazor.Tailwind.Services
|
||||
@using MoonCore.Blazor.Tailwind.Toasts
|
||||
@using MoonCore.Blazor.FlyonUi.Components
|
||||
@using MoonCore.Blazor.FlyonUi.Modals
|
||||
@using MoonCore.Blazor.FlyonUi.Toasts
|
||||
@using MoonCore.Blazor.FlyonUi.Alerts
|
||||
@@ -1,38 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Moonlight.Client</title>
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="/css/style.min.css" />
|
||||
<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>
|
||||
|
||||
<script src="/js/moonlight.js"></script>
|
||||
<script src="/js/moonCore.js"></script>
|
||||
<script src="/ace/ace.js"></script>
|
||||
<script src="/_framework/blazor.webassembly.js"></script>
|
||||
<script>navigator.serviceWorker.register('service-worker.js');</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 11 KiB |
@@ -6,6 +6,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Client", "Moonlig
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Shared", "Moonlight.Shared\Moonlight.Shared.csproj", "{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.ApiServer.Runtime", "Moonlight.ApiServer.Runtime\Moonlight.ApiServer.Runtime.csproj", "{97FC686D-BC8A-4145-90C7-CA86B598441E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Client.Runtime", "Moonlight.Client.Runtime\Moonlight.Client.Runtime.csproj", "{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -24,6 +28,14 @@ Global
|
||||
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C82E4F2A-91D2-4BC7-9AA7-241FDAAFC823}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{97FC686D-BC8A-4145-90C7-CA86B598441E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{97FC686D-BC8A-4145-90C7-CA86B598441E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{97FC686D-BC8A-4145-90C7-CA86B598441E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{97FC686D-BC8A-4145-90C7-CA86B598441E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
EndGlobalSection
|
||||
|
||||