84 lines
3.0 KiB
C#
Raw Normal View History

2026-05-20 21:39:12 +08:00
using System.Diagnostics;
using System.Text.Json;
using YamlDotNet.RepresentationModel;
namespace Neta.Tray;
public sealed class RuntimeBootstrapInfo
{
public string DataDir { get; set; } = string.Empty;
public string ControlBaseUrl { get; set; } = string.Empty;
public string ControlSecret { get; set; } = string.Empty;
public int Pid { get; set; }
public bool Ready { get; set; }
}
public static class RuntimeInfoStore
{
public static RuntimeBootstrapInfo ParseConfigAndRuntimeInfo(string configYaml, string runtimeInfoJson)
{
var dataDir = GetDataDirFromConfigYaml(configYaml);
var runtime = JsonSerializer.Deserialize<RuntimeBootstrapInfo>(runtimeInfoJson, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
})!;
runtime.DataDir = dataDir;
return runtime;
}
public static RuntimeBootstrapInfo? LoadFromInstalledConfig(string baseDirectory)
{
var configPath = Path.Combine(baseDirectory, "config.yaml");
if (!File.Exists(configPath)) return null;
var configYaml = File.ReadAllText(configPath);
var dataDir = GetDataDirFromConfigYaml(configYaml);
var runtimeInfoPath = Path.Combine(dataDir, "runtime-info.json");
if (!File.Exists(runtimeInfoPath)) return null;
return ParseConfigAndRuntimeInfo(configYaml, File.ReadAllText(runtimeInfoPath));
}
public static RuntimeBootstrapInfo WaitUntilAvailable(string baseDirectory, TimeSpan timeout)
{
var deadline = DateTime.UtcNow + timeout;
while (DateTime.UtcNow < deadline)
{
var loaded = LoadFromInstalledConfig(baseDirectory);
if (loaded is not null) return loaded;
Thread.Sleep(200);
}
throw new TimeoutException("等待 runtime-info.json 超时");
}
public static bool HasRuntimeLock(string baseDirectory)
{
var configPath = Path.Combine(baseDirectory, "config.yaml");
if (!File.Exists(configPath)) return false;
var dataDir = GetDataDirFromConfigYaml(File.ReadAllText(configPath));
return File.Exists(Path.Combine(dataDir, "neta.lock"));
}
public static void OpenLogs(string baseDirectory)
{
var runtime = LoadFromInstalledConfig(baseDirectory);
if (runtime is null) return;
Process.Start(new ProcessStartInfo(Path.Combine(runtime.DataDir, "logs")) { UseShellExecute = true });
}
public static void OpenConfigDir(string baseDirectory)
{
Process.Start(new ProcessStartInfo(baseDirectory) { UseShellExecute = true });
}
private static string GetDataDirFromConfigYaml(string configYaml)
{
using var input = new StringReader(configYaml);
var yaml = new YamlStream();
yaml.Load(input);
var root = (YamlMappingNode)yaml.Documents[0].RootNode;
return ((YamlScalarNode)((YamlMappingNode)root.Children[new YamlScalarNode("data")]).Children[new YamlScalarNode("dir")]).Value!.Replace("\\\\", "\\");
}
}