feat(headless): complete portable single-session host
This commit is contained in:
parent
fbebb91848
commit
f8cb840fb1
30 changed files with 3571 additions and 32 deletions
99
src/AcDream.Headless/Platform/HeadlessPathSet.cs
Normal file
99
src/AcDream.Headless/Platform/HeadlessPathSet.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
using AcDream.Headless.Configuration;
|
||||
|
||||
namespace AcDream.Headless.Platform;
|
||||
|
||||
internal sealed record HeadlessPathSet(
|
||||
string ConfigDirectory,
|
||||
string DataDirectory,
|
||||
string CacheDirectory)
|
||||
{
|
||||
internal static HeadlessPathSet Resolve(
|
||||
HeadlessPathOverrides overrides,
|
||||
IHeadlessPlatformEnvironment? platform = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(overrides);
|
||||
platform ??= HeadlessPlatformEnvironment.Instance;
|
||||
|
||||
string config;
|
||||
string data;
|
||||
string cache;
|
||||
if (platform.IsWindows)
|
||||
{
|
||||
string roaming = RequireFolder(
|
||||
platform,
|
||||
Environment.SpecialFolder.ApplicationData);
|
||||
string local = RequireFolder(
|
||||
platform,
|
||||
Environment.SpecialFolder.LocalApplicationData);
|
||||
config = Path.Combine(roaming, "acdream");
|
||||
data = Path.Combine(local, "acdream");
|
||||
cache = Path.Combine(local, "acdream", "cache");
|
||||
}
|
||||
else
|
||||
{
|
||||
string home = RequireFolder(
|
||||
platform,
|
||||
Environment.SpecialFolder.UserProfile);
|
||||
config = ResolveXdg(
|
||||
platform,
|
||||
"XDG_CONFIG_HOME",
|
||||
Path.Combine(home, ".config"),
|
||||
"acdream");
|
||||
data = ResolveXdg(
|
||||
platform,
|
||||
"XDG_DATA_HOME",
|
||||
Path.Combine(home, ".local", "share"),
|
||||
"acdream");
|
||||
cache = ResolveXdg(
|
||||
platform,
|
||||
"XDG_CACHE_HOME",
|
||||
Path.Combine(home, ".cache"),
|
||||
"acdream");
|
||||
}
|
||||
|
||||
return new HeadlessPathSet(
|
||||
Normalize(overrides.ConfigDirectory ?? config, platform),
|
||||
Normalize(overrides.DataDirectory ?? data, platform),
|
||||
Normalize(overrides.CacheDirectory ?? cache, platform));
|
||||
}
|
||||
|
||||
private static string ResolveXdg(
|
||||
IHeadlessPlatformEnvironment platform,
|
||||
string variable,
|
||||
string fallback,
|
||||
string leaf)
|
||||
{
|
||||
string? configured = platform.GetEnvironmentVariable(variable);
|
||||
string root = string.IsNullOrWhiteSpace(configured)
|
||||
? fallback
|
||||
: configured;
|
||||
return Path.Combine(root, leaf);
|
||||
}
|
||||
|
||||
private static string RequireFolder(
|
||||
IHeadlessPlatformEnvironment platform,
|
||||
Environment.SpecialFolder folder)
|
||||
{
|
||||
string value = platform.GetFolderPath(folder);
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new HeadlessConfigurationException(
|
||||
$"The operating system did not provide {folder}.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static string Normalize(
|
||||
string path,
|
||||
IHeadlessPlatformEnvironment platform)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
throw new HeadlessConfigurationException(
|
||||
"Headless directories cannot be empty.");
|
||||
}
|
||||
|
||||
return Path.TrimEndingDirectorySeparator(
|
||||
Path.GetFullPath(path, platform.CurrentDirectory));
|
||||
}
|
||||
}
|
||||
28
src/AcDream.Headless/Platform/HeadlessPlatformEnvironment.cs
Normal file
28
src/AcDream.Headless/Platform/HeadlessPlatformEnvironment.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
namespace AcDream.Headless.Platform;
|
||||
|
||||
internal interface IHeadlessPlatformEnvironment
|
||||
{
|
||||
bool IsWindows { get; }
|
||||
string CurrentDirectory { get; }
|
||||
string? GetEnvironmentVariable(string name);
|
||||
string GetFolderPath(Environment.SpecialFolder folder);
|
||||
}
|
||||
|
||||
internal sealed class HeadlessPlatformEnvironment
|
||||
: IHeadlessPlatformEnvironment
|
||||
{
|
||||
internal static HeadlessPlatformEnvironment Instance { get; } = new();
|
||||
|
||||
private HeadlessPlatformEnvironment()
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsWindows => OperatingSystem.IsWindows();
|
||||
public string CurrentDirectory => Environment.CurrentDirectory;
|
||||
|
||||
public string? GetEnvironmentVariable(string name) =>
|
||||
Environment.GetEnvironmentVariable(name);
|
||||
|
||||
public string GetFolderPath(Environment.SpecialFolder folder) =>
|
||||
Environment.GetFolderPath(folder);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue