refactor!: rename the project from Monitor to MoShiro [CI]
ci/woodpecker/push/main-amd64-build Pipeline was successful
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:
1 parent
27ac7fb787
commit
2e146d4da7
309 files changed
+1565
-1572
No files matched your search
@@ -0,0 +1,95 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Fleet.Core;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using MoShiro.Backend.Application;
|
||||
using MoShiro.Protocol;
|
||||
|
||||
namespace MoShiro.Backend.Api;
|
||||
|
||||
internal static class QueryHelpers
|
||||
{
|
||||
/// <summary>查询的统一超时(默认 10 s):超时返回 503,而不是让请求一直挂着。</summary>
|
||||
public static async Task<IResult> GuardedAsync(HttpContext http, Func<CancellationToken, Task<IResult>> work)
|
||||
{
|
||||
BackendOptions options = http.RequestServices.GetRequiredService<BackendOptions>();
|
||||
using var timeout = CancellationTokenSource.CreateLinkedTokenSource(http.RequestAborted);
|
||||
timeout.CancelAfter(options.QueryTimeout);
|
||||
try
|
||||
{
|
||||
return await work(timeout.Token);
|
||||
}
|
||||
catch (OperationCanceledException) when (!http.RequestAborted.IsCancellationRequested)
|
||||
{
|
||||
return Problems.Create(http, MoShiroErrors.StorageUnavailable, null);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存策略:已经结束的绝对区间(<c>to</c> 早于当前时间 − 2 分钟)可以永久缓存,并带 ETag;相对时间段不缓存。
|
||||
/// 返回非空时表示命中 If-None-Match,直接返回 304。
|
||||
/// </summary>
|
||||
public static IResult? ApplyCaching(HttpContext http, QueryRange range, long nowMs, string material)
|
||||
{
|
||||
bool closed = !range.IsRelative && range.RequestedToMs < nowMs - (2 * Steps.Minute);
|
||||
if (!closed)
|
||||
{
|
||||
http.Response.Headers.CacheControl = "no-store";
|
||||
return null;
|
||||
}
|
||||
|
||||
string etag = ETagOf(http.Request.Path + http.Request.QueryString.Value + material);
|
||||
http.Response.Headers.CacheControl = "public, max-age=31536000, immutable";
|
||||
http.Response.Headers.ETag = etag;
|
||||
return MatchesIfNoneMatch(http, etag) ? TypedResults.StatusCode(StatusCodes.Status304NotModified) : null;
|
||||
}
|
||||
|
||||
/// <summary>目录:<c>max-age=300</c>,并带 ETag。</summary>
|
||||
public static IResult? ApplyCatalogCaching(HttpContext http, string material)
|
||||
{
|
||||
string etag = ETagOf(http.Request.Path + material);
|
||||
http.Response.Headers.CacheControl = "public, max-age=300";
|
||||
http.Response.Headers.ETag = etag;
|
||||
return MatchesIfNoneMatch(http, etag) ? TypedResults.StatusCode(StatusCodes.Status304NotModified) : null;
|
||||
}
|
||||
|
||||
public static string ETagOf(string material) =>
|
||||
"\"" + Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(material)))[..32] + "\"";
|
||||
|
||||
private static bool MatchesIfNoneMatch(HttpContext http, string etag)
|
||||
{
|
||||
foreach (string? candidate in http.Request.Headers.IfNoneMatch)
|
||||
{
|
||||
if (candidate is not null && candidate.Split(',', StringSplitOptions.TrimEntries).Contains(etag))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>线路 id(<c>agent~probe</c>,或只有一个 Probe 时的 Agent id)→ 可以展示的线路。否则 404 / 422(不暴露被隐藏的线路存在与否)。</summary>
|
||||
public static async ValueTask<Result<LineView>> FindVisibleLineAsync(HttpContext http, LineService lines, string id, CancellationToken ct)
|
||||
{
|
||||
Result<LineView> found = await lines.ResolveAsync(id, ct);
|
||||
if (!found.TryGet(out LineView? line, out FleetError? error))
|
||||
{
|
||||
return Result<LineView>.Fail(error);
|
||||
}
|
||||
|
||||
return line.Agent.Agent.Status == Fleet.Server.NodeStatus.Active && (line.Agent.Agent.PublicVisible || PublicGuard.CanSeeHidden(http)) && line.Probe.RevokedAtMs is null
|
||||
? found
|
||||
: Result<LineView>.Fail(MoShiroErrors.AgentNotFound, "line not found");
|
||||
}
|
||||
|
||||
/// <summary>找到可以展示的线路:已激活,并且(对外可见,或者访问者已认证)。否则 404(不暴露被隐藏的线路存在与否)。</summary>
|
||||
public static async ValueTask<Result<AgentView>> FindVisibleAgentAsync(HttpContext http, AgentService agents, string id, CancellationToken ct)
|
||||
{
|
||||
AgentView? view = await agents.GetAsync(new NodeId(id), ct);
|
||||
return view is { Agent.Status: Fleet.Server.NodeStatus.Active } && (view.Agent.PublicVisible || PublicGuard.CanSeeHidden(http))
|
||||
? Result<AgentView>.Ok(view)
|
||||
: Result<AgentView>.Fail(MoShiroErrors.AgentNotFound, "agent not found");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user