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,65 @@
|
||||
using Fleet.Server;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MoShiro.Backend.Api;
|
||||
using MoShiro.Backend.Application;
|
||||
using MoShiro.Backend.Gateway;
|
||||
using MoShiro.Backend.Storage.Sqlite;
|
||||
|
||||
namespace MoShiro.Backend;
|
||||
|
||||
/// <summary>
|
||||
/// 组合根:在这里显式注册所有层。配置来自 <c>appsettings.json</c>、环境变量(<c>MoShiro__DataDirectory</c> 等)和命令行。
|
||||
/// 测试用 <see cref="Build"/> 在真实端口上启动整个后端。
|
||||
/// </summary>
|
||||
public static class BackendHost
|
||||
{
|
||||
public const string ConfigurationSection = "MoShiro";
|
||||
public const int MaxRequestBodyBytes = 64 * 1024;
|
||||
|
||||
public static WebApplication Build(string[] args, Action<BackendOptions>? configureOptions = null, TimeProvider? time = null)
|
||||
{
|
||||
WebApplicationBuilder builder = WebApplication.CreateSlimBuilder(args);
|
||||
|
||||
var options = new BackendOptions();
|
||||
builder.Configuration.GetSection(ConfigurationSection).Bind(options);
|
||||
configureOptions?.Invoke(options);
|
||||
|
||||
builder.WebHost.ConfigureKestrel(kestrel => kestrel.Limits.MaxRequestBodySize = MaxRequestBodyBytes);
|
||||
builder.Logging.AddSimpleConsole(console =>
|
||||
{
|
||||
console.SingleLine = true;
|
||||
console.UseUtcTimestamp = true;
|
||||
console.TimestampFormat = "yyyy-MM-ddTHH:mm:ss.fffZ ";
|
||||
});
|
||||
|
||||
IServiceCollection services = builder.Services;
|
||||
services.AddSingleton(time ?? TimeProvider.System);
|
||||
services.AddMoShiroSqlite(options.DataDirectory);
|
||||
// 国家和运营商:Backend 用节点的来源地址查一次(Probe、Agent 不访问任何外部服务);地址留空就不查
|
||||
if (string.IsNullOrWhiteSpace(options.GeoLookupUrl))
|
||||
{
|
||||
services.AddSingleton<IGeoLookup, NoGeoLookup>();
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddSingleton<IGeoLookup>(new HttpGeoLookup(options.GeoLookupUrl));
|
||||
}
|
||||
|
||||
services.AddMoShiroApplication(options);
|
||||
services.AddMoShiroGateway();
|
||||
services.AddMoShiroApi();
|
||||
|
||||
WebApplication app = builder.Build();
|
||||
// 静默死亡的 Agent(断电、断网)不会关闭连接:15 秒一个 Ping,20 秒没有 Pong 就关闭,这样面板上的在线状态才可信
|
||||
app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(15), KeepAliveTimeout = TimeSpan.FromSeconds(20) });
|
||||
app.UseMoShiroCors(options.CorsOrigins);
|
||||
app.UseMoShiroApi();
|
||||
app.MapMoShiroApi();
|
||||
app.MapFleetEnrollment("/api/agent/v1/enroll");
|
||||
app.MapFleetLink("/api/agent/v1/rpc");
|
||||
return app;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using System.Text.Json;
|
||||
using MoShiro.Backend.Application;
|
||||
|
||||
namespace MoShiro.Backend;
|
||||
|
||||
/// <summary>
|
||||
/// 用 IP 归属查询服务(<c>GET {地址}/lookup?ip=…</c>)查国家和运营商。
|
||||
/// 失败(超时、网络不通、服务返回错误)一律返回 null,不往外抛:展示信息没有也不影响别的功能。
|
||||
/// </summary>
|
||||
public sealed class HttpGeoLookup : IGeoLookup, IDisposable
|
||||
{
|
||||
private readonly HttpClient _http;
|
||||
|
||||
public HttpGeoLookup(string baseUrl)
|
||||
{
|
||||
_http = new HttpClient { BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/"), Timeout = TimeSpan.FromSeconds(6) };
|
||||
_http.DefaultRequestHeaders.UserAgent.ParseAdd("MoShiro");
|
||||
}
|
||||
|
||||
public async ValueTask<GeoInfo?> LookupAsync(string host, CancellationToken ct)
|
||||
{
|
||||
try
|
||||
{
|
||||
using HttpResponseMessage response = await _http.GetAsync("lookup?ip=" + Uri.EscapeDataString(host), ct);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using JsonDocument doc = await JsonDocument.ParseAsync(await response.Content.ReadAsStreamAsync(ct), cancellationToken: ct);
|
||||
return Parse(doc.RootElement);
|
||||
}
|
||||
catch (Exception ex) when (ex is HttpRequestException or TaskCanceledException or JsonException or InvalidOperationException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>只取国家代码、ASN、组织名;其余字段(城市、经纬度、网段……)一概不读。</summary>
|
||||
public static GeoInfo? Parse(JsonElement root)
|
||||
{
|
||||
if (root.TryGetProperty("found", out JsonElement found) && found.ValueKind == JsonValueKind.False)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
bool isPrivate = root.TryGetProperty("is_private", out JsonElement priv) && priv.ValueKind == JsonValueKind.True;
|
||||
string? country = root.TryGetProperty("country_region", out JsonElement region) && region.TryGetProperty("iso_code", out JsonElement code) && code.ValueKind == JsonValueKind.String ? code.GetString() : null;
|
||||
int? asn = null;
|
||||
string? organization = null;
|
||||
if (root.TryGetProperty("network", out JsonElement network))
|
||||
{
|
||||
if (network.TryGetProperty("asn", out JsonElement asnValue) && asnValue.TryGetInt32(out int number))
|
||||
{
|
||||
asn = number;
|
||||
}
|
||||
|
||||
string? isp = network.TryGetProperty("isp", out JsonElement ispValue) && ispValue.ValueKind == JsonValueKind.String ? ispValue.GetString() : null;
|
||||
string? org = network.TryGetProperty("organization", out JsonElement orgValue) && orgValue.ValueKind == JsonValueKind.String ? orgValue.GetString() : null;
|
||||
organization = string.IsNullOrWhiteSpace(isp) ? org : isp;
|
||||
}
|
||||
|
||||
return new GeoInfo(country, asn, organization, isPrivate);
|
||||
}
|
||||
|
||||
public void Dispose() => _http.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>不查(<c>MoShiro__GeoLookupUrl</c> 留空)。</summary>
|
||||
public sealed class NoGeoLookup : IGeoLookup
|
||||
{
|
||||
public ValueTask<GeoInfo?> LookupAsync(string host, CancellationToken ct) => ValueTask.FromResult<GeoInfo?>(null);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<Project>
|
||||
<Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk.Web" />
|
||||
<Import Project="Sdk.props" Sdk="StuDev.AotAnywhere" Condition="'$(UseAotAnywhere)' == 'true'" />
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AssemblyName>moshiro-backend</AssemblyName>
|
||||
<RootNamespace>MoShiro.Backend</RootNamespace>
|
||||
<IsAotCompatible>true</IsAotCompatible>
|
||||
<PublishAot>true</PublishAot>
|
||||
<OptimizationPreference>Size</OptimizationPreference>
|
||||
<StackTraceSupport>false</StackTraceSupport>
|
||||
<EventSourceSupport>false</EventSourceSupport>
|
||||
<DebuggerSupport>false</DebuggerSupport>
|
||||
<MetadataUpdaterSupport>false</MetadataUpdaterSupport>
|
||||
<HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
|
||||
<IlcFoldIdenticalMethodBodies>true</IlcFoldIdenticalMethodBodies>
|
||||
<StripSymbols>true</StripSymbols>
|
||||
<!-- This service exposes APIs only; there are no static web assets to publish. -->
|
||||
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
|
||||
<SqliteStaticLink Condition="'$(SqliteStaticLink)' == '' and '$(PublishAot)' == 'true' and '$(RuntimeIdentifier)' != ''">true</SqliteStaticLink>
|
||||
<EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator>
|
||||
<EnableConfigurationBindingGenerator>true</EnableConfigurationBindingGenerator>
|
||||
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
|
||||
<OpenApiDocumentsDirectory>$(MSBuildProjectDirectory)/../../openapi</OpenApiDocumentsDirectory>
|
||||
<OpenApiGenerateDocumentsOptions>--document-name v1 --file-name v1</OpenApiGenerateDocumentsOptions>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.ApiDescription.Server" PrivateAssets="all" />
|
||||
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" Condition="'$(SqliteStaticLink)' != 'true'" />
|
||||
<PackageReference Include="SQLitePCLRaw.lib.e_sqlite3" ExcludeAssets="native" Condition="'$(SqliteStaticLink)' == 'true'" />
|
||||
<ProjectReference Include="..\MoShiro.Backend.Api\MoShiro.Backend.Api.csproj" />
|
||||
<ProjectReference Include="..\MoShiro.Backend.Gateway\MoShiro.Backend.Gateway.csproj" />
|
||||
<ProjectReference Include="..\MoShiro.Backend.Storage.Sqlite\MoShiro.Backend.Storage.Sqlite.csproj" />
|
||||
</ItemGroup>
|
||||
<Import Project="StaticSqlite.targets" />
|
||||
<Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk.Web" />
|
||||
<Import Project="Sdk.targets" Sdk="StuDev.AotAnywhere" Condition="'$(UseAotAnywhere)' == 'true'" />
|
||||
</Project>
|
||||
@@ -0,0 +1,3 @@
|
||||
using MoShiro.Backend;
|
||||
|
||||
await BackendHost.Build(args).RunAsync();
|
||||
@@ -0,0 +1,71 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<_SqliteToolchainTargets>SetupOSSpecificProps</_SqliteToolchainTargets>
|
||||
<_SqliteToolchainTargets Condition="'$(UseAotAnywhere)' == 'true'">SetupOSSpecificProps;OverwriteTargetTriple;SetPathToZig</_SqliteToolchainTargets>
|
||||
</PropertyGroup>
|
||||
<ItemGroup Condition="'$(SqliteStaticLink)' == 'true'">
|
||||
<DirectPInvoke Include="e_sqlite3" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="PrepareStaticSqliteSource" Condition="'$(SqliteStaticLink)' == 'true'">
|
||||
<Error Condition="'$(RuntimeIdentifier)' != 'linux-x64' and '$(RuntimeIdentifier)' != 'linux-arm64' and
|
||||
'$(RuntimeIdentifier)' != 'linux-musl-x64' and '$(RuntimeIdentifier)' != 'linux-musl-arm64' and
|
||||
'$(RuntimeIdentifier)' != 'osx-x64' and '$(RuntimeIdentifier)' != 'osx-arm64' and
|
||||
'$(RuntimeIdentifier)' != 'win-x64' and '$(RuntimeIdentifier)' != 'win-arm64'"
|
||||
Text="Static SQLite is configured for the eight supported x64/arm64 Linux, musl, macOS and Windows targets. Unsupported RID: $(RuntimeIdentifier)." />
|
||||
<PropertyGroup>
|
||||
<_SqliteCache>$([System.IO.Path]::GetFullPath('$(BaseIntermediateOutputPath)sqlite/$(MoShiroSqliteSourceVersion)/'))</_SqliteCache>
|
||||
<_SqliteArchive>$(_SqliteCache)sqlite-amalgamation-$(MoShiroSqliteSourceVersion).zip</_SqliteArchive>
|
||||
<_SqliteSource>$(_SqliteCache)sqlite-amalgamation-$(MoShiroSqliteSourceVersion)/sqlite3.c</_SqliteSource>
|
||||
<_SqliteObjectDirectory>$(_SqliteCache)$(RuntimeIdentifier)/$(UseAotAnywhere)/</_SqliteObjectDirectory>
|
||||
<_SqliteObject>$(_SqliteObjectDirectory)e_sqlite3.o</_SqliteObject>
|
||||
<_SqliteObject Condition="$(RuntimeIdentifier.StartsWith('win'))">$(_SqliteObjectDirectory)e_sqlite3.obj</_SqliteObject>
|
||||
</PropertyGroup>
|
||||
<MakeDir Directories="$(_SqliteObjectDirectory)" />
|
||||
<DownloadFile SourceUrl="https://www.sqlite.org/$(MoShiroSqliteSourceYear)/sqlite-amalgamation-$(MoShiroSqliteSourceVersion).zip"
|
||||
DestinationFolder="$(_SqliteCache)" Condition="!Exists('$(_SqliteArchive)')" />
|
||||
<GetFileHash Files="$(_SqliteArchive)" Algorithm="SHA256">
|
||||
<Output TaskParameter="Hash" PropertyName="_SqliteArchiveHash" />
|
||||
</GetFileHash>
|
||||
<Error Condition="'$(_SqliteArchiveHash.ToLowerInvariant())' != '$(MoShiroSqliteSourceSha256)'"
|
||||
Text="SQLite source SHA256 mismatch: $(_SqliteArchiveHash)." />
|
||||
<Unzip SourceFiles="$(_SqliteArchive)" DestinationFolder="$(_SqliteCache)" Condition="!Exists('$(_SqliteSource)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileStaticSqliteObject" Condition="'$(SqliteStaticLink)' == 'true'"
|
||||
DependsOnTargets="PrepareStaticSqliteSource;$(_SqliteToolchainTargets)"
|
||||
Inputs="$(_SqliteSource);$(MSBuildThisFileFullPath)" Outputs="$(_SqliteObject)">
|
||||
<PropertyGroup>
|
||||
<_SqliteUseMsvc>false</_SqliteUseMsvc>
|
||||
<_SqliteUseMsvc Condition="$(RuntimeIdentifier.StartsWith('win')) and '$(_AotAnywhereWindowsCross)' != 'true'">true</_SqliteUseMsvc>
|
||||
<_SqliteCompiler>"$(CppCompilerAndLinker)"</_SqliteCompiler>
|
||||
<_SqliteCompiler Condition="'$(CppCompilerAndLinker)' == ''">cc</_SqliteCompiler>
|
||||
<_SqliteCompiler Condition="'$(TargetTriple)' != ''">$(_SqliteCompiler) --target=$(TargetTriple)</_SqliteCompiler>
|
||||
<_SqliteCompiler Condition="'$(SysRoot)' != ''">$(_SqliteCompiler) --sysroot="$(SysRoot)"</_SqliteCompiler>
|
||||
<_SqliteCompiler Condition="'$(UseAotAnywhere)' == 'true'">"$(_AotAnywhereZigExe)" cc -target $(TargetTriple)</_SqliteCompiler>
|
||||
<_SqliteCompiler Condition="'$(_SqliteUseMsvc)' == 'true'">cl</_SqliteCompiler>
|
||||
</PropertyGroup>
|
||||
<Message Importance="high" Text="Compiling SQLite $(MoShiroSqliteSourceVersion) into the $(RuntimeIdentifier) NativeAOT executable." />
|
||||
<Exec Condition="'$(_SqliteUseMsvc)' != 'true'"
|
||||
Command="$(_SqliteCompiler) -Os -fPIC -c "$(_SqliteSource)" -o "$(_SqliteObject)" -DSQLITE_API= -DSQLITE_THREADSAFE=1 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_ENABLE_COLUMN_METADATA -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_SNAPSHOT -DSQLITE_ENABLE_UNLOCK_NOTIFY" />
|
||||
<Exec Condition="'$(_SqliteUseMsvc)' == 'true'"
|
||||
Command="cl /nologo /O1 /MT /c "$(_SqliteSource)" /Fo"$(_SqliteObject)" /DSQLITE_API= /DSQLITE_THREADSAFE=1 /DSQLITE_DEFAULT_MEMSTATUS=0 /DSQLITE_ENABLE_COLUMN_METADATA /DSQLITE_ENABLE_FTS4 /DSQLITE_ENABLE_FTS5 /DSQLITE_ENABLE_MATH_FUNCTIONS /DSQLITE_ENABLE_RTREE /DSQLITE_ENABLE_SNAPSHOT /DSQLITE_ENABLE_UNLOCK_NOTIFY" />
|
||||
</Target>
|
||||
|
||||
<!-- AotAnywhere runs before LinkNative; register the object before either linker starts. -->
|
||||
<Target Name="LinkStaticSqlite" Condition="'$(SqliteStaticLink)' == 'true'"
|
||||
BeforeTargets="AotAnywhereDirectLinkNative;AotAnywhereDirectLinkMacNative;AotAnywhereDirectLinkWindows;LinkNative"
|
||||
DependsOnTargets="CompileStaticSqliteObject">
|
||||
<ItemGroup>
|
||||
<NativeLibrary Include="$(_SqliteObject)" />
|
||||
<LinkerArg Include=""$(_SqliteObject)"" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="RemoveStaticSqliteRuntimeFiles" Condition="'$(SqliteStaticLink)' == 'true'" AfterTargets="ComputeFilesToPublish">
|
||||
<ItemGroup>
|
||||
<ResolvedFileToPublish Remove="@(ResolvedFileToPublish)"
|
||||
Condition="'%(ResolvedFileToPublish.Filename)' == 'libe_sqlite3' or '%(ResolvedFileToPublish.Filename)' == 'e_sqlite3'" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
Reference in new issue
Block a user