Feature/netcore preparation (#2072)

* Use platform detection that works on mono 4.6+

* Move to use package reference for restoring nuget packages.

* DateTimeRoutines does not have Nuget packages that support .NET Standard (and therefore .NET Core). We will have to include them for now until we can get rid of this dependency.

* Start spliting some interfaces into their own files - this will help by allowing us to split them out in the future into a seperate project so the actual implementations can stay within their respective architectures when required

* Move out common libraries

* Few more tidy up tasks to get things working with .NET Standard

* Restructure the solution layout

* Encoding work to reduce rework later on platforms without Windows codepages (or require compliance with RFC1345)

* Move folder structure around to have more natural layout of the solutions

* DI server configuration to get rid of "temporary" hack and dependency circle for serverservice

* Make all encoding consistent to match the expected encoding casing for earlier versions of mono.
This commit is contained in:
Nathan Holland
2017-11-05 22:42:03 +13:00
committed by flightlevel
parent 47a2ffa313
commit 571c52a0f2
235 changed files with 967 additions and 1001 deletions

View File

@@ -0,0 +1,262 @@
using Jackett.Utils;
using NLog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security.AccessControl;
using System.Security.Principal;
using Jackett.Services.Interfaces;
using Jacket.Common;
namespace Jackett.Services
{
public class ConfigurationService : IConfigurationService
{
private ISerializeService serializeService;
private Logger logger;
private IProcessService processService;
public ConfigurationService(ISerializeService s, IProcessService p, Logger l)
{
serializeService = s;
logger = l;
processService = p;
CreateOrMigrateSettings();
}
public void CreateOrMigrateSettings()
{
try
{
if (!Directory.Exists(GetAppDataFolder()))
{
var dir = Directory.CreateDirectory(GetAppDataFolder());
if (System.Environment.OSVersion.Platform != PlatformID.Unix)
{
var access = dir.GetAccessControl();
var directorySecurity = new DirectorySecurity(GetAppDataFolder(), AccessControlSections.All);
directorySecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow));
dir.SetAccessControl(directorySecurity);
}
}
logger.Info("App config/log directory: " + GetAppDataFolder());
}
catch (Exception ex)
{
throw new Exception("Could not create settings directory. " + ex.Message);
}
if (System.Environment.OSVersion.Platform != PlatformID.Unix)
{
try
{
string oldDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Jackett");
if (Directory.Exists(oldDir))
{
// On Windows we need admin permissions to migrate as they were made with admin permissions.
if (ServerUtil.IsUserAdministrator())
{
PerformMigration();
}
else
{
try
{
processService.StartProcessAndLog(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath, "--MigrateSettings", true);
}
catch
{
logger.Error("Unable to migrate settings when not running as administrator.");
Environment.ExitCode = 1;
return;
}
}
}
else
{
PerformMigration();
}
}
catch (Exception ex)
{
logger.Error("ERROR could not migrate settings directory " + ex);
}
}
}
public void PerformMigration()
{
var oldDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Jackett");
if (Directory.Exists(oldDir))
{
foreach (var file in Directory.GetFiles(oldDir, "*", SearchOption.AllDirectories))
{
var path = file.Replace(oldDir, "");
var destPath = GetAppDataFolder() + path;
var destFolder = Path.GetDirectoryName(destPath);
if (!Directory.Exists(destFolder))
{
var dir = Directory.CreateDirectory(destFolder);
var directorySecurity = new DirectorySecurity(destFolder, AccessControlSections.All);
directorySecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.None, AccessControlType.Allow));
dir.SetAccessControl(directorySecurity);
}
if (!File.Exists(destPath))
{
File.Copy(file, destPath);
// The old files were created when running as admin so make sure they are editable by normal users / services.
if (System.Environment.OSVersion.Platform != PlatformID.Unix)
{
var fileInfo = new FileInfo(destFolder);
var fileSecurity = new FileSecurity(destPath, AccessControlSections.All);
fileSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.None, PropagationFlags.None, AccessControlType.Allow));
fileInfo.SetAccessControl(fileSecurity);
}
}
}
Directory.Delete(oldDir, true);
}
}
public T GetConfig<T>()
{
var type = typeof(T);
var fullPath = Path.Combine(GetAppDataFolder(), type.Name + ".json");
try
{
if (!File.Exists(fullPath))
{
logger.Debug("Config file does not exist: " + fullPath);
return default(T);
}
return serializeService.DeSerialise<T>(File.ReadAllText(fullPath));
}
catch (Exception e)
{
logger.Error(e, "Error reading config file " + fullPath);
return default(T);
}
}
public void SaveConfig<T>(T config)
{
var type = typeof(T);
var fullPath = Path.Combine(GetAppDataFolder(), type.Name + ".json");
try
{
var json = serializeService.Serialise(config);
if (!Directory.Exists(GetAppDataFolder()))
Directory.CreateDirectory(GetAppDataFolder());
File.WriteAllText(fullPath, json);
}
catch (Exception e)
{
logger.Error(e, "Error writing config file " + fullPath);
}
}
public string ApplicationFolder()
{
return Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
}
public string GetContentFolder()
{
// If we are debugging we can use the non copied content.
string dir = Path.Combine(ApplicationFolder(), "Content"); ;
#if DEBUG
// When we are running in debug use the source files
var sourcePath = Path.GetFullPath(Path.Combine(ApplicationFolder(), "..\\..\\..\\Jackett\\Content"));
if (Directory.Exists(sourcePath))
{
dir = sourcePath;
}
#endif
return dir;
}
public List<string> GetCardigannDefinitionsFolders()
{
List<string> dirs = new List<string>();
if (System.Environment.OSVersion.Platform == PlatformID.Unix)
{
dirs.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "cardigann/definitions/"));
dirs.Add("/etc/xdg/cardigan/definitions/");
}
else
{
dirs.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "cardigann\\definitions\\"));
dirs.Add(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "cardigann\\definitions\\"));
}
// If we are debugging we can use the non copied definitions.
string dir = Path.Combine(ApplicationFolder(), "Definitions"); ;
#if DEBUG
// When we are running in debug use the source files
var sourcePath = Path.GetFullPath(Path.Combine(ApplicationFolder(), "..\\..\\..\\Jackett\\Definitions"));
if (Directory.Exists(sourcePath))
{
dir = sourcePath;
}
#endif
dirs.Add(dir);
return dirs;
}
public string GetAppDataFolder()
{
return GetAppDataFolderStatic();
}
/// <summary>
/// This is needed for the logger prior to ioc setup.
/// </summary>
/// <returns></returns>
public static string GetAppDataFolderStatic()
{
if (!string.IsNullOrWhiteSpace(JackettStartup.CustomDataFolder))
{
return JackettStartup.CustomDataFolder;
}
if (System.Environment.OSVersion.Platform == PlatformID.Unix)
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Jackett");
}
else
{
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Jackett");
}
}
public string GetIndexerConfigDir()
{
return Path.Combine(GetAppDataFolder(), "Indexers");
}
public string GetConfigFile()
{
return Path.Combine(GetAppDataFolder(), "config.json");
}
public string GetSonarrConfigFile()
{
return Path.Combine(GetAppDataFolder(), "sonarr_api.json");
}
public string GetVersion()
{
return JackettStartup.JackettVersion;
}
}
}