Removing config things

This commit is contained in:
Zoe Roux 2023-03-16 02:32:37 +09:00
parent ebe2da0309
commit 03bd5b4c78
26 changed files with 54 additions and 700 deletions

View File

@ -1,7 +1,12 @@
# Useful config options
LIBRARY_ROOT=./video
TVDB__APIKEY=
THEMOVIEDB__APIKEY=
AUTHENTICATION_SECRET=
PUBLIC_BACK_URL=http://localhost:5000
AUTHENTICATION_SECRET=
# To debug the front end, you can set the following to an external backend
KYOO_URL=https://kyoo.sdg.moe/api
# Database things (optional)
POSTGRES_USER=KyooUser

View File

@ -5,17 +5,15 @@ COPY src/Kyoo.Transcoder .
RUN cmake . && make -j
FROM mcr.microsoft.com/dotnet/sdk:6.0 as builder
WORKDIR /kyoo
COPY Kyoo.sln ./Kyoo.sln
COPY nuget.config ./nuget.config
COPY src/Directory.Build.props src/Directory.Build.props
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
COPY src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj
COPY src/Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj src/Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
COPY src/Kyoo.Host.Console/Kyoo.Host.Console.csproj src/Kyoo.Host.Console/Kyoo.Host.Console.csproj
COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
COPY src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
@ -24,12 +22,14 @@ RUN dotnet restore
COPY . .
ARG VERSION
RUN dotnet publish --no-restore -c Release -o /opt/kyoo "-p:Version=${VERSION:-"0.0.0-dev"};SkipTranscoder=true" src/Kyoo.Host.Console
RUN dotnet publish --no-restore -c Release -o /app "-p:Version=${VERSION:-"0.0.0-dev"};SkipTranscoder=true" src/Kyoo.Host
FROM mcr.microsoft.com/dotnet/aspnet:6.0
RUN apt-get update && apt-get install -y libavutil-dev libavcodec-dev libavformat-dev
EXPOSE 5000
COPY --from=builder /opt/kyoo /usr/lib/kyoo
COPY --from=builder /app /app
COPY --from=transcoder /transcoder/libtranscoder.so /usr/lib/kyoo
CMD ["/usr/lib/kyoo/Kyoo.Host.Console"]
WORKDIR /kyoo
EXPOSE 5000
CMD ["/app/Kyoo.Host"]

View File

@ -8,26 +8,24 @@ FROM mcr.microsoft.com/dotnet/sdk:6.0
RUN apt-get update && apt-get install -y libavutil-dev libavcodec-dev libavformat-dev
WORKDIR /app
COPY Kyoo.sln ./Kyoo.sln
COPY nuget.config ./nuget.config
COPY src/Directory.Build.props src/Directory.Build.props
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
COPY src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj
COPY src/Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj src/Kyoo.TheMovieDb/Kyoo.TheMovieDb.csproj
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
COPY src/Kyoo.Host.Console/Kyoo.Host.Console.csproj src/Kyoo.Host.Console/Kyoo.Host.Console.csproj
COPY src/Kyoo.Host/Kyoo.Host.csproj src/Kyoo.Host/Kyoo.Host.csproj
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
COPY src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
COPY tests/Kyoo.Tests/Kyoo.Tests.csproj tests/Kyoo.Tests/Kyoo.Tests.csproj
RUN dotnet restore
COPY --from=transcoder /transcoder/libtranscoder.so /usr/lib/
WORKDIR /kyoo
EXPOSE 5000
ENV DOTNET_USE_POLLING_FILE_WATCHER 1
CMD ["dotnet", "watch", "run", "--no-restore", "--project", "src/Kyoo.Host.Console"]
CMD ["dotnet", "watch", "run", "--no-restore", "--project", "/app/src/Kyoo.Host"]

View File

@ -13,19 +13,13 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.TheMovieDb", "src\Kyoo
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Tests", "tests\Kyoo.Tests\Kyoo.Tests.csproj", "{0C8AA7EA-E723-4532-852F-35AA4E8AFED5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.Console", "src\Kyoo.Host.Console\Kyoo.Host.Console.csproj", "{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Swagger", "src\Kyoo.Swagger\Kyoo.Swagger.csproj", "{7D1A7596-73F6-4D35-842E-A5AD9C620596}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{FEAE1B0E-D797-470F-9030-0EF743575ECC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Providers", "Providers", "{8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Databases", "Databases", "{865461CA-EC06-4B42-91CF-8723B0A9BB67}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosts", "Hosts", "{C569FF25-7E01-484C-9F72-5B99845AD94B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host.Generic", "src\Kyoo.Host.Generic\Kyoo.Host.Generic.csproj", "{0938459E-2E2B-457F-8120-7D8CA93866A6}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Host", "src\Kyoo.Host\Kyoo.Host.csproj", "{0938459E-2E2B-457F-8120-7D8CA93866A6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -73,10 +67,6 @@ Global
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Release|Any CPU.Build.0 = Release|Any CPU
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5}.Release|Any CPU.Build.0 = Release|Any CPU
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -90,9 +80,5 @@ Global
{0C8AA7EA-E723-4532-852F-35AA4E8AFED5} = {FEAE1B0E-D797-470F-9030-0EF743575ECC}
{BAB270D4-E0EA-4329-BA65-512FDAB01001} = {8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}
{D06BF829-23F5-40F3-A62D-627D9F4B4D6C} = {8D28F5EF-0CD7-4697-A2A7-24EC31A48F21}
{3213C96D-0BF3-460B-A8B5-B9977229408A} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
{6515380E-1E57-42DA-B6E3-E1C8A848818A} = {865461CA-EC06-4B42-91CF-8723B0A9BB67}
{D8658BEA-8949-45AC-BEBB-A4FFC4F800F5} = {C569FF25-7E01-484C-9F72-5B99845AD94B}
{0938459E-2E2B-457F-8120-7D8CA93866A6} = {C569FF25-7E01-484C-9F72-5B99845AD94B}
EndGlobalSection
EndGlobal

View File

@ -1,49 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// An interface that allow one to interact with the host and shutdown or restart the app.
/// </summary>
public interface IApplication
{
/// <summary>
/// Shutdown the process and stop gracefully.
/// </summary>
void Shutdown();
/// <summary>
/// Restart Kyoo from scratch, reload plugins, configurations and restart the web server.
/// </summary>
void Restart();
/// <summary>
/// Get the data directory.
/// </summary>
/// <returns>Retrieve the data directory where runtime data should be stored.</returns>
string GetDataDirectory();
/// <summary>
/// Retrieve the path of the json configuration file
/// (relative to the data directory, see <see cref="GetDataDirectory"/>).
/// </summary>
/// <returns>The configuration file name.</returns>
string GetConfigFile();
}
}

View File

@ -1,86 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
namespace Kyoo.Abstractions.Controllers
{
/// <summary>
/// A class to ease configuration management. This work WITH Microsoft's package, you can still use IOptions patterns
/// to access your options, this manager ease dynamic work and editing.
/// It works with <see cref="ConfigurationReference"/>.
/// </summary>
public interface IConfigurationManager
{
/// <summary>
/// Add an editable configuration to the editable configuration list.
/// </summary>
/// <param name="path">The root path of the editable configuration. It should not be a nested type.</param>
/// <typeparam name="T">The type of the configuration.</typeparam>
void AddTyped<T>(string path);
/// <summary>
/// Add an editable configuration to the editable configuration list.
/// WARNING: this method allow you to add an unmanaged type. This type won't be editable. This can be used
/// for external libraries or variable arguments.
/// </summary>
/// <param name="path">The root path of the editable configuration. It should not be a nested type.</param>
void AddUntyped(string path);
/// <summary>
/// An helper method of <see cref="AddTyped{T}"/> and <see cref="AddUntyped"/>.
/// This register a typed value if <paramref name="type"/> is not <c>null</c> and registers an untyped type
/// if <paramref name="type"/> is <c>null</c>.
/// </summary>
/// <param name="path">The root path of the editable configuration. It should not be a nested type.</param>
/// <param name="type">The type of the configuration or null.</param>
void Register(string path, [CanBeNull] Type type);
/// <summary>
/// Get the value of a setting using it's path.
/// </summary>
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
/// <returns>The value of the settings (if it's a strongly typed one, the given type is instantiated.</returns>
object GetValue(string path);
/// <summary>
/// Get the value of a setting using it's path.
/// If your don't need a strongly typed value, see <see cref="GetValue"/>.
/// </summary>
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
/// <typeparam name="T">A type to strongly type your option.</typeparam>
/// <exception cref="InvalidCastException">If your type is not the same as the registered type.</exception>
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
/// <returns>The value of the settings (if it's a strongly typed one, the given type is instantiated.</returns>
T GetValue<T>(string path);
/// <summary>
/// Edit the value of a setting using it's path. Save it to the json file.
/// </summary>
/// <param name="path">The path of the resource (can be separated by ':' or '__').</param>
/// <param name="value">The new value of the resource.</param>
/// <exception cref="ItemNotFoundException">No setting found at the given path.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task EditValue(string path, object value);
}
}

View File

@ -1,220 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Exceptions;
using Kyoo.Core.Api;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
namespace Kyoo.Core.Controllers
{
/// <summary>
/// A class to ease configuration management. This work WITH Microsoft's package, you can still use IOptions patterns
/// to access your options, this manager ease dynamic work and editing.
/// It works with <see cref="ConfigurationReference"/>.
/// </summary>
public class ConfigurationManager : IConfigurationManager
{
/// <summary>
/// The configuration to retrieve and edit.
/// </summary>
private readonly IConfiguration _configuration;
/// <summary>
/// The application running Kyoo, it is used to retrieve the configuration file.
/// </summary>
private readonly IApplication _application;
/// <summary>
/// The strongly typed list of options
/// </summary>
private readonly Dictionary<string, Type> _references;
/// <summary>
/// Create a new <see cref="ConfigurationApi"/> using the given configuration.
/// </summary>
/// <param name="configuration">The configuration to use.</param>
/// <param name="references">The strongly typed option list.</param>
/// <param name="application">The application running Kyoo, it is used to retrieve the configuration file.</param>
public ConfigurationManager(IConfiguration configuration, IEnumerable<ConfigurationReference> references, IApplication application)
{
_configuration = configuration;
_application = application;
_references = references.ToDictionary(x => x.Path, x => x.Type, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Transform the configuration section in nested expando objects.
/// </summary>
/// <param name="config">The section to convert</param>
/// <returns>The converted section</returns>
private static object _ToUntyped(IConfigurationSection config)
{
ExpandoObject obj = new();
foreach (IConfigurationSection section in config.GetChildren())
{
obj.TryAdd(section.Key, _ToUntyped(section));
}
if (!obj.Any())
return config.Value;
return obj;
}
/// <inheritdoc />
public void AddTyped<T>(string path)
{
foreach (ConfigurationReference confRef in ConfigurationReference.CreateReference<T>(path))
_references.Add(confRef.Path, confRef.Type);
}
/// <inheritdoc />
public void AddUntyped(string path)
{
ConfigurationReference config = ConfigurationReference.CreateUntyped(path);
_references.Add(config.Path, config.Type);
}
/// <inheritdoc />
public void Register(string path, Type type)
{
if (type == null)
{
ConfigurationReference config = ConfigurationReference.CreateUntyped(path);
_references.Add(config.Path, config.Type);
}
else
{
foreach (ConfigurationReference confRef in ConfigurationReference.CreateReference(path, type))
_references.Add(confRef.Path, confRef.Type);
}
}
/// <summary>
/// Get the type of the resource at the given path
/// </summary>
/// <param name="path">The path of the resource</param>
/// <exception cref="ArgumentException">The path is not editable or readable</exception>
/// <exception cref="ItemNotFoundException">No configuration exists for the given path</exception>
/// <returns>The type of the resource at the given path</returns>
private Type _GetType(string path)
{
path = path.Replace("__", ":");
// TODO handle lists and dictionaries.
if (_references.TryGetValue(path, out Type type))
{
if (type != null)
return type;
throw new ArgumentException($"The configuration at {path} is not editable or readable.");
}
string parent = path.Contains(':') ? path[..path.IndexOf(':')] : null;
if (parent != null && _references.TryGetValue(parent, out type) && type == null)
throw new ArgumentException($"The configuration at {path} is not editable or readable.");
throw new ItemNotFoundException($"No configuration exists for the name: {path}");
}
/// <inheritdoc />
public object GetValue(string path)
{
path = path.Replace("__", ":");
// TODO handle lists and dictionaries.
Type type = _GetType(path);
object ret = _configuration.GetValue(type, path);
if (ret != null)
return ret;
object option = Activator.CreateInstance(type);
_configuration.Bind(path, option);
return option;
}
/// <inheritdoc />
public T GetValue<T>(string path)
{
path = path.Replace("__", ":");
// TODO handle lists and dictionaries.
Type type = _GetType(path);
if (typeof(T).IsAssignableFrom(type))
{
throw new InvalidCastException($"The type {typeof(T).Name} is not valid for " +
$"a resource of type {type.Name}.");
}
return (T)GetValue(path);
}
/// <inheritdoc />
public async Task EditValue(string path, object value)
{
path = path.Replace("__", ":");
Type type = _GetType(path);
value = JObject.FromObject(value).ToObject(type);
if (value == null)
throw new ArgumentException("Invalid value format.");
ExpandoObject config = _ToObject(_configuration);
IDictionary<string, object> configDic = config;
configDic[path] = value;
JObject obj = JObject.FromObject(config);
await using StreamWriter writer = new(_application.GetConfigFile());
await writer.WriteAsync(obj.ToString());
}
/// <summary>
/// Transform a configuration to a strongly typed object (the root configuration is an <see cref="ExpandoObject"/>
/// but child elements are using strong types.
/// </summary>
/// <param name="config">The configuration to transform</param>
/// <returns>A strongly typed representation of the configuration.</returns>
[SuppressMessage("ReSharper", "RedundantJumpStatement",
Justification = "A catch block should not be empty.")]
private ExpandoObject _ToObject(IConfiguration config)
{
ExpandoObject obj = new();
foreach (IConfigurationSection section in config.GetChildren())
{
try
{
Type type = _GetType(section.Path);
obj.TryAdd(section.Key, section.Get(type));
}
catch (ArgumentException)
{
obj.TryAdd(section.Key, _ToUntyped(section));
}
catch
{
continue;
}
}
return obj;
}
}
}

View File

@ -66,7 +66,6 @@ namespace Kyoo.Core
builder.RegisterType<LocalFileSystem>().As<IFileSystem>().SingleInstance();
builder.RegisterType<HttpFileSystem>().As<IFileSystem>().SingleInstance();
builder.RegisterType<ConfigurationManager>().As<IConfigurationManager>().SingleInstance();
builder.RegisterType<Transcoder>().As<ITranscoder>().SingleInstance();
builder.RegisterType<ThumbnailsManager>().As<IThumbnailsManager>().InstancePerLifetimeScope();
builder.RegisterType<LibraryManager>().As<ILibraryManager>().InstancePerLifetimeScope();

View File

@ -1,93 +0,0 @@
// Kyoo - A portable and vast media library solution.
// Copyright (c) Kyoo.
//
// See AUTHORS.md and LICENSE file in the project root for full license information.
//
// Kyoo is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// any later version.
//
// Kyoo is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Permissions;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using static Kyoo.Abstractions.Models.Utils.Constants;
namespace Kyoo.Core.Api
{
/// <summary>
/// An API to retrieve or edit configuration settings
/// </summary>
[Route("configuration")]
[Route("config", Order = AlternativeRoute)]
[ApiController]
[PartialPermission("Configuration", Group = Group.Admin)]
[ApiDefinition("Configuration", Group = AdminGroup)]
public class ConfigurationApi : Controller
{
/// <summary>
/// The configuration manager used to retrieve and edit configuration values (while being type safe).
/// </summary>
private readonly IConfigurationManager _manager;
/// <summary>
/// Create a new <see cref="ConfigurationApi"/> using the given configuration.
/// </summary>
/// <param name="manager">The configuration manager used to retrieve and edit configuration values</param>
public ConfigurationApi(IConfigurationManager manager)
{
_manager = manager;
}
/// <summary>
/// Get config value
/// </summary>
/// <remarks>
/// Retrieve a configuration's value from it's slug.
/// </remarks>
/// <param name="slug">The permission to retrieve. You can use ':' or "__" to get a child value.</param>
/// <returns>The associate value or list of values.</returns>
/// <response code="200">Return the configuration value or the list of configurations</response>
/// <response code="404">No configuration exists for the given slug</response>
[HttpGet("{slug}")]
[PartialPermission(Kind.Read)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public ActionResult<object> GetConfiguration(string slug)
{
return _manager.GetValue(slug);
}
/// <summary>
/// Edit config
/// </summary>
/// <remarks>
/// Edit a configuration's value from it's slug.
/// </remarks>
/// <param name="slug">The permission to edit. You can use ':' or "__" to get a child value.</param>
/// <param name="newValue">The new value of the configuration</param>
/// <returns>The edited value.</returns>
/// <response code="200">Return the edited value</response>
/// <response code="404">No configuration exists for the given slug</response>
[HttpPut("{slug}")]
[PartialPermission(Kind.Write)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<object>> EditConfiguration(string slug, [FromBody] object newValue)
{
await _manager.EditValue(slug, newValue);
return newValue;
}
}
}

View File

@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<AssemblyName>Kyoo.Host.Console</AssemblyName>
<RootNamespace>Kyoo.Host.Console</RootNamespace>
<StartupObject>Kyoo.Host.Console.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Kyoo.Host.Generic/Kyoo.Host.Generic.csproj" />
</ItemGroup>
</Project>

View File

@ -23,43 +23,29 @@ using System.Threading;
using System.Threading.Tasks;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using JetBrains.Annotations;
using Kyoo.Abstractions.Controllers;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Hosting.Systemd;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Templates;
using Serilog.Templates.Themes;
using ILogger = Serilog.ILogger;
namespace Kyoo.Host.Generic
namespace Kyoo.Host
{
/// <summary>
/// The main implementation of <see cref="IApplication"/>.
/// Hosts of kyoo (main functions) generally only create a new <see cref="Application"/>
/// and return <see cref="Start(string[])"/>.
/// </summary>
public class Application : IApplication, IDisposable
public class Application : IDisposable
{
/// <summary>
/// The environment in witch Kyoo will run (ether "Production" or "Development").
/// </summary>
private readonly string _environment;
/// <summary>
/// The path to the data directory.
/// </summary>
private string _dataDir;
/// <summary>
/// Should the application restart after a shutdown?
/// </summary>
private bool _shouldRestart;
/// <summary>
/// The cancellation token source used to allow the app to be shutdown or restarted.
/// </summary>
@ -99,10 +85,8 @@ namespace Kyoo.Host.Generic
/// <returns>A task representing the whole process</returns>
public async Task Start(string[] args, Action<ContainerBuilder> configure)
{
_dataDir = _SetupDataDir(args);
LoggerConfiguration config = new();
_ConfigureLogging(config, null, null);
_ConfigureLogging(config);
Log.Logger = config.CreateBootstrapLogger();
_logger = Log.Logger.ForContext<Application>();
@ -110,8 +94,6 @@ namespace Kyoo.Host.Generic
AppDomain.CurrentDomain.UnhandledException += (_, ex)
=> Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception");
do
{
IHost host = _CreateWebHostBuilder(args)
.ConfigureContainer(configure)
.Build();
@ -119,68 +101,6 @@ namespace Kyoo.Host.Generic
_tokenSource = new CancellationTokenSource();
await _StartWithHost(host, _tokenSource.Token);
}
while (_shouldRestart);
}
/// <inheritdoc />
public void Shutdown()
{
_shouldRestart = false;
_tokenSource.Cancel();
}
/// <inheritdoc />
public void Restart()
{
_shouldRestart = true;
_tokenSource.Cancel();
}
/// <inheritdoc />
public string GetDataDirectory()
{
return _dataDir;
}
/// <inheritdoc />
public string GetConfigFile()
{
return "./settings.json";
}
/// <summary>
/// Parse the data directory from environment variables and command line arguments, create it if necessary.
/// Set the current directory to said data folder and place a default configuration file if it does not already
/// exists.
/// </summary>
/// <param name="args">The command line arguments</param>
/// <returns>The current data directory.</returns>
private string _SetupDataDir(string[] args)
{
IConfiguration parsed = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddEnvironmentVariables("KYOO_")
.AddCommandLine(args)
.Build();
string path = parsed.GetValue<string>("datadir");
path ??= Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Kyoo");
path = Path.GetFullPath(path);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
Environment.CurrentDirectory = path;
if (!File.Exists(GetConfigFile()))
{
File.Copy(
Path.Join(AppDomain.CurrentDomain.BaseDirectory, GetConfigFile()),
GetConfigFile()
);
}
return path;
}
/// <summary>
/// Start the given host and log failing exceptions.
@ -191,9 +111,7 @@ namespace Kyoo.Host.Generic
{
try
{
_logger.Information("Running as {Name}", Environment.UserName);
_logger.Information("Version: {Version}", Assembly.GetExecutingAssembly().GetName().Version.ToString(3));
_logger.Information("Data directory: {DataDirectory}", GetDataDirectory());
await host.RunAsync(cancellationToken);
}
catch (Exception ex)
@ -209,25 +127,18 @@ namespace Kyoo.Host.Generic
/// <returns>A new web host instance</returns>
private IHostBuilder _CreateWebHostBuilder(string[] args)
{
IConfiguration configuration = _SetupConfig(new ConfigurationBuilder(), args).Build();
return new HostBuilder()
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
.UseEnvironment(_environment)
.UseSystemd()
.ConfigureAppConfiguration(x => _SetupConfig(x, args))
.UseSerilog((host, services, builder) => _ConfigureLogging(builder, host.Configuration, services))
.UseSerilog((host, services, builder) => _ConfigureLogging(builder))
.ConfigureServices(x => x.AddRouting())
.ConfigureContainer<ContainerBuilder>(x =>
{
x.RegisterInstance(this).As<IApplication>().SingleInstance().ExternallyOwned();
})
.ConfigureWebHost(x => x
.UseKestrel(options => { options.AddServerHeader = false; })
.UseIIS()
.UseIISIntegration()
.UseUrls(configuration.GetValue<string>("basics:url"))
.UseUrls("http://*:5000")
.UseStartup(host => PluginsStartup.FromWebHost(host, new LoggerFactory().AddSerilog()))
);
}
@ -240,9 +151,8 @@ namespace Kyoo.Host.Generic
/// <returns>The modified configuration builder</returns>
private IConfigurationBuilder _SetupConfig(IConfigurationBuilder builder, string[] args)
{
return builder.SetBasePath(GetDataDirectory())
.AddJsonFile(Path.Join(AppDomain.CurrentDomain.BaseDirectory, GetConfigFile()), false, true)
.AddJsonFile(GetConfigFile(), false, true)
return builder
.AddJsonFile(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "./settings.json"), false, true)
.AddEnvironmentVariables()
.AddEnvironmentVariables("KYOO_")
.AddCommandLine(args);
@ -252,51 +162,13 @@ namespace Kyoo.Host.Generic
/// Configure the logging.
/// </summary>
/// <param name="builder">The logger builder to configure.</param>
/// <param name="configuration">The configuration to read settings from.</param>
/// <param name="services">The services to read configuration from.</param>
private void _ConfigureLogging(LoggerConfiguration builder,
[CanBeNull] IConfiguration configuration,
[CanBeNull] IServiceProvider services)
private void _ConfigureLogging(LoggerConfiguration builder)
{
if (configuration != null)
{
try
{
builder.ReadFrom.Configuration(configuration, "logging");
}
catch (Exception ex)
{
_logger.Fatal(ex, "Could not read serilog configuration");
}
}
if (services != null)
builder.ReadFrom.Services(services);
const string template =
"[{@t:HH:mm:ss} {@l:u3} {Substring(SourceContext, LastIndexOf(SourceContext, '.') + 1), 25} "
+ "({@i:D10})] {@m}{#if not EndsWith(@m, '\n')}\n{#end}{@x}";
if (SystemdHelpers.IsSystemdService())
{
const string syslogTemplate = "[{SourceContext,-35}] {Message:lj}{NewLine}{Exception}";
builder
.WriteTo.Console(new ExpressionTemplate(template, theme: TemplateTheme.Code))
.WriteTo.LocalSyslog("Kyoo", outputTemplate: syslogTemplate)
.Enrich.WithThreadId()
.Enrich.FromLogContext();
return;
}
builder
.WriteTo.Console(new ExpressionTemplate(template, theme: TemplateTheme.Code))
.WriteTo.File(
path: Path.Combine(GetDataDirectory(), "logs", "log-.log"),
formatter: new ExpressionTemplate(template),
rollingInterval: RollingInterval.Day,
rollOnFileSizeLimit: true
)
.Enrich.WithThreadId()
.Enrich.FromLogContext();
}

View File

@ -31,7 +31,7 @@ using Kyoo.Core.Models.Options;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
namespace Kyoo.Host.Generic.Controllers
namespace Kyoo.Host.Controllers
{
/// <summary>
/// A composite that merge every <see cref="IFileSystem"/> available

View File

@ -28,7 +28,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Kyoo.Host.Generic.Controllers
namespace Kyoo.Host.Controllers
{
/// <summary>
/// An implementation of <see cref="IPluginManager"/>.

View File

@ -33,7 +33,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Kyoo.Host.Generic.Controllers
namespace Kyoo.Host.Controllers
{
/// <summary>
/// A service to handle long running tasks and a background runner.

View File

@ -24,12 +24,12 @@ using Kyoo.Abstractions;
using Kyoo.Abstractions.Controllers;
using Kyoo.Core.Models.Options;
using Kyoo.Core.Tasks;
using Kyoo.Host.Generic.Controllers;
using Kyoo.Host.Controllers;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using Serilog;
namespace Kyoo.Host.Generic
namespace Kyoo.Host
{
/// <summary>
/// A module that registers host controllers and other needed things.

View File

@ -1,12 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AssemblyName>Kyoo.Host.Generic</AssemblyName>
<RootNamespace>Kyoo.Host.Generic</RootNamespace>
<PackageId>Kyoo.Host</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="5.0.1" />
<PackageReference Include="Serilog" Version="2.10.0" />
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.1.0" />

View File

@ -25,7 +25,7 @@ using Kyoo.Abstractions.Controllers;
using Kyoo.Authentication;
using Kyoo.Core;
using Kyoo.Core.Models.Options;
using Kyoo.Host.Generic.Controllers;
using Kyoo.Host.Controllers;
using Kyoo.Postgresql;
using Kyoo.Swagger;
using Kyoo.TheMovieDb;
@ -39,7 +39,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Kyoo.Host.Generic
namespace Kyoo.Host
{
/// <summary>
/// The Startup class is used to configure the AspNet's webhost.
@ -148,8 +148,7 @@ namespace Kyoo.Host.Generic
/// </summary>
/// <param name="app">The asp net host to configure</param>
/// <param name="container">An autofac container used to create a new scope to configure asp-net.</param>
/// <param name="config">The configuration manager used to register strongly typed config.</param>
public void Configure(IApplicationBuilder app, ILifetimeScope container, IConfigurationManager config)
public void Configure(IApplicationBuilder app, ILifetimeScope container)
{
IEnumerable<IStartupAction> steps = _plugins.GetAllPlugins()
.Append(_hostModule)
@ -162,17 +161,6 @@ namespace Kyoo.Host.Generic
IServiceProvider provider = scope.Resolve<IServiceProvider>();
foreach (IStartupAction step in steps)
step.Run(provider);
IEnumerable<KeyValuePair<string, Type>> pluginConfig = _plugins.GetAllPlugins()
.Append(_hostModule)
.SelectMany(x => x.Configuration)
.GroupBy(x => x.Key.Split(':').First())
.Select(x => x
.OrderBy(y => y.Key.Length)
.First()
);
foreach ((string path, Type type) in pluginConfig)
config.Register(path, type);
}
/// <summary>

View File

@ -17,10 +17,10 @@
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System.Threading.Tasks;
using Kyoo.Host.Generic;
using Kyoo.Host;
using Microsoft.AspNetCore.Hosting;
namespace Kyoo.Host.Console
namespace Kyoo.Host
{
/// <summary>
/// Program entrypoint.

View File

@ -1,6 +1,5 @@
{
"basics": {
"url": "http://*:5000",
"pluginsPath": "plugins/",
"transmuxPath": "cached/transmux",
"transcodePath": "cached/transcode",
@ -44,12 +43,5 @@
},
"profilePicturePath": "users/",
"secret": "4c@mraGB!KRfF@kpS8740y9FcHemKxBsqqxLbdR?"
},
"tvdb": {
"apiKey": ""
},
"themoviedb": {
"apiKey": ""
}
}

View File

@ -6,7 +6,7 @@
<ItemGroup>
<PackageReference Include="EFCore.NamingConventions" Version="5.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.8">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View File

@ -19,7 +19,6 @@
using System;
using System.Threading.Tasks;
using Kyoo.Postgresql;
using Kyoo.Postgresql;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Npgsql;

View File

@ -30,7 +30,7 @@
<ItemGroup>
<ProjectReference Include="../../src/Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
<ProjectReference Include="../../src/Kyoo.Host.Generic/Kyoo.Host.Generic.csproj" />
<ProjectReference Include="..\..\src\Kyoo.Host\Kyoo.Host.csproj" />
<ProjectReference Include="../../src/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj" />
</ItemGroup>
</Project>

View File

@ -8,15 +8,8 @@ services:
ports:
- "5000:5000"
restart: on-failure
environment:
- KYOO_DATADIR=/var/lib/kyoo
- DATABASE__ENABLED=postgres
- DATABASE__CONFIGURATIONS__POSTGRES__SERVER=postgres
- DATABASE__CONFIGURATIONS__POSTGRES__USER=${POSTGRES_USER}
- DATABASE__CONFIGURATIONS__POSTGRES__PASSWORD=${POSTGRES_PASSWORD}
- TVDB__APIKEY=${TVDB__APIKEY}
- THEMOVIEDB__APIKEY=${THEMOVIEDB__APIKEY}
- LIBRARY_ROOT=/video
env_file:
- ./.env
depends_on:
- postgres
volumes:
@ -58,10 +51,8 @@ services:
postgres:
image: "postgres"
restart: on-failure
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
env_file:
- ./.env
volumes:
- db:/var/lib/postgresql/data

View File

@ -4,21 +4,13 @@ services:
back:
image: zoriya/kyoo_back:edge
restart: on-failure
environment:
- KYOO_DATADIR=/var/lib/kyoo
- DATABASE__ENABLED=postgres
- DATABASE__CONFIGURATIONS__POSTGRES__SERVER=postgres
- DATABASE__CONFIGURATIONS__POSTGRES__USER=${POSTGRES_USER}
- DATABASE__CONFIGURATIONS__POSTGRES__PASSWORD=${POSTGRES_PASSWORD}
- DATABASE__CONFIGURATIONS__POSTGRES__DATABASE=${POSTGRES_DB}
- TVDB__APIKEY=${TVDB__APIKEY}
- THEMOVIEDB__APIKEY=${THEMOVIEDB__APIKEY}
- LIBRARY_ROOT=/video
env_file:
- ./.env
depends_on:
- postgres
volumes:
- kyoo:/var/lib/kyoo
- ./cache:/var/lib/kyoo/cached
- kyoo:/kyoo
- ./cache:/kyoo/cached
- ./video:/video
front:
image: zoriya/kyoo_front:edge
@ -43,10 +35,8 @@ services:
postgres:
image: postgres
restart: on-failure
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
env_file:
- ./.env
volumes:
- db:/var/lib/postgresql/data

View File

@ -6,15 +6,11 @@ services:
restart: on-failure
env_file:
- ./.env
- KYOO_DATADIR=/var/lib/kyoo
- TVDB__APIKEY=${TVDB__APIKEY}
- THEMOVIEDB__APIKEY=${THEMOVIEDB__APIKEY}
- LIBRARY_ROOT=/video
depends_on:
- postgres
volumes:
- kyoo:/var/lib/kyoo
- ./cache:/var/lib/kyoo/cached
- kyoo:/kyoo
- ./cache:/kyoo/cached
- ./video:/video
front:
build: ./front