Namespaces, assemblies, projects and directories, the solution, binaries, images, systemd units, config paths, environment variables, protocol method names, the media type and the raw chunk magic all move to MoShiro/moshiro. Existing data and deployments are not compatible and must be recreated. Also fix the architecture tests after the solution layout change and make the update tests independent of their order.
70 lines
3.4 KiB
C#
70 lines
3.4 KiB
C#
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Routing;
|
|
using MoShiro.Backend.Application;
|
|
|
|
namespace MoShiro.Backend.Api;
|
|
|
|
/// <summary>
|
|
/// 节点的展示信息:系统、架构、国家、运营商。<b>只有这几项,没有任何 IP 地址、城市、ASN、经纬度</b>——
|
|
/// 这些在 Backend 里只在查询的那一刻用到,存起来的记录里也没有,所以访客(和任何别的接口)都拿不到。
|
|
/// </summary>
|
|
public static class NodeEndpoints
|
|
{
|
|
private const string Tag = "public-nodes";
|
|
|
|
public static void Map(RouteGroupBuilder group)
|
|
{
|
|
group.MapGet("/nodes", ListAsync)
|
|
.Api("nodes_list", "Display info of the visible agents and probes: system, architecture, country and ISP (never an address)", Tag)
|
|
.Returns<PageDto<NodeInfoDto>>().ProducesProblems(403);
|
|
group.MapGet("/about", AboutAsync)
|
|
.Api("about_get", "The backend's version, tag and build time, if the site shows build info", Tag)
|
|
.Returns<AboutDto>().ProducesProblems(403);
|
|
}
|
|
|
|
/// <summary>这个后端自己的构建信息;没有(本地构建)的字段是 <c>null</c>。</summary>
|
|
internal static BuildDto Backend(bool withCommit) =>
|
|
new(MoShiro.Protocol.BuildInfo.Version, Empty(MoShiro.Protocol.BuildInfo.Tag), withCommit ? Empty(MoShiro.Protocol.BuildInfo.Commit) : null, Empty(MoShiro.Protocol.BuildInfo.BuiltAt));
|
|
|
|
private static string? Empty(string value) => value.Length == 0 ? null : value;
|
|
|
|
private static async Task<IResult> AboutAsync(HttpContext http, SettingsService settings)
|
|
{
|
|
bool show = await settings.IsShowBuildAsync(http.RequestAborted);
|
|
http.Response.Headers.CacheControl = "no-store";
|
|
return TypedResults.Json(new AboutDto(show, show ? Backend(withCommit: false) : null), ApiJsonContext.Default.AboutDto);
|
|
}
|
|
|
|
private static async Task<IResult> ListAsync(HttpContext http, AgentService agents, ProbeService probes, NodeInfoService nodes, SettingsService settings, CancellationToken ct)
|
|
{
|
|
// 和别的公开接口一样:看得见的 Agent(隐藏的只有登录后才看得见)和没有被吊销的 Probe
|
|
var visible = new HashSet<string>(StringComparer.Ordinal);
|
|
foreach (AgentView view in await agents.ListAsync(ct))
|
|
{
|
|
if (view.Agent.Status == Fleet.Server.NodeStatus.Active && (view.Agent.PublicVisible || PublicGuard.CanSeeHidden(http)))
|
|
{
|
|
visible.Add(view.Agent.Id.Value);
|
|
}
|
|
}
|
|
|
|
foreach (ProbeView probe in await probes.ListAsync(ct))
|
|
{
|
|
if (!probe.Revoked)
|
|
{
|
|
visible.Add(probe.Probe.Id);
|
|
}
|
|
}
|
|
|
|
// 版本和 tag 只在站点打开「显示构建信息」时才给访客;关着就是 null
|
|
bool showBuild = await settings.IsShowBuildAsync(ct);
|
|
var items = (await nodes.ListAsync(ct))
|
|
.Where(n => visible.Contains(n.NodeId))
|
|
.OrderBy(n => n.NodeId, StringComparer.Ordinal)
|
|
.Select(n => new NodeInfoDto(n.NodeId, n.Kind, n.Os, n.OsName, n.Arch, n.Country, n.IspKey, n.IspName, showBuild ? n.Version : null, showBuild ? n.Tag : null))
|
|
.ToList();
|
|
http.Response.Headers.CacheControl = "no-store";
|
|
return TypedResults.Json(new PageDto<NodeInfoDto>(items, null), ApiJsonContext.Default.PageDtoNodeInfoDto);
|
|
}
|
|
}
|