mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
0.5.1
插件系统试验
This commit is contained in:
251
LanMountainDesktop.SamplePlugin/SamplePluginRuntimeStatus.cs
Normal file
251
LanMountainDesktop.SamplePlugin/SamplePluginRuntimeStatus.cs
Normal file
@@ -0,0 +1,251 @@
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace LanMountainDesktop.SamplePlugin;
|
||||
|
||||
internal enum SamplePluginHealthState
|
||||
{
|
||||
Healthy,
|
||||
Pending,
|
||||
Faulted
|
||||
}
|
||||
|
||||
internal sealed record SamplePluginStatusEntry(
|
||||
string Key,
|
||||
string Title,
|
||||
SamplePluginHealthState State,
|
||||
string Summary,
|
||||
string Detail,
|
||||
DateTimeOffset UpdatedAt);
|
||||
|
||||
internal static class SamplePluginRuntimeStatus
|
||||
{
|
||||
private static readonly object Gate = new();
|
||||
|
||||
private static SamplePluginStatusEntry _frontend = CreateEntry(
|
||||
"frontend",
|
||||
"Frontend",
|
||||
SamplePluginHealthState.Pending,
|
||||
"Pending",
|
||||
"Frontend surfaces have not been created yet.");
|
||||
|
||||
private static SamplePluginStatusEntry _component = CreateEntry(
|
||||
"component",
|
||||
"Component",
|
||||
SamplePluginHealthState.Pending,
|
||||
"Pending",
|
||||
"The 4x4 component has not been created yet.");
|
||||
|
||||
private static SamplePluginStatusEntry _backend = CreateEntry(
|
||||
"backend",
|
||||
"Backend",
|
||||
SamplePluginHealthState.Pending,
|
||||
"Pending",
|
||||
"Plugin initialization has not finished yet.");
|
||||
|
||||
private static SamplePluginStatusEntry _service = CreateEntry(
|
||||
"service",
|
||||
"Service",
|
||||
SamplePluginHealthState.Pending,
|
||||
"Pending",
|
||||
"Heartbeat service has not started yet.");
|
||||
|
||||
public static void Reset(string hostName, string version, string dataDirectory)
|
||||
{
|
||||
lock (Gate)
|
||||
{
|
||||
_frontend = CreateEntry(
|
||||
"frontend",
|
||||
"Frontend",
|
||||
SamplePluginHealthState.Pending,
|
||||
"Pending",
|
||||
"Waiting for the settings page or widget surface to render.");
|
||||
|
||||
_component = CreateEntry(
|
||||
"component",
|
||||
"Component",
|
||||
SamplePluginHealthState.Pending,
|
||||
"Pending",
|
||||
"The 4x4 component has not been created yet.");
|
||||
|
||||
_backend = CreateEntry(
|
||||
"backend",
|
||||
"Backend",
|
||||
SamplePluginHealthState.Healthy,
|
||||
"Healthy",
|
||||
$"Plugin initialized. Host: {hostName}; Version: {version}; Data: {dataDirectory}");
|
||||
|
||||
_service = CreateEntry(
|
||||
"service",
|
||||
"Service",
|
||||
SamplePluginHealthState.Pending,
|
||||
"Pending",
|
||||
"Heartbeat service is starting.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void MarkFrontendReady(string detail)
|
||||
{
|
||||
lock (Gate)
|
||||
{
|
||||
_frontend = CreateEntry(
|
||||
"frontend",
|
||||
"Frontend",
|
||||
SamplePluginHealthState.Healthy,
|
||||
"Healthy",
|
||||
detail);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MarkComponentCreated(string detail)
|
||||
{
|
||||
lock (Gate)
|
||||
{
|
||||
_component = CreateEntry(
|
||||
"component",
|
||||
"Component",
|
||||
SamplePluginHealthState.Healthy,
|
||||
"Created",
|
||||
detail);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MarkBackendReady(string detail)
|
||||
{
|
||||
lock (Gate)
|
||||
{
|
||||
_backend = CreateEntry(
|
||||
"backend",
|
||||
"Backend",
|
||||
SamplePluginHealthState.Healthy,
|
||||
"Healthy",
|
||||
detail);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MarkBackendFaulted(string detail)
|
||||
{
|
||||
lock (Gate)
|
||||
{
|
||||
_backend = CreateEntry(
|
||||
"backend",
|
||||
"Backend",
|
||||
SamplePluginHealthState.Faulted,
|
||||
"Faulted",
|
||||
detail);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MarkServiceHeartbeat(DateTimeOffset timestamp)
|
||||
{
|
||||
lock (Gate)
|
||||
{
|
||||
_service = CreateEntry(
|
||||
"service",
|
||||
"Service",
|
||||
SamplePluginHealthState.Healthy,
|
||||
"Healthy",
|
||||
$"Heartbeat service is running. Last heartbeat: {timestamp.LocalDateTime:HH:mm:ss}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void MarkServiceFaulted(string detail)
|
||||
{
|
||||
lock (Gate)
|
||||
{
|
||||
_service = CreateEntry(
|
||||
"service",
|
||||
"Service",
|
||||
SamplePluginHealthState.Faulted,
|
||||
"Faulted",
|
||||
detail);
|
||||
}
|
||||
}
|
||||
|
||||
public static IReadOnlyList<SamplePluginStatusEntry> GetSnapshot()
|
||||
{
|
||||
lock (Gate)
|
||||
{
|
||||
return
|
||||
[
|
||||
_frontend,
|
||||
_component,
|
||||
_backend,
|
||||
_service
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private static SamplePluginStatusEntry CreateEntry(
|
||||
string key,
|
||||
string title,
|
||||
SamplePluginHealthState state,
|
||||
string summary,
|
||||
string detail)
|
||||
{
|
||||
return new SamplePluginStatusEntry(
|
||||
key,
|
||||
title,
|
||||
state,
|
||||
summary,
|
||||
detail,
|
||||
DateTimeOffset.Now);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SamplePluginHeartbeatService : IDisposable
|
||||
{
|
||||
private readonly string _heartbeatFilePath;
|
||||
private readonly Timer _timer;
|
||||
private int _disposed;
|
||||
|
||||
public SamplePluginHeartbeatService(string dataDirectory)
|
||||
{
|
||||
Directory.CreateDirectory(dataDirectory);
|
||||
_heartbeatFilePath = Path.Combine(dataDirectory, "service-heartbeat.txt");
|
||||
_timer = new Timer(OnTimerTick);
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
PublishHeartbeat();
|
||||
_timer.Change(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _disposed, 1) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_timer.Dispose();
|
||||
}
|
||||
|
||||
private void OnTimerTick(object? state)
|
||||
{
|
||||
PublishHeartbeat();
|
||||
}
|
||||
|
||||
private void PublishHeartbeat()
|
||||
{
|
||||
if (Volatile.Read(ref _disposed) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var now = DateTimeOffset.Now;
|
||||
try
|
||||
{
|
||||
File.WriteAllText(
|
||||
_heartbeatFilePath,
|
||||
now.ToString("O", CultureInfo.InvariantCulture));
|
||||
SamplePluginRuntimeStatus.MarkServiceHeartbeat(now);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SamplePluginRuntimeStatus.MarkServiceFaulted($"Heartbeat write failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user