diff --git a/.gitmodules b/.gitmodules
index 616ea2bb..3085af6a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -3,6 +3,6 @@
url = ../Kyoo.Transcoder.git
branch = master
[submodule "WebApp"]
- path = Kyoo.WebApp
+ path = Kyoo.WebApp/Front
url = ../Kyoo.WebApp.git
branch = master
diff --git a/Kyoo.Authentication/AuthenticationModule.cs b/Kyoo.Authentication/AuthenticationModule.cs
index fe7e07e3..26dc5fc8 100644
--- a/Kyoo.Authentication/AuthenticationModule.cs
+++ b/Kyoo.Authentication/AuthenticationModule.cs
@@ -53,9 +53,9 @@ namespace Kyoo.Authentication
private readonly IConfiguration _configuration;
///
- /// A logger factory to allow IdentityServer to log things.
+ /// The logger used to allow IdentityServer to log things.
///
- private readonly ILoggerFactory _loggerFactory;
+ private readonly ILogger _logger;
///
/// The environment information to check if the app runs in debug mode
@@ -67,14 +67,14 @@ namespace Kyoo.Authentication
/// Create a new authentication module instance and use the given configuration and environment.
///
/// The configuration to use
- /// The logger factory to allow IdentityServer to log things
+ /// The logger used to allow IdentityServer to log things
/// The environment information to check if the app runs in debug mode
public AuthenticationModule(IConfiguration configuration,
- ILoggerFactory loggerFactory,
+ ILogger logger,
IWebHostEnvironment environment)
{
_configuration = configuration;
- _loggerFactory = loggerFactory;
+ _logger = logger;
_environment = environment;
}
@@ -83,7 +83,7 @@ namespace Kyoo.Authentication
{
builder.RegisterType().As().SingleInstance();
- DefaultCorsPolicyService cors = new(_loggerFactory.CreateLogger())
+ DefaultCorsPolicyService cors = new(_logger)
{
AllowedOrigins = { new Uri(_configuration.GetPublicUrl()).GetLeftPart(UriPartial.Authority) }
};
diff --git a/Kyoo.Common/Controllers/IPlugin.cs b/Kyoo.Common/Controllers/IPlugin.cs
index 4d86f06c..090774a7 100644
--- a/Kyoo.Common/Controllers/IPlugin.cs
+++ b/Kyoo.Common/Controllers/IPlugin.cs
@@ -93,5 +93,14 @@ namespace Kyoo.Controllers
{
// Skipped
}
+
+ ///
+ /// An optional callback function called when the startups ends and this plugin has been flagged has disabled.
+ /// It allow a plugin to log an error or warning message to inform why it has been disabled.
+ ///
+ void Disabled()
+ {
+ // Skipped
+ }
}
}
\ No newline at end of file
diff --git a/Kyoo.Common/Utility/Utility.cs b/Kyoo.Common/Utility/Utility.cs
index 72d25fd5..ab4fc92d 100644
--- a/Kyoo.Common/Utility/Utility.cs
+++ b/Kyoo.Common/Utility/Utility.cs
@@ -155,7 +155,8 @@ namespace Kyoo
IEnumerable types = genericType.IsInterface
? type.GetInterfaces()
: type.GetInheritanceTree();
- return types.Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericType);
+ return types.Prepend(type)
+ .Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericType);
}
///
@@ -179,7 +180,8 @@ namespace Kyoo
IEnumerable types = genericType.IsInterface
? type.GetInterfaces()
: type.GetInheritanceTree();
- return types.FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericType);
+ return types.Prepend(type)
+ .FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericType);
}
///
diff --git a/Kyoo.WebApp b/Kyoo.WebApp
deleted file mode 160000
index 49cf0c3d..00000000
--- a/Kyoo.WebApp
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 49cf0c3d17f889f40fa9adbb383edfc0d2c99779
diff --git a/Kyoo.WebApp/Front b/Kyoo.WebApp/Front
new file mode 160000
index 00000000..dca10903
--- /dev/null
+++ b/Kyoo.WebApp/Front
@@ -0,0 +1 @@
+Subproject commit dca10903ff54a8999732695b5c2a0a5c94f85200
diff --git a/Kyoo.WebApp/Kyoo.WebApp.csproj b/Kyoo.WebApp/Kyoo.WebApp.csproj
new file mode 100644
index 00000000..dcf3c30e
--- /dev/null
+++ b/Kyoo.WebApp/Kyoo.WebApp.csproj
@@ -0,0 +1,61 @@
+
+
+ net5.0
+ true
+ Latest
+ false
+ $(DefaultItemExcludes);$(SpaRoot)node_modules/**
+ Front/
+
+
+ false
+
+ SDG
+ Zoe Roux
+ https://github.com/AnonymusRaccoon/Kyoo
+ default
+
+
+
+
+
+
+
+
+
+
+
+
+
+ wwwroot/%(RecursiveDir)%(Filename)%(Extension)
+ Always
+
+
+
+
+ wwwroot/%(RecursiveDir)%(Filename)%(Extension)
+ Always
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Kyoo.WebApp/WebAppModule.cs b/Kyoo.WebApp/WebAppModule.cs
new file mode 100644
index 00000000..889ec177
--- /dev/null
+++ b/Kyoo.WebApp/WebAppModule.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Kyoo.Controllers;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.SpaServices.AngularCli;
+using Microsoft.AspNetCore.StaticFiles;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace Kyoo.WebApp
+{
+ ///
+ /// A module to enable the web-app (the front-end of kyoo).
+ ///
+ public class WebAppModule : IPlugin
+ {
+ ///
+ public string Slug => "webapp";
+
+ ///
+ public string Name => "WebApp";
+
+ ///
+ public string Description => "A module to enable the web-app (the front-end of kyoo).";
+
+ ///
+ public Dictionary Configuration => new();
+
+ ///
+ public bool Enabled => Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "wwwroot"));
+
+
+ ///
+ /// A logger only used to inform the user if the webapp could not be enabled.
+ ///
+ private readonly ILogger _logger;
+
+ ///
+ /// Create a new .
+ ///
+ /// A logger only used to inform the user if the webapp could not be enabled.
+ public WebAppModule(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ ///
+ public void Disabled()
+ {
+ _logger.LogError("The web app files could not be found, it will be disabled. " +
+ "If you cloned the project, you probably forgot to use the --recurse flag");
+ }
+
+ ///
+ public void Configure(IServiceCollection services)
+ {
+ services.AddSpaStaticFiles(x =>
+ {
+ x.RootPath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "wwwroot");
+ });
+ }
+
+ ///
+ public IEnumerable ConfigureSteps => new IStartupAction[]
+ {
+ SA.New((app, env) =>
+ {
+ if (!env.IsDevelopment())
+ app.UseSpaStaticFiles();
+ }, SA.StaticFiles),
+ SA.New((app, contentTypeProvider) =>
+ {
+ app.UseStaticFiles(new StaticFileOptions
+ {
+ ContentTypeProvider = contentTypeProvider,
+ FileProvider = new PhysicalFileProvider(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "wwwroot"))
+ });
+ }, SA.StaticFiles),
+ SA.New(app =>
+ {
+ app.Use((ctx, next) =>
+ {
+ ctx.Response.Headers.Remove("X-Powered-By");
+ ctx.Response.Headers.Remove("Server");
+ ctx.Response.Headers.Add("Feature-Policy", "autoplay 'self'; fullscreen");
+ ctx.Response.Headers.Add("Content-Security-Policy", "default-src 'self' blob:; script-src 'self' blob: 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; frame-src 'self'");
+ ctx.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
+ ctx.Response.Headers.Add("Referrer-Policy", "no-referrer");
+ ctx.Response.Headers.Add("Access-Control-Allow-Origin", "null");
+ ctx.Response.Headers.Add("X-Content-Type-Options", "nosniff");
+ return next();
+ });
+ }, SA.Endpoint - 499),
+ SA.New((app, env) =>
+ {
+ app.UseSpa(spa =>
+ {
+ spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp", "Front");
+
+ if (env.IsDevelopment())
+ spa.UseAngularCliServer("start");
+ });
+ }, SA.Endpoint - 500)
+ };
+ }
+}
\ No newline at end of file
diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs
index 2727124c..c55aa906 100644
--- a/Kyoo/Controllers/PluginManager.cs
+++ b/Kyoo/Controllers/PluginManager.cs
@@ -110,12 +110,15 @@ namespace Kyoo.Controllers
_logger.LogTrace("Loading new plugins...");
string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories);
- _plugins.AddRange(plugins
+ IPlugin[] newPlugins = plugins
.Concat(pluginsPaths.SelectMany(LoadPlugin))
.GroupBy(x => x.Name)
.Select(x => x.First())
- .Where(x => x.Enabled)
- );
+ .ToArray();
+ _plugins.AddRange(newPlugins.Where(x => x.Enabled));
+
+ foreach (IPlugin plugin in newPlugins.Where(x => !x.Enabled))
+ plugin.Disabled();
if (!_plugins.Any())
_logger.LogInformation("No plugin enabled");
diff --git a/Kyoo/PluginsStartup.cs b/Kyoo/PluginsStartup.cs
index c13c9364..4f69423d 100644
--- a/Kyoo/PluginsStartup.cs
+++ b/Kyoo/PluginsStartup.cs
@@ -49,7 +49,7 @@ namespace Kyoo
_configuration = configuration;
// TODO enable the web app only if it was build with it.
_plugins.LoadPlugins(
- typeof(CoreModule),
+ typeof(CoreModule),
typeof(WebAppModule),
typeof(AuthenticationModule),
typeof(PostgresModule),
@@ -198,8 +198,16 @@ namespace Kyoo
return _hostEnvironment;
if (serviceType == typeof(IConfiguration))
return _configuration;
- if (serviceType == typeof(ILoggerFactory))
- return _loggerFactory;
+ if (serviceType.GetGenericTypeDefinition() == typeof(ILogger<>))
+ {
+ return Utility.RunGenericMethod
public const string JsonConfigPath = "./settings.json";
+
+ ///
+ /// The string representation of the environment used in .
+ ///
+#if DEBUG
+ private const string Environment = "Development";
+#else
+ private const string Environment = "Production";
+#endif
///
/// Main function of the program
///
/// Command line arguments
- [SuppressMessage("ReSharper", "ConditionIsAlwaysTrueOrFalse")]
public static async Task Main(string[] args)
{
if (!File.Exists(JsonConfigPath))
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, JsonConfigPath), JsonConfigPath);
- IHostBuilder builder = CreateWebHostBuilder(args);
+ IHost host = CreateWebHostBuilder(args)
+ .UseEnvironment(Environment)
+ .Build();
- // TODO remove ENVIRONEMENT handling and force it to the build env
-
- bool? debug = Environment.GetEnvironmentVariable("ENVIRONMENT")?.ToLowerInvariant() switch
- {
- "d" => true,
- "dev" => true,
- "debug" => true,
- "development" => true,
- "p" => false,
- "prod" => false,
- "production" => false,
- _ => null
- };
-
- if (debug == null && Environment.GetEnvironmentVariable("ENVIRONMENT") != null)
- {
- Console.WriteLine(
- $"Invalid ENVIRONMENT variable. Supported values are \"debug\" and \"prod\". Ignoring...");
- }
-
- #if DEBUG
- debug ??= true;
- #endif
-
- if (debug != null)
- builder = builder.UseEnvironment(debug == true ? "Development" : "Production");
-
try
{
- Console.WriteLine($"Running as {Environment.UserName}.");
- await builder.Build().RunAsync();
+ host.Services.GetRequiredService>()
+ .LogInformation("Running as {Name}", System.Environment.UserName);
+ await host.RunAsync();
}
catch (Exception ex)
{
- await Console.Error.WriteLineAsync($"Unhandled exception: {ex}");
+ host.Services.GetRequiredService>().LogCritical(ex, "Unhandled exception");
}
}
@@ -79,7 +62,7 @@ namespace Kyoo
/// The modified configuration builder
private static IConfigurationBuilder SetupConfig(IConfigurationBuilder builder, string[] args)
{
- return builder.SetBasePath(Environment.CurrentDirectory)
+ return builder.SetBasePath(System.Environment.CurrentDirectory)
.AddJsonFile(JsonConfigPath, false, true)
.AddEnvironmentVariables()
.AddCommandLine(args);
@@ -129,5 +112,10 @@ namespace Kyoo
.UseStartup(host => PluginsStartup.FromWebHost(host, loggingConfiguration))
);
}
+
+ ///
+ /// An useless class only used to have a logger in the main.
+ ///
+ private class Application {}
}
}