refactor!: rename the project from Monitor to MoShiro [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful

Namespaces, assemblies, solution, binaries, images, systemd units, config paths, environment variables, protocol methods and the Linux user are all renamed. Breaking: existing databases, node identities and installed units must be recreated.
This commit is contained in:
justme committed 2026-10-07 02:03:25 +08:00
1 parent 27ac7fb787
commit 2e146d4da7
309 files changed
+1565 -1572

No files matched your search

@@ -0,0 +1,91 @@
using Fleet.Core;
using MoShiro.Backend.Analysis;
using MoShiro.Protocol;
namespace MoShiro.Backend.Application;
/// <summary>请求的指标:导出 id(<c>rtt.p95</c>)与评分 id(<c>score.mc</c>)。</summary>
public sealed record MetricSelection(IReadOnlyList<string> ExportIds, IReadOnlyList<string> ScoreModelIds)
{
public bool WantsScores => ScoreModelIds.Count > 0;
public IEnumerable<string> AllIds => ExportIds.Concat(ScoreModelIds.Select(m => "score." + m));
public static Result<MetricSelection> Resolve(string? metrics, string? presets, int maxMetrics)
{
var ids = new List<string>();
if (presets is not null)
{
foreach (string presetId in presets.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
{
PresetDef? preset = MetricRegistry.FindPreset(presetId);
if (preset is null)
{
return Result<MetricSelection>.Fail(MoShiroErrors.UnknownPreset, $"unknown preset {presetId}");
}
ids.AddRange(preset.MetricIds);
}
}
if (metrics is not null)
{
ids.AddRange(metrics.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
}
ids = [.. ids.Distinct(StringComparer.Ordinal)];
if (ids.Count > maxMetrics)
{
return Result<MetricSelection>.Fail(MoShiroErrors.TooManyMetrics, $"at most {maxMetrics} metrics per request");
}
var exports = new List<string>();
var scores = new List<string>();
foreach (string id in ids)
{
if (id.StartsWith("score.", StringComparison.Ordinal))
{
string model = id["score.".Length..];
if (ModelRegistry.Find(model) is null)
{
return Result<MetricSelection>.Fail(MoShiroErrors.UnknownMetric, $"unknown metric {id}");
}
scores.Add(model);
}
else if (MetricRegistry.TryFindExport(id, out _, out _))
{
exports.Add(id);
}
else
{
return Result<MetricSelection>.Fail(MoShiroErrors.UnknownMetric, $"unknown metric {id}");
}
}
return Result<MetricSelection>.Ok(new MetricSelection(exports, scores));
}
}
public static class ExportEvaluator
{
/// <summary>导出指定的值;没有样本的指标不出现在结果里。</summary>
public static Dictionary<string, double> Evaluate(MetricSet set, IEnumerable<string> exportIds, double durationSeconds)
{
var values = new Dictionary<string, double>(StringComparer.Ordinal);
foreach (string id in exportIds)
{
if (MetricRegistry.TryFindExport(id, out MetricDef def, out MetricExport export)
&& set.TryGet(def.Id, out Accumulator acc)
&& MetricDef.Export(acc, export, durationSeconds) is { } value
&& double.IsFinite(value))
{
values[id] = value;
}
}
return values;
}
public static IEnumerable<string> AllExportIds() => MetricRegistry.AllExports().Select(e => e.Export.Id);
}