Logging Enhancements (#1521)
* Recreated Kavita Logging with Serilog instead of Default. This needs to be move out of the appsettings now, to allow auto updater to patch. * Refactored the code to be completely configured via Code rather than appsettings.json. This is a required step for Auto Updating. * Added in the ability to send logs directly to the UI only for users on the log route. Stopping implementation as Alerts page will handle the rest of the implementation. * Fixed up the backup service to not rely on Config from appsettings.json * Tweaked the Logging levels available * Moved everything over to File-scoped namespaces * Moved everything over to File-scoped namespaces * Code cleanup, removed an old migration and changed so debug logging doesn't print sensitive db data * Removed dead code
This commit is contained in:
parent
9f715cc35f
commit
d1a14f7e68
212 changed files with 16599 additions and 16834 deletions
|
|
@ -5,348 +5,238 @@ using System.Text.Json;
|
|||
using Kavita.Common.EnvironmentInfo;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Kavita.Common
|
||||
namespace Kavita.Common;
|
||||
|
||||
public static class Configuration
|
||||
{
|
||||
public static class Configuration
|
||||
public static readonly string AppSettingsFilename = Path.Join("config", GetAppSettingFilename());
|
||||
|
||||
public static string Branch
|
||||
{
|
||||
public static readonly string AppSettingsFilename = Path.Join("config", GetAppSettingFilename());
|
||||
get => GetBranch(GetAppSettingFilename());
|
||||
set => SetBranch(GetAppSettingFilename(), value);
|
||||
}
|
||||
|
||||
public static string Branch
|
||||
public static int Port
|
||||
{
|
||||
get => GetPort(GetAppSettingFilename());
|
||||
set => SetPort(GetAppSettingFilename(), value);
|
||||
}
|
||||
|
||||
public static string JwtToken
|
||||
{
|
||||
get => GetJwtToken(GetAppSettingFilename());
|
||||
set => SetJwtToken(GetAppSettingFilename(), value);
|
||||
}
|
||||
|
||||
|
||||
public static string DatabasePath
|
||||
{
|
||||
get => GetDatabasePath(GetAppSettingFilename());
|
||||
set => SetDatabasePath(GetAppSettingFilename(), value);
|
||||
}
|
||||
|
||||
private static string GetAppSettingFilename()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(AppSettingsFilename))
|
||||
{
|
||||
get => GetBranch(GetAppSettingFilename());
|
||||
set => SetBranch(GetAppSettingFilename(), value);
|
||||
return AppSettingsFilename;
|
||||
}
|
||||
|
||||
public static int Port
|
||||
{
|
||||
get => GetPort(GetAppSettingFilename());
|
||||
set => SetPort(GetAppSettingFilename(), value);
|
||||
}
|
||||
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
var isDevelopment = environment == Environments.Development;
|
||||
return "appsettings" + (isDevelopment ? ".Development" : string.Empty) + ".json";
|
||||
}
|
||||
|
||||
public static string JwtToken
|
||||
{
|
||||
get => GetJwtToken(GetAppSettingFilename());
|
||||
set => SetJwtToken(GetAppSettingFilename(), value);
|
||||
}
|
||||
#region JWT Token
|
||||
|
||||
public static string LogLevel
|
||||
private static string GetJwtToken(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
get => GetLogLevel(GetAppSettingFilename());
|
||||
set => SetLogLevel(GetAppSettingFilename(), value);
|
||||
}
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
const string key = "TokenKey";
|
||||
|
||||
public static string LogPath
|
||||
{
|
||||
get => GetLoggingFile(GetAppSettingFilename());
|
||||
set => SetLoggingFile(GetAppSettingFilename(), value);
|
||||
}
|
||||
|
||||
public static string DatabasePath
|
||||
{
|
||||
get => GetDatabasePath(GetAppSettingFilename());
|
||||
set => SetDatabasePath(GetAppSettingFilename(), value);
|
||||
}
|
||||
|
||||
private static string GetAppSettingFilename()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(AppSettingsFilename))
|
||||
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
|
||||
{
|
||||
return AppSettingsFilename;
|
||||
}
|
||||
|
||||
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
||||
var isDevelopment = environment == Environments.Development;
|
||||
return "appsettings" + (isDevelopment ? ".Development" : string.Empty) + ".json";
|
||||
}
|
||||
|
||||
#region JWT Token
|
||||
|
||||
private static string GetJwtToken(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
const string key = "TokenKey";
|
||||
|
||||
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
|
||||
{
|
||||
return tokenElement.GetString();
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error reading app settings: " + ex.Message);
|
||||
return tokenElement.GetString();
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private static void SetJwtToken(string filePath, string token)
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentToken = GetJwtToken(filePath);
|
||||
var json = File.ReadAllText(filePath)
|
||||
.Replace("\"TokenKey\": \"" + currentToken, "\"TokenKey\": \"" + token);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow exception */
|
||||
}
|
||||
Console.WriteLine("Error reading app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
public static bool CheckIfJwtTokenSet()
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetJwtToken(GetAppSettingFilename()) != "super secret unguessable key";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error writing app settings: " + ex.Message);
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return false;
|
||||
private static void SetJwtToken(string filePath, string token)
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentToken = GetJwtToken(filePath);
|
||||
var json = File.ReadAllText(filePath)
|
||||
.Replace("\"TokenKey\": \"" + currentToken, "\"TokenKey\": \"" + token);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow exception */
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CheckIfJwtTokenSet()
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetJwtToken(GetAppSettingFilename()) != "super secret unguessable key";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error writing app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
#endregion
|
||||
return false;
|
||||
}
|
||||
|
||||
#region Port
|
||||
#endregion
|
||||
|
||||
private static void SetPort(string filePath, int port)
|
||||
#region Port
|
||||
|
||||
private static void SetPort(string filePath, int port)
|
||||
{
|
||||
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
|
||||
{
|
||||
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var currentPort = GetPort(filePath);
|
||||
var json = File.ReadAllText(filePath).Replace("\"Port\": " + currentPort, "\"Port\": " + port);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow Exception */
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
private static int GetPort(string filePath)
|
||||
try
|
||||
{
|
||||
const int defaultPort = 5000;
|
||||
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
|
||||
{
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
const string key = "Port";
|
||||
|
||||
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
|
||||
{
|
||||
return tokenElement.GetInt32();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error writing app settings: " + ex.Message);
|
||||
}
|
||||
var currentPort = GetPort(filePath);
|
||||
var json = File.ReadAllText(filePath).Replace("\"Port\": " + currentPort, "\"Port\": " + port);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow Exception */
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetPort(string filePath)
|
||||
{
|
||||
const int defaultPort = 5000;
|
||||
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
|
||||
{
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LogLevel
|
||||
|
||||
private static void SetLogLevel(string filePath, string logLevel)
|
||||
try
|
||||
{
|
||||
try
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
const string key = "Port";
|
||||
|
||||
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
|
||||
{
|
||||
var currentLevel = GetLogLevel(filePath);
|
||||
var json = File.ReadAllText(filePath)
|
||||
.Replace($"\"Default\": \"{currentLevel}\"", $"\"Default\": \"{logLevel}\"");
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow Exception */
|
||||
return tokenElement.GetInt32();
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLogLevel(string filePath)
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
Console.WriteLine("Error writing app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
if (jsonObj.TryGetProperty("Logging", out JsonElement tokenElement))
|
||||
return defaultPort;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static string GetBranch(string filePath)
|
||||
{
|
||||
const string defaultBranch = "main";
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
const string key = "Branch";
|
||||
|
||||
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
|
||||
{
|
||||
return tokenElement.GetString();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error reading app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
return defaultBranch;
|
||||
}
|
||||
|
||||
private static void SetBranch(string filePath, string updatedBranch)
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentBranch = GetBranch(filePath);
|
||||
var json = File.ReadAllText(filePath)
|
||||
.Replace("\"Branch\": " + currentBranch, "\"Branch\": " + updatedBranch);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow Exception */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string GetDatabasePath(string filePath)
|
||||
{
|
||||
const string defaultFile = "config/kavita.db";
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
|
||||
if (jsonObj.TryGetProperty("ConnectionStrings", out JsonElement tokenElement))
|
||||
{
|
||||
foreach (var property in tokenElement.EnumerateObject())
|
||||
{
|
||||
foreach (var property in tokenElement.EnumerateObject())
|
||||
{
|
||||
if (!property.Name.Equals("LogLevel")) continue;
|
||||
foreach (var logProperty in property.Value.EnumerateObject().Where(logProperty => logProperty.Name.Equals("Default")))
|
||||
{
|
||||
return logProperty.Value.GetString();
|
||||
}
|
||||
}
|
||||
if (!property.Name.Equals("DefaultConnection")) continue;
|
||||
return property.Value.GetString();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error writing app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
return "Information";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error writing app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
#endregion
|
||||
return defaultFile;
|
||||
}
|
||||
|
||||
private static string GetBranch(string filePath)
|
||||
/// <summary>
|
||||
/// This should NEVER be called except by MigrateConfigFiles
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="updatedPath"></param>
|
||||
private static void SetDatabasePath(string filePath, string updatedPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
const string defaultBranch = "main";
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
const string key = "Branch";
|
||||
|
||||
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
|
||||
{
|
||||
return tokenElement.GetString();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error reading app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
return defaultBranch;
|
||||
var existingString = GetDatabasePath(filePath);
|
||||
var json = File.ReadAllText(filePath)
|
||||
.Replace(existingString,
|
||||
"Data source=" + updatedPath);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
|
||||
private static void SetBranch(string filePath, string updatedBranch)
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentBranch = GetBranch(filePath);
|
||||
var json = File.ReadAllText(filePath)
|
||||
.Replace("\"Branch\": " + currentBranch, "\"Branch\": " + updatedBranch);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow Exception */
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetLoggingFile(string filePath)
|
||||
{
|
||||
const string defaultFile = "config/logs/kavita.log";
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
|
||||
if (jsonObj.TryGetProperty("Logging", out JsonElement tokenElement))
|
||||
{
|
||||
foreach (var property in tokenElement.EnumerateObject())
|
||||
{
|
||||
if (!property.Name.Equals("File")) continue;
|
||||
foreach (var logProperty in property.Value.EnumerateObject())
|
||||
{
|
||||
if (logProperty.Name.Equals("Path"))
|
||||
{
|
||||
return logProperty.Value.GetString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error writing app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
return defaultFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This should NEVER be called except by <see cref="MigrateConfigFiles"/>
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="directory"></param>
|
||||
private static void SetLoggingFile(string filePath, string directory)
|
||||
{
|
||||
try
|
||||
{
|
||||
var currentFile = GetLoggingFile(filePath);
|
||||
var json = File.ReadAllText(filePath)
|
||||
.Replace("\"Path\": \"" + currentFile + "\"", "\"Path\": \"" + directory + "\"");
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
/* Swallow Exception */
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetDatabasePath(string filePath)
|
||||
{
|
||||
const string defaultFile = "config/kavita.db";
|
||||
|
||||
try
|
||||
{
|
||||
var json = File.ReadAllText(filePath);
|
||||
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
|
||||
|
||||
if (jsonObj.TryGetProperty("ConnectionStrings", out JsonElement tokenElement))
|
||||
{
|
||||
foreach (var property in tokenElement.EnumerateObject())
|
||||
{
|
||||
if (!property.Name.Equals("DefaultConnection")) continue;
|
||||
return property.Value.GetString();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("Error writing app settings: " + ex.Message);
|
||||
}
|
||||
|
||||
return defaultFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This should NEVER be called except by MigrateConfigFiles
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="updatedPath"></param>
|
||||
private static void SetDatabasePath(string filePath, string updatedPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existingString = GetDatabasePath(filePath);
|
||||
var json = File.ReadAllText(filePath)
|
||||
.Replace(existingString,
|
||||
"Data source=" + updatedPath);
|
||||
File.WriteAllText(filePath, json);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
/* Swallow Exception */
|
||||
}
|
||||
/* Swallow Exception */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,157 +4,156 @@ using System.Diagnostics;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Kavita.Common.EnvironmentInfo
|
||||
namespace Kavita.Common.EnvironmentInfo;
|
||||
|
||||
public class OsInfo : IOsInfo
|
||||
{
|
||||
public class OsInfo : IOsInfo
|
||||
public static Os Os { get; }
|
||||
|
||||
public static bool IsNotWindows => !IsWindows;
|
||||
public static bool IsLinux => Os == Os.Linux || Os == Os.LinuxMusl || Os == Os.Bsd;
|
||||
public static bool IsOsx => Os == Os.Osx;
|
||||
public static bool IsWindows => Os == Os.Windows;
|
||||
|
||||
// this needs to not be static so we can mock it
|
||||
public bool IsDocker { get; }
|
||||
|
||||
public string Version { get; }
|
||||
public string Name { get; }
|
||||
public string FullName { get; }
|
||||
|
||||
static OsInfo()
|
||||
{
|
||||
public static Os Os { get; }
|
||||
var platform = Environment.OSVersion.Platform;
|
||||
|
||||
public static bool IsNotWindows => !IsWindows;
|
||||
public static bool IsLinux => Os == Os.Linux || Os == Os.LinuxMusl || Os == Os.Bsd;
|
||||
public static bool IsOsx => Os == Os.Osx;
|
||||
public static bool IsWindows => Os == Os.Windows;
|
||||
|
||||
// this needs to not be static so we can mock it
|
||||
public bool IsDocker { get; }
|
||||
|
||||
public string Version { get; }
|
||||
public string Name { get; }
|
||||
public string FullName { get; }
|
||||
|
||||
static OsInfo()
|
||||
switch (platform)
|
||||
{
|
||||
var platform = Environment.OSVersion.Platform;
|
||||
|
||||
switch (platform)
|
||||
case PlatformID.Win32NT:
|
||||
{
|
||||
case PlatformID.Win32NT:
|
||||
{
|
||||
Os = Os.Windows;
|
||||
break;
|
||||
}
|
||||
|
||||
case PlatformID.MacOSX:
|
||||
case PlatformID.Unix:
|
||||
{
|
||||
Os = GetPosixFlavour();
|
||||
break;
|
||||
}
|
||||
Os = Os.Windows;
|
||||
break;
|
||||
}
|
||||
|
||||
case PlatformID.MacOSX:
|
||||
case PlatformID.Unix:
|
||||
{
|
||||
Os = GetPosixFlavour();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public OsInfo(IEnumerable<IOsVersionAdapter> versionAdapters)
|
||||
}
|
||||
|
||||
public OsInfo(IEnumerable<IOsVersionAdapter> versionAdapters)
|
||||
{
|
||||
OsVersionModel osInfo = null;
|
||||
|
||||
foreach (var osVersionAdapter in versionAdapters.Where(c => c.Enabled))
|
||||
{
|
||||
OsVersionModel osInfo = null;
|
||||
|
||||
foreach (var osVersionAdapter in versionAdapters.Where(c => c.Enabled))
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
osInfo = osVersionAdapter.Read();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Couldn't get OS Version info: " + e.Message);
|
||||
}
|
||||
|
||||
if (osInfo != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
osInfo = osVersionAdapter.Read();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Couldn't get OS Version info: " + e.Message);
|
||||
}
|
||||
|
||||
if (osInfo != null)
|
||||
{
|
||||
Name = osInfo.Name;
|
||||
Version = osInfo.Version;
|
||||
FullName = osInfo.FullName;
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = Os.ToString();
|
||||
FullName = Name;
|
||||
}
|
||||
|
||||
if (IsLinux && File.Exists("/proc/1/cgroup") && File.ReadAllText("/proc/1/cgroup").Contains("/docker/"))
|
||||
{
|
||||
IsDocker = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public OsInfo()
|
||||
if (osInfo != null)
|
||||
{
|
||||
Name = osInfo.Name;
|
||||
Version = osInfo.Version;
|
||||
FullName = osInfo.FullName;
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = Os.ToString();
|
||||
FullName = Name;
|
||||
|
||||
if (IsLinux && File.Exists("/proc/1/cgroup") && File.ReadAllText("/proc/1/cgroup").Contains("/docker/"))
|
||||
{
|
||||
IsDocker = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static Os GetPosixFlavour()
|
||||
if (IsLinux && File.Exists("/proc/1/cgroup") && File.ReadAllText("/proc/1/cgroup").Contains("/docker/"))
|
||||
{
|
||||
var output = RunAndCapture("uname", "-s");
|
||||
IsDocker = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (output.StartsWith("Darwin"))
|
||||
{
|
||||
return Os.Osx;
|
||||
}
|
||||
else if (output.Contains("BSD"))
|
||||
{
|
||||
return Os.Bsd;
|
||||
}
|
||||
else
|
||||
{
|
||||
public OsInfo()
|
||||
{
|
||||
Name = Os.ToString();
|
||||
FullName = Name;
|
||||
|
||||
if (IsLinux && File.Exists("/proc/1/cgroup") && File.ReadAllText("/proc/1/cgroup").Contains("/docker/"))
|
||||
{
|
||||
IsDocker = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static Os GetPosixFlavour()
|
||||
{
|
||||
var output = RunAndCapture("uname", "-s");
|
||||
|
||||
if (output.StartsWith("Darwin"))
|
||||
{
|
||||
return Os.Osx;
|
||||
}
|
||||
else if (output.Contains("BSD"))
|
||||
{
|
||||
return Os.Bsd;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if ISMUSL
|
||||
return Os.LinuxMusl;
|
||||
#else
|
||||
return Os.Linux;
|
||||
return Os.Linux;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string RunAndCapture(string filename, string args)
|
||||
private static string RunAndCapture(string filename, string args)
|
||||
{
|
||||
var p = new Process
|
||||
{
|
||||
var p = new Process
|
||||
StartInfo =
|
||||
{
|
||||
StartInfo =
|
||||
{
|
||||
FileName = filename,
|
||||
Arguments = args,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true
|
||||
}
|
||||
};
|
||||
FileName = filename,
|
||||
Arguments = args,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true
|
||||
}
|
||||
};
|
||||
|
||||
p.Start();
|
||||
p.Start();
|
||||
|
||||
// To avoid deadlocks, always read the output stream first and then wait.
|
||||
var output = p.StandardOutput.ReadToEnd();
|
||||
p.WaitForExit(1000);
|
||||
// To avoid deadlocks, always read the output stream first and then wait.
|
||||
var output = p.StandardOutput.ReadToEnd();
|
||||
p.WaitForExit(1000);
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IOsInfo
|
||||
{
|
||||
string Version { get; }
|
||||
string Name { get; }
|
||||
string FullName { get; }
|
||||
|
||||
bool IsDocker { get; }
|
||||
}
|
||||
|
||||
public enum Os
|
||||
{
|
||||
Windows,
|
||||
Linux,
|
||||
Osx,
|
||||
LinuxMusl,
|
||||
Bsd
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IOsInfo
|
||||
{
|
||||
string Version { get; }
|
||||
string Name { get; }
|
||||
string FullName { get; }
|
||||
|
||||
bool IsDocker { get; }
|
||||
}
|
||||
|
||||
public enum Os
|
||||
{
|
||||
Windows,
|
||||
Linux,
|
||||
Osx,
|
||||
LinuxMusl,
|
||||
Bsd
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
namespace Kavita.Common.EnvironmentInfo
|
||||
namespace Kavita.Common.EnvironmentInfo;
|
||||
|
||||
public interface IOsVersionAdapter
|
||||
{
|
||||
public interface IOsVersionAdapter
|
||||
{
|
||||
bool Enabled { get; }
|
||||
OsVersionModel Read();
|
||||
}
|
||||
}
|
||||
bool Enabled { get; }
|
||||
OsVersionModel Read();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,26 @@
|
|||
namespace Kavita.Common.EnvironmentInfo
|
||||
namespace Kavita.Common.EnvironmentInfo;
|
||||
|
||||
public class OsVersionModel
|
||||
{
|
||||
public class OsVersionModel
|
||||
public OsVersionModel(string name, string version, string fullName = null)
|
||||
{
|
||||
public OsVersionModel(string name, string version, string fullName = null)
|
||||
Name = Trim(name);
|
||||
Version = Trim(version);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(fullName))
|
||||
{
|
||||
Name = Trim(name);
|
||||
Version = Trim(version);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(fullName))
|
||||
{
|
||||
fullName = $"{Name} {Version}";
|
||||
}
|
||||
|
||||
FullName = Trim(fullName);
|
||||
fullName = $"{Name} {Version}";
|
||||
}
|
||||
|
||||
private static string Trim(string source)
|
||||
{
|
||||
return source.Trim().Trim('"', '\'');
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string FullName { get; }
|
||||
public string Version { get; }
|
||||
FullName = Trim(fullName);
|
||||
}
|
||||
}
|
||||
|
||||
private static string Trim(string source)
|
||||
{
|
||||
return source.Trim().Trim('"', '\'');
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public string FullName { get; }
|
||||
public string Version { get; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,20 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace Kavita.Common.Extensions
|
||||
namespace Kavita.Common.Extensions;
|
||||
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static class EnumExtensions
|
||||
{
|
||||
public static string ToDescription<TEnum>(this TEnum value) where TEnum : struct
|
||||
{
|
||||
var fi = value.GetType().GetField(value.ToString() ?? string.Empty);
|
||||
var fi = value.GetType().GetField(value.ToString() ?? string.Empty);
|
||||
|
||||
if (fi == null)
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
if (fi == null)
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||
var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||
|
||||
return attributes is {Length: > 0} ? attributes[0].Description : value.ToString();
|
||||
return attributes is {Length: > 0} ? attributes[0].Description : value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Kavita.Common.Extensions
|
||||
namespace Kavita.Common.Extensions;
|
||||
|
||||
public static class PathExtensions
|
||||
{
|
||||
public static class PathExtensions
|
||||
{
|
||||
public static string GetParentDirectory(string filePath)
|
||||
{
|
||||
return Path.GetDirectoryName(filePath);
|
||||
return Path.GetDirectoryName(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +1,55 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Kavita.Common
|
||||
namespace Kavita.Common;
|
||||
|
||||
public static class HashUtil
|
||||
{
|
||||
public static class HashUtil
|
||||
private static string CalculateCrc(string input)
|
||||
{
|
||||
private static string CalculateCrc(string input)
|
||||
uint mCrc = 0xffffffff;
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(input);
|
||||
foreach (byte myByte in bytes)
|
||||
{
|
||||
uint mCrc = 0xffffffff;
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(input);
|
||||
foreach (byte myByte in bytes)
|
||||
mCrc ^= (uint)myByte << 24;
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
mCrc ^= (uint)myByte << 24;
|
||||
for (var i = 0; i < 8; i++)
|
||||
if ((Convert.ToUInt32(mCrc) & 0x80000000) == 0x80000000)
|
||||
{
|
||||
if ((Convert.ToUInt32(mCrc) & 0x80000000) == 0x80000000)
|
||||
{
|
||||
mCrc = (mCrc << 1) ^ 0x04C11DB7;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCrc <<= 1;
|
||||
}
|
||||
mCrc = (mCrc << 1) ^ 0x04C11DB7;
|
||||
}
|
||||
else
|
||||
{
|
||||
mCrc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $"{mCrc:x8}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a unique, Anonymous Token that will represent this unique Kavita installation.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string AnonymousToken()
|
||||
return $"{mCrc:x8}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates a unique, Anonymous Token that will represent this unique Kavita installation.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string AnonymousToken()
|
||||
{
|
||||
var seed = $"{Environment.ProcessorCount}_{Environment.OSVersion.Platform}_{Configuration.JwtToken}_{Environment.UserName}";
|
||||
return CalculateCrc(seed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a unique API key to this server instance
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string ApiKey()
|
||||
{
|
||||
var id = Guid.NewGuid();
|
||||
if (id.Equals(Guid.Empty))
|
||||
{
|
||||
var seed = $"{Environment.ProcessorCount}_{Environment.OSVersion.Platform}_{Configuration.JwtToken}_{Environment.UserName}";
|
||||
return CalculateCrc(seed);
|
||||
id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a unique API key to this server instance
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string ApiKey()
|
||||
{
|
||||
var id = Guid.NewGuid();
|
||||
if (id.Equals(Guid.Empty))
|
||||
{
|
||||
id = Guid.NewGuid();
|
||||
}
|
||||
|
||||
return id.ToString();
|
||||
}
|
||||
return id.ToString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,24 @@
|
|||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Kavita.Common
|
||||
namespace Kavita.Common;
|
||||
|
||||
/// <summary>
|
||||
/// These are used for errors to send to the UI that should not be reported to Sentry
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class KavitaException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// These are used for errors to send to the UI that should not be reported to Sentry
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class KavitaException : Exception
|
||||
{
|
||||
public KavitaException()
|
||||
{ }
|
||||
public KavitaException()
|
||||
{ }
|
||||
|
||||
public KavitaException(string message) : base(message)
|
||||
{ }
|
||||
public KavitaException(string message) : base(message)
|
||||
{ }
|
||||
|
||||
public KavitaException(string message, Exception inner)
|
||||
: base(message, inner) { }
|
||||
public KavitaException(string message, Exception inner)
|
||||
: base(message, inner) { }
|
||||
|
||||
protected KavitaException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
protected KavitaException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue