Merge pull request #445 from Moonlight-Panel/v2.1_OptimizeNugetBuilding
Optimize nuget building. Refactored startup. Fixed smaller issues
This commit is contained in:
@@ -1,30 +0,0 @@
|
|||||||
**/.dockerignore
|
|
||||||
**/.env
|
|
||||||
**/.git
|
|
||||||
**/.gitignore
|
|
||||||
**/.project
|
|
||||||
**/.settings
|
|
||||||
**/.toolstarget
|
|
||||||
**/.vs
|
|
||||||
**/.vscode
|
|
||||||
**/.idea
|
|
||||||
**/*.*proj.user
|
|
||||||
**/*.dbmdl
|
|
||||||
**/*.jfm
|
|
||||||
**/azds.yaml
|
|
||||||
**/bin
|
|
||||||
**/charts
|
|
||||||
**/docker-compose*
|
|
||||||
**/Dockerfile*
|
|
||||||
**/node_modules
|
|
||||||
**/npm-debug.log
|
|
||||||
**/obj
|
|
||||||
**/secrets.dev.yaml
|
|
||||||
**/values.dev.yaml
|
|
||||||
**/storage
|
|
||||||
**/compose.yml
|
|
||||||
LICENSE
|
|
||||||
README.md
|
|
||||||
|
|
||||||
# For the people who run moonlight inside the main repo with the relative data path
|
|
||||||
data
|
|
||||||
@@ -1,9 +1,35 @@
|
|||||||
using Moonlight.ApiServer;
|
using Moonlight.ApiServer.Runtime;
|
||||||
using Moonlight.ApiServer.Runtime;
|
using Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
var startup = new Startup();
|
|
||||||
|
|
||||||
var pluginLoader = new PluginLoader();
|
var pluginLoader = new PluginLoader();
|
||||||
pluginLoader.Initialize();
|
pluginLoader.Initialize();
|
||||||
|
/*
|
||||||
await startup.Run(args, pluginLoader.Instances);
|
await startup.Run(args, pluginLoader.Instances);
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
var cs = new Startup();
|
||||||
|
|
||||||
|
await cs.Initialize(args, pluginLoader.Instances);
|
||||||
|
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
await cs.AddMoonlight(builder);
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
await cs.AddMoonlight(app);
|
||||||
|
|
||||||
|
// Handle setup of wasm app hosting in the runtime
|
||||||
|
// so the Moonlight.ApiServer doesn't need the wasm package
|
||||||
|
if (cs.Configuration.Frontend.EnableHosting)
|
||||||
|
{
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
app.UseWebAssemblyDebugging();
|
||||||
|
|
||||||
|
app.UseBlazorFrameworkFiles();
|
||||||
|
app.UseStaticFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await app.RunAsync();
|
||||||
@@ -1,24 +1,45 @@
|
|||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
using YamlDotNet.Serialization;
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Configuration;
|
namespace Moonlight.ApiServer.Configuration;
|
||||||
|
|
||||||
public class AppConfiguration
|
public record AppConfiguration
|
||||||
{
|
{
|
||||||
|
[YamlMember(Description = "The public url your instance should be accessible through")]
|
||||||
public string PublicUrl { get; set; } = "http://localhost:5165";
|
public string PublicUrl { get; set; } = "http://localhost:5165";
|
||||||
|
|
||||||
|
[YamlMember(Description = "The credentials of the postgres which moonlight should use")]
|
||||||
public DatabaseConfig Database { get; set; } = new();
|
public DatabaseConfig Database { get; set; } = new();
|
||||||
|
|
||||||
|
[YamlMember(Description = "Settings regarding authentication")]
|
||||||
public AuthenticationConfig Authentication { get; set; } = new();
|
public AuthenticationConfig Authentication { get; set; } = new();
|
||||||
|
|
||||||
|
[YamlMember(Description = "These options are only meant for development purposes")]
|
||||||
public DevelopmentConfig Development { get; set; } = new();
|
public DevelopmentConfig Development { get; set; } = new();
|
||||||
public ClientConfig Client { get; set; } = new();
|
public FrontendData Frontend { get; set; } = new();
|
||||||
public KestrelConfig Kestrel { get; set; } = new();
|
public KestrelConfig Kestrel { get; set; } = new();
|
||||||
public MetricsData Metrics { get; set; } = new();
|
public MetricsData Metrics { get; set; } = new();
|
||||||
|
|
||||||
public class ClientConfig
|
public static AppConfiguration CreateEmpty()
|
||||||
{
|
{
|
||||||
public bool Enable { get; set; } = true;
|
return new AppConfiguration()
|
||||||
|
{
|
||||||
|
// Set arrays as empty here
|
||||||
|
|
||||||
|
Kestrel = new()
|
||||||
|
{
|
||||||
|
AllowedOrigins = []
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DatabaseConfig
|
public record FrontendData
|
||||||
|
{
|
||||||
|
[YamlMember(Description = "Enable the hosting of the frontend. Disable this if you only want to run the api server")]
|
||||||
|
public bool EnableHosting { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record DatabaseConfig
|
||||||
{
|
{
|
||||||
public string Host { get; set; } = "your-database-host.name";
|
public string Host { get; set; } = "your-database-host.name";
|
||||||
public int Port { get; set; } = 5432;
|
public int Port { get; set; } = 5432;
|
||||||
@@ -29,15 +50,19 @@ public class AppConfiguration
|
|||||||
public string Database { get; set; } = "db_name";
|
public string Database { get; set; } = "db_name";
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AuthenticationConfig
|
public record AuthenticationConfig
|
||||||
{
|
{
|
||||||
|
[YamlMember(Description = "The secret token to use for creating jwts and encrypting things. This needs to be at least 32 characters long")]
|
||||||
public string Secret { get; set; } = Formatter.GenerateString(32);
|
public string Secret { get; set; } = Formatter.GenerateString(32);
|
||||||
|
|
||||||
|
[YamlMember(Description = "The lifespan of generated user tokens in hours")]
|
||||||
public int TokenDuration { get; set; } = 24 * 10;
|
public int TokenDuration { get; set; } = 24 * 10;
|
||||||
|
|
||||||
|
[YamlMember(Description = "This enables the use of the local oauth2 provider, so moonlight will use itself as an oauth2 provider")]
|
||||||
public bool EnableLocalOAuth2 { get; set; } = true;
|
public bool EnableLocalOAuth2 { get; set; } = true;
|
||||||
public OAuth2Data OAuth2 { get; set; } = new();
|
public OAuth2Data OAuth2 { get; set; } = new();
|
||||||
|
|
||||||
public class OAuth2Data
|
public record OAuth2Data
|
||||||
{
|
{
|
||||||
public string Secret { get; set; } = Formatter.GenerateString(32);
|
public string Secret { get; set; } = Formatter.GenerateString(32);
|
||||||
public string ClientId { get; set; } = Formatter.GenerateString(8);
|
public string ClientId { get; set; } = Formatter.GenerateString(8);
|
||||||
@@ -46,24 +71,32 @@ public class AppConfiguration
|
|||||||
public string? AccessEndpoint { get; set; }
|
public string? AccessEndpoint { get; set; }
|
||||||
public string? AuthorizationRedirect { get; set; }
|
public string? AuthorizationRedirect { get; set; }
|
||||||
|
|
||||||
|
[YamlMember(Description = "This specifies if the first registered user will become an admin automatically. This only works when using local oauth2")]
|
||||||
public bool FirstUserAdmin { get; set; } = true;
|
public bool FirstUserAdmin { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DevelopmentConfig
|
public record DevelopmentConfig
|
||||||
{
|
{
|
||||||
|
[YamlMember(Description = "This toggles the availability of the api docs via /api/swagger")]
|
||||||
public bool EnableApiDocs { get; set; } = false;
|
public bool EnableApiDocs { get; set; } = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KestrelConfig
|
public record KestrelConfig
|
||||||
{
|
{
|
||||||
|
[YamlMember(Description = "The upload limit in megabytes for the api server")]
|
||||||
public int UploadLimit { get; set; } = 100;
|
public int UploadLimit { get; set; } = 100;
|
||||||
public string AllowedOrigins { get; set; } = "*";
|
|
||||||
|
[YamlMember(Description = "The allowed origins for the api server. Use * to allow all origins (which is not advised)")]
|
||||||
|
public string[] AllowedOrigins { get; set; } = ["*"];
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MetricsData
|
public record MetricsData
|
||||||
{
|
{
|
||||||
|
[YamlMember(Description = "This enables the collecting of metrics and allows access to the /metrics endpoint")]
|
||||||
public bool Enable { get; set; } = false;
|
public bool Enable { get; set; } = false;
|
||||||
|
|
||||||
|
[YamlMember(Description = "The interval in which metrics are created, specified in seconds")]
|
||||||
public int Interval { get; set; } = 15;
|
public int Interval { get; set; } = 15;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
namespace Moonlight.ApiServer.Database.Entities;
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Database.Entities;
|
|
||||||
|
|
||||||
public class ApiKey
|
public class ApiKey
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
namespace Moonlight.ApiServer.Database.Entities;
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Database.Entities;
|
|
||||||
|
|
||||||
public class User
|
public class User
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
using Moonlight.Shared.Http.Requests.Admin.Sys;
|
using Moonlight.Shared.Http.Requests.Admin.Sys;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using MoonCore.Helpers;
|
|
||||||
using Moonlight.Shared.Http.Requests.Admin.Sys;
|
using Moonlight.Shared.Http.Requests.Admin.Sys;
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys;
|
namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys;
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Extended.Abstractions;
|
using MoonCore.Extended.Abstractions;
|
||||||
using MoonCore.Helpers;
|
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
using Moonlight.ApiServer.Database.Entities;
|
using Moonlight.ApiServer.Database.Entities;
|
||||||
using Moonlight.ApiServer.Interfaces;
|
using Moonlight.ApiServer.Interfaces;
|
||||||
using Moonlight.Shared.Http.Requests.Auth;
|
using Moonlight.Shared.Http.Requests.Auth;
|
||||||
using Moonlight.Shared.Http.Responses.Auth;
|
using Moonlight.Shared.Http.Responses.Auth;
|
||||||
using Moonlight.Shared.Http.Responses.OAuth2;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Http.Controllers.Auth;
|
namespace Moonlight.ApiServer.Http.Controllers.Auth;
|
||||||
|
|
||||||
@@ -76,7 +74,7 @@ public class AuthController : Controller
|
|||||||
// Generate token
|
// Generate token
|
||||||
var securityTokenDescriptor = new SecurityTokenDescriptor()
|
var securityTokenDescriptor = new SecurityTokenDescriptor()
|
||||||
{
|
{
|
||||||
Expires = DateTime.Now.AddYears(Configuration.Authentication.TokenDuration),
|
Expires = DateTime.Now.AddHours(Configuration.Authentication.TokenDuration),
|
||||||
IssuedAt = DateTime.Now,
|
IssuedAt = DateTime.Now,
|
||||||
NotBefore = DateTime.Now.AddMinutes(-1),
|
NotBefore = DateTime.Now.AddMinutes(-1),
|
||||||
Claims = new Dictionary<string, object>()
|
Claims = new Dictionary<string, object>()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
using Moonlight.Shared.Misc;
|
using Moonlight.Shared.Misc;
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<link href="manifest.webmanifest" rel="manifest" />
|
<link href="manifest.webmanifest" rel="manifest" />
|
||||||
<link rel="apple-touch-icon" sizes="512x512" href="/img/icon-512.png" />
|
<link rel="apple-touch-icon" sizes="512x512" href="/_content/Moonlight.Client/img/icon-512.png" />
|
||||||
<link rel="apple-touch-icon" sizes="192x192" href="/img/icon-192.png" />
|
<link rel="apple-touch-icon" sizes="192x192" href="/_content/Moonlight.Client/img/icon-192.png" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Security.Claims;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
@@ -55,11 +56,11 @@ public partial class OAuth2Controller : Controller
|
|||||||
throw new HttpApiException("Invalid oauth2 request", 400);
|
throw new HttpApiException("Invalid oauth2 request", 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
Response.StatusCode = 200;
|
string html;
|
||||||
|
|
||||||
if (view == "register")
|
if (view == "register")
|
||||||
{
|
{
|
||||||
var html = await ComponentHelper.RenderComponent<Register>(HttpContext.RequestServices, parameters =>
|
html = await ComponentHelper.RenderComponent<Register>(HttpContext.RequestServices, parameters =>
|
||||||
{
|
{
|
||||||
parameters.Add("ClientId", clientId);
|
parameters.Add("ClientId", clientId);
|
||||||
parameters.Add("RedirectUri", redirectUri);
|
parameters.Add("RedirectUri", redirectUri);
|
||||||
@@ -70,7 +71,7 @@ public partial class OAuth2Controller : Controller
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var html = await ComponentHelper.RenderComponent<Login>(HttpContext.RequestServices, parameters =>
|
html = await ComponentHelper.RenderComponent<Login>(HttpContext.RequestServices, parameters =>
|
||||||
{
|
{
|
||||||
parameters.Add("ClientId", clientId);
|
parameters.Add("ClientId", clientId);
|
||||||
parameters.Add("RedirectUri", redirectUri);
|
parameters.Add("RedirectUri", redirectUri);
|
||||||
@@ -79,6 +80,10 @@ public partial class OAuth2Controller : Controller
|
|||||||
|
|
||||||
await Response.WriteAsync(html);
|
await Response.WriteAsync(html);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Results
|
||||||
|
.Text(html, "text/html")
|
||||||
|
.ExecuteAsync(HttpContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
[AllowAnonymous]
|
[AllowAnonymous]
|
||||||
@@ -116,7 +121,6 @@ public partial class OAuth2Controller : Controller
|
|||||||
var code = await GenerateCode(user);
|
var code = await GenerateCode(user);
|
||||||
|
|
||||||
Response.Redirect($"{redirectUri}?code={code}");
|
Response.Redirect($"{redirectUri}?code={code}");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -124,39 +128,38 @@ public partial class OAuth2Controller : Controller
|
|||||||
var code = await GenerateCode(user);
|
var code = await GenerateCode(user);
|
||||||
|
|
||||||
Response.Redirect($"{redirectUri}?code={code}");
|
Response.Redirect($"{redirectUri}?code={code}");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (HttpApiException e)
|
catch (HttpApiException e)
|
||||||
{
|
{
|
||||||
errorMessage = e.Title;
|
errorMessage = e.Title;
|
||||||
}
|
|
||||||
|
|
||||||
Response.StatusCode = 200;
|
string html;
|
||||||
|
|
||||||
if (view == "register")
|
if (view == "register")
|
||||||
{
|
{
|
||||||
var html = await ComponentHelper.RenderComponent<Register>(HttpContext.RequestServices, parameters =>
|
html = await ComponentHelper.RenderComponent<Register>(HttpContext.RequestServices, parameters =>
|
||||||
{
|
{
|
||||||
parameters.Add("ClientId", clientId);
|
parameters.Add("ClientId", clientId);
|
||||||
parameters.Add("RedirectUri", redirectUri);
|
parameters.Add("RedirectUri", redirectUri);
|
||||||
parameters.Add("ResponseType", responseType);
|
parameters.Add("ResponseType", responseType);
|
||||||
parameters.Add("ErrorMessage", errorMessage!);
|
parameters.Add("ErrorMessage", errorMessage!);
|
||||||
});
|
});
|
||||||
|
|
||||||
await Response.WriteAsync(html);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var html = await ComponentHelper.RenderComponent<Login>(HttpContext.RequestServices, parameters =>
|
html = await ComponentHelper.RenderComponent<Login>(HttpContext.RequestServices, parameters =>
|
||||||
{
|
{
|
||||||
parameters.Add("ClientId", clientId);
|
parameters.Add("ClientId", clientId);
|
||||||
parameters.Add("RedirectUri", redirectUri);
|
parameters.Add("RedirectUri", redirectUri);
|
||||||
parameters.Add("ResponseType", responseType);
|
parameters.Add("ResponseType", responseType);
|
||||||
parameters.Add("ErrorMessage", errorMessage!);
|
parameters.Add("ErrorMessage", errorMessage!);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await Response.WriteAsync(html);
|
await Results
|
||||||
|
.Text(html, "text/html")
|
||||||
|
.ExecuteAsync(HttpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using MoonCore.Extended.Abstractions;
|
using MoonCore.Extended.Abstractions;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Diagnostics.Metrics;
|
using System.Diagnostics.Metrics;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Moonlight.ApiServer.Interfaces;
|
using Moonlight.ApiServer.Interfaces;
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Diagnostics.Metrics;
|
using System.Diagnostics.Metrics;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using MoonCore.Extended.Abstractions;
|
using MoonCore.Extended.Abstractions;
|
||||||
using Moonlight.ApiServer.Database.Entities;
|
using Moonlight.ApiServer.Database.Entities;
|
||||||
using Moonlight.ApiServer.Interfaces;
|
using Moonlight.ApiServer.Interfaces;
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
using Moonlight.ApiServer.Database;
|
using Moonlight.ApiServer.Database;
|
||||||
@@ -8,7 +12,6 @@ using Moonlight.ApiServer.Models;
|
|||||||
using Moonlight.ApiServer.Plugins;
|
using Moonlight.ApiServer.Plugins;
|
||||||
using Moonlight.ApiServer.Services;
|
using Moonlight.ApiServer.Services;
|
||||||
using OpenTelemetry.Metrics;
|
using OpenTelemetry.Metrics;
|
||||||
using OpenTelemetry.Trace;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Implementations.Startup;
|
namespace Moonlight.ApiServer.Implementations.Startup;
|
||||||
|
|
||||||
@@ -83,7 +86,7 @@ public class CoreStartup : IPluginStartup
|
|||||||
|
|
||||||
#region Client / Frontend
|
#region Client / Frontend
|
||||||
|
|
||||||
if (configuration.Client.Enable)
|
if (configuration.Frontend.EnableHosting)
|
||||||
{
|
{
|
||||||
builder.Services.AddSingleton(new FrontendConfigurationOption()
|
builder.Services.AddSingleton(new FrontendConfigurationOption()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net9.0</TargetFramework>
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
@@ -12,15 +12,9 @@
|
|||||||
<Folder Include="Database\Migrations\" />
|
<Folder Include="Database\Migrations\" />
|
||||||
<Folder Include="Helpers\" />
|
<Folder Include="Helpers\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="..\.dockerignore">
|
|
||||||
<Link>.dockerignore</Link>
|
|
||||||
<Pack>false</Pack>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PackageId>Moonlight.ApiServer</PackageId>
|
<PackageId>Moonlight.ApiServer</PackageId>
|
||||||
<Version>2.1.2</Version>
|
<Version>2.1.3</Version>
|
||||||
<Authors>Moonlight Panel</Authors>
|
<Authors>Moonlight Panel</Authors>
|
||||||
<Description>A build of the api server for moonlight development</Description>
|
<Description>A build of the api server for moonlight development</Description>
|
||||||
<PackageProjectUrl>https://github.com/Moonlight-Panel/Moonlight</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Moonlight-Panel/Moonlight</PackageProjectUrl>
|
||||||
@@ -32,7 +26,6 @@
|
|||||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
||||||
<PackageReference Include="Hangfire.Core" Version="1.8.20" />
|
<PackageReference Include="Hangfire.Core" Version="1.8.20" />
|
||||||
<PackageReference Include="Hangfire.EntityFrameworkCore" Version="0.7.0" />
|
<PackageReference Include="Hangfire.EntityFrameworkCore" Version="0.7.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.7" />
|
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.7" />
|
||||||
<PackageReference Include="MoonCore" Version="1.9.2" />
|
<PackageReference Include="MoonCore" Version="1.9.2" />
|
||||||
<PackageReference Include="MoonCore.Extended" Version="1.3.5" />
|
<PackageReference Include="MoonCore.Extended" Version="1.3.5" />
|
||||||
@@ -45,16 +38,6 @@
|
|||||||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="**\*.cs" Exclude="storage\**\*;bin\**\*;obj\**\*">
|
|
||||||
<Pack>true</Pack>
|
|
||||||
<PackagePath>src</PackagePath>
|
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="**\*.razor" Exclude="storage\**\*;bin\**\*;obj\**\*">
|
|
||||||
<Pack>true</Pack>
|
|
||||||
<PackagePath>src</PackagePath>
|
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<Compile Remove="storage\**\*" />
|
<Compile Remove="storage\**\*" />
|
||||||
<Content Remove="storage\**\*" />
|
<Content Remove="storage\**\*" />
|
||||||
<None Remove="storage\**\*" />
|
<None Remove="storage\**\*" />
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
namespace Moonlight.ApiServer.Plugins;
|
namespace Moonlight.ApiServer.Plugins;
|
||||||
|
|
||||||
public interface IPluginStartup
|
public interface IPluginStartup
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
using Moonlight.ApiServer;
|
|
||||||
|
|
||||||
var startup = new Startup();
|
|
||||||
|
|
||||||
await startup.Run(args);
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using MoonCore.Attributes;
|
using MoonCore.Attributes;
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using MoonCore.Attributes;
|
using MoonCore.Attributes;
|
||||||
using MoonCore.Helpers;
|
using MoonCore.Helpers;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Moonlight.ApiServer.Interfaces;
|
using Moonlight.ApiServer.Interfaces;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using MoonCore.Attributes;
|
using MoonCore.Attributes;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
using Moonlight.Shared.Http.Responses.Admin.Sys;
|
using Moonlight.Shared.Http.Responses.Admin.Sys;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.FileProviders;
|
using Microsoft.Extensions.FileProviders;
|
||||||
using MoonCore.Attributes;
|
using MoonCore.Attributes;
|
||||||
using MoonCore.Exceptions;
|
using MoonCore.Exceptions;
|
||||||
@@ -82,7 +83,7 @@ public class FrontendService
|
|||||||
public async Task<Stream> GenerateZip() // TODO: Rework to be able to extract everything successfully
|
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
|
// We only allow the access to this function when we are actually hosting the frontend
|
||||||
if (!Configuration.Client.Enable)
|
if (!Configuration.Frontend.EnableHosting)
|
||||||
throw new HttpApiException("The hosting of the wasm client has been disabled", 400);
|
throw new HttpApiException("The hosting of the wasm client has been disabled", 400);
|
||||||
|
|
||||||
// Load and check wasm path
|
// Load and check wasm path
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
using System.Diagnostics.Metrics;
|
using System.Diagnostics.Metrics;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Moonlight.ApiServer.Configuration;
|
using Moonlight.ApiServer.Configuration;
|
||||||
using Moonlight.ApiServer.Interfaces;
|
using Moonlight.ApiServer.Interfaces;
|
||||||
|
|
||||||
|
|||||||
@@ -1,547 +0,0 @@
|
|||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
using Hangfire;
|
|
||||||
using Hangfire.EntityFrameworkCore;
|
|
||||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using MoonCore.EnvConfiguration;
|
|
||||||
using MoonCore.Extended.Abstractions;
|
|
||||||
using MoonCore.Extended.Extensions;
|
|
||||||
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;
|
|
||||||
using Moonlight.ApiServer.Database.Entities;
|
|
||||||
using Moonlight.ApiServer.Implementations;
|
|
||||||
using Moonlight.ApiServer.Implementations.Startup;
|
|
||||||
using Moonlight.ApiServer.Interfaces;
|
|
||||||
using Moonlight.ApiServer.Plugins;
|
|
||||||
|
|
||||||
namespace Moonlight.ApiServer;
|
|
||||||
|
|
||||||
// Cry about it
|
|
||||||
#pragma warning disable ASP0000
|
|
||||||
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
private string[] Args;
|
|
||||||
|
|
||||||
// Logging
|
|
||||||
private ILoggerProvider[] LoggerProviders;
|
|
||||||
private ILoggerFactory LoggerFactory;
|
|
||||||
private ILogger<Startup> Logger;
|
|
||||||
|
|
||||||
// Configuration
|
|
||||||
private AppConfiguration Configuration;
|
|
||||||
private IConfigurationRoot ConfigurationRoot;
|
|
||||||
|
|
||||||
// WebApplication Stuff
|
|
||||||
private WebApplication WebApplication;
|
|
||||||
private WebApplicationBuilder WebApplicationBuilder;
|
|
||||||
|
|
||||||
// Plugin Loading
|
|
||||||
private IPluginStartup[] PluginStartups;
|
|
||||||
private IPluginStartup[] AdditionalPlugins;
|
|
||||||
private IServiceProvider PluginLoadServiceProvider;
|
|
||||||
|
|
||||||
public async Task Run(string[] args, IPluginStartup[]? additionalPlugins = null)
|
|
||||||
{
|
|
||||||
Args = args;
|
|
||||||
AdditionalPlugins = additionalPlugins ?? [];
|
|
||||||
|
|
||||||
await PrintVersion();
|
|
||||||
|
|
||||||
await CreateStorage();
|
|
||||||
await SetupAppConfiguration();
|
|
||||||
await SetupLogging();
|
|
||||||
await InitializePlugins();
|
|
||||||
|
|
||||||
await CreateWebApplicationBuilder();
|
|
||||||
|
|
||||||
await ConfigureKestrel();
|
|
||||||
await RegisterAppConfiguration();
|
|
||||||
await RegisterLogging();
|
|
||||||
await RegisterBase();
|
|
||||||
await RegisterDatabase();
|
|
||||||
await RegisterAuth();
|
|
||||||
await RegisterCors();
|
|
||||||
await RegisterHangfire();
|
|
||||||
await HookPluginBuild();
|
|
||||||
await RegisterPluginAssets();
|
|
||||||
|
|
||||||
await BuildWebApplication();
|
|
||||||
|
|
||||||
await PrepareDatabase();
|
|
||||||
|
|
||||||
await UseCors();
|
|
||||||
await UseBase();
|
|
||||||
await UseAuth();
|
|
||||||
await UseHangfire();
|
|
||||||
await HookPluginConfigure();
|
|
||||||
|
|
||||||
await MapBase();
|
|
||||||
await HookPluginEndpoints();
|
|
||||||
|
|
||||||
await WebApplication.RunAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task PrintVersion()
|
|
||||||
{
|
|
||||||
// Fancy start console output... yes very fancy :>
|
|
||||||
var rainbow = new Crayon.Rainbow(0.5);
|
|
||||||
foreach (var c in "Moonlight")
|
|
||||||
{
|
|
||||||
Console.Write(
|
|
||||||
rainbow
|
|
||||||
.Next()
|
|
||||||
.Bold()
|
|
||||||
.Text(c.ToString())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task CreateStorage()
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory("storage");
|
|
||||||
Directory.CreateDirectory(Path.Combine("storage", "logs"));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Base
|
|
||||||
|
|
||||||
private Task RegisterBase()
|
|
||||||
{
|
|
||||||
WebApplicationBuilder.Services.AutoAddServices<Startup>();
|
|
||||||
WebApplicationBuilder.Services.AddHttpClient();
|
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddApiExceptionHandler();
|
|
||||||
|
|
||||||
// Add pre-existing services
|
|
||||||
WebApplicationBuilder.Services.AddSingleton(Configuration);
|
|
||||||
|
|
||||||
// Configure controllers
|
|
||||||
var mvcBuilder = WebApplicationBuilder.Services.AddControllers();
|
|
||||||
|
|
||||||
// Add plugin assemblies as application parts
|
|
||||||
foreach (var pluginStartup in PluginStartups.Select(x => x.GetType().Assembly).Distinct())
|
|
||||||
mvcBuilder.AddApplicationPart(pluginStartup.GetType().Assembly);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task UseBase()
|
|
||||||
{
|
|
||||||
WebApplication.UseRouting();
|
|
||||||
WebApplication.UseExceptionHandler();
|
|
||||||
|
|
||||||
if (Configuration.Client.Enable)
|
|
||||||
{
|
|
||||||
if (WebApplication.Environment.IsDevelopment())
|
|
||||||
WebApplication.UseWebAssemblyDebugging();
|
|
||||||
|
|
||||||
WebApplication.UseBlazorFrameworkFiles();
|
|
||||||
WebApplication.UseStaticFiles();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task MapBase()
|
|
||||||
{
|
|
||||||
WebApplication.MapControllers();
|
|
||||||
|
|
||||||
if (Configuration.Client.Enable)
|
|
||||||
WebApplication.MapFallbackToController("Index", "Frontend");
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task ConfigureKestrel()
|
|
||||||
{
|
|
||||||
WebApplicationBuilder.WebHost.ConfigureKestrel(kestrelOptions =>
|
|
||||||
{
|
|
||||||
var maxUploadInBytes = ByteConverter
|
|
||||||
.FromMegaBytes(Configuration.Kestrel.UploadLimit)
|
|
||||||
.Bytes;
|
|
||||||
|
|
||||||
kestrelOptions.Limits.MaxRequestBodySize = maxUploadInBytes;
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Plugin Loading
|
|
||||||
|
|
||||||
private Task InitializePlugins()
|
|
||||||
{
|
|
||||||
// Create service provider for starting up
|
|
||||||
var serviceCollection = new ServiceCollection();
|
|
||||||
|
|
||||||
serviceCollection.AddSingleton(Configuration);
|
|
||||||
|
|
||||||
serviceCollection.AddLogging(builder =>
|
|
||||||
{
|
|
||||||
builder.ClearProviders();
|
|
||||||
builder.AddAnsiConsole();
|
|
||||||
});
|
|
||||||
|
|
||||||
PluginLoadServiceProvider = serviceCollection.BuildServiceProvider();
|
|
||||||
|
|
||||||
// Collect startups
|
|
||||||
var pluginStartups = new List<IPluginStartup>();
|
|
||||||
|
|
||||||
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
|
||||||
|
|
||||||
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
|
||||||
// MLBUILD_PLUGIN_STARTUP_HERE
|
|
||||||
|
|
||||||
|
|
||||||
PluginStartups = pluginStartups.ToArray();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task RegisterPluginAssets()
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Hooks
|
|
||||||
|
|
||||||
private async Task HookPluginBuild()
|
|
||||||
{
|
|
||||||
foreach (var pluginAppStartup in PluginStartups)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await pluginAppStartup.BuildApplication(PluginLoadServiceProvider, WebApplicationBuilder);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError(
|
|
||||||
"An error occured while processing 'BuildApp' for '{name}': {e}",
|
|
||||||
pluginAppStartup.GetType().FullName,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HookPluginConfigure()
|
|
||||||
{
|
|
||||||
foreach (var pluginAppStartup in PluginStartups)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await pluginAppStartup.ConfigureApplication(PluginLoadServiceProvider, WebApplication);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError(
|
|
||||||
"An error occured while processing 'ConfigureApp' for '{name}': {e}",
|
|
||||||
pluginAppStartup.GetType().FullName,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HookPluginEndpoints()
|
|
||||||
{
|
|
||||||
foreach (var pluginEndpointStartup in PluginStartups)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await pluginEndpointStartup.ConfigureEndpoints(PluginLoadServiceProvider, WebApplication);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError(
|
|
||||||
"An error occured while processing 'ConfigureEndpoints' for '{name}': {e}",
|
|
||||||
pluginEndpointStartup.GetType().FullName,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Configurations
|
|
||||||
|
|
||||||
private async Task SetupAppConfiguration()
|
|
||||||
{
|
|
||||||
// Configure configuration (wow)
|
|
||||||
var configurationBuilder = new ConfigurationBuilder();
|
|
||||||
|
|
||||||
// Ensure configuration file exists
|
|
||||||
var jsonFilePath = Path.Combine(Directory.GetCurrentDirectory(), "storage", "app.json");
|
|
||||||
|
|
||||||
if (!File.Exists(jsonFilePath))
|
|
||||||
await File.WriteAllTextAsync(jsonFilePath, JsonSerializer.Serialize(new AppConfiguration()));
|
|
||||||
|
|
||||||
configurationBuilder.AddJsonFile(
|
|
||||||
jsonFilePath
|
|
||||||
);
|
|
||||||
|
|
||||||
configurationBuilder.AddEnvironmentVariables(prefix: "MOONLIGHT_", separator: "_");
|
|
||||||
|
|
||||||
ConfigurationRoot = configurationBuilder.Build();
|
|
||||||
|
|
||||||
// Retrieve configuration
|
|
||||||
Configuration = ConfigurationRoot.Get<AppConfiguration>()!;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task RegisterAppConfiguration()
|
|
||||||
{
|
|
||||||
WebApplicationBuilder.Services.AddSingleton(Configuration);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Web Application
|
|
||||||
|
|
||||||
private Task CreateWebApplicationBuilder()
|
|
||||||
{
|
|
||||||
WebApplicationBuilder = WebApplication.CreateBuilder(Args);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task BuildWebApplication()
|
|
||||||
{
|
|
||||||
WebApplication = WebApplicationBuilder.Build();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Logging
|
|
||||||
|
|
||||||
private Task SetupLogging()
|
|
||||||
{
|
|
||||||
LoggerFactory = new LoggerFactory();
|
|
||||||
LoggerFactory.AddAnsiConsole();
|
|
||||||
|
|
||||||
Logger = LoggerFactory.CreateLogger<Startup>();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task RegisterLogging()
|
|
||||||
{
|
|
||||||
// Configure application logging
|
|
||||||
WebApplicationBuilder.Logging.ClearProviders();
|
|
||||||
WebApplicationBuilder.Logging.AddAnsiConsole();
|
|
||||||
WebApplicationBuilder.Logging.AddFile(Path.Combine("storage", "logs", "moonlight.log"));
|
|
||||||
|
|
||||||
// Logging levels
|
|
||||||
var logConfigPath = Path.Combine("storage", "logConfig.json");
|
|
||||||
|
|
||||||
// Ensure logging config, add a default one is missing
|
|
||||||
if (!File.Exists(logConfigPath))
|
|
||||||
{
|
|
||||||
var defaultLogLevels = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "Default", "Information" },
|
|
||||||
{ "Microsoft.AspNetCore", "Warning" },
|
|
||||||
{ "System.Net.Http.HttpClient", "Warning" }
|
|
||||||
};
|
|
||||||
|
|
||||||
var logLevelsJson = JsonSerializer.Serialize(defaultLogLevels);
|
|
||||||
await File.WriteAllTextAsync(logConfigPath, logLevelsJson);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add logging configuration
|
|
||||||
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
|
|
||||||
WebApplicationBuilder.Logging.AddFilter(
|
|
||||||
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware",
|
|
||||||
LogLevel.Critical
|
|
||||||
);
|
|
||||||
|
|
||||||
WebApplicationBuilder.Logging.AddFilter(
|
|
||||||
"Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware",
|
|
||||||
LogLevel.Critical
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Database
|
|
||||||
|
|
||||||
private Task RegisterDatabase()
|
|
||||||
{
|
|
||||||
WebApplicationBuilder.Services.AddDatabaseMappings();
|
|
||||||
WebApplicationBuilder.Services.AddServiceCollectionAccessor();
|
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddScoped(typeof(DatabaseRepository<>));
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task PrepareDatabase()
|
|
||||||
{
|
|
||||||
await WebApplication.Services.EnsureDatabaseMigrated();
|
|
||||||
|
|
||||||
WebApplication.Services.GenerateDatabaseMappings();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Authentication & Authorisation
|
|
||||||
|
|
||||||
private Task RegisterAuth()
|
|
||||||
{
|
|
||||||
WebApplicationBuilder.Services
|
|
||||||
.AddAuthentication("coreAuthentication")
|
|
||||||
.AddJwtBearer("coreAuthentication", options =>
|
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new()
|
|
||||||
{
|
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
|
|
||||||
Configuration.Authentication.Secret
|
|
||||||
)),
|
|
||||||
ValidateIssuerSigningKey = true,
|
|
||||||
ValidateLifetime = true,
|
|
||||||
ClockSkew = TimeSpan.Zero,
|
|
||||||
ValidateAudience = true,
|
|
||||||
ValidAudience = Configuration.PublicUrl,
|
|
||||||
ValidateIssuer = true,
|
|
||||||
ValidIssuer = Configuration.PublicUrl
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddJwtBearerInvalidation("coreAuthentication");
|
|
||||||
WebApplicationBuilder.Services.AddScoped<IJwtInvalidateHandler, UserAuthInvalidation>();
|
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddAuthorization();
|
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddAuthorizationPermissions(options =>
|
|
||||||
{
|
|
||||||
options.ClaimName = "permissions";
|
|
||||||
options.Prefix = "permissions:";
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add local oauth2 provider if enabled
|
|
||||||
if (Configuration.Authentication.EnableLocalOAuth2)
|
|
||||||
WebApplicationBuilder.Services.AddScoped<IOAuth2Provider, LocalOAuth2Provider>();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task UseAuth()
|
|
||||||
{
|
|
||||||
WebApplication.UseAuthentication();
|
|
||||||
|
|
||||||
WebApplication.UseAuthorization();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Cors
|
|
||||||
|
|
||||||
private Task RegisterCors()
|
|
||||||
{
|
|
||||||
var allowedOrigins = Configuration.Kestrel.AllowedOrigins.Split(";", StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddCors(options =>
|
|
||||||
{
|
|
||||||
var cors = new CorsPolicyBuilder();
|
|
||||||
|
|
||||||
if (allowedOrigins.Contains("*"))
|
|
||||||
{
|
|
||||||
cors.SetIsOriginAllowed(_ => true)
|
|
||||||
.AllowAnyMethod()
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowCredentials();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cors.WithOrigins(allowedOrigins)
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowAnyMethod()
|
|
||||||
.AllowCredentials();
|
|
||||||
}
|
|
||||||
|
|
||||||
options.AddDefaultPolicy(
|
|
||||||
cors.Build()
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task UseCors()
|
|
||||||
{
|
|
||||||
WebApplication.UseCors();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Hangfire
|
|
||||||
|
|
||||||
private Task RegisterHangfire()
|
|
||||||
{
|
|
||||||
WebApplicationBuilder.Services.AddHangfire((provider, configuration) =>
|
|
||||||
{
|
|
||||||
configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180);
|
|
||||||
configuration.UseSimpleAssemblyNameTypeSerializer();
|
|
||||||
configuration.UseRecommendedSerializerSettings();
|
|
||||||
configuration.UseEFCoreStorage(() =>
|
|
||||||
{
|
|
||||||
var scope = provider.CreateScope();
|
|
||||||
return scope.ServiceProvider.GetRequiredService<CoreDataContext>();
|
|
||||||
}, new EFCoreStorageOptions());
|
|
||||||
});
|
|
||||||
|
|
||||||
WebApplicationBuilder.Services.AddHangfireServer();
|
|
||||||
|
|
||||||
WebApplicationBuilder.Logging.AddFilter(
|
|
||||||
"Hangfire.Server.BackgroundServerProcess",
|
|
||||||
LogLevel.Warning
|
|
||||||
);
|
|
||||||
|
|
||||||
WebApplicationBuilder.Logging.AddFilter(
|
|
||||||
"Hangfire.BackgroundJobServer",
|
|
||||||
LogLevel.Warning
|
|
||||||
);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task UseHangfire()
|
|
||||||
{
|
|
||||||
if (WebApplication.Environment.IsDevelopment())
|
|
||||||
WebApplication.UseHangfireDashboard();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
61
Moonlight.ApiServer/Startup/Startup.Auth.cs
Normal file
61
Moonlight.ApiServer/Startup/Startup.Auth.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using MoonCore.Extended.JwtInvalidation;
|
||||||
|
using MoonCore.Permissions;
|
||||||
|
using Moonlight.ApiServer.Implementations;
|
||||||
|
using Moonlight.ApiServer.Interfaces;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task RegisterAuth()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder.Services
|
||||||
|
.AddAuthentication("coreAuthentication")
|
||||||
|
.AddJwtBearer("coreAuthentication", options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters = new()
|
||||||
|
{
|
||||||
|
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(
|
||||||
|
Configuration.Authentication.Secret
|
||||||
|
)),
|
||||||
|
ValidateIssuerSigningKey = true,
|
||||||
|
ValidateLifetime = true,
|
||||||
|
ClockSkew = TimeSpan.Zero,
|
||||||
|
ValidateAudience = true,
|
||||||
|
ValidAudience = Configuration.PublicUrl,
|
||||||
|
ValidateIssuer = true,
|
||||||
|
ValidIssuer = Configuration.PublicUrl
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
WebApplicationBuilder.Services.AddJwtBearerInvalidation("coreAuthentication");
|
||||||
|
WebApplicationBuilder.Services.AddScoped<IJwtInvalidateHandler, UserAuthInvalidation>();
|
||||||
|
|
||||||
|
WebApplicationBuilder.Services.AddAuthorization();
|
||||||
|
|
||||||
|
WebApplicationBuilder.Services.AddAuthorizationPermissions(options =>
|
||||||
|
{
|
||||||
|
options.ClaimName = "permissions";
|
||||||
|
options.Prefix = "permissions:";
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add local oauth2 provider if enabled
|
||||||
|
if (Configuration.Authentication.EnableLocalOAuth2)
|
||||||
|
WebApplicationBuilder.Services.AddScoped<IOAuth2Provider, LocalOAuth2Provider>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UseAuth()
|
||||||
|
{
|
||||||
|
WebApplication.UseAuthentication();
|
||||||
|
|
||||||
|
WebApplication.UseAuthorization();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
Moonlight.ApiServer/Startup/Startup.Base.cs
Normal file
63
Moonlight.ApiServer/Startup/Startup.Base.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MoonCore.Extended.Extensions;
|
||||||
|
using MoonCore.Extensions;
|
||||||
|
using MoonCore.Helpers;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task RegisterBase()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder.Services.AutoAddServices<Startup>();
|
||||||
|
WebApplicationBuilder.Services.AddHttpClient();
|
||||||
|
|
||||||
|
WebApplicationBuilder.Services.AddApiExceptionHandler();
|
||||||
|
|
||||||
|
// Add pre-existing services
|
||||||
|
WebApplicationBuilder.Services.AddSingleton(Configuration);
|
||||||
|
|
||||||
|
// Configure controllers
|
||||||
|
var mvcBuilder = WebApplicationBuilder.Services.AddControllers();
|
||||||
|
|
||||||
|
// Add plugin assemblies as application parts
|
||||||
|
foreach (var pluginStartup in PluginStartups.Select(x => x.GetType().Assembly).Distinct())
|
||||||
|
mvcBuilder.AddApplicationPart(pluginStartup.GetType().Assembly);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UseBase()
|
||||||
|
{
|
||||||
|
WebApplication.UseRouting();
|
||||||
|
WebApplication.UseExceptionHandler();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task MapBase()
|
||||||
|
{
|
||||||
|
WebApplication.MapControllers();
|
||||||
|
|
||||||
|
if (Configuration.Frontend.EnableHosting)
|
||||||
|
WebApplication.MapFallbackToController("Index", "Frontend");
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ConfigureKestrel()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder.WebHost.ConfigureKestrel(kestrelOptions =>
|
||||||
|
{
|
||||||
|
var maxUploadInBytes = ByteConverter
|
||||||
|
.FromMegaBytes(Configuration.Kestrel.UploadLimit)
|
||||||
|
.Bytes;
|
||||||
|
|
||||||
|
kestrelOptions.Limits.MaxRequestBodySize = maxUploadInBytes;
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
35
Moonlight.ApiServer/Startup/Startup.Config.cs
Normal file
35
Moonlight.ApiServer/Startup/Startup.Config.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MoonCore.EnvConfiguration;
|
||||||
|
using MoonCore.Yaml;
|
||||||
|
using Moonlight.ApiServer.Configuration;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private async Task SetupAppConfiguration()
|
||||||
|
{
|
||||||
|
var configPath = Path.Combine("storage", "config.yml");
|
||||||
|
|
||||||
|
await YamlDefaultGenerator.Generate<AppConfiguration>(configPath);
|
||||||
|
|
||||||
|
// Configure configuration (wow)
|
||||||
|
var configurationBuilder = new ConfigurationBuilder();
|
||||||
|
|
||||||
|
configurationBuilder.AddYamlFile(configPath);
|
||||||
|
configurationBuilder.AddEnvironmentVariables(prefix: "MOONLIGHT_", separator: "_");
|
||||||
|
|
||||||
|
var configurationRoot = configurationBuilder.Build();
|
||||||
|
|
||||||
|
// Retrieve configuration
|
||||||
|
Configuration = AppConfiguration.CreateEmpty();
|
||||||
|
configurationRoot.Bind(Configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task RegisterAppConfiguration()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder.Services.AddSingleton(Configuration);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
25
Moonlight.ApiServer/Startup/Startup.Database.cs
Normal file
25
Moonlight.ApiServer/Startup/Startup.Database.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MoonCore.Extended.Abstractions;
|
||||||
|
using MoonCore.Extended.Extensions;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task RegisterDatabase()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder.Services.AddDatabaseMappings();
|
||||||
|
WebApplicationBuilder.Services.AddServiceCollectionAccessor();
|
||||||
|
|
||||||
|
WebApplicationBuilder.Services.AddScoped(typeof(DatabaseRepository<>));
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PrepareDatabase()
|
||||||
|
{
|
||||||
|
await WebApplication.Services.EnsureDatabaseMigrated();
|
||||||
|
|
||||||
|
WebApplication.Services.GenerateDatabaseMappings();
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Moonlight.ApiServer/Startup/Startup.Hangfire.cs
Normal file
48
Moonlight.ApiServer/Startup/Startup.Hangfire.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using Hangfire;
|
||||||
|
using Hangfire.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Moonlight.ApiServer.Database;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task RegisterHangfire()
|
||||||
|
{
|
||||||
|
WebApplicationBuilder.Services.AddHangfire((provider, configuration) =>
|
||||||
|
{
|
||||||
|
configuration.SetDataCompatibilityLevel(CompatibilityLevel.Version_180);
|
||||||
|
configuration.UseSimpleAssemblyNameTypeSerializer();
|
||||||
|
configuration.UseRecommendedSerializerSettings();
|
||||||
|
configuration.UseEFCoreStorage(() =>
|
||||||
|
{
|
||||||
|
var scope = provider.CreateScope();
|
||||||
|
return scope.ServiceProvider.GetRequiredService<CoreDataContext>();
|
||||||
|
}, new EFCoreStorageOptions());
|
||||||
|
});
|
||||||
|
|
||||||
|
WebApplicationBuilder.Services.AddHangfireServer();
|
||||||
|
|
||||||
|
WebApplicationBuilder.Logging.AddFilter(
|
||||||
|
"Hangfire.Server.BackgroundServerProcess",
|
||||||
|
LogLevel.Warning
|
||||||
|
);
|
||||||
|
|
||||||
|
WebApplicationBuilder.Logging.AddFilter(
|
||||||
|
"Hangfire.BackgroundJobServer",
|
||||||
|
LogLevel.Warning
|
||||||
|
);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UseHangfire()
|
||||||
|
{
|
||||||
|
if (WebApplication.Environment.IsDevelopment())
|
||||||
|
WebApplication.UseHangfireDashboard();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
63
Moonlight.ApiServer/Startup/Startup.Logging.cs
Normal file
63
Moonlight.ApiServer/Startup/Startup.Logging.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MoonCore.Logging;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task SetupLogging()
|
||||||
|
{
|
||||||
|
var loggerFactory = new LoggerFactory();
|
||||||
|
loggerFactory.AddAnsiConsole();
|
||||||
|
|
||||||
|
Logger = loggerFactory.CreateLogger<Startup>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RegisterLogging()
|
||||||
|
{
|
||||||
|
// Configure application logging
|
||||||
|
WebApplicationBuilder.Logging.ClearProviders();
|
||||||
|
WebApplicationBuilder.Logging.AddAnsiConsole();
|
||||||
|
WebApplicationBuilder.Logging.AddFile(Path.Combine("storage", "logs", "moonlight.log"));
|
||||||
|
|
||||||
|
// Logging levels
|
||||||
|
var logConfigPath = Path.Combine("storage", "logConfig.json");
|
||||||
|
|
||||||
|
// Ensure logging config, add a default one is missing
|
||||||
|
if (!File.Exists(logConfigPath))
|
||||||
|
{
|
||||||
|
var defaultLogLevels = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "Default", "Information" },
|
||||||
|
{ "Microsoft.AspNetCore", "Warning" },
|
||||||
|
{ "System.Net.Http.HttpClient", "Warning" }
|
||||||
|
};
|
||||||
|
|
||||||
|
var logLevelsJson = JsonSerializer.Serialize(defaultLogLevels);
|
||||||
|
await File.WriteAllTextAsync(logConfigPath, logLevelsJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add logging configuration
|
||||||
|
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
|
||||||
|
WebApplicationBuilder.Logging.AddFilter(
|
||||||
|
"Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware",
|
||||||
|
LogLevel.Critical
|
||||||
|
);
|
||||||
|
|
||||||
|
WebApplicationBuilder.Logging.AddFilter(
|
||||||
|
"Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware",
|
||||||
|
LogLevel.Critical
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
73
Moonlight.ApiServer/Startup/Startup.Misc.cs
Normal file
73
Moonlight.ApiServer/Startup/Startup.Misc.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task PrintVersion()
|
||||||
|
{
|
||||||
|
// Fancy start console output... yes very fancy :>
|
||||||
|
var rainbow = new Crayon.Rainbow(0.5);
|
||||||
|
foreach (var c in "Moonlight")
|
||||||
|
{
|
||||||
|
Console.Write(
|
||||||
|
rainbow
|
||||||
|
.Next()
|
||||||
|
.Bold()
|
||||||
|
.Text(c.ToString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task CreateStorage()
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory("storage");
|
||||||
|
Directory.CreateDirectory(Path.Combine("storage", "logs"));
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task RegisterCors()
|
||||||
|
{
|
||||||
|
var allowedOrigins = Configuration.Kestrel.AllowedOrigins;
|
||||||
|
|
||||||
|
WebApplicationBuilder.Services.AddCors(options =>
|
||||||
|
{
|
||||||
|
var cors = new CorsPolicyBuilder();
|
||||||
|
|
||||||
|
if (allowedOrigins.Contains("*"))
|
||||||
|
{
|
||||||
|
cors.SetIsOriginAllowed(_ => true)
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowCredentials();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cors.WithOrigins(allowedOrigins)
|
||||||
|
.AllowAnyHeader()
|
||||||
|
.AllowAnyMethod()
|
||||||
|
.AllowCredentials();
|
||||||
|
}
|
||||||
|
|
||||||
|
options.AddDefaultPolicy(
|
||||||
|
cors.Build()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task UseCors()
|
||||||
|
{
|
||||||
|
WebApplication.UseCors();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
87
Moonlight.ApiServer/Startup/Startup.Plugins.cs
Normal file
87
Moonlight.ApiServer/Startup/Startup.Plugins.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using MoonCore.Logging;
|
||||||
|
using Moonlight.ApiServer.Plugins;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private IServiceProvider PluginLoadServiceProvider;
|
||||||
|
private IPluginStartup[] PluginStartups;
|
||||||
|
|
||||||
|
private Task InitializePlugins()
|
||||||
|
{
|
||||||
|
// Create service provider for starting up
|
||||||
|
var serviceCollection = new ServiceCollection();
|
||||||
|
|
||||||
|
serviceCollection.AddSingleton(Configuration);
|
||||||
|
|
||||||
|
serviceCollection.AddLogging(builder =>
|
||||||
|
{
|
||||||
|
builder.ClearProviders();
|
||||||
|
builder.AddAnsiConsole();
|
||||||
|
});
|
||||||
|
|
||||||
|
PluginLoadServiceProvider = serviceCollection.BuildServiceProvider();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HookPluginBuild()
|
||||||
|
{
|
||||||
|
foreach (var pluginAppStartup in PluginStartups)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await pluginAppStartup.BuildApplication(PluginLoadServiceProvider, WebApplicationBuilder);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(
|
||||||
|
"An error occured while processing 'BuildApp' for '{name}': {e}",
|
||||||
|
pluginAppStartup.GetType().FullName,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HookPluginConfigure()
|
||||||
|
{
|
||||||
|
foreach (var pluginAppStartup in PluginStartups)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await pluginAppStartup.ConfigureApplication(PluginLoadServiceProvider, WebApplication);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(
|
||||||
|
"An error occured while processing 'ConfigureApp' for '{name}': {e}",
|
||||||
|
pluginAppStartup.GetType().FullName,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HookPluginEndpoints()
|
||||||
|
{
|
||||||
|
foreach (var pluginEndpointStartup in PluginStartups)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await pluginEndpointStartup.ConfigureEndpoints(PluginLoadServiceProvider, WebApplication);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(
|
||||||
|
"An error occured while processing 'ConfigureEndpoints' for '{name}': {e}",
|
||||||
|
pluginEndpointStartup.GetType().FullName,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
Moonlight.ApiServer/Startup/Startup.cs
Normal file
67
Moonlight.ApiServer/Startup/Startup.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Moonlight.ApiServer.Configuration;
|
||||||
|
using Moonlight.ApiServer.Plugins;
|
||||||
|
|
||||||
|
namespace Moonlight.ApiServer.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private string[] Args;
|
||||||
|
|
||||||
|
// Logger
|
||||||
|
public ILogger<Startup> Logger { get; private set; }
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
public AppConfiguration Configuration { get; private set; }
|
||||||
|
|
||||||
|
// WebApplication Stuff
|
||||||
|
public WebApplication WebApplication { get; private set; }
|
||||||
|
public WebApplicationBuilder WebApplicationBuilder { get; private set; }
|
||||||
|
|
||||||
|
public Task Initialize(string[] args, IPluginStartup[]? plugins = null)
|
||||||
|
{
|
||||||
|
Args = args;
|
||||||
|
PluginStartups = plugins ?? [];
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddMoonlight(WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
WebApplicationBuilder = builder;
|
||||||
|
|
||||||
|
await PrintVersion();
|
||||||
|
|
||||||
|
await CreateStorage();
|
||||||
|
await SetupAppConfiguration();
|
||||||
|
await SetupLogging();
|
||||||
|
await InitializePlugins();
|
||||||
|
|
||||||
|
await ConfigureKestrel();
|
||||||
|
await RegisterAppConfiguration();
|
||||||
|
await RegisterLogging();
|
||||||
|
await RegisterBase();
|
||||||
|
await RegisterDatabase();
|
||||||
|
await RegisterAuth();
|
||||||
|
await RegisterCors();
|
||||||
|
await RegisterHangfire();
|
||||||
|
await HookPluginBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddMoonlight(WebApplication application)
|
||||||
|
{
|
||||||
|
WebApplication = application;
|
||||||
|
|
||||||
|
await PrepareDatabase();
|
||||||
|
|
||||||
|
await UseCors();
|
||||||
|
await UseBase();
|
||||||
|
await UseAuth();
|
||||||
|
await UseHangfire();
|
||||||
|
await HookPluginConfigure();
|
||||||
|
|
||||||
|
await MapBase();
|
||||||
|
await HookPluginEndpoints();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -64,6 +64,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<_ContentIncludedByDefault Remove="wwwroot\js\moonCore.js" />
|
<_ContentIncludedByDefault Remove="wwwroot\js\moonCore.js" />
|
||||||
<_ContentIncludedByDefault Remove="wwwroot\js\moonlight.js" />
|
<_ContentIncludedByDefault Remove="wwwroot\js\moonlight.js" />
|
||||||
|
<_ContentIncludedByDefault Remove="wwwroot\svg\logo.svg" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,9 +1,20 @@
|
|||||||
using Moonlight.Client;
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
using Moonlight.Client.Runtime;
|
using Moonlight.Client.Runtime;
|
||||||
|
using Moonlight.Client.Startup;
|
||||||
var startup = new Startup();
|
|
||||||
|
|
||||||
var pluginLoader = new PluginLoader();
|
var pluginLoader = new PluginLoader();
|
||||||
pluginLoader.Initialize();
|
pluginLoader.Initialize();
|
||||||
|
|
||||||
await startup.Run(args, pluginLoader.Instances);
|
var startup = new Startup();
|
||||||
|
|
||||||
|
await startup.Initialize(pluginLoader.Instances);
|
||||||
|
|
||||||
|
var wasmHostBuilder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||||
|
|
||||||
|
await startup.AddMoonlight(wasmHostBuilder);
|
||||||
|
|
||||||
|
var wasmApp = wasmHostBuilder.Build();
|
||||||
|
|
||||||
|
await startup.AddMoonlight(wasmApp);
|
||||||
|
|
||||||
|
await wasmApp.RunAsync();
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"apiUrl": "http://localhost:5165",
|
|
||||||
"hostEnvironment": "Static",
|
|
||||||
"theme": {
|
|
||||||
"variables": {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": [
|
|
||||||
],
|
|
||||||
"plugins": {
|
|
||||||
"assemblies": [
|
|
||||||
],
|
|
||||||
"entrypoints": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 41 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 163 KiB |
@@ -12,7 +12,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PackageTags>frontend</PackageTags>
|
<PackageTags>frontend</PackageTags>
|
||||||
<PackageId>Moonlight.Client</PackageId>
|
<PackageId>Moonlight.Client</PackageId>
|
||||||
<Version>2.1.2</Version>
|
<Version>2.1.3</Version>
|
||||||
<Authors>Moonlight Panel</Authors>
|
<Authors>Moonlight Panel</Authors>
|
||||||
<Description>A build of the client for moonlight development</Description>
|
<Description>A build of the client for moonlight development</Description>
|
||||||
<PackageProjectUrl>https://github.com/Moonlight-Panel/Moonlight</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Moonlight-Panel/Moonlight</PackageProjectUrl>
|
||||||
@@ -27,16 +27,6 @@
|
|||||||
<PackageReference Include="MoonCore.Blazor.FlyonUi" Version="1.0.7" />
|
<PackageReference Include="MoonCore.Blazor.FlyonUi" Version="1.0.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="**\*.cs" Exclude="storage\**\*;bin\**\*;obj\**\*">
|
|
||||||
<Pack>true</Pack>
|
|
||||||
<PackagePath>src</PackagePath>
|
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<None Include="Styles\**\*" Exclude="storage\**\*;bin\**\*;obj\**\*;Styles\node_modules\**\*">
|
|
||||||
<Pack>true</Pack>
|
|
||||||
<PackagePath>styles</PackagePath>
|
|
||||||
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
<Compile Remove="storage\**\*" />
|
<Compile Remove="storage\**\*" />
|
||||||
<Content Remove="storage\**\*" />
|
<Content Remove="storage\**\*" />
|
||||||
<None Remove="storage\**\*" />
|
<None Remove="storage\**\*" />
|
||||||
|
|||||||
@@ -1,310 +0,0 @@
|
|||||||
using System.Text.Json;
|
|
||||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
using MoonCore.Blazor.FlyonUi;
|
|
||||||
using MoonCore.Blazor.FlyonUi.Auth;
|
|
||||||
using MoonCore.Blazor.Services;
|
|
||||||
using MoonCore.Extensions;
|
|
||||||
using MoonCore.Helpers;
|
|
||||||
using MoonCore.Logging;
|
|
||||||
using MoonCore.Permissions;
|
|
||||||
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;
|
|
||||||
|
|
||||||
public class Startup
|
|
||||||
{
|
|
||||||
private string[] Args;
|
|
||||||
|
|
||||||
// Configuration
|
|
||||||
private FrontendConfiguration Configuration;
|
|
||||||
|
|
||||||
// Logging
|
|
||||||
private ILoggerFactory LoggerFactory;
|
|
||||||
private ILogger<Startup> Logger;
|
|
||||||
|
|
||||||
// WebAssemblyHost
|
|
||||||
private WebAssemblyHostBuilder WebAssemblyHostBuilder;
|
|
||||||
private WebAssemblyHost WebAssemblyHost;
|
|
||||||
|
|
||||||
// Plugin Loading
|
|
||||||
private IPluginStartup[] AdditionalPlugins;
|
|
||||||
private IPluginStartup[] PluginStartups;
|
|
||||||
private IServiceProvider PluginLoadServiceProvider;
|
|
||||||
|
|
||||||
public async Task Run(string[] args, IPluginStartup[]? additionalPlugins = null)
|
|
||||||
{
|
|
||||||
Args = args;
|
|
||||||
AdditionalPlugins = additionalPlugins ?? [];
|
|
||||||
|
|
||||||
await PrintVersion();
|
|
||||||
await SetupLogging();
|
|
||||||
|
|
||||||
await CreateWebAssemblyHostBuilder();
|
|
||||||
|
|
||||||
await LoadConfiguration();
|
|
||||||
await InitializePlugins();
|
|
||||||
|
|
||||||
await RegisterLogging();
|
|
||||||
await RegisterBase();
|
|
||||||
await RegisterAuthentication();
|
|
||||||
await HookPluginBuild();
|
|
||||||
|
|
||||||
await BuildWebAssemblyHost();
|
|
||||||
|
|
||||||
await HookPluginConfigure();
|
|
||||||
await LoadAssets();
|
|
||||||
|
|
||||||
await WebAssemblyHost.RunAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task PrintVersion()
|
|
||||||
{
|
|
||||||
// Fancy start console output... yes very fancy :>
|
|
||||||
Console.Write("Running ");
|
|
||||||
|
|
||||||
var rainbow = new Crayon.Rainbow(0.5);
|
|
||||||
foreach (var c in "Moonlight")
|
|
||||||
{
|
|
||||||
Console.Write(
|
|
||||||
rainbow
|
|
||||||
.Next()
|
|
||||||
.Bold()
|
|
||||||
.Text(c.ToString())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LoadConfiguration()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var httpClient = new HttpClient();
|
|
||||||
httpClient.BaseAddress = new Uri(WebAssemblyHostBuilder.HostEnvironment.BaseAddress);
|
|
||||||
|
|
||||||
var jsonText = await httpClient.GetStringAsync("frontend.json");
|
|
||||||
|
|
||||||
Configuration = JsonSerializer.Deserialize<FrontendConfiguration>(jsonText, new JsonSerializerOptions()
|
|
||||||
{
|
|
||||||
PropertyNameCaseInsensitive = true
|
|
||||||
})!;
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddSingleton(Configuration);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogCritical("Unable to load configuration. Unable to continue: {e}", e);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task RegisterBase()
|
|
||||||
{
|
|
||||||
WebAssemblyHostBuilder.RootComponents.Add<App>("#app");
|
|
||||||
WebAssemblyHostBuilder.RootComponents.Add<HeadOutlet>("head::after");
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddScoped(_ =>
|
|
||||||
new HttpClient
|
|
||||||
{
|
|
||||||
BaseAddress = new Uri(Configuration.ApiUrl)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddScoped(sp =>
|
|
||||||
{
|
|
||||||
var httpClient = sp.GetRequiredService<HttpClient>();
|
|
||||||
var httpApiClient = new HttpApiClient(httpClient);
|
|
||||||
|
|
||||||
var localStorageService = sp.GetRequiredService<LocalStorageService>();
|
|
||||||
|
|
||||||
httpApiClient.OnConfigureRequest += async request =>
|
|
||||||
{
|
|
||||||
var accessToken = await localStorageService.GetString("AccessToken");
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(accessToken))
|
|
||||||
return;
|
|
||||||
|
|
||||||
request.Headers.Add("Authorization", $"Bearer {accessToken}");
|
|
||||||
};
|
|
||||||
|
|
||||||
return httpApiClient;
|
|
||||||
});
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddScoped<WindowService>();
|
|
||||||
WebAssemblyHostBuilder.Services.AddFileManagerOperations();
|
|
||||||
WebAssemblyHostBuilder.Services.AddFlyonUiServices();
|
|
||||||
WebAssemblyHostBuilder.Services.AddScoped<LocalStorageService>();
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddScoped<ThemeService>();
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AutoAddServices<Startup>();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Asset Loading
|
|
||||||
|
|
||||||
private async Task LoadAssets()
|
|
||||||
{
|
|
||||||
var jsRuntime = WebAssemblyHost.Services.GetRequiredService<IJSRuntime>();
|
|
||||||
|
|
||||||
foreach (var scriptName in Configuration.Scripts)
|
|
||||||
await jsRuntime.InvokeVoidAsync("moonlight.assets.loadJavascript", scriptName);
|
|
||||||
|
|
||||||
foreach (var styleName in Configuration.Styles)
|
|
||||||
await jsRuntime.InvokeVoidAsync("moonlight.assets.loadStylesheet", styleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Plugins
|
|
||||||
|
|
||||||
private Task InitializePlugins()
|
|
||||||
{
|
|
||||||
// Define minimal service collection
|
|
||||||
var startupSc = new ServiceCollection();
|
|
||||||
|
|
||||||
// Create logging proxy
|
|
||||||
startupSc.AddLogging(builder =>
|
|
||||||
{
|
|
||||||
builder.ClearProviders();
|
|
||||||
builder.AddAnsiConsole();
|
|
||||||
});
|
|
||||||
|
|
||||||
PluginLoadServiceProvider = startupSc.BuildServiceProvider();
|
|
||||||
|
|
||||||
// Collect startups
|
|
||||||
var pluginStartups = new List<IPluginStartup>();
|
|
||||||
|
|
||||||
pluginStartups.AddRange(AdditionalPlugins); // Used by the development server
|
|
||||||
|
|
||||||
// Do NOT remove the following comment, as its used to place the plugin startup register calls
|
|
||||||
// MLBUILD_PLUGIN_STARTUP_HERE
|
|
||||||
|
|
||||||
|
|
||||||
PluginStartups = pluginStartups.ToArray();
|
|
||||||
|
|
||||||
// Add application assembly service
|
|
||||||
var appAssemblyService = new ApplicationAssemblyService();
|
|
||||||
|
|
||||||
appAssemblyService.Assemblies.AddRange(
|
|
||||||
PluginStartups
|
|
||||||
.Select(x => x.GetType().Assembly)
|
|
||||||
.Distinct()
|
|
||||||
);
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddSingleton(appAssemblyService);
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Hooks
|
|
||||||
|
|
||||||
private async Task HookPluginBuild()
|
|
||||||
{
|
|
||||||
foreach (var pluginAppStartup in PluginStartups)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await pluginAppStartup.BuildApplication(PluginLoadServiceProvider, WebAssemblyHostBuilder);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError(
|
|
||||||
"An error occured while processing 'BuildApp' for '{name}': {e}",
|
|
||||||
pluginAppStartup.GetType().FullName,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task HookPluginConfigure()
|
|
||||||
{
|
|
||||||
foreach (var pluginAppStartup in PluginStartups)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await pluginAppStartup.ConfigureApplication(PluginLoadServiceProvider, WebAssemblyHost);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError(
|
|
||||||
"An error occured while processing 'ConfigureApp' for '{name}': {e}",
|
|
||||||
pluginAppStartup.GetType().FullName,
|
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Logging
|
|
||||||
|
|
||||||
private Task SetupLogging()
|
|
||||||
{
|
|
||||||
LoggerFactory = new LoggerFactory();
|
|
||||||
LoggerFactory.AddAnsiConsole();
|
|
||||||
|
|
||||||
Logger = LoggerFactory.CreateLogger<Startup>();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task RegisterLogging()
|
|
||||||
{
|
|
||||||
WebAssemblyHostBuilder.Logging.ClearProviders();
|
|
||||||
WebAssemblyHostBuilder.Logging.AddAnsiConsole();
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Web Application
|
|
||||||
|
|
||||||
private Task CreateWebAssemblyHostBuilder()
|
|
||||||
{
|
|
||||||
WebAssemblyHostBuilder = WebAssemblyHostBuilder.CreateDefault(Args);
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task BuildWebAssemblyHost()
|
|
||||||
{
|
|
||||||
WebAssemblyHost = WebAssemblyHostBuilder.Build();
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Authentication
|
|
||||||
|
|
||||||
private Task RegisterAuthentication()
|
|
||||||
{
|
|
||||||
WebAssemblyHostBuilder.Services.AddAuthorizationCore();
|
|
||||||
WebAssemblyHostBuilder.Services.AddCascadingAuthenticationState();
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddAuthenticationStateManager<RemoteAuthStateManager>();
|
|
||||||
|
|
||||||
WebAssemblyHostBuilder.Services.AddAuthorizationPermissions(options =>
|
|
||||||
{
|
|
||||||
options.ClaimName = "permissions";
|
|
||||||
options.Prefix = "permissions:";
|
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
25
Moonlight.Client/Startup/Startup.Auth.cs
Normal file
25
Moonlight.Client/Startup/Startup.Auth.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MoonCore.Blazor.FlyonUi.Auth;
|
||||||
|
using MoonCore.Permissions;
|
||||||
|
using Moonlight.Client.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task RegisterAuthentication()
|
||||||
|
{
|
||||||
|
WebAssemblyHostBuilder.Services.AddAuthorizationCore();
|
||||||
|
WebAssemblyHostBuilder.Services.AddCascadingAuthenticationState();
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddAuthenticationStateManager<RemoteAuthStateManager>();
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddAuthorizationPermissions(options =>
|
||||||
|
{
|
||||||
|
options.ClaimName = "permissions";
|
||||||
|
options.Prefix = "permissions:";
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
56
Moonlight.Client/Startup/Startup.Base.cs
Normal file
56
Moonlight.Client/Startup/Startup.Base.cs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MoonCore.Blazor.FlyonUi;
|
||||||
|
using MoonCore.Blazor.Services;
|
||||||
|
using MoonCore.Extensions;
|
||||||
|
using MoonCore.Helpers;
|
||||||
|
using Moonlight.Client.Services;
|
||||||
|
using Moonlight.Client.UI;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task RegisterBase()
|
||||||
|
{
|
||||||
|
WebAssemblyHostBuilder.RootComponents.Add<App>("#app");
|
||||||
|
WebAssemblyHostBuilder.RootComponents.Add<HeadOutlet>("head::after");
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddScoped(_ =>
|
||||||
|
new HttpClient
|
||||||
|
{
|
||||||
|
BaseAddress = new Uri(Configuration.ApiUrl)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddScoped(sp =>
|
||||||
|
{
|
||||||
|
var httpClient = sp.GetRequiredService<HttpClient>();
|
||||||
|
var httpApiClient = new HttpApiClient(httpClient);
|
||||||
|
|
||||||
|
var localStorageService = sp.GetRequiredService<LocalStorageService>();
|
||||||
|
|
||||||
|
httpApiClient.OnConfigureRequest += async request =>
|
||||||
|
{
|
||||||
|
var accessToken = await localStorageService.GetString("AccessToken");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(accessToken))
|
||||||
|
return;
|
||||||
|
|
||||||
|
request.Headers.Add("Authorization", $"Bearer {accessToken}");
|
||||||
|
};
|
||||||
|
|
||||||
|
return httpApiClient;
|
||||||
|
});
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddScoped<WindowService>();
|
||||||
|
WebAssemblyHostBuilder.Services.AddFileManagerOperations();
|
||||||
|
WebAssemblyHostBuilder.Services.AddFlyonUiServices();
|
||||||
|
WebAssemblyHostBuilder.Services.AddScoped<LocalStorageService>();
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddScoped<ThemeService>();
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AutoAddServices<Startup>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
24
Moonlight.Client/Startup/Startup.Logging.cs
Normal file
24
Moonlight.Client/Startup/Startup.Logging.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using MoonCore.Logging;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task SetupLogging()
|
||||||
|
{
|
||||||
|
var loggerFactory = new LoggerFactory();
|
||||||
|
loggerFactory.AddAnsiConsole();
|
||||||
|
|
||||||
|
Logger = loggerFactory.CreateLogger<Startup>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task RegisterLogging()
|
||||||
|
{
|
||||||
|
WebAssemblyHostBuilder.Logging.ClearProviders();
|
||||||
|
WebAssemblyHostBuilder.Logging.AddAnsiConsole();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
Moonlight.Client/Startup/Startup.Misc.cs
Normal file
52
Moonlight.Client/Startup/Startup.Misc.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Text.Json;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Moonlight.Shared.Misc;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private Task PrintVersion()
|
||||||
|
{
|
||||||
|
// Fancy start console output... yes very fancy :>
|
||||||
|
Console.Write("Running ");
|
||||||
|
|
||||||
|
var rainbow = new Crayon.Rainbow(0.5);
|
||||||
|
foreach (var c in "Moonlight")
|
||||||
|
{
|
||||||
|
Console.Write(
|
||||||
|
rainbow
|
||||||
|
.Next()
|
||||||
|
.Bold()
|
||||||
|
.Text(c.ToString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadConfiguration()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var httpClient = new HttpClient();
|
||||||
|
httpClient.BaseAddress = new Uri(WebAssemblyHostBuilder.HostEnvironment.BaseAddress);
|
||||||
|
|
||||||
|
var jsonText = await httpClient.GetStringAsync("frontend.json");
|
||||||
|
|
||||||
|
Configuration = JsonSerializer.Deserialize<FrontendConfiguration>(jsonText, new JsonSerializerOptions()
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true
|
||||||
|
})!;
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddSingleton(Configuration);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogCritical("Unable to load configuration. Unable to continue: {e}", e);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
78
Moonlight.Client/Startup/Startup.Plugins.cs
Normal file
78
Moonlight.Client/Startup/Startup.Plugins.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MoonCore.Logging;
|
||||||
|
using Moonlight.Client.Plugins;
|
||||||
|
using Moonlight.Client.Services;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
private IPluginStartup[] PluginStartups;
|
||||||
|
private IServiceProvider PluginLoadServiceProvider;
|
||||||
|
|
||||||
|
private Task InitializePlugins()
|
||||||
|
{
|
||||||
|
// Define minimal service collection
|
||||||
|
var startupSc = new ServiceCollection();
|
||||||
|
|
||||||
|
// Create logging proxy
|
||||||
|
startupSc.AddLogging(builder =>
|
||||||
|
{
|
||||||
|
builder.ClearProviders();
|
||||||
|
builder.AddAnsiConsole();
|
||||||
|
});
|
||||||
|
|
||||||
|
PluginLoadServiceProvider = startupSc.BuildServiceProvider();
|
||||||
|
|
||||||
|
// Add application assembly service
|
||||||
|
var appAssemblyService = new ApplicationAssemblyService();
|
||||||
|
|
||||||
|
appAssemblyService.Assemblies.AddRange(
|
||||||
|
PluginStartups
|
||||||
|
.Select(x => x.GetType().Assembly)
|
||||||
|
.Distinct()
|
||||||
|
);
|
||||||
|
|
||||||
|
WebAssemblyHostBuilder.Services.AddSingleton(appAssemblyService);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HookPluginBuild()
|
||||||
|
{
|
||||||
|
foreach (var pluginAppStartup in PluginStartups)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await pluginAppStartup.BuildApplication(PluginLoadServiceProvider, WebAssemblyHostBuilder);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(
|
||||||
|
"An error occured while processing 'BuildApp' for '{name}': {e}",
|
||||||
|
pluginAppStartup.GetType().FullName,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task HookPluginConfigure()
|
||||||
|
{
|
||||||
|
foreach (var pluginAppStartup in PluginStartups)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await pluginAppStartup.ConfigureApplication(PluginLoadServiceProvider, WebAssemblyHost);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.LogError(
|
||||||
|
"An error occured while processing 'ConfigureApp' for '{name}': {e}",
|
||||||
|
pluginAppStartup.GetType().FullName,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
Moonlight.Client/Startup/Startup.cs
Normal file
48
Moonlight.Client/Startup/Startup.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||||
|
using Moonlight.Client.Plugins;
|
||||||
|
using Moonlight.Shared.Misc;
|
||||||
|
|
||||||
|
namespace Moonlight.Client.Startup;
|
||||||
|
|
||||||
|
public partial class Startup
|
||||||
|
{
|
||||||
|
public ILogger<Startup> Logger { get; private set; }
|
||||||
|
|
||||||
|
// WebAssemblyHost
|
||||||
|
public WebAssemblyHostBuilder WebAssemblyHostBuilder { get; private set; }
|
||||||
|
public WebAssemblyHost WebAssemblyHost { get; private set; }
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
public FrontendConfiguration Configuration { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
|
public Task Initialize(IPluginStartup[]? plugins = null)
|
||||||
|
{
|
||||||
|
PluginStartups = plugins ?? [];
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddMoonlight(WebAssemblyHostBuilder builder)
|
||||||
|
{
|
||||||
|
WebAssemblyHostBuilder = builder;
|
||||||
|
|
||||||
|
await PrintVersion();
|
||||||
|
await SetupLogging();
|
||||||
|
|
||||||
|
await LoadConfiguration();
|
||||||
|
await InitializePlugins();
|
||||||
|
|
||||||
|
await RegisterLogging();
|
||||||
|
await RegisterBase();
|
||||||
|
await RegisterAuthentication();
|
||||||
|
await HookPluginBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task AddMoonlight(WebAssemblyHost assemblyHost)
|
||||||
|
{
|
||||||
|
WebAssemblyHost = assemblyHost;
|
||||||
|
|
||||||
|
await HookPluginConfigure();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
class="inline-grid shrink-0 align-middle">
|
class="inline-grid shrink-0 align-middle">
|
||||||
<img
|
<img
|
||||||
class="h-8 rounded-full"
|
class="h-8 rounded-full"
|
||||||
src="/svg/logo.svg"
|
src="/_content/Moonlight.Client/svg/logo.svg"
|
||||||
alt=""/>
|
alt=""/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<span
|
<span
|
||||||
class="inline-grid shrink-0 align-middle">
|
class="inline-grid shrink-0 align-middle">
|
||||||
<img class="h-8 rounded-full"
|
<img class="h-8 rounded-full"
|
||||||
src="/svg/logo.svg"
|
src="/_content/Moonlight.Client/svg/logo.svg"
|
||||||
alt=""/>
|
alt=""/>
|
||||||
</span>
|
</span>
|
||||||
<span class="truncate">Moonlight v2.1</span>
|
<span class="truncate">Moonlight v2.1</span>
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
<div class="flex min-w-0 items-center gap-3">
|
<div class="flex min-w-0 items-center gap-3">
|
||||||
<span class="inline-grid shrink-0 align-middle">
|
<span class="inline-grid shrink-0 align-middle">
|
||||||
<img class="h-8 rounded-full"
|
<img class="h-8 rounded-full"
|
||||||
src="/img/pfp_placeholder.png"
|
src="/_content/Moonlight.Client/img/pfp_placeholder.png"
|
||||||
alt=""/>
|
alt=""/>
|
||||||
</span>
|
</span>
|
||||||
<div class="min-w-0">
|
<div class="min-w-0">
|
||||||
@@ -118,7 +118,7 @@
|
|||||||
<div data-slot="avatar"
|
<div data-slot="avatar"
|
||||||
class="inline-grid shrink-0 align-middle">
|
class="inline-grid shrink-0 align-middle">
|
||||||
<img
|
<img
|
||||||
class="h-8 rounded-full" src="/placeholder.jpg" alt=""/>
|
class="h-8 rounded-full" src="/_content/Moonlight.Client/svg/logo.svg" alt=""/>
|
||||||
</div>
|
</div>
|
||||||
<div class="truncate">Moonlight v2.1</div>
|
<div class="truncate">Moonlight v2.1</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
@page "/admin/api/create"
|
@page "/admin/api/create"
|
||||||
|
|
||||||
@using System.Text.Json
|
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Shared.Http.Requests.Admin.ApiKeys
|
@using Moonlight.Shared.Http.Requests.Admin.ApiKeys
|
||||||
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
@page "/admin/api/{Id:int}"
|
@page "/admin/api/{Id:int}"
|
||||||
|
|
||||||
@using System.Text.Json
|
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Shared.Http.Requests.Admin.ApiKeys
|
@using Moonlight.Shared.Http.Requests.Admin.ApiKeys
|
||||||
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
@page "/admin/system/files"
|
@page "/admin/system/files"
|
||||||
|
|
||||||
@using Microsoft.AspNetCore.Authorization
|
@using Microsoft.AspNetCore.Authorization
|
||||||
@using MoonCore.Blazor.Services
|
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Client.Implementations
|
@using Moonlight.Client.Implementations
|
||||||
@using MoonCore.Blazor.FlyonUi.Files.Manager
|
@using MoonCore.Blazor.FlyonUi.Files.Manager
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
@page "/admin/users/create"
|
@page "/admin/users/create"
|
||||||
|
|
||||||
@using System.Text.Json
|
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||||
@using MoonCore.Blazor.FlyonUi.Forms
|
@using MoonCore.Blazor.FlyonUi.Forms
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
@page "/admin/users/{Id:int}"
|
@page "/admin/users/{Id:int}"
|
||||||
|
|
||||||
@using System.Text.Json
|
|
||||||
@using MoonCore.Helpers
|
@using MoonCore.Helpers
|
||||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -9,7 +9,7 @@
|
|||||||
<Title>Moonlight.Shared</Title>
|
<Title>Moonlight.Shared</Title>
|
||||||
<PackageTags>shared</PackageTags>
|
<PackageTags>shared</PackageTags>
|
||||||
<PackageId>Moonlight.Shared</PackageId>
|
<PackageId>Moonlight.Shared</PackageId>
|
||||||
<Version>2.1.1</Version>
|
<Version>2.1.3</Version>
|
||||||
<Authors>Moonlight Panel</Authors>
|
<Authors>Moonlight Panel</Authors>
|
||||||
<Description>A build of the shared classes for moonlight development</Description>
|
<Description>A build of the shared classes for moonlight development</Description>
|
||||||
<PackageProjectUrl>https://github.com/Moonlight-Panel/Moonlight</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/Moonlight-Panel/Moonlight</PackageProjectUrl>
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.ApiServer.Runtime
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Client.Runtime", "Moonlight.Client.Runtime\Moonlight.Client.Runtime.csproj", "{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Moonlight.Client.Runtime", "Moonlight.Client.Runtime\Moonlight.Client.Runtime.csproj", "{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Runtime", "Runtime", "{DCE3A43F-ACA8-41C6-BE27-3B3AA033B843}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -38,5 +40,7 @@ Global
|
|||||||
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Release|Any CPU.Build.0 = Release|Any CPU
|
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{97FC686D-BC8A-4145-90C7-CA86B598441E} = {DCE3A43F-ACA8-41C6-BE27-3B3AA033B843}
|
||||||
|
{72F21AA4-4721-4B4C-B2FF-CFDCBB1BCB05} = {DCE3A43F-ACA8-41C6-BE27-3B3AA033B843}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
Reference in New Issue
Block a user