From 83e5120377ad69673df73d6aae0db96af5992927 Mon Sep 17 00:00:00 2001 From: JustMe Date: Wed, 7 Oct 2026 01:49:04 +0800 Subject: [PATCH] refactor!: rename the project from Monitor to MoShiro 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. --- .woodpecker/verify.yml | 2 +- AGENTS.md | 16 +-- Directory.Packages.props | 6 +- Monitor.slnx => MoShiro.slnx | 34 +++--- README.md | 14 +-- backend/{Monitor.slnx => MoShiro.slnx} | 32 +++--- backend/README.md | 24 ++-- backend/agent/README.md | 14 +-- .../AgentApp.cs | 52 ++++----- .../AgentConfig.cs | 4 +- .../Chunks/ChunkAssembler.cs | 8 +- .../DataPlane/Registries.cs | 6 +- .../Host/HostSampler.cs | 4 +- .../src/MoShiro.Agent/MoShiro.Agent.csproj} | 8 +- .../Peer/PeerHub.cs | 22 ++-- .../Program.cs | 4 +- .../Tasks/TargetRunners.cs | 6 +- .../Tasks/TaskManager.cs | 6 +- .../Tests/TestRunner.cs | 34 +++--- backend/fleet/src/Fleet.Core/StringId.cs | 2 +- backend/fleet/src/Fleet.Link/FleetLink.cs | 2 +- backend/fleet/src/Fleet.Rpc/FleetMethods.cs | 2 +- .../FleetServerOptions.cs | 2 +- .../Fleet.Server.Abstractions/IFleetStore.cs | 2 +- .../Fleet.Server.Link/FleetServerBuilder.cs | 2 +- backend/fleet/tools/fleet-enroll/Program.cs | 2 +- backend/openapi/v1.json | 4 +- backend/probe/README.md | 18 +-- .../Link/AgentConnection.cs | 26 ++--- .../Link/AgentDirectory.cs | 4 +- .../Link/Support.cs | 10 +- .../src/MoShiro.Probe/MoShiro.Probe.csproj} | 8 +- .../ProbeApp.cs | 20 ++-- .../ProbeConfig.cs | 2 +- .../Program.cs | 4 +- .../MoShiro.Probe.Tests.csproj} | 2 +- .../ProbeTests.cs | 4 +- .../Blocks/BlockBase.cs | 4 +- .../Blocks/BlockCatalog.cs | 4 +- .../Blocks/Bulk.cs | 4 +- .../Blocks/Echo.cs | 4 +- .../Blocks/Session.cs | 4 +- .../Blocks/Train.cs | 4 +- .../Core/Contracts.cs | 4 +- .../Core/MonoClock.cs | 2 +- .../Core/RowStore.cs | 4 +- .../Core/RunningBlock.cs | 2 +- .../Execution/BudgetGuard.cs | 4 +- .../Merging/ChunkFinalizer.cs | 4 +- .../Merging/FragmentMerger.cs | 10 +- .../MoShiro.Measurement.csproj} | 4 +- .../Net/Tcp.cs | 4 +- .../Net/TcpInfo.cs | 4 +- .../Net/UdpMux.cs | 4 +- .../Platform/PlatformDetector.cs | 4 +- .../Update/UpdateBridge.cs | 8 +- .../Catalog/KindSpec.cs | 2 +- .../Catalog/Kinds/Kinds.cs | 2 +- .../Catalog/ParamSpec.cs | 2 +- .../Ids/MonitorIds.cs | 2 +- .../MoShiro.Protocol.csproj} | 10 +- .../MonitorErrors.cs | 6 +- .../ProtocolLimits.cs | 14 +-- .../Raw/Crc32c.cs | 2 +- .../Raw/RawChunk.cs | 2 +- .../Raw/RawChunkCodec.cs | 12 +- .../Raw/StreamBuilder.cs | 2 +- .../Rpc/MonitorRpc.cs | 38 +++---- .../Tasks/TaskSet.cs | 6 +- .../Wire/TcpWire.cs | 2 +- .../Wire/UdpPacket.cs | 2 +- .../MeasurementTests.cs | 4 +- .../MoShiro.Measurement.Tests.csproj} | 2 +- .../PlatformDetectorTests.cs | 2 +- .../CatalogTests.cs | 12 +- .../MoShiro.Protocol.Tests.csproj} | 4 +- .../RawChunkCodecTests.cs | 10 +- .../Accumulators/Accumulator.cs | 2 +- .../Accumulators/AccumulatorCodec.cs | 2 +- .../Accumulators/HistogramAcc.cs | 2 +- .../Clock/ClockDriftFit.cs | 2 +- .../Engine/ChangePoint.cs | 2 +- .../Engine/ChunkView.cs | 4 +- .../Engine/MetricDef.cs | 4 +- .../Engine/TestEvaluator.cs | 4 +- .../Engine/WindowEvaluator.cs | 4 +- .../Metrics/LinkMetrics.cs | 2 +- .../Metrics/MetricRegistry.cs | 2 +- .../Metrics/SessionMetrics.cs | 2 +- .../Metrics/TcpMetrics.cs | 2 +- .../MoShiro.Backend.Analysis.csproj} | 2 +- .../Models/Models.cs | 2 +- .../Models/ServiceModel.cs | 2 +- .../Ops/EchoOps.cs | 4 +- .../Ops/Ops.cs | 2 +- .../Ops/SessionOps.cs | 4 +- .../Admin/AgentEndpoints.cs | 12 +- .../Admin/AuthEndpoints.cs | 8 +- .../Admin/BuildEndpoints.cs | 8 +- .../Admin/DataEndpoints.cs | 14 +-- .../Admin/LinkEndpoints.cs | 10 +- .../Admin/SystemEndpoints.cs | 6 +- .../Admin/TaskEndpoints.cs | 8 +- .../ApiModule.cs | 14 +-- .../Common/Concurrency.cs | 2 +- .../Common/EndpointConventions.cs | 2 +- .../Common/Guards.cs | 18 +-- .../Common/Mappers.cs | 8 +- .../Common/Problems.cs | 30 ++--- .../Common/QueryHelpers.cs | 12 +- .../Contracts/AdminDtos.cs | 2 +- .../Contracts/ApiJsonContext.cs | 4 +- .../Contracts/CommonDtos.cs | 2 +- .../Contracts/PublicDtos.cs | 2 +- .../MoShiro.Backend.Api.csproj} | 2 +- .../OpsEndpoints.cs | 10 +- .../Public/CatalogEndpoints.cs | 14 +-- .../Public/HostEndpoints.cs | 10 +- .../Public/LiveEndpoints.cs | 8 +- .../Public/LiveTopics.cs | 10 +- .../Public/NodeEndpoints.cs | 6 +- .../Public/QueryEndpoints.cs | 12 +- .../Admin/EventService.cs | 2 +- .../Admin/JoinTokenService.cs | 2 +- .../Admin/OpsService.cs | 24 ++-- .../Admin/RawBrowserService.cs | 10 +- .../Admin/SettingsService.cs | 2 +- .../Agents/AgentEventService.cs | 6 +- .../Agents/AgentRuntime.cs | 4 +- .../Agents/AgentService.cs | 4 +- .../Agents/HostStatusService.cs | 6 +- .../Agents/LinkService.cs | 2 +- .../Agents/MonitorFleetHooks.cs | 28 ++--- .../Agents/ProbeService.cs | 20 ++-- .../Analysis/AnalysisScheduler.cs | 4 +- .../Analysis/MetricRecompute.cs | 4 +- .../Analysis/WindowComputer.cs | 6 +- .../ApplicationServiceCollectionExtensions.cs | 8 +- .../Auth/AuthModels.cs | 2 +- .../Auth/AuthService.cs | 8 +- .../Auth/LoginRateLimiter.cs | 2 +- .../BackendCounters.cs | 2 +- .../BackendOptions.cs | 4 +- .../Ingest/IngestService.cs | 6 +- .../Live/HotLayer.cs | 6 +- .../Live/HotLayerBackfill.cs | 4 +- .../Live/LiveHub.cs | 4 +- .../MoShiro.Backend.Application.csproj} | 2 +- .../Models/AgentModels.cs | 4 +- .../Models/RawModels.cs | 4 +- .../Models/TaskAndTestModels.cs | 4 +- .../Nodes/IspClassifier.cs | 2 +- .../Nodes/NodeInfo.cs | 2 +- .../Nodes/NodeInfoService.cs | 4 +- .../Ports/IAgentGateway.cs | 4 +- .../Ports/IAuthStore.cs | 2 +- .../Ports/StorePorts.cs | 6 +- .../Query/Bucketing.cs | 4 +- .../Query/Lines.cs | 12 +- .../Query/MetricSelection.cs | 14 +-- .../Query/QueryResults.cs | 4 +- .../Query/QueryService.cs | 12 +- .../Query/RangeResolver.cs | 14 +-- .../Query/RowLoader.cs | 8 +- .../Query/SourcePlanner.cs | 2 +- .../Query/Steps.cs | 2 +- .../Retention/RetentionService.cs | 2 +- .../StartupTasks.cs | 2 +- .../Tasks/EffectiveTasks.cs | 4 +- .../Tasks/TaskPlanner.cs | 6 +- .../Tasks/TaskService.cs | 14 +-- .../Tests/Plans.cs | 4 +- .../Tests/TestFinalizer.cs | 6 +- .../Tests/TestModels.cs | 4 +- .../Tests/TestService.cs | 24 ++-- .../Updates/ReleaseService.cs | 6 +- .../ValidationError.cs | 6 +- .../ConnectionShutdown.cs | 2 +- .../FleetGateway.cs | 22 ++-- .../GatewayServiceCollectionExtensions.cs | 28 ++--- .../MoShiro.Backend.Gateway.csproj} | 2 +- .../ProbeAgentsStateProvider.cs | 8 +- .../RawChunkInbox.cs | 8 +- .../TaskSetStateProvider.cs | 8 +- .../MoShiro.Backend.Storage.Sqlite.csproj} | 4 +- .../Schema.cs | 2 +- .../Sql.cs | 2 +- .../SqliteAgentStore.cs | 24 ++-- .../SqliteAuthStore.cs | 4 +- .../SqliteConfigStores.cs | 10 +- .../SqliteDatabase.cs | 4 +- .../SqliteHostStore.cs | 6 +- .../SqliteMetricStore.cs | 6 +- .../SqliteNodeMetaStore.cs | 4 +- .../SqliteRawStore.cs | 6 +- .../SqliteStorageHealth.cs | 4 +- .../SqliteTestStore.cs | 6 +- .../StorageJson.cs | 2 +- .../StorageServiceCollectionExtensions.cs | 6 +- .../BackendHost.cs | 28 ++--- .../HttpGeoLookup.cs | 8 +- .../MoShiro.Backend.csproj} | 10 +- .../Program.cs | 2 +- .../StaticSqlite.targets | 12 +- .../AccumulatorTests.cs | 4 +- .../MoShiro.Backend.Analysis.Tests.csproj} | 4 +- .../ModelAndTestEvaluatorTests.cs | 6 +- .../OpTests.cs | 6 +- .../AgentEndToEndTests.cs | 8 +- .../AgentHarness.cs | 10 +- .../AotSmokeTests.cs | 14 +-- .../ApiBasicsTests.cs | 6 +- .../ArchitectureTests.cs | 59 +++++----- .../BackendFixture.cs | 12 +- .../EnrollmentAndTaskSetTests.cs | 8 +- .../HostTests.cs | 8 +- .../IngestAndQueryTests.cs | 10 +- .../LinkTests.cs | 4 +- .../LiveTests.cs | 6 +- .../LoginRateLimitTests.cs | 2 +- .../MoShiro.Backend.Tests.csproj} | 8 +- .../NodeInfoTests.cs | 6 +- .../OnDemandTestsTests.cs | 8 +- .../OpenApiConformanceTests.cs | 2 +- .../OperationsAndSecurityTests.cs | 12 +- .../PersistenceTests.cs | 6 +- .../PlanTests.cs | 6 +- .../ProbeEndToEndTests.cs | 2 +- .../ProbeHarness.cs | 6 +- .../QueryPlanningTests.cs | 28 ++--- .../SseClient.cs | 2 +- .../StorageTests.cs | 26 ++--- .../UpdateTests.cs | 19 ++-- .../AgentSimulator.cs | 46 ++++---- .../AgentWire.cs | 2 +- .../ChunkFactory.cs | 4 +- .../MoShiro.TestSupport.csproj} | 2 +- .../ProbeSimulator.cs | 26 ++--- .../MoShiro.Tar.csproj} | 0 ci/{Monitor.Tar => MoShiro.Tar}/Program.cs | 2 +- ci/build-main-amd64.sh | 6 +- ci/index-backend-image.sh | 2 +- ci/package-cross-platform.ps1 | 20 ++-- ci/publish-gitea-release.sh | 42 +++---- ci/release-cross-platform.ps1 | 10 +- ci/release-linux.sh | 18 +-- ci/release-node-images.sh | 20 ++-- compose.yaml | 14 +-- docs/analysis.md | 4 +- docs/api-guidelines.md | 2 +- docs/api.md | 8 +- docs/architecture.md | 16 +-- docs/coding-style.md | 8 +- docs/deployment.md | 94 ++++++++-------- docs/enrollment.md | 26 ++--- docs/fleet/link.md | 6 +- docs/fleet/overview.md | 16 +-- docs/fleet/update.md | 22 ++-- docs/measurement.md | 12 +- docs/project-layout.md | 106 +++++++++--------- docs/protocol.md | 34 +++--- docs/storage.md | 6 +- packaging/compose/agent/compose.yaml | 12 +- packaging/compose/backend/compose.yaml | 8 +- packaging/compose/probe/compose.yaml | 12 +- packaging/container/Agent.Containerfile | 16 +-- .../container/Agent.NativeBuild.Containerfile | 32 +++--- packaging/container/Backend.Containerfile | 8 +- packaging/container/Probe.Containerfile | 16 +-- .../container/Probe.NativeBuild.Containerfile | 32 +++--- packaging/install.sh | 46 ++++---- packaging/openwrt/monitor.keep | 1 - ...{monitor-probe.init => moshiro-probe.init} | 10 +- packaging/openwrt/moshiro.keep | 1 + .../systemd/monitor-probe-container.service | 16 --- .../systemd/monitor-probe-docker.service | 16 --- .../systemd/monitor-probe-rootless.service | 16 --- ...ervice => moshiro-agent-container.service} | 10 +- ...r.service => moshiro-agent-docker.service} | 10 +- ...service => moshiro-agent-rootless.service} | 10 +- ...or-agent.service => moshiro-agent.service} | 10 +- .../systemd/moshiro-probe-container.service | 16 +++ .../systemd/moshiro-probe-docker.service | 16 +++ .../systemd/moshiro-probe-rootless.service | 16 +++ ...or-probe.service => moshiro-probe.service} | 10 +- packaging/update/install-updater.sh | 48 ++++---- .../{monitor-update.sh => moshiro-update.sh} | 28 ++--- scripts/package.sh | 8 +- scripts/publish.sh | 18 +-- scripts/smoke-linux.sh | 28 ++--- scripts/smoke-systemd.sh | 22 ++-- scripts/smoke-wsl.py | 14 +-- scripts/stability_wsl.py | 62 +++++----- scripts/test-container-updater.py | 10 +- web/README.md | 2 +- web/admin/index.html | 2 +- web/admin/package.json | 2 +- web/admin/src/App.tsx | 4 +- web/admin/src/pages/Agents.tsx | 2 +- web/admin/src/pages/Probes.tsx | 4 +- web/build-info.mjs | 8 +- web/display/index.html | 2 +- web/display/package.json | 2 +- web/package-lock.json | 12 +- web/package.json | 2 +- web/shared/api/schema.ts | 2 +- web/shared/api/source.ts | 6 +- web/shared/hooks.ts | 4 +- web/shared/ui/index.tsx | 2 +- 309 files changed, 1505 insertions(+), 1499 deletions(-) rename Monitor.slnx => MoShiro.slnx (55%) rename backend/{Monitor.slnx => MoShiro.slnx} (58%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/AgentApp.cs (89%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/AgentConfig.cs (96%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/Chunks/ChunkAssembler.cs (95%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/DataPlane/Registries.cs (99%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/Host/HostSampler.cs (99%) rename backend/{probe/src/Monitor.Probe/Monitor.Probe.csproj => agent/src/MoShiro.Agent/MoShiro.Agent.csproj} (78%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/Peer/PeerHub.cs (93%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/Program.cs (93%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/Tasks/TargetRunners.cs (98%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/Tasks/TaskManager.cs (99%) rename backend/agent/src/{Monitor.Agent => MoShiro.Agent}/Tests/TestRunner.cs (90%) rename backend/probe/src/{Monitor.Probe => MoShiro.Probe}/Link/AgentConnection.cs (95%) rename backend/probe/src/{Monitor.Probe => MoShiro.Probe}/Link/AgentDirectory.cs (98%) rename backend/probe/src/{Monitor.Probe => MoShiro.Probe}/Link/Support.cs (93%) rename backend/{agent/src/Monitor.Agent/Monitor.Agent.csproj => probe/src/MoShiro.Probe/MoShiro.Probe.csproj} (78%) rename backend/probe/src/{Monitor.Probe => MoShiro.Probe}/ProbeApp.cs (92%) rename backend/probe/src/{Monitor.Probe => MoShiro.Probe}/ProbeConfig.cs (98%) rename backend/probe/src/{Monitor.Probe => MoShiro.Probe}/Program.cs (95%) rename backend/probe/tests/{Monitor.Probe.Tests/Monitor.Probe.Tests.csproj => MoShiro.Probe.Tests/MoShiro.Probe.Tests.csproj} (82%) rename backend/probe/tests/{Monitor.Probe.Tests => MoShiro.Probe.Tests}/ProbeTests.cs (98%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Blocks/BlockBase.cs (98%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Blocks/BlockCatalog.cs (97%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Blocks/Bulk.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Blocks/Echo.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Blocks/Session.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Blocks/Train.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Core/Contracts.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Core/MonoClock.cs (97%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Core/RowStore.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Core/RunningBlock.cs (98%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Execution/BudgetGuard.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Merging/ChunkFinalizer.cs (98%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Merging/FragmentMerger.cs (96%) rename backend/shared/{Monitor.Measurement/Monitor.Measurement.csproj => MoShiro.Measurement/MoShiro.Measurement.csproj} (67%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Net/Tcp.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Net/TcpInfo.cs (98%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Net/UdpMux.cs (99%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Platform/PlatformDetector.cs (98%) rename backend/shared/{Monitor.Measurement => MoShiro.Measurement}/Update/UpdateBridge.cs (96%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Catalog/KindSpec.cs (99%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Catalog/Kinds/Kinds.cs (99%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Catalog/ParamSpec.cs (99%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Ids/MonitorIds.cs (98%) rename backend/shared/{Monitor.Protocol/Monitor.Protocol.csproj => MoShiro.Protocol/MoShiro.Protocol.csproj} (87%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/MonitorErrors.cs (95%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/ProtocolLimits.cs (75%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Raw/Crc32c.cs (96%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Raw/RawChunk.cs (99%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Raw/RawChunkCodec.cs (97%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Raw/StreamBuilder.cs (98%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Rpc/MonitorRpc.cs (94%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Tasks/TaskSet.cs (94%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Wire/TcpWire.cs (99%) rename backend/shared/{Monitor.Protocol => MoShiro.Protocol}/Wire/UdpPacket.cs (99%) rename backend/shared/tests/{Monitor.Measurement.Tests => MoShiro.Measurement.Tests}/MeasurementTests.cs (99%) rename backend/shared/tests/{Monitor.Measurement.Tests/Monitor.Measurement.Tests.csproj => MoShiro.Measurement.Tests/MoShiro.Measurement.Tests.csproj} (82%) rename backend/shared/tests/{Monitor.Measurement.Tests => MoShiro.Measurement.Tests}/PlatformDetectorTests.cs (97%) rename backend/shared/tests/{Monitor.Protocol.Tests => MoShiro.Protocol.Tests}/CatalogTests.cs (93%) rename backend/shared/tests/{Monitor.Protocol.Tests/Monitor.Protocol.Tests.csproj => MoShiro.Protocol.Tests/MoShiro.Protocol.Tests.csproj} (65%) rename backend/shared/tests/{Monitor.Protocol.Tests => MoShiro.Protocol.Tests}/RawChunkCodecTests.cs (97%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Accumulators/Accumulator.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Accumulators/AccumulatorCodec.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Accumulators/HistogramAcc.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Clock/ClockDriftFit.cs (98%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Engine/ChangePoint.cs (98%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Engine/ChunkView.cs (95%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Engine/MetricDef.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Engine/TestEvaluator.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Engine/WindowEvaluator.cs (97%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Metrics/LinkMetrics.cs (98%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Metrics/MetricRegistry.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Metrics/SessionMetrics.cs (98%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Metrics/TcpMetrics.cs (98%) rename backend/src/{Monitor.Backend.Analysis/Monitor.Backend.Analysis.csproj => MoShiro.Backend.Analysis/MoShiro.Backend.Analysis.csproj} (63%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Models/Models.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Models/ServiceModel.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Ops/EchoOps.cs (99%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Ops/Ops.cs (98%) rename backend/src/{Monitor.Backend.Analysis => MoShiro.Backend.Analysis}/Ops/SessionOps.cs (99%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Admin/AgentEndpoints.cs (97%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Admin/AuthEndpoints.cs (94%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Admin/BuildEndpoints.cs (96%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Admin/DataEndpoints.cs (94%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Admin/LinkEndpoints.cs (92%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Admin/SystemEndpoints.cs (98%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Admin/TaskEndpoints.cs (97%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/ApiModule.cs (93%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Common/Concurrency.cs (97%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Common/EndpointConventions.cs (96%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Common/Guards.cs (90%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Common/Mappers.cs (98%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Common/Problems.cs (71%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Common/QueryHelpers.cs (93%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Contracts/AdminDtos.cs (99%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Contracts/ApiJsonContext.cs (97%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Contracts/CommonDtos.cs (97%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Contracts/PublicDtos.cs (99%) rename backend/src/{Monitor.Backend.Api/Monitor.Backend.Api.csproj => MoShiro.Backend.Api/MoShiro.Backend.Api.csproj} (76%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/OpsEndpoints.cs (91%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Public/CatalogEndpoints.cs (90%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Public/HostEndpoints.cs (95%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Public/LiveEndpoints.cs (99%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Public/LiveTopics.cs (95%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Public/NodeEndpoints.cs (92%) rename backend/src/{Monitor.Backend.Api => MoShiro.Backend.Api}/Public/QueryEndpoints.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Admin/EventService.cs (91%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Admin/JoinTokenService.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Admin/OpsService.cs (75%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Admin/RawBrowserService.cs (88%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Admin/SettingsService.cs (99%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Agents/AgentEventService.cs (93%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Agents/AgentRuntime.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Agents/AgentService.cs (99%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Agents/HostStatusService.cs (94%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Agents/LinkService.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Agents/MonitorFleetHooks.cs (90%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Agents/ProbeService.cs (93%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Analysis/AnalysisScheduler.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Analysis/MetricRecompute.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Analysis/WindowComputer.cs (95%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/ApplicationServiceCollectionExtensions.cs (91%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Auth/AuthModels.cs (96%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Auth/AuthService.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Auth/LoginRateLimiter.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/BackendCounters.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/BackendOptions.cs (96%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Ingest/IngestService.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Live/HotLayer.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Live/HotLayerBackfill.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Live/LiveHub.cs (97%) rename backend/src/{Monitor.Backend.Application/Monitor.Backend.Application.csproj => MoShiro.Backend.Application/MoShiro.Backend.Application.csproj} (81%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Models/AgentModels.cs (94%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Models/RawModels.cs (96%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Models/TaskAndTestModels.cs (93%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Nodes/IspClassifier.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Nodes/NodeInfo.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Nodes/NodeInfoService.cs (99%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Ports/IAgentGateway.cs (96%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Ports/IAuthStore.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Ports/StorePorts.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/Bucketing.cs (96%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/Lines.cs (92%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/MetricSelection.cs (89%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/QueryResults.cs (95%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/QueryService.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/RangeResolver.cs (92%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/RowLoader.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/SourcePlanner.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Query/Steps.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Retention/RetentionService.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/StartupTasks.cs (96%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Tasks/EffectiveTasks.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Tasks/TaskPlanner.cs (96%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Tasks/TaskService.cs (96%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Tests/Plans.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Tests/TestFinalizer.cs (97%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Tests/TestModels.cs (94%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Tests/TestService.cs (94%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/Updates/ReleaseService.cs (98%) rename backend/src/{Monitor.Backend.Application => MoShiro.Backend.Application}/ValidationError.cs (85%) rename backend/src/{Monitor.Backend.Gateway => MoShiro.Backend.Gateway}/ConnectionShutdown.cs (97%) rename backend/src/{Monitor.Backend.Gateway => MoShiro.Backend.Gateway}/FleetGateway.cs (72%) rename backend/src/{Monitor.Backend.Gateway => MoShiro.Backend.Gateway}/GatewayServiceCollectionExtensions.cs (63%) rename backend/src/{Monitor.Backend.Gateway/Monitor.Backend.Gateway.csproj => MoShiro.Backend.Gateway/MoShiro.Backend.Gateway.csproj} (79%) rename backend/src/{Monitor.Backend.Gateway => MoShiro.Backend.Gateway}/ProbeAgentsStateProvider.cs (86%) rename backend/src/{Monitor.Backend.Gateway => MoShiro.Backend.Gateway}/RawChunkInbox.cs (84%) rename backend/src/{Monitor.Backend.Gateway => MoShiro.Backend.Gateway}/TaskSetStateProvider.cs (92%) rename backend/src/{Monitor.Backend.Storage.Sqlite/Monitor.Backend.Storage.Sqlite.csproj => MoShiro.Backend.Storage.Sqlite/MoShiro.Backend.Storage.Sqlite.csproj} (60%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/Schema.cs (99%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/Sql.cs (98%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteAgentStore.cs (94%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteAuthStore.cs (98%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteConfigStores.cs (97%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteDatabase.cs (98%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteHostStore.cs (95%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteMetricStore.cs (99%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteNodeMetaStore.cs (96%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteRawStore.cs (99%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteStorageHealth.cs (93%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/SqliteTestStore.cs (98%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/StorageJson.cs (95%) rename backend/src/{Monitor.Backend.Storage.Sqlite => MoShiro.Backend.Storage.Sqlite}/StorageServiceCollectionExtensions.cs (91%) rename backend/src/{Monitor.Backend => MoShiro.Backend}/BackendHost.cs (79%) rename backend/src/{Monitor.Backend => MoShiro.Backend}/HttpGeoLookup.cs (93%) rename backend/src/{Monitor.Backend/Monitor.Backend.csproj => MoShiro.Backend/MoShiro.Backend.csproj} (85%) rename backend/src/{Monitor.Backend => MoShiro.Backend}/Program.cs (65%) rename backend/src/{Monitor.Backend => MoShiro.Backend}/StaticSqlite.targets (90%) rename backend/tests/{Monitor.Backend.Analysis.Tests => MoShiro.Backend.Analysis.Tests}/AccumulatorTests.cs (98%) rename backend/tests/{Monitor.Backend.Analysis.Tests/Monitor.Backend.Analysis.Tests.csproj => MoShiro.Backend.Analysis.Tests/MoShiro.Backend.Analysis.Tests.csproj} (67%) rename backend/tests/{Monitor.Backend.Analysis.Tests => MoShiro.Backend.Analysis.Tests}/ModelAndTestEvaluatorTests.cs (98%) rename backend/tests/{Monitor.Backend.Analysis.Tests => MoShiro.Backend.Analysis.Tests}/OpTests.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/AgentEndToEndTests.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/AgentHarness.cs (96%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/AotSmokeTests.cs (96%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/ApiBasicsTests.cs (98%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/ArchitectureTests.cs (81%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/BackendFixture.cs (96%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/EnrollmentAndTaskSetTests.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/HostTests.cs (98%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/IngestAndQueryTests.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/LinkTests.cs (98%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/LiveTests.cs (98%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/LoginRateLimitTests.cs (98%) rename backend/tests/{Monitor.Backend.Tests/Monitor.Backend.Tests.csproj => MoShiro.Backend.Tests/MoShiro.Backend.Tests.csproj} (67%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/NodeInfoTests.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/OnDemandTestsTests.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/OpenApiConformanceTests.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/OperationsAndSecurityTests.cs (98%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/PersistenceTests.cs (97%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/PlanTests.cs (86%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/ProbeEndToEndTests.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/ProbeHarness.cs (93%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/QueryPlanningTests.cs (92%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/SseClient.cs (99%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/StorageTests.cs (97%) rename backend/tests/{Monitor.Backend.Tests => MoShiro.Backend.Tests}/UpdateTests.cs (93%) rename backend/tests/{Monitor.TestSupport => MoShiro.TestSupport}/AgentSimulator.cs (92%) rename backend/tests/{Monitor.TestSupport => MoShiro.TestSupport}/AgentWire.cs (98%) rename backend/tests/{Monitor.TestSupport => MoShiro.TestSupport}/ChunkFactory.cs (99%) rename backend/tests/{Monitor.TestSupport/Monitor.TestSupport.csproj => MoShiro.TestSupport/MoShiro.TestSupport.csproj} (77%) rename backend/tests/{Monitor.TestSupport => MoShiro.TestSupport}/ProbeSimulator.cs (96%) rename ci/{Monitor.Tar/Monitor.Tar.csproj => MoShiro.Tar/MoShiro.Tar.csproj} (100%) rename ci/{Monitor.Tar => MoShiro.Tar}/Program.cs (96%) delete mode 100644 packaging/openwrt/monitor.keep rename packaging/openwrt/{monitor-probe.init => moshiro-probe.init} (65%) create mode 100644 packaging/openwrt/moshiro.keep delete mode 100644 packaging/systemd/monitor-probe-container.service delete mode 100644 packaging/systemd/monitor-probe-docker.service delete mode 100644 packaging/systemd/monitor-probe-rootless.service rename packaging/systemd/{monitor-agent-docker.service => moshiro-agent-container.service} (57%) rename packaging/systemd/{monitor-agent-container.service => moshiro-agent-docker.service} (57%) rename packaging/systemd/{monitor-agent-rootless.service => moshiro-agent-rootless.service} (56%) rename packaging/systemd/{monitor-agent.service => moshiro-agent.service} (84%) create mode 100644 packaging/systemd/moshiro-probe-container.service create mode 100644 packaging/systemd/moshiro-probe-docker.service create mode 100644 packaging/systemd/moshiro-probe-rootless.service rename packaging/systemd/{monitor-probe.service => moshiro-probe.service} (83%) rename packaging/update/{monitor-update.sh => moshiro-update.sh} (90%) diff --git a/.woodpecker/verify.yml b/.woodpecker/verify.yml index b8b2958..c9b527e 100644 --- a/.woodpecker/verify.yml +++ b/.woodpecker/verify.yml @@ -23,4 +23,4 @@ steps: environment: NUGET_PACKAGES: /home/justme/.nuget/packages commands: - - cd backend && dotnet test --solution Monitor.slnx -c Release + - cd backend && dotnet test --solution MoShiro.slnx -c Release diff --git a/AGENTS.md b/AGENTS.md index 5925e03..4b59fea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,7 +2,7 @@ ## Project -Monitor is a self-hosted network path quality monitor. Backend coordinates Agents and Probes, stores measurements, and serves the REST/SSE API. `web/display` is the read-only overview; `web/admin` manages nodes, tests, and settings. +MoShiro is a self-hosted network path quality monitor. Backend coordinates Agents and Probes, stores measurements, and serves the REST/SSE API. `web/display` is the read-only overview; `web/admin` manages nodes, tests, and settings. ## Branch and workspace safety @@ -10,12 +10,12 @@ Monitor is a self-hosted network path quality monitor. Backend coordinates Agent - A push to `main` builds images only if its commit message contains `[CI]` (for a merged PR, put it in the PR or merge commit title). Without `[CI]` nothing is built; use `[CI SKIP]` to skip the pipeline entirely. When squashing or pushing to `main`, add `[CI]` unless a build is explicitly not wanted. - Before editing, inspect `git status`. Preserve pre-existing user changes: do not reset, clean, stash, or include unrelated files in a commit. - Do not commit credentials, API keys, registry passwords, or generated runtime data. CI credentials belong in Woodpecker secrets (`zot_secret`, `gitea_token`, `release_signing_key` for signing release manifests, `release_api_token` with the `release` scope). The release signing private key never goes into the repository or the panel; only the public key in `packaging/update/` does. -- Keep development OCI images in the `monitor-dev/` repository path and release images in `monitor/`. Do not let a development build overwrite release tags such as `latest`. +- Keep development OCI images in the `moshiro-dev/` repository path and release images in `moshiro/`. Do not let a development build overwrite release tags such as `latest`. ## Project layout -- `backend/src/Monitor.Backend/`: service entry point and composition. -- `backend/src/Monitor.Backend.Api/`: REST endpoints, contracts, and OpenAPI. +- `backend/src/MoShiro.Backend/`: service entry point and composition. +- `backend/src/MoShiro.Backend.Api/`: REST endpoints, contracts, and OpenAPI. - `backend/agent/`, `backend/probe/`: node applications and their READMEs. - `backend/fleet/`, `backend/shared/`: reusable node framework, measurement engine, protocols, and data formats. - `web/display/`, `web/admin/`: Vite applications; `web/shared/`: API client, generated types, charts, and shared UI. @@ -25,12 +25,12 @@ Monitor is a self-hosted network path quality monitor. Backend coordinates Agent Requirements: .NET SDK 10 and Node.js/npm. The SDK selection is defined by the root `global.json`; NuGet package versions are centralized in the root `Directory.Packages.props`. -- All .NET projects: `dotnet build Monitor.slnx -c Release` from the repository root. -- Backend build: `cd backend && dotnet build Monitor.slnx -c Release` -- Backend tests: `cd backend && dotnet test --solution Monitor.slnx -c Release` +- All .NET projects: `dotnet build MoShiro.slnx -c Release` from the repository root. +- Backend build: `cd backend && dotnet build MoShiro.slnx -c Release` +- Backend tests: `cd backend && dotnet test --solution MoShiro.slnx -c Release` - Frontend dependencies/build: `npm ci --prefix web && npm run build --prefix web` - Frontend style check: `npm run lint:css --prefix web` -- Local backend: from `backend/`, run `dotnet run --project src/Monitor.Backend -- --urls http://localhost:5000`. +- Local backend: from `backend/`, run `dotnet run --project src/MoShiro.Backend -- --urls http://localhost:5000`. - Local web apps: from the repository root, run `npm ci --prefix web` then `npm run dev --prefix web`. The current dev config uses display port 5173 and admin port 5175; `/admin/` is proxied through the display server. Check the Vite configs when working on another branch because ports can differ. - After changing API contracts, regenerate/check `backend/openapi/v1.json` and run `npm run gen:api --prefix web` so frontend API types stay aligned. diff --git a/Directory.Packages.props b/Directory.Packages.props index 55fb462..b6b6d54 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -2,9 +2,9 @@ true - 3530400 - 2026 - 1e71ddf93849c6a6ecf58b827c0692073d2dd7ee40196158068f7b29f422e87d + 3530400 + 2026 + 1e71ddf93849c6a6ecf58b827c0692073d2dd7ee40196158068f7b29f422e87d diff --git a/Monitor.slnx b/MoShiro.slnx similarity index 55% rename from Monitor.slnx rename to MoShiro.slnx index 8a5c58c..f15c43c 100644 --- a/Monitor.slnx +++ b/MoShiro.slnx @@ -17,36 +17,36 @@ - - + + - - + + - + - + - + - - - - - - + + + + + + - - - + + + - + diff --git a/README.md b/README.md index 96b9d39..3d5c731 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Monitor +# MoShiro -Monitor 是一个自托管的网络线路质量观测工具。它在 Probe 与多个 Agent 之间执行主动网络测量,记录逐包和逐事件结果;Backend 保存原始数据并生成可查询的线路指标,Web 界面用于查看、比较和管理节点。 +MoShiro 是一个自托管的网络线路质量观测工具。它在 Probe 与多个 Agent 之间执行主动网络测量,记录逐包和逐事件结果;Backend 保存原始数据并生成可查询的线路指标,Web 界面用于查看、比较和管理节点。 它面向需要比较不同网络出口、评估线路稳定性,或观察特定网络服务体验的场景。Agent 与 Probe 专注于测量和上报;它们不提供远程终端、命令执行或文件管理能力。 @@ -48,10 +48,10 @@ Monitor 是一个自托管的网络线路质量观测工具。它在 Probe 与 从仓库根目录构建全部 .NET 项目(Backend、Agent、Probe、Fleet、测试和 CI 工具): ```sh -dotnet build Monitor.slnx -c Release +dotnet build MoShiro.slnx -c Release ``` -NuGet 包版本统一在根目录 `Directory.Packages.props` 管理,项目中的 `PackageReference` 不写版本号。AotAnywhere 的 MSBuild SDK 版本在根目录 `global.json` 的 `msbuild-sdks` 中管理。`backend/Monitor.slnx` 保留用于只构建后端目录内的项目。 +NuGet 包版本统一在根目录 `Directory.Packages.props` 管理,项目中的 `PackageReference` 不写版本号。AotAnywhere 的 MSBuild SDK 版本在根目录 `global.json` 的 `msbuild-sdks` 中管理。`backend/MoShiro.slnx` 保留用于只构建后端目录内的项目。 安装前端依赖并构建展示端和管理端(在仓库根目录运行): @@ -72,7 +72,7 @@ Backend、Agent 和 Probe 均以 OCI 镜像发布,支持 Linux/amd64 与 Linux ```sh cd backend -dotnet run --project src/Monitor.Backend -- --urls http://localhost:5000 +dotnet run --project src/MoShiro.Backend -- --urls http://localhost:5000 ``` 2. **启动前端。** 保持 Backend 运行,在另一个终端的仓库根目录运行: @@ -88,7 +88,7 @@ npm run dev --prefix web - Pull request 和 `dev` 分支 push:先跑 Backend tests,通过后再构建前端。 - 在需要跳过 Backend tests 的提交信息后加 `[SKIP TESTS]`;Gitea pull request 需要把标记写进 PR 标题。前端构建仍会运行。 -- `main` 上的提交信息包含 `[CI]` 时,并行构建 Backend、Agent、Probe 的 Linux/amd64 镜像,推送到 Zot 的 `monitor-dev/` 仓库;普通 main push 不构建。 +- `main` 上的提交信息包含 `[CI]` 时,并行构建 Backend、Agent、Probe 的 Linux/amd64 镜像,推送到 Zot 的 `moshiro-dev/` 仓库;普通 main push 不构建。 - 推送 `vMAJOR.MINOR.PATCH` tag 会触发全平台正式构建和 Release 发布。 完整触发条件、开发镜像标签和发布路径见 [`docs/deployment.md`](docs/deployment.md)。 @@ -120,7 +120,7 @@ npm run dev --prefix web ## 测试 ```sh -dotnet test --solution Monitor.slnx +dotnet test --solution MoShiro.slnx ``` ```sh diff --git a/backend/Monitor.slnx b/backend/MoShiro.slnx similarity index 58% rename from backend/Monitor.slnx rename to backend/MoShiro.slnx index c69c642..e453cc3 100644 --- a/backend/Monitor.slnx +++ b/backend/MoShiro.slnx @@ -17,33 +17,33 @@ - - + + - - + + - + - + - + - - - - - - + + + + + + - - - + + + diff --git a/backend/README.md b/backend/README.md index aae510d..7e0021f 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,17 +1,17 @@ # Backend -Backend 是 Monitor 的控制面和数据服务,负责 Agent 注册与连接、任务编排、原始测量数据持久化、指标分析,以及供前端使用的 REST API 和 SSE 实时数据流。 +Backend 是 MoShiro 的控制面和数据服务,负责 Agent 注册与连接、任务编排、原始测量数据持久化、指标分析,以及供前端使用的 REST API 和 SSE 实时数据流。 ## 组件 | 路径 | 职责 | | --- | --- | -| `src/Monitor.Backend/` | 应用入口与依赖组合 | -| `src/Monitor.Backend.Api/` | Public、Admin API 和 OpenAPI | -| `src/Monitor.Backend.Gateway/` | Fleet RPC、节点状态与测量数据接收 | -| `src/Monitor.Backend.Application/` | 业务用例、查询、任务和后台服务 | -| `src/Monitor.Backend.Analysis/` | 指标计算、累加器和服务模型 | -| `src/Monitor.Backend.Storage.Sqlite/` | 段文件与 SQLite 存储 | +| `src/MoShiro.Backend/` | 应用入口与依赖组合 | +| `src/MoShiro.Backend.Api/` | Public、Admin API 和 OpenAPI | +| `src/MoShiro.Backend.Gateway/` | Fleet RPC、节点状态与测量数据接收 | +| `src/MoShiro.Backend.Application/` | 业务用例、查询、任务和后台服务 | +| `src/MoShiro.Backend.Analysis/` | 指标计算、累加器和服务模型 | +| `src/MoShiro.Backend.Storage.Sqlite/` | 段文件与 SQLite 存储 | | `fleet/` | 通用节点身份、注册和连接框架 | | `shared/` | 测量引擎、协议和数据格式 | | `tests/` | 集成测试和测试支持代码 | @@ -26,14 +26,14 @@ Backend 是 Monitor 的控制面和数据服务,负责 Agent 注册与连接 ```sh cd backend -dotnet build Monitor.slnx -c Release -dotnet test --solution Monitor.slnx +dotnet build MoShiro.slnx -c Release +dotnet test --solution MoShiro.slnx ``` 发布当前平台的 NativeAOT Backend: ```sh -dotnet publish src/Monitor.Backend -c Release -r -p:PublishAot=true +dotnet publish src/MoShiro.Backend -c Release -r -p:PublishAot=true ``` 例如 `` 可为 `win-x64`、`linux-x64` 或 `linux-arm64`。NativeAOT 发布需要对应平台的 C/C++ 工具链。仓库根目录的 `scripts/publish.sh backend ` 可构建单个平台的 Backend 可执行文件;容器发布由 Woodpecker tag 流水线完成,详见 [`../docs/deployment.md`](../docs/deployment.md)。 @@ -46,9 +46,9 @@ dotnet publish src/Monitor.Backend -c Release -r -p:PublishAot=true ```sh cd backend -dotnet run --project src/Monitor.Backend -- --urls http://localhost:5000 +dotnet run --project src/MoShiro.Backend -- --urls http://localhost:5000 ``` -首次启动时可用 `Monitor__InitialAdminUser` 和 `Monitor__InitialAdminPassword` 设置初始管理员。数据目录、公开地址、Cookie 和 CORS 等设置通过 `Monitor` 配置节传入;完整配置说明见 [`../docs/deployment.md`](../docs/deployment.md)。站点默认需要登录,可在管理端修改公开设置。 +首次启动时可用 `MoShiro__InitialAdminUser` 和 `MoShiro__InitialAdminPassword` 设置初始管理员。数据目录、公开地址、Cookie 和 CORS 等设置通过 `MoShiro` 配置节传入;完整配置说明见 [`../docs/deployment.md`](../docs/deployment.md)。站点默认需要登录,可在管理端修改公开设置。 OpenAPI 文档由构建生成到 `openapi/v1.json`。API 设计和端点说明见 [`../docs/api.md`](../docs/api.md);项目总览见仓库根目录的 [`README.md`](../README.md)。 diff --git a/backend/agent/README.md b/backend/agent/README.md index c52e71a..b70a50b 100644 --- a/backend/agent/README.md +++ b/backend/agent/README.md @@ -1,4 +1,4 @@ -# Monitor Agent +# MoShiro Agent Agent 是部署在 VPS 或其他可达网络节点上的采集进程。它向 Backend 注册并保持连接,接受 Probe 的测量会话,执行线路任务中的 Agent 侧工作,再将两端数据合并后上报。 @@ -18,14 +18,14 @@ Probe ──TLS 控制 / UDP、TCP 测量──> Agent ──长连接与数据 ```sh cd backend -dotnet build agent/src/Monitor.Agent -c Release +dotnet build agent/src/MoShiro.Agent -c Release dotnet build fleet/tools/fleet-enroll -c Release ``` 发布 NativeAOT 程序需要对应平台的 C/C++ 工具链;`` 应与构建环境和目标平台匹配: ```sh -dotnet publish agent/src/Monitor.Agent -c Release -r -p:PublishAot=true +dotnet publish agent/src/MoShiro.Agent -c Release -r -p:PublishAot=true dotnet publish fleet/tools/fleet-enroll -c Release -r -p:PublishAot=true ``` @@ -36,7 +36,7 @@ dotnet publish fleet/tools/fleet-enroll -c Release -r -p:PublishAot=true 先在管理端创建加入令牌,然后在 Agent 主机上运行一次性注册工具: ```sh -fleet-enroll --server https:// --join --name --identity-dir /etc/monitor +fleet-enroll --server https:// --join --name --identity-dir /etc/moshiro ``` 注册工具会在身份目录写入节点身份和证书。准备本地 `agent.json`,其中 `fleet.server` 指向 Backend,`fleet.identity_dir` 指向上述目录;`listen`、`limits` 和 `reporting` 可按节点环境调整。配置文件不会由 Backend 修改。限制目标网段和测量预算时,应按实际网络与机器能力配置;`allowed_target_cidrs` 默认为空,不允许 Agent 执行目标探测任务。 @@ -44,12 +44,12 @@ fleet-enroll --server https:// --join --name --ide 启动 Agent: ```sh -monitor-agent --config /etc/monitor/agent.json +moshiro-agent --config /etc/moshiro/agent.json ``` -容器节点的运行方式(podman + systemd)和宿主机更新器见 [`../../docs/deployment.md`](../../docs/deployment.md)。也可使用 OCI 镜像 `registry.oeo.one/monitor/monitor-agent:`,自动选择 Linux amd64 或 arm64 镜像。镜像同时包含 `fleet-enroll`;可通过 `--entrypoint /usr/local/bin/fleet-enroll` 执行首次注册。容器默认读取命名 volume 中的 `/etc/monitor/agent.json` 与身份文件;建议使用宿主网络,并按 ICMP 测量需求添加 `NET_RAW` 能力。镜像以 UID/GID 1654 运行,新命名 volume 由引擎按镜像目录初始化权限。 +容器节点的运行方式(podman + systemd)和宿主机更新器见 [`../../docs/deployment.md`](../../docs/deployment.md)。也可使用 OCI 镜像 `registry.oeo.one/moshiro/moshiro-agent:`,自动选择 Linux amd64 或 arm64 镜像。镜像同时包含 `fleet-enroll`;可通过 `--entrypoint /usr/local/bin/fleet-enroll` 执行首次注册。容器默认读取命名 volume 中的 `/etc/moshiro/agent.json` 与身份文件;建议使用宿主网络,并按 ICMP 测量需求添加 `NET_RAW` 能力。镜像以 UID/GID 1654 运行,新命名 volume 由引擎按镜像目录初始化权限。 -不传 `--config` 时默认读取 `/etc/monitor/agent.json`。Agent 默认监听控制端口 `7443/tcp`,数据端口 `7443/udp` 和 `7444/tcp`;防火墙和面板中的节点端口配置需与本地配置一致。`reporting.host_stats` 可关闭主机状态上报;启用时只上报资源使用等汇总数据,不包含主机名、进程或 IP。 +不传 `--config` 时默认读取 `/etc/moshiro/agent.json`。Agent 默认监听控制端口 `7443/tcp`,数据端口 `7443/udp` 和 `7444/tcp`;防火墙和面板中的节点端口配置需与本地配置一致。`reporting.host_stats` 可关闭主机状态上报;启用时只上报资源使用等汇总数据,不包含主机名、进程或 IP。 ## 设计说明 diff --git a/backend/agent/src/Monitor.Agent/AgentApp.cs b/backend/agent/src/MoShiro.Agent/AgentApp.cs similarity index 89% rename from backend/agent/src/Monitor.Agent/AgentApp.cs rename to backend/agent/src/MoShiro.Agent/AgentApp.cs index a23f2f8..70d72b6 100644 --- a/backend/agent/src/Monitor.Agent/AgentApp.cs +++ b/backend/agent/src/MoShiro.Agent/AgentApp.cs @@ -4,15 +4,15 @@ using Fleet.Core; using Fleet.Hosting; using Fleet.Link; using Fleet.Rpc; -using Monitor.Measurement; -using Monitor.Protocol; +using MoShiro.Measurement; +using MoShiro.Protocol; -namespace Monitor.Agent; +namespace MoShiro.Agent; /// Agent 的组装点:数据面、点对点监听、与 Backend 的链路都在这里接起来。没有全局状态,测试可以在同一进程里启动多个。 public sealed class AgentApp : IDisposable { - public const string Version = Monitor.Protocol.BuildInfo.Version; + public const string Version = MoShiro.Protocol.BuildInfo.Version; private readonly AgentConfig _config; private readonly LoadedNodeIdentity _identity; @@ -35,7 +35,7 @@ public sealed class AgentApp : IDisposable private readonly TestRunner _tests; private readonly FleetLink _link; - /// 配置目录(容器里的 /etc/monitor):宿主机更新器和节点在这里交换清单、请求和状态。 + /// 配置目录(容器里的 /etc/moshiro):宿主机更新器和节点在这里交换清单、请求和状态。 public AgentApp(AgentConfig config, LoadedNodeIdentity identity, string dataDirectory, TimeProvider time, INodeLog log) { _update = new UpdateBridge(dataDirectory, new ConfigStore(dataDirectory).Write, log); @@ -185,48 +185,48 @@ public sealed class AgentApp : IDisposable HashSet? allowed = _config.Policy.AllowMethods is { } list ? [.. list] : null; bool Allow(string method) => allowed is null || allowed.Contains(method); - if (Allow(MonitorMethods.TestRun)) + if (Allow(MoShiroMethods.TestRun)) { router.On( - MonitorMethods.TestRun, - MonitorJsonContext.Default.TestRunParams, - MonitorJsonContext.Default.TestRunResult, + MoShiroMethods.TestRun, + MoShiroJsonContext.Default.TestRunParams, + MoShiroJsonContext.Default.TestRunResult, (_, run, _) => ValueTask.FromResult(_tests.Start(run))); } - if (Allow(MonitorMethods.TestCancel)) + if (Allow(MoShiroMethods.TestCancel)) { router.On( - MonitorMethods.TestCancel, - MonitorJsonContext.Default.TestCancelParams, - MonitorJsonContext.Default.TestRunResult, + MoShiroMethods.TestCancel, + MoShiroJsonContext.Default.TestCancelParams, + MoShiroJsonContext.Default.TestRunResult, (_, cancel, _) => ValueTask.FromResult(Result.Ok(new TestRunResult { Accepted = _tests.Cancel(cancel.TestId) }))); } - if (Allow(MonitorMethods.UpdateOffer)) + if (Allow(MoShiroMethods.UpdateOffer)) { - router.OnNotify(MonitorMethods.UpdateOffer, MonitorJsonContext.Default.UpdateOfferParams, (_, offer, _) => + router.OnNotify(MoShiroMethods.UpdateOffer, MoShiroJsonContext.Default.UpdateOfferParams, (_, offer, _) => { _update.WriteOffer(offer); return ValueTask.CompletedTask; }); } - if (Allow(MonitorMethods.UpdateApply)) + if (Allow(MoShiroMethods.UpdateApply)) { - router.OnNotify(MonitorMethods.UpdateApply, MonitorJsonContext.Default.UpdateOfferParams, (_, _, _) => + router.OnNotify(MoShiroMethods.UpdateApply, MoShiroJsonContext.Default.UpdateOfferParams, (_, _, _) => { _update.RequestApply(); return ValueTask.CompletedTask; }); } - if (Allow(MonitorMethods.ProbeDisconnect)) + if (Allow(MoShiroMethods.ProbeDisconnect)) { router.On( - MonitorMethods.ProbeDisconnect, - MonitorJsonContext.Default.ProbeDisconnectParams, - MonitorJsonContext.Default.TestRunResult, + MoShiroMethods.ProbeDisconnect, + MoShiroJsonContext.Default.ProbeDisconnectParams, + MoShiroJsonContext.Default.TestRunResult, async (_, request, _) => Result.Ok(new TestRunResult { Accepted = await _hub.DisconnectAsync(request.ProbeId.Value) })); } @@ -236,11 +236,11 @@ public sealed class AgentApp : IDisposable Identity = _identity.Identity, NodeId = _identity.NodeId, NodeVersion = Version, - Capabilities = [MonitorCapabilities.Base, MonitorCapabilities.KindsPrefix + string.Join(',', BlockCatalog.AgentKinds)], + Capabilities = [MoShiroCapabilities.Base, MoShiroCapabilities.KindsPrefix + string.Join(',', BlockCatalog.AgentKinds)], HelloMeta = HelloMeta, HeartbeatExtra = HeartbeatExtra, }; - var link = new FleetLink(options, router, [new StateHandler(TaskSet.StateType, MonitorJsonContext.Default.TaskSet, _tasks.ApplyAsync)], _outbox, _time, _log); + var link = new FleetLink(options, router, [new StateHandler(TaskSet.StateType, MoShiroJsonContext.Default.TaskSet, _tasks.ApplyAsync)], _outbox, _time, _log); // 链路重新连上之后补报:在线的 Probe 都告诉 Backend(Backend 重启或链路抖动期间错过了 probe_connected) link.OnConnected = async (_, _) => @@ -257,7 +257,7 @@ public sealed class AgentApp : IDisposable { var meta = new AgentHelloMeta { - Platform = Monitor.Measurement.PlatformDetector.Detect(), + Platform = MoShiro.Measurement.PlatformDetector.Detect(), TlsSpki = _identity.File.TlsSpki, ProbeTcpPort = ControlPort, ProbeUdpPorts = [.. UdpPorts], @@ -269,7 +269,7 @@ public sealed class AgentApp : IDisposable MaxConcurrentTests = _config.Limits.MaxConcurrentTests, }, }; - return JsonSerializer.SerializeToElement(meta, MonitorJsonContext.Default.AgentHelloMeta); + return JsonSerializer.SerializeToElement(meta, MoShiroJsonContext.Default.AgentHelloMeta); } private long _lastIn; @@ -296,6 +296,6 @@ public sealed class AgentApp : IDisposable _lastIn = packetsIn; _lastOut = packetsOut; _lastAtMs = nowMs; - return JsonSerializer.SerializeToElement(extra, MonitorJsonContext.Default.AgentHeartbeatExtra); + return JsonSerializer.SerializeToElement(extra, MoShiroJsonContext.Default.AgentHeartbeatExtra); } } diff --git a/backend/agent/src/Monitor.Agent/AgentConfig.cs b/backend/agent/src/MoShiro.Agent/AgentConfig.cs similarity index 96% rename from backend/agent/src/Monitor.Agent/AgentConfig.cs rename to backend/agent/src/MoShiro.Agent/AgentConfig.cs index 16ed3e9..cc89cb3 100644 --- a/backend/agent/src/Monitor.Agent/AgentConfig.cs +++ b/backend/agent/src/MoShiro.Agent/AgentConfig.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Monitor.Agent; +namespace MoShiro.Agent; /// /// agent.json:节点本地配置,面板无法修改。其中 limits 是本地硬上限:期望任务集超出这些范围时, @@ -40,7 +40,7 @@ public sealed class FleetSection public string Server { get; set; } = ""; [JsonPropertyName("identity_dir")] - public string IdentityDir { get; set; } = "/etc/monitor"; + public string IdentityDir { get; set; } = "/etc/moshiro"; } public sealed class ListenSection diff --git a/backend/agent/src/Monitor.Agent/Chunks/ChunkAssembler.cs b/backend/agent/src/MoShiro.Agent/Chunks/ChunkAssembler.cs similarity index 95% rename from backend/agent/src/Monitor.Agent/Chunks/ChunkAssembler.cs rename to backend/agent/src/MoShiro.Agent/Chunks/ChunkAssembler.cs index fc0098d..21f050e 100644 --- a/backend/agent/src/Monitor.Agent/Chunks/ChunkAssembler.cs +++ b/backend/agent/src/MoShiro.Agent/Chunks/ChunkAssembler.cs @@ -1,9 +1,9 @@ using Fleet.Core; using Fleet.Link; -using Monitor.Measurement; -using Monitor.Protocol; +using MoShiro.Measurement; +using MoShiro.Protocol; -namespace Monitor.Agent; +namespace MoShiro.Agent; /// /// Probe 的列块到达之后:找到对应的流 → 与 Agent 在数据面记录的列合并 → 盖章(块头、时钟锚点)→ 编码 → 放进发件箱(通道 16)。 @@ -70,6 +70,6 @@ public sealed class ChunkAssembler /// Agent 自己采集的块(目标任务)直接发出。 public void Emit(RawChunk chunk) { - _outbox.Enqueue(MonitorChannels.RawChunk, chunk.Header.ChunkId.Value, RawChunkCodec.Encode(chunk)); + _outbox.Enqueue(MoShiroChannels.RawChunk, chunk.Header.ChunkId.Value, RawChunkCodec.Encode(chunk)); } } diff --git a/backend/agent/src/Monitor.Agent/DataPlane/Registries.cs b/backend/agent/src/MoShiro.Agent/DataPlane/Registries.cs similarity index 99% rename from backend/agent/src/Monitor.Agent/DataPlane/Registries.cs rename to backend/agent/src/MoShiro.Agent/DataPlane/Registries.cs index fff6753..5703c4d 100644 --- a/backend/agent/src/Monitor.Agent/DataPlane/Registries.cs +++ b/backend/agent/src/MoShiro.Agent/DataPlane/Registries.cs @@ -4,10 +4,10 @@ using System.Net.Sockets; using Fleet.Core; using Fleet.Link; using Fleet.Rpc; -using Monitor.Measurement; -using Monitor.Protocol; +using MoShiro.Measurement; +using MoShiro.Protocol; -namespace Monitor.Agent; +namespace MoShiro.Agent; /// 进程内计数(只有计数,没有主机信息):用于心跳和面板上的节点状态。数据面的包计数由共享的 提供。 public sealed class AgentCounters diff --git a/backend/agent/src/Monitor.Agent/Host/HostSampler.cs b/backend/agent/src/MoShiro.Agent/Host/HostSampler.cs similarity index 99% rename from backend/agent/src/Monitor.Agent/Host/HostSampler.cs rename to backend/agent/src/MoShiro.Agent/Host/HostSampler.cs index b24d775..05e1791 100644 --- a/backend/agent/src/Monitor.Agent/Host/HostSampler.cs +++ b/backend/agent/src/MoShiro.Agent/Host/HostSampler.cs @@ -1,7 +1,7 @@ using System.Globalization; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Agent; +namespace MoShiro.Agent; /// /// 主机资源占用的只读快照:CPU 占用、内存、根分区、网卡累计流量与瞬时网速、系统运行时长。 diff --git a/backend/probe/src/Monitor.Probe/Monitor.Probe.csproj b/backend/agent/src/MoShiro.Agent/MoShiro.Agent.csproj similarity index 78% rename from backend/probe/src/Monitor.Probe/Monitor.Probe.csproj rename to backend/agent/src/MoShiro.Agent/MoShiro.Agent.csproj index 6a2dca7..7896c09 100644 --- a/backend/probe/src/Monitor.Probe/Monitor.Probe.csproj +++ b/backend/agent/src/MoShiro.Agent/MoShiro.Agent.csproj @@ -4,8 +4,8 @@ Condition="'$(UseAotAnywhere)' == 'true'" /> Exe - monitor-probe - Monitor.Probe + moshiro-agent + MoShiro.Agent true true true @@ -15,10 +15,10 @@ false - + - + Agent → Backend 的上行:事件和测试状态是尽力而为的通知(链路断开时丢弃;列块走发件箱,不会丢)。 public sealed class BackendUplink @@ -31,7 +31,7 @@ public sealed class BackendUplink } var parameters = new AgentEventParams { Kind = kind, AtUtcMs = _time.GetUtcNow().ToUnixTimeMilliseconds(), Detail = detail, Probe = probe }; - await SafeAsync(() => session.NotifyAsync(MonitorMethods.Event, parameters, MonitorJsonContext.Default.AgentEventParams, CancellationToken.None)); + await SafeAsync(() => session.NotifyAsync(MoShiroMethods.Event, parameters, MoShiroJsonContext.Default.AgentEventParams, CancellationToken.None)); } public async ValueTask SendHostAsync(HostSnapshot snapshot) @@ -42,7 +42,7 @@ public sealed class BackendUplink return; } - await SafeAsync(() => session.NotifyAsync(MonitorMethods.Host, snapshot, MonitorJsonContext.Default.HostSnapshot, CancellationToken.None)); + await SafeAsync(() => session.NotifyAsync(MoShiroMethods.Host, snapshot, MoShiroJsonContext.Default.HostSnapshot, CancellationToken.None)); } public async ValueTask SendTestStatusAsync(TestId test, string status, int? phase = null, string? errorCode = null) @@ -54,7 +54,7 @@ public sealed class BackendUplink } var parameters = new TestStatusParams { TestId = test, Status = status, Phase = phase, ErrorCode = errorCode }; - await SafeAsync(() => session.NotifyAsync(MonitorMethods.TestStatus, parameters, MonitorJsonContext.Default.TestStatusParams, CancellationToken.None)); + await SafeAsync(() => session.NotifyAsync(MoShiroMethods.TestStatus, parameters, MoShiroJsonContext.Default.TestStatusParams, CancellationToken.None)); } private static async ValueTask SafeAsync(Func send) @@ -115,7 +115,7 @@ public sealed class PeerHub var order = new Queue(); rpc.OnBinary = async (frame, token) => { - if (!OutboxFrame.TryParse(frame, out byte channel, out Guid id, out ReadOnlyMemory payload) || channel != MonitorChannels.ColumnBlock) + if (!OutboxFrame.TryParse(frame, out byte channel, out Guid id, out ReadOnlyMemory payload) || channel != MoShiroChannels.ColumnBlock) { return; } @@ -251,7 +251,7 @@ public sealed class PeerHub { Type = LineTaskSet.StateType, Version = set.Version, - Doc = JsonSerializer.SerializeToElement(set, MonitorJsonContext.Default.LineTaskSet), + Doc = JsonSerializer.SerializeToElement(set, MoShiroJsonContext.Default.LineTaskSet), }; try { @@ -270,8 +270,8 @@ public sealed class PeerHub private static RpcRouter BuildRouter() => new RpcRouter() .On( - MonitorMethods.Clock, - MonitorJsonContext.Default.ClockParams, - MonitorJsonContext.Default.ClockResult, + MoShiroMethods.Clock, + MoShiroJsonContext.Default.ClockParams, + MoShiroJsonContext.Default.ClockResult, (context, _, _) => ValueTask.FromResult(Result.Ok(new ClockResult { AgentMonoUs = context.Clock.NowUs() }))); } diff --git a/backend/agent/src/Monitor.Agent/Program.cs b/backend/agent/src/MoShiro.Agent/Program.cs similarity index 93% rename from backend/agent/src/Monitor.Agent/Program.cs rename to backend/agent/src/MoShiro.Agent/Program.cs index fd273c2..096bf85 100644 --- a/backend/agent/src/Monitor.Agent/Program.cs +++ b/backend/agent/src/MoShiro.Agent/Program.cs @@ -1,6 +1,6 @@ using Fleet.Core; using Fleet.Hosting; -using Monitor.Agent; +using MoShiro.Agent; TimeProvider time = TimeProvider.System; INodeLog log = new ConsoleNodeLog(time); @@ -11,7 +11,7 @@ if (PlatformCheck.VerifyCrypto() is { } problem) return 1; } -string configPath = "/etc/monitor/agent.json"; +string configPath = "/etc/moshiro/agent.json"; for (int i = 0; i < args.Length - 1; i++) { if (args[i] == "--config") diff --git a/backend/agent/src/Monitor.Agent/Tasks/TargetRunners.cs b/backend/agent/src/MoShiro.Agent/Tasks/TargetRunners.cs similarity index 98% rename from backend/agent/src/Monitor.Agent/Tasks/TargetRunners.cs rename to backend/agent/src/MoShiro.Agent/Tasks/TargetRunners.cs index 667cab7..a5dbf29 100644 --- a/backend/agent/src/Monitor.Agent/Tasks/TargetRunners.cs +++ b/backend/agent/src/MoShiro.Agent/Tasks/TargetRunners.cs @@ -1,10 +1,10 @@ using System.Net; using System.Text.Json; using Fleet.Core; -using Monitor.Measurement; -using Monitor.Protocol; +using MoShiro.Measurement; +using MoShiro.Protocol; -namespace Monitor.Agent; +namespace MoShiro.Agent; /// /// 目标任务(Agent 自己探测一个地址,没有对端):用和线路任务同一套积木( 里的拨号方,例如 icmp_echo、connect), diff --git a/backend/agent/src/Monitor.Agent/Tasks/TaskManager.cs b/backend/agent/src/MoShiro.Agent/Tasks/TaskManager.cs similarity index 99% rename from backend/agent/src/Monitor.Agent/Tasks/TaskManager.cs rename to backend/agent/src/MoShiro.Agent/Tasks/TaskManager.cs index 070ed17..a8254a0 100644 --- a/backend/agent/src/Monitor.Agent/Tasks/TaskManager.cs +++ b/backend/agent/src/MoShiro.Agent/Tasks/TaskManager.cs @@ -1,10 +1,10 @@ using System.Text.Json; using Fleet.Core; using Fleet.Rpc; -using Monitor.Measurement; -using Monitor.Protocol; +using MoShiro.Measurement; +using MoShiro.Protocol; -namespace Monitor.Agent; +namespace MoShiro.Agent; /// /// 期望任务集(task_set)的调和器:每个任务先经过 (参数校验 + 本地硬上限)。 diff --git a/backend/agent/src/Monitor.Agent/Tests/TestRunner.cs b/backend/agent/src/MoShiro.Agent/Tests/TestRunner.cs similarity index 90% rename from backend/agent/src/Monitor.Agent/Tests/TestRunner.cs rename to backend/agent/src/MoShiro.Agent/Tests/TestRunner.cs index cfb7017..23c2ddc 100644 --- a/backend/agent/src/Monitor.Agent/Tests/TestRunner.cs +++ b/backend/agent/src/MoShiro.Agent/Tests/TestRunner.cs @@ -1,15 +1,15 @@ using System.Collections.Concurrent; using Fleet.Core; using Fleet.Rpc; -using Monitor.Measurement; -using Monitor.Protocol; +using MoShiro.Measurement; +using MoShiro.Protocol; -namespace Monitor.Agent; +namespace MoShiro.Agent; /// -/// 按需测试的编排(monitor.test.run):Agent 是时间的主人。每个阶段: -/// 登记数据面的流 → monitor.test.phase(Probe 准备好自己一侧的角色)→ 运行(单向数据流由 Agent 发包,回显类等待 Probe 发包) -/// → monitor.test.phase_end(Probe 收尾,回复它交出的列块个数)→ 等所有列块合并上传 → phase_done。 +/// 按需测试的编排(moshiro.test.run):Agent 是时间的主人。每个阶段: +/// 登记数据面的流 → moshiro.test.phase(Probe 准备好自己一侧的角色)→ 运行(单向数据流由 Agent 发包,回显类等待 Probe 发包) +/// → moshiro.test.phase_end(Probe 收尾,回复它交出的列块个数)→ 等所有列块合并上传 → phase_done。 /// 同一时间只能运行 max_concurrent_tests 个测试;Probe 掉线或被取消时测试中止,已经上传的阶段数据保留。 /// public sealed class TestRunner @@ -43,17 +43,17 @@ public sealed class TestRunner public int Running => _running.Count; - /// 校验并接受一个测试(立即返回),实际运行在后台进行,状态通过 monitor.test.status 回报。 + /// 校验并接受一个测试(立即返回),实际运行在后台进行,状态通过 moshiro.test.status 回报。 public Result Start(TestRunParams run) { if (_sessions.Get(run.ProbeId.Value) is not { } probe) { - return Result.Fail(MonitorErrors.ProbeOffline, $"probe {run.ProbeId.Value} is not connected to this agent"); + return Result.Fail(MoShiroErrors.ProbeOffline, $"probe {run.ProbeId.Value} is not connected to this agent"); } if (run.Phases.Count == 0) { - return Result.Fail(MonitorErrors.ValidationFailed, "a test needs at least one phase"); + return Result.Fail(MoShiroErrors.ValidationFailed, "a test needs at least one phase"); } var resolved = new List<(TestPhase Phase, TaskDecision Decision)>(); @@ -64,7 +64,7 @@ public sealed class TestRunner if (!decision.Accepted) { return Result.Fail( - decision.Reason == RejectReasons.Unsupported ? FleetErrors.Unsupported : MonitorErrors.BudgetExceeded, + decision.Reason == RejectReasons.Unsupported ? FleetErrors.Unsupported : MoShiroErrors.BudgetExceeded, $"phase {phase.Kind} refused: {decision.Reason}"); } @@ -84,7 +84,7 @@ public sealed class TestRunner if (_running.Count >= _maxConcurrent || !_running.TryAdd(run.TestId.Value, running)) { running.Dispose(); - return Result.Fail(MonitorErrors.TestBusy, "this agent is already running a test"); + return Result.Fail(MoShiroErrors.TestBusy, "this agent is already running a test"); } _ = Task.Run(() => RunAsync(run.TestId, resolved, running), CancellationToken.None); @@ -154,7 +154,7 @@ public sealed class TestRunner catch (OperationCanceledException) { finalStatus = running.Lost ? TestStatuses.Failed : TestStatuses.Aborted; - errorCode = running.Lost ? MonitorErrors.ProbeOffline.Value : null; + errorCode = running.Lost ? MoShiroErrors.ProbeOffline.Value : null; await TryAbortProbeAsync(running.Probe, test); } catch (TestFailure failure) @@ -183,7 +183,7 @@ public sealed class TestRunner _streams.Add(stream); try { - RpcSession rpc = probe.Rpc ?? throw new TestFailure(MonitorErrors.ProbeOffline.Value); + RpcSession rpc = probe.Rpc ?? throw new TestFailure(MoShiroErrors.ProbeOffline.Value); var start = new TestPhaseStartParams { TestId = test, @@ -194,7 +194,7 @@ public sealed class TestRunner DurationSeconds = durationSeconds, Port = stream.Port, }; - Result accepted = await rpc.RequestAsync(MonitorMethods.TestPhase, start, MonitorJsonContext.Default.TestPhaseStartParams, MonitorJsonContext.Default.TestPhaseStartResult, ct); + Result accepted = await rpc.RequestAsync(MoShiroMethods.TestPhase, start, MoShiroJsonContext.Default.TestPhaseStartParams, MoShiroJsonContext.Default.TestPhaseStartResult, ct); if (!accepted.TryGet(out TestPhaseStartResult? started, out FleetError? error) || !started.Accepted) { throw new TestFailure(error?.Code.Value ?? FleetErrors.Unsupported.Value); @@ -209,7 +209,7 @@ public sealed class TestRunner } catch (BlockFaultException) { - throw new TestFailure(MonitorErrors.ProbeOffline.Value); + throw new TestFailure(MoShiroErrors.ProbeOffline.Value); } } else @@ -219,7 +219,7 @@ public sealed class TestRunner long sent = stream.Running.Block.Produced; var end = new TestPhaseEndParams { TestId = test, Phase = index, StreamId = stream.Id, SentCount = sent }; - Result ended = await rpc.RequestAsync(MonitorMethods.TestPhaseEnd, end, MonitorJsonContext.Default.TestPhaseEndParams, MonitorJsonContext.Default.TestPhaseEndResult, ct, s_phaseSlack); + Result ended = await rpc.RequestAsync(MoShiroMethods.TestPhaseEnd, end, MoShiroJsonContext.Default.TestPhaseEndParams, MoShiroJsonContext.Default.TestPhaseEndResult, ct, s_phaseSlack); if (!ended.TryGet(out TestPhaseEndResult? finished, out FleetError? endError)) { throw new TestFailure(endError.Code.Value); @@ -254,7 +254,7 @@ public sealed class TestRunner try { - await rpc.NotifyAsync(MonitorMethods.TestAbort, new TestAbortParams { TestId = test }, MonitorJsonContext.Default.TestAbortParams, CancellationToken.None); + await rpc.NotifyAsync(MoShiroMethods.TestAbort, new TestAbortParams { TestId = test }, MoShiroJsonContext.Default.TestAbortParams, CancellationToken.None); } catch (Exception ex) when (ex is ObjectDisposedException or InvalidOperationException or IOException) { diff --git a/backend/fleet/src/Fleet.Core/StringId.cs b/backend/fleet/src/Fleet.Core/StringId.cs index 87f4058..71371bb 100644 --- a/backend/fleet/src/Fleet.Core/StringId.cs +++ b/backend/fleet/src/Fleet.Core/StringId.cs @@ -3,7 +3,7 @@ using System.Text.Json.Serialization; namespace Fleet.Core; -/// 节点 ID(带类型前缀的 ULID)。Monitor 中的 AgentId 就是 NodeId。 +/// 节点 ID(带类型前缀的 ULID)。MoShiro 中的 AgentId 就是 NodeId。 [JsonConverter(typeof(NodeIdJsonConverter))] public readonly record struct NodeId(string Value) { diff --git a/backend/fleet/src/Fleet.Link/FleetLink.cs b/backend/fleet/src/Fleet.Link/FleetLink.cs index 0fdcc5f..5d86ded 100644 --- a/backend/fleet/src/Fleet.Link/FleetLink.cs +++ b/backend/fleet/src/Fleet.Link/FleetLink.cs @@ -49,7 +49,7 @@ public sealed class FleetLinkOptions public string NodeVersion { get; init; } = "0.0.0"; - /// 框架之外的能力,例如 monitor.v1 与 monitor.kinds:udp_echo,tcp_echo。 + /// 框架之外的能力,例如 moshiro.v1 与 moshiro.kinds:udp_echo,tcp_echo。 public IReadOnlyList Capabilities { get; init; } = []; /// 附加到 fleet.hello 的产品元数据。 diff --git a/backend/fleet/src/Fleet.Rpc/FleetMethods.cs b/backend/fleet/src/Fleet.Rpc/FleetMethods.cs index 9053db9..6062ead 100644 --- a/backend/fleet/src/Fleet.Rpc/FleetMethods.cs +++ b/backend/fleet/src/Fleet.Rpc/FleetMethods.cs @@ -58,7 +58,7 @@ public sealed class HelloParams [JsonPropertyName("now_utc_ms")] public long NowUtcMs { get; set; } - /// 产品自定义的元数据(例如 Monitor 的 tls_spki、probe_ports、local_limits 摘要)。 + /// 产品自定义的元数据(例如 MoShiro 的 tls_spki、probe_ports、local_limits 摘要)。 [JsonPropertyName("meta")] public JsonElement? Meta { get; set; } } diff --git a/backend/fleet/src/Fleet.Server.Abstractions/FleetServerOptions.cs b/backend/fleet/src/Fleet.Server.Abstractions/FleetServerOptions.cs index fd99ac7..0a581bf 100644 --- a/backend/fleet/src/Fleet.Server.Abstractions/FleetServerOptions.cs +++ b/backend/fleet/src/Fleet.Server.Abstractions/FleetServerOptions.cs @@ -2,7 +2,7 @@ namespace Fleet.Server; public sealed class FleetServerOptions { - /// 节点 ID 的类型前缀,Monitor 使用 agt。 + /// 节点 ID 的类型前缀,MoShiro 使用 agt。 public string NodeIdPrefix { get; set; } = "node"; public int MaxFrameBytes { get; set; } = 16 << 20; diff --git a/backend/fleet/src/Fleet.Server.Abstractions/IFleetStore.cs b/backend/fleet/src/Fleet.Server.Abstractions/IFleetStore.cs index ed00273..e4d7af0 100644 --- a/backend/fleet/src/Fleet.Server.Abstractions/IFleetStore.cs +++ b/backend/fleet/src/Fleet.Server.Abstractions/IFleetStore.cs @@ -2,7 +2,7 @@ using Fleet.Core; namespace Fleet.Server; -/// Fleet 服务端需要的存储。产品可以自己实现(Monitor 把它放进 monitor.db)。 +/// Fleet 服务端需要的存储。产品可以自己实现(MoShiro 把它放进 moshiro.db)。 public interface IFleetStore { ValueTask FindJoinTokenAsync(ReadOnlyMemory tokenSha256, CancellationToken ct); diff --git a/backend/fleet/src/Fleet.Server.Link/FleetServerBuilder.cs b/backend/fleet/src/Fleet.Server.Link/FleetServerBuilder.cs index 7141df9..755deb2 100644 --- a/backend/fleet/src/Fleet.Server.Link/FleetServerBuilder.cs +++ b/backend/fleet/src/Fleet.Server.Link/FleetServerBuilder.cs @@ -50,7 +50,7 @@ public sealed class FleetServerBuilder return this; } - /// 注册产品的 RPC 方法(monitor.* 等)。处理函数通过 在调用时解析服务,避免构造期的循环依赖。 + /// 注册产品的 RPC 方法(moshiro.* 等)。处理函数通过 在调用时解析服务,避免构造期的循环依赖。 public FleetServerBuilder MapMethods(Action, IServiceProvider> configure) { _routeConfigurators.Add(configure); diff --git a/backend/fleet/tools/fleet-enroll/Program.cs b/backend/fleet/tools/fleet-enroll/Program.cs index 2ede74b..3c31989 100644 --- a/backend/fleet/tools/fleet-enroll/Program.cs +++ b/backend/fleet/tools/fleet-enroll/Program.cs @@ -2,7 +2,7 @@ using System.Text.Json.Nodes; using Fleet.Core; using Fleet.Enrollment.Client; -// fleet-enroll --server https://panel --join jt_xxx --name jp-1 --identity-dir /etc/monitor [--meta '{"probe_tcp_port":7443,...}'] [--version 1.0] +// fleet-enroll --server https://panel --join jt_xxx --name jp-1 --identity-dir /etc/moshiro [--meta '{"probe_tcp_port":7443,...}'] [--version 1.0] // 一次性运行:生成身份、注册、写入身份目录,然后退出。 string? Arg(string name) => args.SkipWhile(a => a != name).Skip(1).FirstOrDefault(); diff --git a/backend/openapi/v1.json b/backend/openapi/v1.json index bc9085e..fb33894 100644 --- a/backend/openapi/v1.json +++ b/backend/openapi/v1.json @@ -1,7 +1,7 @@ { "openapi": "3.1.1", "info": { - "title": "monitor-backend | v1", + "title": "moshiro-backend | v1", "version": "1.0.0" }, "paths": { @@ -3168,7 +3168,7 @@ "tags": [ "admin-data" ], - "summary": "Download a raw chunk (application/vnd.monitor.rawchunk)", + "summary": "Download a raw chunk (application/vnd.moshiro.rawchunk)", "operationId": "raw_chunks_get", "parameters": [ { diff --git a/backend/probe/README.md b/backend/probe/README.md index 6e764cc..76db344 100644 --- a/backend/probe/README.md +++ b/backend/probe/README.md @@ -1,4 +1,4 @@ -# Monitor Probe +# MoShiro Probe Probe 是网络测量的发起端,通常运行在家宽或其他需要观测的网络出口。它连接 Backend(身份、Agent 列表、状态)和 Agent(测量),执行线路任务,并把本端采集的原始数据交给 Agent 汇总上报。Probe 不提供远程命令或文件管理功能。 @@ -13,7 +13,7 @@ Backend ──任务──> Agent <──测量会话──> Probe Probe 使用面板生成的 `probe.json` 读取自身身份、面板地址(`server`)和本地测试限制。连上面板之后,面板下发要连接的 Agent 列表;Probe 将列表缓存到同目录的 `agents.json`,面板暂时连不上时靠它继续测量。`probe.json` 含私钥,请限制文件访问权限,不要提交到版本控制。 -容器节点的运行方式(podman + systemd)和宿主机更新器见 [`../../docs/deployment.md`](../../docs/deployment.md);Probe 也可以用 OCI 镜像 `registry.oeo.one/monitor/monitor-probe:`,容器默认读取 `/etc/monitor/probe.json`,命名 volume 保存身份配置和缓存,镜像以 UID/GID 1654 运行。 +容器节点的运行方式(podman + systemd)和宿主机更新器见 [`../../docs/deployment.md`](../../docs/deployment.md);Probe 也可以用 OCI 镜像 `registry.oeo.one/moshiro/moshiro-probe:`,容器默认读取 `/etc/moshiro/probe.json`,命名 volume 保存身份配置和缓存,镜像以 UID/GID 1654 运行。 ## 构建 @@ -21,33 +21,33 @@ Probe 使用面板生成的 `probe.json` 读取自身身份、面板地址(`se ```sh cd backend -dotnet build probe/src/Monitor.Probe -c Release +dotnet build probe/src/MoShiro.Probe -c Release ``` 发布 NativeAOT 程序需要对应平台的 C/C++ 工具链;`` 应与构建环境和目标平台匹配: ```sh -dotnet publish probe/src/Monitor.Probe -c Release -r -p:PublishAot=true +dotnet publish probe/src/MoShiro.Probe -c Release -r -p:PublishAot=true ``` 也可在仓库根目录运行 `bash scripts/publish.sh probe `,再使用 `scripts/package.sh probe ` 生成部署包。支持平台和安装流程见 [`../../docs/deployment.md`](../../docs/deployment.md)。 ## 配置与运行 -在管理端创建 Probe 并下载一次性身份配置,将文件保存为目标机上的 `/etc/monitor/probe.json`。随后运行: +在管理端创建 Probe 并下载一次性身份配置,将文件保存为目标机上的 `/etc/moshiro/probe.json`。随后运行: ```sh -monitor-probe --config /etc/monitor/probe.json +moshiro-probe --config /etc/moshiro/probe.json ``` -不传 `--config` 时默认读取 `/etc/monitor/probe.json`。配置中的 `limits` 是本地硬上限,Backend 无法远程放宽;路由器等低性能设备可调低测试码率和包速率,避免 Probe 自身成为测量瓶颈。部署时可使用仓库的 `packaging/` 文件和安装脚本。 +不传 `--config` 时默认读取 `/etc/moshiro/probe.json`。配置中的 `limits` 是本地硬上限,Backend 无法远程放宽;路由器等低性能设备可调低测试码率和包速率,避免 Probe 自身成为测量瓶颈。部署时可使用仓库的 `packaging/` 文件和安装脚本。 -也可使用 OCI 镜像 `registry.oeo.one/monitor/monitor-probe:`,自动选择 Linux amd64 或 arm64 镜像。容器默认读取 `/etc/monitor/probe.json`,并在同一目录维护 `agents.json` 缓存,因此挂载目录必须允许 UID/GID 1654 读写。建议使用宿主网络,并按 ICMP 测量需求添加 `NET_RAW` 能力。 +也可使用 OCI 镜像 `registry.oeo.one/moshiro/moshiro-probe:`,自动选择 Linux amd64 或 arm64 镜像。容器默认读取 `/etc/moshiro/probe.json`,并在同一目录维护 `agents.json` 缓存,因此挂载目录必须允许 UID/GID 1654 读写。建议使用宿主网络,并按 ICMP 测量需求添加 `NET_RAW` 能力。 ## 设计说明 - Probe 只执行编译进程序的测量模块。它不落盘测量数据,也不能执行命令或自行更新(更新由宿主机上的更新器完成,Probe 只写清单和请求文件)。 -- 测量模块由 `backend/shared/Monitor.Measurement/` 与 Agent 共用;Probe 负责发起连接、调度任务和记录本端数据。 +- 测量模块由 `backend/shared/MoShiro.Measurement/` 与 Agent 共用;Probe 负责发起连接、调度任务和记录本端数据。 - 测量模型和协议细节见 [`../../docs/measurement.md`](../../docs/measurement.md) 与 [`../../docs/protocol.md`](../../docs/protocol.md);整体架构见 [`../../docs/architecture.md`](../../docs/architecture.md)。 Docker 与 rootless/rootful Podman 共用 `packaging/compose/probe/compose.yaml`,配置、身份和缓存放在命名 volume 中,无需宿主配置目录、keep-id 或手动 chown。首次导入和自动更新见部署文档。 diff --git a/backend/probe/src/Monitor.Probe/Link/AgentConnection.cs b/backend/probe/src/MoShiro.Probe/Link/AgentConnection.cs similarity index 95% rename from backend/probe/src/Monitor.Probe/Link/AgentConnection.cs rename to backend/probe/src/MoShiro.Probe/Link/AgentConnection.cs index f01ad3d..1a2e621 100644 --- a/backend/probe/src/Monitor.Probe/Link/AgentConnection.cs +++ b/backend/probe/src/MoShiro.Probe/Link/AgentConnection.cs @@ -6,10 +6,10 @@ using Fleet.Core; using Fleet.Identity; using Fleet.Link; using Fleet.Rpc; -using Monitor.Measurement; -using Monitor.Protocol; +using MoShiro.Measurement; +using MoShiro.Protocol; -namespace Monitor.Probe; +namespace MoShiro.Probe; /// 所有连接共用的东西。 public sealed record ConnectionEnv(NodeIdentity Identity, string ProbeId, ProbeLimits Limits, AgentDirectory Directory, MonoClock Clock, TimeProvider Time, INodeLog Log); @@ -154,7 +154,7 @@ public sealed class AgentConnection for (int i = 0; i < rounds; i++) { long sent = _env.Clock.NowUs(); - Result reply = await rpc.RequestAsync(MonitorMethods.Clock, new ClockParams { ProbeMonoUs = sent }, MonitorJsonContext.Default.ClockParams, MonitorJsonContext.Default.ClockResult, ct); + Result reply = await rpc.RequestAsync(MoShiroMethods.Clock, new ClockParams { ProbeMonoUs = sent }, MoShiroJsonContext.Default.ClockParams, MoShiroJsonContext.Default.ClockResult, ct); if (reply.TryGet(out ClockResult? value, out _)) { clock.Add(sent, value.AgentMonoUs, _env.Clock.NowUs()); @@ -189,7 +189,7 @@ public sealed class AgentConnection var result = new StateSyncResult { AppliedVersion = sync.Version }; if (sync.Type == LineTaskSet.StateType) { - LineTaskSet? set = sync.Doc.Deserialize(MonitorJsonContext.Default.LineTaskSet); + LineTaskSet? set = sync.Doc.Deserialize(MoShiroJsonContext.Default.LineTaskSet); if (set is null) { return Result.Fail(FleetErrors.InvalidParams, "line_task_set could not be parsed"); @@ -201,18 +201,18 @@ public sealed class AgentConnection return Result.Ok(result); }) .On( - MonitorMethods.TestPhase, - MonitorJsonContext.Default.TestPhaseStartParams, - MonitorJsonContext.Default.TestPhaseStartResult, + MoShiroMethods.TestPhase, + MoShiroJsonContext.Default.TestPhaseStartParams, + MoShiroJsonContext.Default.TestPhaseStartResult, (session, start, _) => ValueTask.FromResult(Result.Ok(new TestPhaseStartResult { Accepted = session.StartPhase(start) }))) .On( - MonitorMethods.TestPhaseEnd, - MonitorJsonContext.Default.TestPhaseEndParams, - MonitorJsonContext.Default.TestPhaseEndResult, + MoShiroMethods.TestPhaseEnd, + MoShiroJsonContext.Default.TestPhaseEndParams, + MoShiroJsonContext.Default.TestPhaseEndResult, async (session, end, ct) => Result.Ok(new TestPhaseEndResult { Fragments = await session.EndPhaseAsync(end, ct) })) .OnNotify( - MonitorMethods.TestAbort, - MonitorJsonContext.Default.TestAbortParams, + MoShiroMethods.TestAbort, + MoShiroJsonContext.Default.TestAbortParams, async (session, abort, _) => await session.AbortAsync(abort.TestId)) .OnNotify( FleetMethods.OutboxAck, diff --git a/backend/probe/src/Monitor.Probe/Link/AgentDirectory.cs b/backend/probe/src/MoShiro.Probe/Link/AgentDirectory.cs similarity index 98% rename from backend/probe/src/Monitor.Probe/Link/AgentDirectory.cs rename to backend/probe/src/MoShiro.Probe/Link/AgentDirectory.cs index 4c74202..4a59d2c 100644 --- a/backend/probe/src/Monitor.Probe/Link/AgentDirectory.cs +++ b/backend/probe/src/MoShiro.Probe/Link/AgentDirectory.cs @@ -1,9 +1,9 @@ using System.Text.Json; using Fleet.Core; using Fleet.Hosting; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Probe; +namespace MoShiro.Probe; /// /// Probe 要连接的 Agent 列表:由面板作为期望状态(probe_agents)直接下发;面板连不上时用上一次保存的 agents.json。 diff --git a/backend/probe/src/Monitor.Probe/Link/Support.cs b/backend/probe/src/MoShiro.Probe/Link/Support.cs similarity index 93% rename from backend/probe/src/Monitor.Probe/Link/Support.cs rename to backend/probe/src/MoShiro.Probe/Link/Support.cs index e593ef6..253be3a 100644 --- a/backend/probe/src/Monitor.Probe/Link/Support.cs +++ b/backend/probe/src/MoShiro.Probe/Link/Support.cs @@ -1,13 +1,13 @@ using System.Text.Json; using Fleet.Core; using Fleet.Link; -using Monitor.Measurement; -using Monitor.Protocol; +using MoShiro.Measurement; +using MoShiro.Protocol; -namespace Monitor.Probe; +namespace MoShiro.Probe; /// -/// 估计 Agent 单调时钟 − Probe 单调时钟:每次 monitor.clock 往返取中点,在最近 8 次里取往返最短的一次 +/// 估计 Agent 单调时钟 − Probe 单调时钟:每次 moshiro.clock 往返取中点,在最近 8 次里取往返最短的一次 /// (往返越短,对称性假设的误差越小)。Probe 的列块头里带着这个偏移,Backend 据此对齐两端的时间戳。 /// public sealed class ClockEstimator @@ -82,6 +82,6 @@ public sealed class FragmentShipper : IFragmentSink } } - _outbox.Enqueue(MonitorChannels.ColumnBlock, header.ChunkId.Value, RawChunkCodec.Encode(new RawChunk(header, streams))); + _outbox.Enqueue(MoShiroChannels.ColumnBlock, header.ChunkId.Value, RawChunkCodec.Encode(new RawChunk(header, streams))); } } diff --git a/backend/agent/src/Monitor.Agent/Monitor.Agent.csproj b/backend/probe/src/MoShiro.Probe/MoShiro.Probe.csproj similarity index 78% rename from backend/agent/src/Monitor.Agent/Monitor.Agent.csproj rename to backend/probe/src/MoShiro.Probe/MoShiro.Probe.csproj index f25af4d..54d4202 100644 --- a/backend/agent/src/Monitor.Agent/Monitor.Agent.csproj +++ b/backend/probe/src/MoShiro.Probe/MoShiro.Probe.csproj @@ -4,8 +4,8 @@ Condition="'$(UseAotAnywhere)' == 'true'" /> Exe - monitor-agent - Monitor.Agent + moshiro-probe + MoShiro.Probe true true true @@ -15,10 +15,10 @@ false - + - + /// Probe 的组装点:到面板的长连接(身份、Agent 列表、状态)+ 每个 Agent 一个测量连接(认证、重连、角色)。没有全局状态,测试可以在同一进程里启动多个。 @@ -15,7 +15,7 @@ namespace Monitor.Probe; /// public sealed class ProbeApp : IDisposable { - public const string Version = Monitor.Protocol.BuildInfo.Version; + public const string Version = MoShiro.Protocol.BuildInfo.Version; private readonly ConnectionEnv _env; private readonly Dictionary _connections = []; @@ -38,25 +38,25 @@ public sealed class ProbeApp : IDisposable Identity = identity, NodeId = new NodeId(file.ProbeId), NodeVersion = Version, - Capabilities = [MonitorCapabilities.Base], - HeartbeatExtra = () => JsonSerializer.SerializeToElement(new ProbeHeartbeatExtra { Update = update.ReadStatus() }, MonitorJsonContext.Default.ProbeHeartbeatExtra), - HelloMeta = () => JsonSerializer.SerializeToElement(new ProbeHelloMeta { Platform = PlatformDetector.Detect() }, MonitorJsonContext.Default.ProbeHelloMeta), + Capabilities = [MoShiroCapabilities.Base], + HeartbeatExtra = () => JsonSerializer.SerializeToElement(new ProbeHeartbeatExtra { Update = update.ReadStatus() }, MoShiroJsonContext.Default.ProbeHeartbeatExtra), + HelloMeta = () => JsonSerializer.SerializeToElement(new ProbeHelloMeta { Platform = PlatformDetector.Detect() }, MoShiroJsonContext.Default.ProbeHelloMeta), }; var list = new StateHandler( ProbeAgentList.StateType, - MonitorJsonContext.Default.ProbeAgentList, + MoShiroJsonContext.Default.ProbeAgentList, (version, doc, _) => { directory.Apply(doc); return ValueTask.FromResult(new StateSyncResult { AppliedVersion = version }); }); var router = new RpcRouter() - .OnNotify(MonitorMethods.UpdateOffer, MonitorJsonContext.Default.UpdateOfferParams, (_, offer, _) => + .OnNotify(MoShiroMethods.UpdateOffer, MoShiroJsonContext.Default.UpdateOfferParams, (_, offer, _) => { update.WriteOffer(offer); return ValueTask.CompletedTask; }) - .OnNotify(MonitorMethods.UpdateApply, MonitorJsonContext.Default.UpdateOfferParams, (_, _, _) => + .OnNotify(MoShiroMethods.UpdateApply, MoShiroJsonContext.Default.UpdateOfferParams, (_, _, _) => { update.RequestApply(); return ValueTask.CompletedTask; diff --git a/backend/probe/src/Monitor.Probe/ProbeConfig.cs b/backend/probe/src/MoShiro.Probe/ProbeConfig.cs similarity index 98% rename from backend/probe/src/Monitor.Probe/ProbeConfig.cs rename to backend/probe/src/MoShiro.Probe/ProbeConfig.cs index bcaf11e..5bb9aa8 100644 --- a/backend/probe/src/Monitor.Probe/ProbeConfig.cs +++ b/backend/probe/src/MoShiro.Probe/ProbeConfig.cs @@ -1,6 +1,6 @@ using System.Text.Json.Serialization; -namespace Monitor.Probe; +namespace MoShiro.Probe; /// /// probe.json:面板 POST /api/admin/probe/identity 生成的文件(只能下载一次)。 diff --git a/backend/probe/src/Monitor.Probe/Program.cs b/backend/probe/src/MoShiro.Probe/Program.cs similarity index 95% rename from backend/probe/src/Monitor.Probe/Program.cs rename to backend/probe/src/MoShiro.Probe/Program.cs index 2a025ac..cadfb11 100644 --- a/backend/probe/src/Monitor.Probe/Program.cs +++ b/backend/probe/src/MoShiro.Probe/Program.cs @@ -1,6 +1,6 @@ using Fleet.Core; using Fleet.Hosting; -using Monitor.Probe; +using MoShiro.Probe; TimeProvider time = TimeProvider.System; INodeLog log = new ConsoleNodeLog(time); @@ -11,7 +11,7 @@ if (PlatformCheck.VerifyCrypto() is { } problem) return 1; } -string configPath = "/etc/monitor/probe.json"; +string configPath = "/etc/moshiro/probe.json"; for (int i = 0; i < args.Length - 1; i++) { if (args[i] == "--config") diff --git a/backend/probe/tests/Monitor.Probe.Tests/Monitor.Probe.Tests.csproj b/backend/probe/tests/MoShiro.Probe.Tests/MoShiro.Probe.Tests.csproj similarity index 82% rename from backend/probe/tests/Monitor.Probe.Tests/Monitor.Probe.Tests.csproj rename to backend/probe/tests/MoShiro.Probe.Tests/MoShiro.Probe.Tests.csproj index 1367d6a..d27508f 100644 --- a/backend/probe/tests/Monitor.Probe.Tests/Monitor.Probe.Tests.csproj +++ b/backend/probe/tests/MoShiro.Probe.Tests/MoShiro.Probe.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/backend/probe/tests/Monitor.Probe.Tests/ProbeTests.cs b/backend/probe/tests/MoShiro.Probe.Tests/ProbeTests.cs similarity index 98% rename from backend/probe/tests/Monitor.Probe.Tests/ProbeTests.cs rename to backend/probe/tests/MoShiro.Probe.Tests/ProbeTests.cs index 89d3f20..d8bfa02 100644 --- a/backend/probe/tests/Monitor.Probe.Tests/ProbeTests.cs +++ b/backend/probe/tests/MoShiro.Probe.Tests/ProbeTests.cs @@ -1,8 +1,8 @@ using Fleet.Core; using Fleet.Hosting; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Probe.Tests; +namespace MoShiro.Probe.Tests; public sealed class ProbeTests { diff --git a/backend/shared/Monitor.Measurement/Blocks/BlockBase.cs b/backend/shared/MoShiro.Measurement/Blocks/BlockBase.cs similarity index 98% rename from backend/shared/Monitor.Measurement/Blocks/BlockBase.cs rename to backend/shared/MoShiro.Measurement/Blocks/BlockBase.cs index 8463d00..afa65cf 100644 --- a/backend/shared/Monitor.Measurement/Blocks/BlockBase.cs +++ b/backend/shared/MoShiro.Measurement/Blocks/BlockBase.cs @@ -1,7 +1,7 @@ using System.Net; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 积木的公共部分:环境、参数、把行切成列块交出去。 public abstract class BlockBase : IBlock diff --git a/backend/shared/Monitor.Measurement/Blocks/BlockCatalog.cs b/backend/shared/MoShiro.Measurement/Blocks/BlockCatalog.cs similarity index 97% rename from backend/shared/Monitor.Measurement/Blocks/BlockCatalog.cs rename to backend/shared/MoShiro.Measurement/Blocks/BlockCatalog.cs index 3970f2b..43465ab 100644 --- a/backend/shared/Monitor.Measurement/Blocks/BlockCatalog.cs +++ b/backend/shared/MoShiro.Measurement/Blocks/BlockCatalog.cs @@ -1,6 +1,6 @@ -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// /// 一种采集方法(Kind)的两个角色:拨号方(Probe)和监听方(Agent),以及它能不能作为目标任务(Agent 自己探测一个地址,没有对端)运行。 diff --git a/backend/shared/Monitor.Measurement/Blocks/Bulk.cs b/backend/shared/MoShiro.Measurement/Blocks/Bulk.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Blocks/Bulk.cs rename to backend/shared/MoShiro.Measurement/Blocks/Bulk.cs index 5fc0591..cc08f70 100644 --- a/backend/shared/Monitor.Measurement/Blocks/Bulk.cs +++ b/backend/shared/MoShiro.Measurement/Blocks/Bulk.cs @@ -1,7 +1,7 @@ using System.Net.Sockets; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 批量传输的收发循环(两端共用)。 internal static class BulkIo diff --git a/backend/shared/Monitor.Measurement/Blocks/Echo.cs b/backend/shared/MoShiro.Measurement/Blocks/Echo.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Blocks/Echo.cs rename to backend/shared/MoShiro.Measurement/Blocks/Echo.cs index 94c51b8..ef639db 100644 --- a/backend/shared/Monitor.Measurement/Blocks/Echo.cs +++ b/backend/shared/MoShiro.Measurement/Blocks/Echo.cs @@ -1,8 +1,8 @@ using System.Net; using System.Net.Sockets; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// /// 回显积木的行表(拨号方,行的主导方):发出时记 size、t1,回复到达时按序号回填 t4,到点把已经稳定的行切成列块。 diff --git a/backend/shared/Monitor.Measurement/Blocks/Session.cs b/backend/shared/MoShiro.Measurement/Blocks/Session.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Blocks/Session.cs rename to backend/shared/MoShiro.Measurement/Blocks/Session.cs index 0e52380..18b96d8 100644 --- a/backend/shared/Monitor.Measurement/Blocks/Session.cs +++ b/backend/shared/MoShiro.Measurement/Blocks/Session.cs @@ -1,9 +1,9 @@ using System.Net.NetworkInformation; using System.Net.Sockets; using System.Security.Authentication; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 什么也不做的监听方:connect 的另一端就是 TCP 监听器本身(接受连接、认证失败就关闭),不需要积木,但需要占一个流编号。 public sealed class IdleListener : BlockBase diff --git a/backend/shared/Monitor.Measurement/Blocks/Train.cs b/backend/shared/MoShiro.Measurement/Blocks/Train.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Blocks/Train.cs rename to backend/shared/MoShiro.Measurement/Blocks/Train.cs index 33a1117..7cfadac 100644 --- a/backend/shared/Monitor.Measurement/Blocks/Train.cs +++ b/backend/shared/MoShiro.Measurement/Blocks/Train.cs @@ -1,8 +1,8 @@ using System.Diagnostics; using System.Net; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// /// 单向数据流(UDP train),监听方(Agent,行的主导方):按声明的码率均匀发包,发出的每个包 (seq, size, t_send) 记在按序号的记录里, diff --git a/backend/shared/Monitor.Measurement/Core/Contracts.cs b/backend/shared/MoShiro.Measurement/Core/Contracts.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Core/Contracts.cs rename to backend/shared/MoShiro.Measurement/Core/Contracts.cs index 9919324..1dea055 100644 --- a/backend/shared/Monitor.Measurement/Core/Contracts.cs +++ b/backend/shared/MoShiro.Measurement/Core/Contracts.cs @@ -1,9 +1,9 @@ using System.Net; using System.Text.Json; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// /// 数据面会话:session_id 和密钥(由点对点握手里的 ECDH 派生)。两端的数据面包都用它认证。 diff --git a/backend/shared/Monitor.Measurement/Core/MonoClock.cs b/backend/shared/MoShiro.Measurement/Core/MonoClock.cs similarity index 97% rename from backend/shared/Monitor.Measurement/Core/MonoClock.cs rename to backend/shared/MoShiro.Measurement/Core/MonoClock.cs index ca52868..a316445 100644 --- a/backend/shared/Monitor.Measurement/Core/MonoClock.cs +++ b/backend/shared/MoShiro.Measurement/Core/MonoClock.cs @@ -1,4 +1,4 @@ -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 节点的单调时钟(微秒):t1…t4、t_send、t_recv 都用它;Probe 和 Agent 各自一个,块头里的时钟锚点把它对应到 UTC。 public sealed class MonoClock diff --git a/backend/shared/Monitor.Measurement/Core/RowStore.cs b/backend/shared/MoShiro.Measurement/Core/RowStore.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Core/RowStore.cs rename to backend/shared/MoShiro.Measurement/Core/RowStore.cs index 9160195..77845b2 100644 --- a/backend/shared/Monitor.Measurement/Core/RowStore.cs +++ b/backend/shared/MoShiro.Measurement/Core/RowStore.cs @@ -1,6 +1,6 @@ -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// /// 一侧记录的行:只含这一侧拥有的列(见 ),按连接键(通常是 seq)索引的环形缓冲, diff --git a/backend/shared/Monitor.Measurement/Core/RunningBlock.cs b/backend/shared/MoShiro.Measurement/Core/RunningBlock.cs similarity index 98% rename from backend/shared/Monitor.Measurement/Core/RunningBlock.cs rename to backend/shared/MoShiro.Measurement/Core/RunningBlock.cs index c246ba5..1ba7e7b 100644 --- a/backend/shared/Monitor.Measurement/Core/RunningBlock.cs +++ b/backend/shared/MoShiro.Measurement/Core/RunningBlock.cs @@ -1,4 +1,4 @@ -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 一个运行中的积木:自己的取消令牌和后台任务。Probe 和 Agent 共用。 public sealed class RunningBlock : IDisposable diff --git a/backend/shared/Monitor.Measurement/Execution/BudgetGuard.cs b/backend/shared/MoShiro.Measurement/Execution/BudgetGuard.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Execution/BudgetGuard.cs rename to backend/shared/MoShiro.Measurement/Execution/BudgetGuard.cs index f01e5e5..add768e 100644 --- a/backend/shared/Monitor.Measurement/Execution/BudgetGuard.cs +++ b/backend/shared/MoShiro.Measurement/Execution/BudgetGuard.cs @@ -1,8 +1,8 @@ using System.Net; using System.Text.Json; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 节点的本地硬上限(写在本机配置里,Backend 无法修改)。 public sealed class NodeLimits diff --git a/backend/shared/Monitor.Measurement/Merging/ChunkFinalizer.cs b/backend/shared/MoShiro.Measurement/Merging/ChunkFinalizer.cs similarity index 98% rename from backend/shared/Monitor.Measurement/Merging/ChunkFinalizer.cs rename to backend/shared/MoShiro.Measurement/Merging/ChunkFinalizer.cs index c91de05..53379cb 100644 --- a/backend/shared/Monitor.Measurement/Merging/ChunkFinalizer.cs +++ b/backend/shared/MoShiro.Measurement/Merging/ChunkFinalizer.cs @@ -1,8 +1,8 @@ using System.Text.Json; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// Agent 单调时钟(微秒)与 UTC(毫秒)的对应关系:块头里的时钟锚点。 public readonly record struct ClockAnchor(long AgentMonoUs, long UtcMs); diff --git a/backend/shared/Monitor.Measurement/Merging/FragmentMerger.cs b/backend/shared/MoShiro.Measurement/Merging/FragmentMerger.cs similarity index 96% rename from backend/shared/Monitor.Measurement/Merging/FragmentMerger.cs rename to backend/shared/MoShiro.Measurement/Merging/FragmentMerger.cs index e029204..04653d0 100644 --- a/backend/shared/Monitor.Measurement/Merging/FragmentMerger.cs +++ b/backend/shared/MoShiro.Measurement/Merging/FragmentMerger.cs @@ -1,8 +1,8 @@ using System.Text.Json; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// Agent 一侧为合并保留的按键记录(由正在运行的积木提供)。 public interface IRecordSource @@ -29,7 +29,7 @@ public static class FragmentMerger StreamSpec? streamSpec = spec.FindStream(stream.Name); if (streamSpec is null) { - return Result>.Fail(MonitorErrors.ValidationFailed, $"stream {stream.Name} is not declared by {spec.Id}"); + return Result>.Fail(MoShiroErrors.ValidationFailed, $"stream {stream.Name} is not declared by {spec.Id}"); } Result merged = Join(streamSpec, stream, fragment.Header, records.Records(streamId, stream.Name)); @@ -71,7 +71,7 @@ public static class FragmentMerger RawColumn? key = probe.Find(spec.Key); if (key is null || probeColumns.Any(c => probe.Find(c.Name) is null)) { - return Result.Fail(MonitorErrors.ValidationFailed, $"a fragment of stream {spec.Name} needs the columns {string.Join(", ", new[] { spec.Key }.Concat(probeColumns.Select(c => c.Name)))}"); + return Result.Fail(MoShiroErrors.ValidationFailed, $"a fragment of stream {spec.Name} needs the columns {string.Join(", ", new[] { spec.Key }.Concat(probeColumns.Select(c => c.Name)))}"); } return spec.Driver == Side.Probe ? JoinOnProbeRows(spec, probe, key, agent) : JoinOnAgentRows(spec, probe, key, header, agent); @@ -118,7 +118,7 @@ public static class FragmentMerger { if (!TryGetRange(header, out uint from, out uint to)) { - return Result.Fail(MonitorErrors.ValidationFailed, $"a fragment of stream {spec.Name} must declare its sequence range"); + return Result.Fail(MoShiroErrors.ValidationFailed, $"a fragment of stream {spec.Name} must declare its sequence range"); } // 行取自 Agent 的记录:范围内发出过的每一个包都有一行,Probe 没有报告到达的就是丢失 diff --git a/backend/shared/Monitor.Measurement/Monitor.Measurement.csproj b/backend/shared/MoShiro.Measurement/MoShiro.Measurement.csproj similarity index 67% rename from backend/shared/Monitor.Measurement/Monitor.Measurement.csproj rename to backend/shared/MoShiro.Measurement/MoShiro.Measurement.csproj index 8853475..baf3b8d 100644 --- a/backend/shared/Monitor.Measurement/Monitor.Measurement.csproj +++ b/backend/shared/MoShiro.Measurement/MoShiro.Measurement.csproj @@ -3,8 +3,8 @@ true - + - + diff --git a/backend/shared/Monitor.Measurement/Net/Tcp.cs b/backend/shared/MoShiro.Measurement/Net/Tcp.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Net/Tcp.cs rename to backend/shared/MoShiro.Measurement/Net/Tcp.cs index f0e6fe4..30adafb 100644 --- a/backend/shared/Monitor.Measurement/Net/Tcp.cs +++ b/backend/shared/MoShiro.Measurement/Net/Tcp.cs @@ -5,9 +5,9 @@ using System.Net.Sockets; using System.Security.Authentication; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 拨号方的一条数据面 TCP 连接(已经完成 TLS 和首帧认证)。 public sealed class TcpLink : IDisposable diff --git a/backend/shared/Monitor.Measurement/Net/TcpInfo.cs b/backend/shared/MoShiro.Measurement/Net/TcpInfo.cs similarity index 98% rename from backend/shared/Monitor.Measurement/Net/TcpInfo.cs rename to backend/shared/MoShiro.Measurement/Net/TcpInfo.cs index d9a60d7..8a2be0c 100644 --- a/backend/shared/Monitor.Measurement/Net/TcpInfo.cs +++ b/backend/shared/MoShiro.Measurement/Net/TcpInfo.cs @@ -1,8 +1,8 @@ using System.Buffers.Binary; using System.Net.Sockets; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 内核对一条 TCP 连接的采样(Linux TCP_INFO)。 public readonly record struct TcpInfoSample(long SrttUs, long RttVarUs, long Cwnd, long TotalRetrans, long SegsOut, long BytesAcked); diff --git a/backend/shared/Monitor.Measurement/Net/UdpMux.cs b/backend/shared/MoShiro.Measurement/Net/UdpMux.cs similarity index 99% rename from backend/shared/Monitor.Measurement/Net/UdpMux.cs rename to backend/shared/MoShiro.Measurement/Net/UdpMux.cs index dc03456..9d036af 100644 --- a/backend/shared/Monitor.Measurement/Net/UdpMux.cs +++ b/backend/shared/MoShiro.Measurement/Net/UdpMux.cs @@ -2,9 +2,9 @@ using System.Collections.Concurrent; using System.Net; using System.Net.Sockets; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// 一个通过校验的 UDP 包,交给按 stream_id 登记的处理函数。处理函数在接收循环里同步执行,不能阻塞。 public readonly ref struct UdpDelivery diff --git a/backend/shared/Monitor.Measurement/Platform/PlatformDetector.cs b/backend/shared/MoShiro.Measurement/Platform/PlatformDetector.cs similarity index 98% rename from backend/shared/Monitor.Measurement/Platform/PlatformDetector.cs rename to backend/shared/MoShiro.Measurement/Platform/PlatformDetector.cs index b3e5dd4..39d4fd6 100644 --- a/backend/shared/Monitor.Measurement/Platform/PlatformDetector.cs +++ b/backend/shared/MoShiro.Measurement/Platform/PlatformDetector.cs @@ -1,7 +1,7 @@ using System.Runtime.InteropServices; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// /// 读出本机的系统名和架构,只用于在面板上展示。故意只取粗粒度的信息: diff --git a/backend/shared/Monitor.Measurement/Update/UpdateBridge.cs b/backend/shared/MoShiro.Measurement/Update/UpdateBridge.cs similarity index 96% rename from backend/shared/Monitor.Measurement/Update/UpdateBridge.cs rename to backend/shared/MoShiro.Measurement/Update/UpdateBridge.cs index 255268a..236088c 100644 --- a/backend/shared/Monitor.Measurement/Update/UpdateBridge.cs +++ b/backend/shared/MoShiro.Measurement/Update/UpdateBridge.cs @@ -1,12 +1,12 @@ using System.Text; using System.Text.Json; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement; +namespace MoShiro.Measurement; /// -/// 节点进程和宿主机更新器之间的文件交换(容器里 /etc/monitor,也就是数据目录): +/// 节点进程和宿主机更新器之间的文件交换(容器里 /etc/moshiro,也就是数据目录): /// 节点把面板发来的清单和签名写进 update/,把「更新」请求写成 update/apply.request;更新器验签并更新,状态由宿主更新器写在只读挂载的 update-status/status.json。 /// 节点进程不执行任何命令,也不信任清单的内容(验签在宿主机上)。没有安装更新器时目录写不了或没人读,调用只是返回 false。 /// @@ -88,7 +88,7 @@ public sealed class UpdateBridge return null; } - return JsonSerializer.Deserialize(File.ReadAllBytes(_statusFile), MonitorJsonContext.Default.UpdateStatus); + return JsonSerializer.Deserialize(File.ReadAllBytes(_statusFile), MoShiroJsonContext.Default.UpdateStatus); } catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or JsonException) { diff --git a/backend/shared/Monitor.Protocol/Catalog/KindSpec.cs b/backend/shared/MoShiro.Protocol/Catalog/KindSpec.cs similarity index 99% rename from backend/shared/Monitor.Protocol/Catalog/KindSpec.cs rename to backend/shared/MoShiro.Protocol/Catalog/KindSpec.cs index 7345228..01059f9 100644 --- a/backend/shared/Monitor.Protocol/Catalog/KindSpec.cs +++ b/backend/shared/MoShiro.Protocol/Catalog/KindSpec.cs @@ -1,4 +1,4 @@ -namespace Monitor.Protocol; +namespace MoShiro.Protocol; [Flags] public enum Scope diff --git a/backend/shared/Monitor.Protocol/Catalog/Kinds/Kinds.cs b/backend/shared/MoShiro.Protocol/Catalog/Kinds/Kinds.cs similarity index 99% rename from backend/shared/Monitor.Protocol/Catalog/Kinds/Kinds.cs rename to backend/shared/MoShiro.Protocol/Catalog/Kinds/Kinds.cs index d311e91..f89639a 100644 --- a/backend/shared/Monitor.Protocol/Catalog/Kinds/Kinds.cs +++ b/backend/shared/MoShiro.Protocol/Catalog/Kinds/Kinds.cs @@ -1,4 +1,4 @@ -namespace Monitor.Protocol; +namespace MoShiro.Protocol; /// /// Kind 目录。新增一种采集方法 = 在这里加一个静态字段并放进 ; diff --git a/backend/shared/Monitor.Protocol/Catalog/ParamSpec.cs b/backend/shared/MoShiro.Protocol/Catalog/ParamSpec.cs similarity index 99% rename from backend/shared/Monitor.Protocol/Catalog/ParamSpec.cs rename to backend/shared/MoShiro.Protocol/Catalog/ParamSpec.cs index 0f415cd..133304f 100644 --- a/backend/shared/Monitor.Protocol/Catalog/ParamSpec.cs +++ b/backend/shared/MoShiro.Protocol/Catalog/ParamSpec.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Text.Json; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; public enum ParamType { diff --git a/backend/shared/Monitor.Protocol/Ids/MonitorIds.cs b/backend/shared/MoShiro.Protocol/Ids/MonitorIds.cs similarity index 98% rename from backend/shared/Monitor.Protocol/Ids/MonitorIds.cs rename to backend/shared/MoShiro.Protocol/Ids/MonitorIds.cs index 2881993..2b9f68e 100644 --- a/backend/shared/Monitor.Protocol/Ids/MonitorIds.cs +++ b/backend/shared/MoShiro.Protocol/Ids/MonitorIds.cs @@ -1,7 +1,7 @@ using System.Text.Json.Serialization; using Fleet.Core; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; [JsonConverter(typeof(ProbeIdJsonConverter))] public readonly record struct ProbeId(string Value) diff --git a/backend/shared/Monitor.Protocol/Monitor.Protocol.csproj b/backend/shared/MoShiro.Protocol/MoShiro.Protocol.csproj similarity index 87% rename from backend/shared/Monitor.Protocol/Monitor.Protocol.csproj rename to backend/shared/MoShiro.Protocol/MoShiro.Protocol.csproj index 1d2bc78..5eb7cd2 100644 --- a/backend/shared/Monitor.Protocol/Monitor.Protocol.csproj +++ b/backend/shared/MoShiro.Protocol/MoShiro.Protocol.csproj @@ -7,7 +7,7 @@ @@ -16,14 +16,14 @@ $(IntermediateOutputPath)BuildInfo.g.cs - + - - - + + + diff --git a/backend/shared/Monitor.Protocol/MonitorErrors.cs b/backend/shared/MoShiro.Protocol/MonitorErrors.cs similarity index 95% rename from backend/shared/Monitor.Protocol/MonitorErrors.cs rename to backend/shared/MoShiro.Protocol/MonitorErrors.cs index 7de2b95..91c7259 100644 --- a/backend/shared/Monitor.Protocol/MonitorErrors.cs +++ b/backend/shared/MoShiro.Protocol/MonitorErrors.cs @@ -1,9 +1,9 @@ using Fleet.Core; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; -/// Monitor 的错误码(在 Fleet 错误码之上扩展)。REST、JSON-RPC、OpenAPI 共用同一份。 -public static class MonitorErrors +/// MoShiro 的错误码(在 Fleet 错误码之上扩展)。REST、JSON-RPC、OpenAPI 共用同一份。 +public static class MoShiroErrors { public static readonly ErrorCode ValidationFailed = new("validation_failed"); public static readonly ErrorCode BudgetExceeded = new("budget_exceeded"); diff --git a/backend/shared/Monitor.Protocol/ProtocolLimits.cs b/backend/shared/MoShiro.Protocol/ProtocolLimits.cs similarity index 75% rename from backend/shared/Monitor.Protocol/ProtocolLimits.cs rename to backend/shared/MoShiro.Protocol/ProtocolLimits.cs index f227b86..90f3c86 100644 --- a/backend/shared/Monitor.Protocol/ProtocolLimits.cs +++ b/backend/shared/MoShiro.Protocol/ProtocolLimits.cs @@ -1,4 +1,4 @@ -namespace Monitor.Protocol; +namespace MoShiro.Protocol; public static class ProtocolVersion { @@ -25,8 +25,8 @@ public static class ProtocolLimits public const long MaxLineBudgetBitsPerSecond = 100_000; } -/// 二进制通道号(0–15 属于 Fleet,Monitor 从 16 开始)。 -public static class MonitorChannels +/// 二进制通道号(0–15 属于 Fleet,MoShiro 从 16 开始)。 +public static class MoShiroChannels { /// Agent → Backend:RawChunk(发件箱)。 public const byte RawChunk = 16; @@ -35,9 +35,9 @@ public static class MonitorChannels public const byte ColumnBlock = 17; } -public static class MonitorCapabilities +public static class MoShiroCapabilities { - public const string Base = "monitor.v1"; - public const string KindsPrefix = "monitor.kinds:"; - public const string BlocksPrefix = "monitor.blocks:"; + public const string Base = "moshiro.v1"; + public const string KindsPrefix = "moshiro.kinds:"; + public const string BlocksPrefix = "moshiro.blocks:"; } diff --git a/backend/shared/Monitor.Protocol/Raw/Crc32c.cs b/backend/shared/MoShiro.Protocol/Raw/Crc32c.cs similarity index 96% rename from backend/shared/Monitor.Protocol/Raw/Crc32c.cs rename to backend/shared/MoShiro.Protocol/Raw/Crc32c.cs index 0a6d0f9..e18bf9e 100644 --- a/backend/shared/Monitor.Protocol/Raw/Crc32c.cs +++ b/backend/shared/MoShiro.Protocol/Raw/Crc32c.cs @@ -1,4 +1,4 @@ -namespace Monitor.Protocol; +namespace MoShiro.Protocol; /// CRC-32C(Castagnoli),RawChunk 的完整性校验。 public static class Crc32c diff --git a/backend/shared/Monitor.Protocol/Raw/RawChunk.cs b/backend/shared/MoShiro.Protocol/Raw/RawChunk.cs similarity index 99% rename from backend/shared/Monitor.Protocol/Raw/RawChunk.cs rename to backend/shared/MoShiro.Protocol/Raw/RawChunk.cs index d6ae3d3..0255d66 100644 --- a/backend/shared/Monitor.Protocol/Raw/RawChunk.cs +++ b/backend/shared/MoShiro.Protocol/Raw/RawChunk.cs @@ -2,7 +2,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using Fleet.Core; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; /// Agent 单调时钟与 UTC 的锚点,以及 Probe 时钟相对 Agent 时钟的偏移估计。 public sealed class ChunkClock diff --git a/backend/shared/Monitor.Protocol/Raw/RawChunkCodec.cs b/backend/shared/MoShiro.Protocol/Raw/RawChunkCodec.cs similarity index 97% rename from backend/shared/Monitor.Protocol/Raw/RawChunkCodec.cs rename to backend/shared/MoShiro.Protocol/Raw/RawChunkCodec.cs index 00c5298..aaaca96 100644 --- a/backend/shared/Monitor.Protocol/Raw/RawChunkCodec.cs +++ b/backend/shared/MoShiro.Protocol/Raw/RawChunkCodec.cs @@ -3,18 +3,18 @@ using System.IO.Compression; using System.Text.Json; using Fleet.Core; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; /// /// RawChunk 的编解码(Probe、Agent、Backend、离线工具共用同一份代码)。 -/// 布局:"MNRC" | u8 container_version | u32 crc32c(压缩数据) | Brotli( u32 header_len | header JSON | 各列数据 )。 +/// 布局:"MSRC" | u8 container_version | u32 crc32c(压缩数据) | Brotli( u32 header_len | header JSON | 各列数据 )。 /// 列数据:可空列先写有效位图,再写有效值;plain 为无符号 varint(有符号类型用 zigzag),delta 为与上一个有效值之差的 zigzag varint。 /// public static class RawChunkCodec { private const int PrefixBytes = 4 + 1 + 4; - private static ReadOnlySpan Magic => "MNRC"u8; + private static ReadOnlySpan Magic => "MSRC"u8; /// 压缩之前的正文:u32 header_len | header JSON | 各列数据。布局变化时黄金字节测试会失败,提醒升级版本。 public static byte[] EncodeBody(RawChunk chunk) @@ -40,7 +40,7 @@ public static class RawChunkCodec header.Streams.Add(streamHeader); } - byte[] headerJson = JsonSerializer.SerializeToUtf8Bytes(header, MonitorJsonContext.Default.RawChunkHeader); + byte[] headerJson = JsonSerializer.SerializeToUtf8Bytes(header, MoShiroJsonContext.Default.RawChunkHeader); using var body = new MemoryStream(); Span length = stackalloc byte[4]; @@ -114,7 +114,7 @@ public static class RawChunkCodec RawChunkHeader? header; try { - header = JsonSerializer.Deserialize(plain.AsSpan(4, (int)headerLength), MonitorJsonContext.Default.RawChunkHeader); + header = JsonSerializer.Deserialize(plain.AsSpan(4, (int)headerLength), MoShiroJsonContext.Default.RawChunkHeader); } catch (JsonException) { @@ -159,7 +159,7 @@ public static class RawChunkCodec } private static Result Corrupt(string message) => - Result.Fail(MonitorErrors.RawCorrupt, message); + Result.Fail(MoShiroErrors.RawCorrupt, message); private static byte[]? Inflate(ReadOnlySpan payload) { diff --git a/backend/shared/Monitor.Protocol/Raw/StreamBuilder.cs b/backend/shared/MoShiro.Protocol/Raw/StreamBuilder.cs similarity index 98% rename from backend/shared/Monitor.Protocol/Raw/StreamBuilder.cs rename to backend/shared/MoShiro.Protocol/Raw/StreamBuilder.cs index 65a5d38..4c2ec45 100644 --- a/backend/shared/Monitor.Protocol/Raw/StreamBuilder.cs +++ b/backend/shared/MoShiro.Protocol/Raw/StreamBuilder.cs @@ -1,4 +1,4 @@ -namespace Monitor.Protocol; +namespace MoShiro.Protocol; /// 按 逐行构造一个 (用于测试、模拟器和离线工具,不用于节点热路径)。 public sealed class StreamBuilder diff --git a/backend/shared/Monitor.Protocol/Rpc/MonitorRpc.cs b/backend/shared/MoShiro.Protocol/Rpc/MonitorRpc.cs similarity index 94% rename from backend/shared/Monitor.Protocol/Rpc/MonitorRpc.cs rename to backend/shared/MoShiro.Protocol/Rpc/MonitorRpc.cs index d5228e7..83864cc 100644 --- a/backend/shared/Monitor.Protocol/Rpc/MonitorRpc.cs +++ b/backend/shared/MoShiro.Protocol/Rpc/MonitorRpc.cs @@ -2,25 +2,25 @@ using System.Text.Json; using System.Text.Json.Serialization; using Fleet.Core; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; -/// monitor.* 方法名。新增方法 = 在这里定义名称和 params/result,再在组装处加一行 .On(...)。 -public static class MonitorMethods +/// moshiro.* 方法名。新增方法 = 在这里定义名称和 params/result,再在组装处加一行 .On(...)。 +public static class MoShiroMethods { - public const string TestRun = "monitor.test.run"; - public const string TestCancel = "monitor.test.cancel"; - public const string ProbeDisconnect = "monitor.probe.disconnect"; - public const string TestStatus = "monitor.test.status"; - public const string Event = "monitor.event"; - public const string Host = "monitor.host"; - public const string UpdateOffer = "monitor.update.offer"; - public const string UpdateApply = "monitor.update.apply"; + public const string TestRun = "moshiro.test.run"; + public const string TestCancel = "moshiro.test.cancel"; + public const string ProbeDisconnect = "moshiro.probe.disconnect"; + public const string TestStatus = "moshiro.test.status"; + public const string Event = "moshiro.event"; + public const string Host = "moshiro.host"; + public const string UpdateOffer = "moshiro.update.offer"; + public const string UpdateApply = "moshiro.update.apply"; // Probe ↔ Agent(点对点会话) - public const string Clock = "monitor.clock"; - public const string TestPhase = "monitor.test.phase"; - public const string TestPhaseEnd = "monitor.test.phase_end"; - public const string TestAbort = "monitor.test.abort"; + public const string Clock = "moshiro.clock"; + public const string TestPhase = "moshiro.test.phase"; + public const string TestPhaseEnd = "moshiro.test.phase_end"; + public const string TestAbort = "moshiro.test.abort"; } public static class AgentEventKinds @@ -159,7 +159,7 @@ public sealed class ProbeAgentList public List Agents { get; set; } = []; } -/// 注册元数据(Monitor 定义,经 Fleet 的 meta 字段带上来)。 +/// 注册元数据(MoShiro 定义,经 Fleet 的 meta 字段带上来)。 public sealed class AgentEnrollMeta { [JsonPropertyName("probe_tcp_port")] @@ -220,7 +220,7 @@ public sealed class PlatformInfo } /// -/// 面板给节点的更新清单(monitor.update.offer):manifest 是发布清单的原始文本,signature 是 base64 的签名。 +/// 面板给节点的更新清单(moshiro.update.offer):manifest 是发布清单的原始文本,signature 是 base64 的签名。 /// 节点只是把它们原样放进数据目录;验签、拉取、重启都由宿主机上的更新器完成(节点进程不执行任何命令,也不信任清单的内容)。 /// public sealed class UpdateOfferParams @@ -436,7 +436,7 @@ public sealed class LineTaskSet public List TcpPorts { get; set; } = []; } -/// monitor.clock:Probe 用它估计与 Agent 单调时钟的偏移(对称往返假设)。 +/// moshiro.clock:Probe 用它估计与 Agent 单调时钟的偏移(对称往返假设)。 public sealed class ClockParams { [JsonPropertyName("probe_mono_us")] @@ -543,4 +543,4 @@ public static class FragmentKeys [JsonSerializable(typeof(AgentHelloMeta))] [JsonSerializable(typeof(AgentHeartbeatExtra))] [JsonSerializable(typeof(RawChunkHeader))] -public sealed partial class MonitorJsonContext : JsonSerializerContext; +public sealed partial class MoShiroJsonContext : JsonSerializerContext; diff --git a/backend/shared/Monitor.Protocol/Tasks/TaskSet.cs b/backend/shared/MoShiro.Protocol/Tasks/TaskSet.cs similarity index 94% rename from backend/shared/Monitor.Protocol/Tasks/TaskSet.cs rename to backend/shared/MoShiro.Protocol/Tasks/TaskSet.cs index 2c320a5..88771f4 100644 --- a/backend/shared/Monitor.Protocol/Tasks/TaskSet.cs +++ b/backend/shared/MoShiro.Protocol/Tasks/TaskSet.cs @@ -3,7 +3,7 @@ using System.Text.Json; using System.Text.Json.Serialization; using Fleet.Core; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; /// Task = { id, scope, kind, target, params, schedule, enabled }。参数已经按 ParamSpec 校验并补全默认值。 public sealed class TaskSpec @@ -79,9 +79,9 @@ public static class TaskSchedule { return minutes >= 60 ? Result.Ok(minutes) - : Result.Fail(MonitorErrors.ValidationFailed, "every:N requires N >= 60 minutes"); + : Result.Fail(MoShiroErrors.ValidationFailed, "every:N requires N >= 60 minutes"); } - return Result.Fail(MonitorErrors.ValidationFailed, "schedule must be continuous, once or every:"); + return Result.Fail(MoShiroErrors.ValidationFailed, "schedule must be continuous, once or every:"); } } diff --git a/backend/shared/Monitor.Protocol/Wire/TcpWire.cs b/backend/shared/MoShiro.Protocol/Wire/TcpWire.cs similarity index 99% rename from backend/shared/Monitor.Protocol/Wire/TcpWire.cs rename to backend/shared/MoShiro.Protocol/Wire/TcpWire.cs index 6ca01af..b03a5b3 100644 --- a/backend/shared/Monitor.Protocol/Wire/TcpWire.cs +++ b/backend/shared/MoShiro.Protocol/Wire/TcpWire.cs @@ -2,7 +2,7 @@ using System.Buffers.Binary; using System.Security.Cryptography; using Fleet.Core; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; /// /// 数据面的 TCP 连接(Fleet 之外的线格式)。连接都由 Probe 发起;TLS 是可选的(ClientHello 以 0x16 开头, diff --git a/backend/shared/Monitor.Protocol/Wire/UdpPacket.cs b/backend/shared/MoShiro.Protocol/Wire/UdpPacket.cs similarity index 99% rename from backend/shared/Monitor.Protocol/Wire/UdpPacket.cs rename to backend/shared/MoShiro.Protocol/Wire/UdpPacket.cs index 2827ba6..737b57c 100644 --- a/backend/shared/Monitor.Protocol/Wire/UdpPacket.cs +++ b/backend/shared/MoShiro.Protocol/Wire/UdpPacket.cs @@ -1,7 +1,7 @@ using System.Buffers.Binary; using System.Security.Cryptography; -namespace Monitor.Protocol; +namespace MoShiro.Protocol; public enum UdpPacketType : byte { diff --git a/backend/shared/tests/Monitor.Measurement.Tests/MeasurementTests.cs b/backend/shared/tests/MoShiro.Measurement.Tests/MeasurementTests.cs similarity index 99% rename from backend/shared/tests/Monitor.Measurement.Tests/MeasurementTests.cs rename to backend/shared/tests/MoShiro.Measurement.Tests/MeasurementTests.cs index f0875a9..1912f09 100644 --- a/backend/shared/tests/Monitor.Measurement.Tests/MeasurementTests.cs +++ b/backend/shared/tests/MoShiro.Measurement.Tests/MeasurementTests.cs @@ -1,8 +1,8 @@ using System.Text.Json; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Measurement.Tests; +namespace MoShiro.Measurement.Tests; public sealed class MeasurementTests { diff --git a/backend/shared/tests/Monitor.Measurement.Tests/Monitor.Measurement.Tests.csproj b/backend/shared/tests/MoShiro.Measurement.Tests/MoShiro.Measurement.Tests.csproj similarity index 82% rename from backend/shared/tests/Monitor.Measurement.Tests/Monitor.Measurement.Tests.csproj rename to backend/shared/tests/MoShiro.Measurement.Tests/MoShiro.Measurement.Tests.csproj index e067df9..c8f64bd 100644 --- a/backend/shared/tests/Monitor.Measurement.Tests/Monitor.Measurement.Tests.csproj +++ b/backend/shared/tests/MoShiro.Measurement.Tests/MoShiro.Measurement.Tests.csproj @@ -5,7 +5,7 @@ - + diff --git a/backend/shared/tests/Monitor.Measurement.Tests/PlatformDetectorTests.cs b/backend/shared/tests/MoShiro.Measurement.Tests/PlatformDetectorTests.cs similarity index 97% rename from backend/shared/tests/Monitor.Measurement.Tests/PlatformDetectorTests.cs rename to backend/shared/tests/MoShiro.Measurement.Tests/PlatformDetectorTests.cs index 365c7df..ddb2575 100644 --- a/backend/shared/tests/Monitor.Measurement.Tests/PlatformDetectorTests.cs +++ b/backend/shared/tests/MoShiro.Measurement.Tests/PlatformDetectorTests.cs @@ -1,4 +1,4 @@ -namespace Monitor.Measurement.Tests; +namespace MoShiro.Measurement.Tests; public sealed class PlatformDetectorTests { diff --git a/backend/shared/tests/Monitor.Protocol.Tests/CatalogTests.cs b/backend/shared/tests/MoShiro.Protocol.Tests/CatalogTests.cs similarity index 93% rename from backend/shared/tests/Monitor.Protocol.Tests/CatalogTests.cs rename to backend/shared/tests/MoShiro.Protocol.Tests/CatalogTests.cs index 2a98537..56cc60e 100644 --- a/backend/shared/tests/Monitor.Protocol.Tests/CatalogTests.cs +++ b/backend/shared/tests/MoShiro.Protocol.Tests/CatalogTests.cs @@ -1,8 +1,8 @@ using System.Text.Json; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Protocol.Tests; +namespace MoShiro.Protocol.Tests; public sealed class CatalogTests { @@ -101,8 +101,8 @@ public sealed class CatalogTests Tasks = [new TaskSpec { Id = new TaskId("tsk_1"), Kind = "udp_echo", Params = new Dictionary { ["rate_hz"] = Json("10") } }], Peers = [new PeerSpec { ProbeId = new ProbeId("prb_1"), PublicKey = "AAAA" }], }; - string text = JsonSerializer.Serialize(set, MonitorJsonContext.Default.TaskSet); - TaskSet back = JsonSerializer.Deserialize(text, MonitorJsonContext.Default.TaskSet)!; + string text = JsonSerializer.Serialize(set, MoShiroJsonContext.Default.TaskSet); + TaskSet back = JsonSerializer.Deserialize(text, MoShiroJsonContext.Default.TaskSet)!; Assert.Contains("\"id\":\"tsk_1\"", text); Assert.Equal(7, back.Version); @@ -114,7 +114,7 @@ public sealed class CatalogTests [Fact] public void AgentEnrollMeta_ToleratesUnknownFields_AndKeepsDefaults() { - AgentEnrollMeta meta = JsonSerializer.Deserialize("{\"kinds\":[\"udp_echo\"],\"future\":1}", MonitorJsonContext.Default.AgentEnrollMeta)!; + AgentEnrollMeta meta = JsonSerializer.Deserialize("{\"kinds\":[\"udp_echo\"],\"future\":1}", MoShiroJsonContext.Default.AgentEnrollMeta)!; Assert.Equal(7443, meta.ProbeTcpPort); Assert.Equal(["udp_echo"], meta.Kinds); } @@ -122,7 +122,7 @@ public sealed class CatalogTests [Fact] public void ErrorCodes_AreSnakeCase() { - foreach (System.Reflection.FieldInfo field in typeof(MonitorErrors).GetFields()) + foreach (System.Reflection.FieldInfo field in typeof(MoShiroErrors).GetFields()) { string value = ((ErrorCode)field.GetValue(null)!).Value; Assert.Matches("^[a-z]+(_[a-z]+)*$", value); diff --git a/backend/shared/tests/Monitor.Protocol.Tests/Monitor.Protocol.Tests.csproj b/backend/shared/tests/MoShiro.Protocol.Tests/MoShiro.Protocol.Tests.csproj similarity index 65% rename from backend/shared/tests/Monitor.Protocol.Tests/Monitor.Protocol.Tests.csproj rename to backend/shared/tests/MoShiro.Protocol.Tests/MoShiro.Protocol.Tests.csproj index 644ddc0..c7bb997 100644 --- a/backend/shared/tests/Monitor.Protocol.Tests/Monitor.Protocol.Tests.csproj +++ b/backend/shared/tests/MoShiro.Protocol.Tests/MoShiro.Protocol.Tests.csproj @@ -5,8 +5,8 @@ - - + + diff --git a/backend/shared/tests/Monitor.Protocol.Tests/RawChunkCodecTests.cs b/backend/shared/tests/MoShiro.Protocol.Tests/RawChunkCodecTests.cs similarity index 97% rename from backend/shared/tests/Monitor.Protocol.Tests/RawChunkCodecTests.cs rename to backend/shared/tests/MoShiro.Protocol.Tests/RawChunkCodecTests.cs index 6d65147..1f659ec 100644 --- a/backend/shared/tests/Monitor.Protocol.Tests/RawChunkCodecTests.cs +++ b/backend/shared/tests/MoShiro.Protocol.Tests/RawChunkCodecTests.cs @@ -1,10 +1,10 @@ using System.Buffers.Binary; using System.IO.Compression; using Fleet.Core; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Protocol.Tests; +namespace MoShiro.Protocol.Tests; public sealed class RawChunkCodecTests { @@ -103,7 +103,7 @@ public sealed class RawChunkCodecTests byte[] badCrc = (byte[])good.Clone(); badCrc[^1] ^= 0xFF; - Assert.Equal(MonitorErrors.RawCorrupt, RawChunkCodec.Decode(badMagic).Error.Code); + Assert.Equal(MoShiroErrors.RawCorrupt, RawChunkCodec.Decode(badMagic).Error.Code); Assert.Contains("version", RawChunkCodec.Decode(badVersion).Error.Message); Assert.Contains("crc", RawChunkCodec.Decode(badCrc).Error.Message); Assert.False(RawChunkCodec.Decode(good.AsSpan(0, good.Length / 2)).IsSuccess); @@ -190,7 +190,7 @@ public sealed class RawChunkCodecTests private static byte[] Wrap(byte[] payload) { byte[] result = new byte[9 + payload.Length]; - "MNRC"u8.CopyTo(result); + "MSRC"u8.CopyTo(result); result[4] = ProtocolVersion.Container; BinaryPrimitives.WriteUInt32LittleEndian(result.AsSpan(5), Crc32c.Compute(payload)); payload.CopyTo(result, 9); diff --git a/backend/src/Monitor.Backend.Analysis/Accumulators/Accumulator.cs b/backend/src/MoShiro.Backend.Analysis/Accumulators/Accumulator.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Accumulators/Accumulator.cs rename to backend/src/MoShiro.Backend.Analysis/Accumulators/Accumulator.cs index 06077e3..197ae00 100644 --- a/backend/src/Monitor.Backend.Analysis/Accumulators/Accumulator.cs +++ b/backend/src/MoShiro.Backend.Analysis/Accumulators/Accumulator.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; public enum AccKind : byte { diff --git a/backend/src/Monitor.Backend.Analysis/Accumulators/AccumulatorCodec.cs b/backend/src/MoShiro.Backend.Analysis/Accumulators/AccumulatorCodec.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Accumulators/AccumulatorCodec.cs rename to backend/src/MoShiro.Backend.Analysis/Accumulators/AccumulatorCodec.cs index b0c987a..81af219 100644 --- a/backend/src/Monitor.Backend.Analysis/Accumulators/AccumulatorCodec.cs +++ b/backend/src/MoShiro.Backend.Analysis/Accumulators/AccumulatorCodec.cs @@ -2,7 +2,7 @@ using System.Buffers.Binary; using System.Text; using Fleet.Core; -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// 一个时间桶里所有指标的累加器:指标 id → 累加器。 public sealed class MetricSet diff --git a/backend/src/Monitor.Backend.Analysis/Accumulators/HistogramAcc.cs b/backend/src/MoShiro.Backend.Analysis/Accumulators/HistogramAcc.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Accumulators/HistogramAcc.cs rename to backend/src/MoShiro.Backend.Analysis/Accumulators/HistogramAcc.cs index 4f58669..3027934 100644 --- a/backend/src/Monitor.Backend.Analysis/Accumulators/HistogramAcc.cs +++ b/backend/src/MoShiro.Backend.Analysis/Accumulators/HistogramAcc.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// /// 固定对数桶直方图:100 µs ~ 30 s,每 2 倍 8 个桶(相对误差 ≤ 4.5%)。 diff --git a/backend/src/Monitor.Backend.Analysis/Clock/ClockDriftFit.cs b/backend/src/MoShiro.Backend.Analysis/Clock/ClockDriftFit.cs similarity index 98% rename from backend/src/Monitor.Backend.Analysis/Clock/ClockDriftFit.cs rename to backend/src/MoShiro.Backend.Analysis/Clock/ClockDriftFit.cs index 838ffac..7952041 100644 --- a/backend/src/Monitor.Backend.Analysis/Clock/ClockDriftFit.cs +++ b/backend/src/MoShiro.Backend.Analysis/Clock/ClockDriftFit.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// /// 估计两端的时钟偏移和线性漂移:单向时延 x(t) = 偏移 + 漂移·t + 真实的时延变化。 diff --git a/backend/src/Monitor.Backend.Analysis/Engine/ChangePoint.cs b/backend/src/MoShiro.Backend.Analysis/Engine/ChangePoint.cs similarity index 98% rename from backend/src/Monitor.Backend.Analysis/Engine/ChangePoint.cs rename to backend/src/MoShiro.Backend.Analysis/Engine/ChangePoint.cs index e5e3e67..b061bf9 100644 --- a/backend/src/Monitor.Backend.Analysis/Engine/ChangePoint.cs +++ b/backend/src/MoShiro.Backend.Analysis/Engine/ChangePoint.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// 变点检测(均值漂移):找到使前后两段均值差最显著的位置,用来判断 QoS 从什么时候开始限速。 public static class ChangePoint diff --git a/backend/src/Monitor.Backend.Analysis/Engine/ChunkView.cs b/backend/src/MoShiro.Backend.Analysis/Engine/ChunkView.cs similarity index 95% rename from backend/src/Monitor.Backend.Analysis/Engine/ChunkView.cs rename to backend/src/MoShiro.Backend.Analysis/Engine/ChunkView.cs index ad7d536..3208a72 100644 --- a/backend/src/Monitor.Backend.Analysis/Engine/ChunkView.cs +++ b/backend/src/MoShiro.Backend.Analysis/Engine/ChunkView.cs @@ -1,7 +1,7 @@ using System.Text.Json; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// 算子把观测值交给这里;窗口评估器负责按时间分桶。 public interface IObservationSink diff --git a/backend/src/Monitor.Backend.Analysis/Engine/MetricDef.cs b/backend/src/MoShiro.Backend.Analysis/Engine/MetricDef.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Engine/MetricDef.cs rename to backend/src/MoShiro.Backend.Analysis/Engine/MetricDef.cs index d257f0e..1a60b6a 100644 --- a/backend/src/Monitor.Backend.Analysis/Engine/MetricDef.cs +++ b/backend/src/MoShiro.Backend.Analysis/Engine/MetricDef.cs @@ -1,8 +1,8 @@ using System.Security.Cryptography; using System.Text; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; public enum Unit { diff --git a/backend/src/Monitor.Backend.Analysis/Engine/TestEvaluator.cs b/backend/src/MoShiro.Backend.Analysis/Engine/TestEvaluator.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Engine/TestEvaluator.cs rename to backend/src/MoShiro.Backend.Analysis/Engine/TestEvaluator.cs index 14fede2..5988e98 100644 --- a/backend/src/Monitor.Backend.Analysis/Engine/TestEvaluator.cs +++ b/backend/src/MoShiro.Backend.Analysis/Engine/TestEvaluator.cs @@ -1,7 +1,7 @@ using System.Text.Json; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; public sealed class TestStepResult { diff --git a/backend/src/Monitor.Backend.Analysis/Engine/WindowEvaluator.cs b/backend/src/MoShiro.Backend.Analysis/Engine/WindowEvaluator.cs similarity index 97% rename from backend/src/Monitor.Backend.Analysis/Engine/WindowEvaluator.cs rename to backend/src/MoShiro.Backend.Analysis/Engine/WindowEvaluator.cs index d6f41b0..2b50fa8 100644 --- a/backend/src/Monitor.Backend.Analysis/Engine/WindowEvaluator.cs +++ b/backend/src/MoShiro.Backend.Analysis/Engine/WindowEvaluator.cs @@ -1,6 +1,6 @@ -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// /// 把原始块按时间分桶算成累加器。流式路径(1s 桶)和持久路径(分钟窗口)调用同一份代码, diff --git a/backend/src/Monitor.Backend.Analysis/Metrics/LinkMetrics.cs b/backend/src/MoShiro.Backend.Analysis/Metrics/LinkMetrics.cs similarity index 98% rename from backend/src/Monitor.Backend.Analysis/Metrics/LinkMetrics.cs rename to backend/src/MoShiro.Backend.Analysis/Metrics/LinkMetrics.cs index d76d8b0..090686e 100644 --- a/backend/src/Monitor.Backend.Analysis/Metrics/LinkMetrics.cs +++ b/backend/src/MoShiro.Backend.Analysis/Metrics/LinkMetrics.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// 线路基础指标(udp_echo / icmp_echo 的回显流)。新增指标 = 加一行声明。 public static class LinkMetrics diff --git a/backend/src/Monitor.Backend.Analysis/Metrics/MetricRegistry.cs b/backend/src/MoShiro.Backend.Analysis/Metrics/MetricRegistry.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Metrics/MetricRegistry.cs rename to backend/src/MoShiro.Backend.Analysis/Metrics/MetricRegistry.cs index 140bd8a..e332a84 100644 --- a/backend/src/Monitor.Backend.Analysis/Metrics/MetricRegistry.cs +++ b/backend/src/MoShiro.Backend.Analysis/Metrics/MetricRegistry.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; public sealed record PresetDef(string Id, string Label, IReadOnlyList MetricIds); diff --git a/backend/src/Monitor.Backend.Analysis/Metrics/SessionMetrics.cs b/backend/src/MoShiro.Backend.Analysis/Metrics/SessionMetrics.cs similarity index 98% rename from backend/src/Monitor.Backend.Analysis/Metrics/SessionMetrics.cs rename to backend/src/MoShiro.Backend.Analysis/Metrics/SessionMetrics.cs index 0a164a2..6f5acbb 100644 --- a/backend/src/Monitor.Backend.Analysis/Metrics/SessionMetrics.cs +++ b/backend/src/MoShiro.Backend.Analysis/Metrics/SessionMetrics.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// 连接建立、长连接、UDP 压测(udp_train)的指标。 public static class SessionMetrics diff --git a/backend/src/Monitor.Backend.Analysis/Metrics/TcpMetrics.cs b/backend/src/MoShiro.Backend.Analysis/Metrics/TcpMetrics.cs similarity index 98% rename from backend/src/Monitor.Backend.Analysis/Metrics/TcpMetrics.cs rename to backend/src/MoShiro.Backend.Analysis/Metrics/TcpMetrics.cs index 83851a2..a4759f1 100644 --- a/backend/src/Monitor.Backend.Analysis/Metrics/TcpMetrics.cs +++ b/backend/src/MoShiro.Backend.Analysis/Metrics/TcpMetrics.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// TCP 指标:回显的 RTT 与卡顿、内核采样的重传、批量传输的吞吐。 public static class TcpMetrics diff --git a/backend/src/Monitor.Backend.Analysis/Monitor.Backend.Analysis.csproj b/backend/src/MoShiro.Backend.Analysis/MoShiro.Backend.Analysis.csproj similarity index 63% rename from backend/src/Monitor.Backend.Analysis/Monitor.Backend.Analysis.csproj rename to backend/src/MoShiro.Backend.Analysis/MoShiro.Backend.Analysis.csproj index a546806..b2d12ee 100644 --- a/backend/src/Monitor.Backend.Analysis/Monitor.Backend.Analysis.csproj +++ b/backend/src/MoShiro.Backend.Analysis/MoShiro.Backend.Analysis.csproj @@ -3,6 +3,6 @@ true - + diff --git a/backend/src/Monitor.Backend.Analysis/Models/Models.cs b/backend/src/MoShiro.Backend.Analysis/Models/Models.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Models/Models.cs rename to backend/src/MoShiro.Backend.Analysis/Models/Models.cs index 506b574..aeb9825 100644 --- a/backend/src/Monitor.Backend.Analysis/Models/Models.cs +++ b/backend/src/MoShiro.Backend.Analysis/Models/Models.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// 线路基础质量:RTT、丢包、抖动、连续丢包。 public sealed class BaseModel : ServiceModelBase diff --git a/backend/src/Monitor.Backend.Analysis/Models/ServiceModel.cs b/backend/src/MoShiro.Backend.Analysis/Models/ServiceModel.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Models/ServiceModel.cs rename to backend/src/MoShiro.Backend.Analysis/Models/ServiceModel.cs index d37b2b7..843b318 100644 --- a/backend/src/Monitor.Backend.Analysis/Models/ServiceModel.cs +++ b/backend/src/MoShiro.Backend.Analysis/Models/ServiceModel.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// 模型的输入:一个时间段内的导出值(例如 rtt.p95)。没有数据的指标不存在。 public sealed class MetricView diff --git a/backend/src/Monitor.Backend.Analysis/Ops/EchoOps.cs b/backend/src/MoShiro.Backend.Analysis/Ops/EchoOps.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Ops/EchoOps.cs rename to backend/src/MoShiro.Backend.Analysis/Ops/EchoOps.cs index 7ac94c4..f160ef9 100644 --- a/backend/src/Monitor.Backend.Analysis/Ops/EchoOps.cs +++ b/backend/src/MoShiro.Backend.Analysis/Ops/EchoOps.cs @@ -1,6 +1,6 @@ -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; public enum Dir { diff --git a/backend/src/Monitor.Backend.Analysis/Ops/Ops.cs b/backend/src/MoShiro.Backend.Analysis/Ops/Ops.cs similarity index 98% rename from backend/src/Monitor.Backend.Analysis/Ops/Ops.cs rename to backend/src/MoShiro.Backend.Analysis/Ops/Ops.cs index 4ee101d..ab9ecd1 100644 --- a/backend/src/Monitor.Backend.Analysis/Ops/Ops.cs +++ b/backend/src/MoShiro.Backend.Analysis/Ops/Ops.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// 算子工厂:Ops.Rtt、Ops.Loss(Dir.Up) 等,供 MetricDef 声明使用。 public static class Ops diff --git a/backend/src/Monitor.Backend.Analysis/Ops/SessionOps.cs b/backend/src/MoShiro.Backend.Analysis/Ops/SessionOps.cs similarity index 99% rename from backend/src/Monitor.Backend.Analysis/Ops/SessionOps.cs rename to backend/src/MoShiro.Backend.Analysis/Ops/SessionOps.cs index fb521fe..2fd97fb 100644 --- a/backend/src/Monitor.Backend.Analysis/Ops/SessionOps.cs +++ b/backend/src/MoShiro.Backend.Analysis/Ops/SessionOps.cs @@ -1,6 +1,6 @@ -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Analysis; +namespace MoShiro.Backend.Analysis; /// tcp_info 流的辅助:side 为 0 表示 Probe 一侧记录(Probe 时钟),否则为 Agent 一侧。 internal static class TcpInfoTime diff --git a/backend/src/Monitor.Backend.Api/Admin/AgentEndpoints.cs b/backend/src/MoShiro.Backend.Api/Admin/AgentEndpoints.cs similarity index 97% rename from backend/src/Monitor.Backend.Api/Admin/AgentEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Admin/AgentEndpoints.cs index a9ff75d..9360dd0 100644 --- a/backend/src/Monitor.Backend.Api/Admin/AgentEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Admin/AgentEndpoints.cs @@ -2,10 +2,10 @@ using Fleet.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// Agent 管理:列表、修改、审批、启停、接管、删除;加入令牌;Probe 身份。 public static class AgentEndpoints @@ -77,7 +77,7 @@ public static class AgentEndpoints AgentView? view = await agents.GetAsync(new NodeId(id), ct); if (view is null) { - return Problems.Create(http, MonitorErrors.AgentNotFound, "agent not found"); + return Problems.Create(http, MoShiroErrors.AgentNotFound, "agent not found"); } Concurrency.SetETag(http, view.Agent.RowVersion); @@ -166,7 +166,7 @@ public static class AgentEndpoints private static async Task GetProbeAsync(HttpContext http, ProbeService probes, string id, CancellationToken ct) => await probes.GetAsync(id, ct) is { } view ? TypedResults.Json(Mappers.ToDto(view), ApiJsonContext.Default.ProbeDto) - : Problems.Create(http, MonitorErrors.ProbeNotFound, "probe not found"); + : Problems.Create(http, MoShiroErrors.ProbeNotFound, "probe not found"); private static async Task PatchProbeAsync(HttpContext http, ProbeService probes, PatchProbeRequest request, string id, CancellationToken ct) { @@ -211,7 +211,7 @@ public static class AgentEndpoints return Problems.From(http, error); } - return dropped ? TypedResults.NoContent() : Problems.Create(http, MonitorErrors.ProbeOffline, "this probe has no session with this agent"); + return dropped ? TypedResults.NoContent() : Problems.Create(http, MoShiroErrors.ProbeOffline, "this probe has no session with this agent"); } /// Probe 要连的面板地址:配置的公开地址,没有就用这次请求的地址。 diff --git a/backend/src/Monitor.Backend.Api/Admin/AuthEndpoints.cs b/backend/src/MoShiro.Backend.Api/Admin/AuthEndpoints.cs similarity index 94% rename from backend/src/Monitor.Backend.Api/Admin/AuthEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Admin/AuthEndpoints.cs index 6294413..54a47d4 100644 --- a/backend/src/Monitor.Backend.Api/Admin/AuthEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Admin/AuthEndpoints.cs @@ -2,10 +2,10 @@ using Fleet.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 登录、退出、当前身份。登录接口限流,失败一律返回 401,不区分“用户不存在”和“密码错误”。 public static class AuthEndpoints @@ -35,7 +35,7 @@ public static class AuthEndpoints string source = http.Connection.RemoteIpAddress?.ToString() ?? "unknown"; if (!limiter.TryAcquire(source, out int retryAfter)) { - return Problems.RetryAfter(http, new FleetError(MonitorErrors.TooManyRequests, "too many sign-in attempts"), retryAfter); + return Problems.RetryAfter(http, new FleetError(MoShiroErrors.TooManyRequests, "too many sign-in attempts"), retryAfter); } Result result = await auth.LoginAsync(request.Username ?? "", request.Password ?? "", http.RequestAborted); diff --git a/backend/src/Monitor.Backend.Api/Admin/BuildEndpoints.cs b/backend/src/MoShiro.Backend.Api/Admin/BuildEndpoints.cs similarity index 96% rename from backend/src/Monitor.Backend.Api/Admin/BuildEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Admin/BuildEndpoints.cs index c85ef3f..e59949a 100644 --- a/backend/src/Monitor.Backend.Api/Admin/BuildEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Admin/BuildEndpoints.cs @@ -2,10 +2,10 @@ using Fleet.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 构建信息与更新:后端和每个节点的版本、tag、构建时间,CI 签名的发布清单,以及「更新这个节点」的请求。更新本身由节点宿主机上的更新器验签并执行。 public static class BuildEndpoints @@ -54,7 +54,7 @@ public static class BuildEndpoints } private static async Task RequestUpdateAsync(HttpContext http, ReleaseService releases, string id, CancellationToken ct) => - await releases.RequestUpdateAsync(new NodeId(id), ct) ? TypedResults.NoContent() : Problems.Create(http, MonitorErrors.AgentOffline, "the node is not connected"); + await releases.RequestUpdateAsync(new NodeId(id), ct) ? TypedResults.NoContent() : Problems.Create(http, MoShiroErrors.AgentOffline, "the node is not connected"); private static ReleaseDto ToDto(ReleaseOffer offer) => new(offer.Component, offer.Seq, offer.Tag, offer.Version, offer.Digest); diff --git a/backend/src/Monitor.Backend.Api/Admin/DataEndpoints.cs b/backend/src/MoShiro.Backend.Api/Admin/DataEndpoints.cs similarity index 94% rename from backend/src/Monitor.Backend.Api/Admin/DataEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Admin/DataEndpoints.cs index d85927a..3dda979 100644 --- a/backend/src/Monitor.Backend.Api/Admin/DataEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Admin/DataEndpoints.cs @@ -3,10 +3,10 @@ using Fleet.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 原始数据检索与下载、事件、指标重算进度。 public static class DataEndpoints @@ -18,8 +18,8 @@ public static class DataEndpoints group.MapGet("/raw/chunks", ListChunksAsync) .Api("raw_chunks_list", "Raw chunk metadata", Tag).Returns>().ProducesProblems(400, 401, 403); group.MapGet("/raw/chunks/{chunk_id}", DownloadChunkAsync) - .Api("raw_chunks_get", "Download a raw chunk (application/vnd.monitor.rawchunk)", Tag) - .Produces(StatusCodes.Status200OK, contentType: "application/vnd.monitor.rawchunk").ProducesProblems(401, 403, 404, 410); + .Api("raw_chunks_get", "Download a raw chunk (application/vnd.moshiro.rawchunk)", Tag) + .Produces(StatusCodes.Status200OK, contentType: "application/vnd.moshiro.rawchunk").ProducesProblems(401, 403, 404, 410); group.MapGet("/events", ListEventsAsync) .Api("events_list", "Agent events", Tag).Returns>().ProducesProblems(400, 401, 403); group.MapGet("/analysis/recompute", RecomputeAsync) @@ -57,7 +57,7 @@ public static class DataEndpoints { if (!Guid.TryParse(chunk_id, out Guid id)) { - return Problems.Create(http, MonitorErrors.ChunkNotFound, "chunk not found"); + return Problems.Create(http, MoShiroErrors.ChunkNotFound, "chunk not found"); } Result<(RawChunkMeta Meta, byte[] Bytes)> result = await raw.GetAsync(new ChunkId(id), http.RequestAborted); @@ -67,7 +67,7 @@ public static class DataEndpoints } http.Response.Headers.CacheControl = "private, max-age=3600"; - return TypedResults.File(found.Bytes, "application/vnd.monitor.rawchunk", chunk_id + ".mnrc"); + return TypedResults.File(found.Bytes, "application/vnd.moshiro.rawchunk", chunk_id + ".msrc"); } private static async Task ListEventsAsync( diff --git a/backend/src/Monitor.Backend.Api/Admin/LinkEndpoints.cs b/backend/src/MoShiro.Backend.Api/Admin/LinkEndpoints.cs similarity index 92% rename from backend/src/Monitor.Backend.Api/Admin/LinkEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Admin/LinkEndpoints.cs index 5737f62..7ee75d6 100644 --- a/backend/src/Monitor.Backend.Api/Admin/LinkEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Admin/LinkEndpoints.cs @@ -2,10 +2,10 @@ using Fleet.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 线路开关:哪些(Probe,Agent)要连。自动连接的总开关是设置 fleet.auto_link;这里看每一对的结果,并且手动强制开、关或取消手动设置。 public static class LinkEndpoints @@ -40,12 +40,12 @@ public static class LinkEndpoints { if (await probes.GetAsync(probe_id, ct) is not { Revoked: false } probe) { - return Problems.Create(http, MonitorErrors.ProbeNotFound, "probe not found"); + return Problems.Create(http, MoShiroErrors.ProbeNotFound, "probe not found"); } if (await agents.GetAsync(new NodeId(agent_id), ct) is not { } agent) { - return Problems.Create(http, MonitorErrors.AgentNotFound, "agent not found"); + return Problems.Create(http, MoShiroErrors.AgentNotFound, "agent not found"); } await links.SetAsync(probe_id, agent_id, request.Enabled, ct); diff --git a/backend/src/Monitor.Backend.Api/Admin/SystemEndpoints.cs b/backend/src/MoShiro.Backend.Api/Admin/SystemEndpoints.cs similarity index 98% rename from backend/src/Monitor.Backend.Api/Admin/SystemEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Admin/SystemEndpoints.cs index d833295..00a6037 100644 --- a/backend/src/Monitor.Backend.Api/Admin/SystemEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Admin/SystemEndpoints.cs @@ -3,10 +3,10 @@ using Fleet.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// API 令牌、站点设置与保留期、用户。令牌明文只在创建的响应里出现一次。 public static class SystemEndpoints diff --git a/backend/src/Monitor.Backend.Api/Admin/TaskEndpoints.cs b/backend/src/MoShiro.Backend.Api/Admin/TaskEndpoints.cs similarity index 97% rename from backend/src/Monitor.Backend.Api/Admin/TaskEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Admin/TaskEndpoints.cs index eb30c46..66b8c41 100644 --- a/backend/src/Monitor.Backend.Api/Admin/TaskEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Admin/TaskEndpoints.cs @@ -2,10 +2,10 @@ using Fleet.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 任务(线路模板、单个 Agent 的覆盖、目标任务)与按需测试。参数按 Kind 的 ParamSpec 校验,并检查带宽预算。 public static class TaskEndpoints @@ -76,7 +76,7 @@ public static class TaskEndpoints TaskRecord? task = await tasks.GetAsync(new TaskId(id), ct); if (task is null) { - return Problems.Create(http, MonitorErrors.TaskNotFound, "task not found"); + return Problems.Create(http, MoShiroErrors.TaskNotFound, "task not found"); } Concurrency.SetETag(http, task.RowVersion); diff --git a/backend/src/Monitor.Backend.Api/ApiModule.cs b/backend/src/MoShiro.Backend.Api/ApiModule.cs similarity index 93% rename from backend/src/Monitor.Backend.Api/ApiModule.cs rename to backend/src/MoShiro.Backend.Api/ApiModule.cs index bbab80b..6cb4d31 100644 --- a/backend/src/Monitor.Backend.Api/ApiModule.cs +++ b/backend/src/MoShiro.Backend.Api/ApiModule.cs @@ -5,17 +5,17 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Json; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; -using Monitor.Backend.Application; +using MoShiro.Backend.Application; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// -/// Api 层的入口:服务注册、中间件、端点映射。新增资源时在 里加一行。 +/// Api 层的入口:服务注册、中间件、端点映射。新增资源时在 里加一行。 /// Api 只调用 Application;错误码到 HTTP 状态的映射只在这一层做一次()。 /// public static class ApiModule { - public static IServiceCollection AddMonitorApi(this IServiceCollection services) + public static IServiceCollection AddMoShiroApi(this IServiceCollection services) { services.AddSingleton(); services.Configure(options => @@ -48,7 +48,7 @@ public static class ApiModule /// 跨域(可选):只对 /api/public 和 /api/admin 生效,只放行名单里的来源,且不带凭据(Cookie 不会跨域), /// 所以跨域的前端只能用 Bearer 令牌。需要放在认证和路由之前。 /// - public static IApplicationBuilder UseMonitorCors(this IApplicationBuilder app, string? origins) + public static IApplicationBuilder UseMoShiroCors(this IApplicationBuilder app, string? origins) { string[] allowed = (origins ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); if (allowed.Length == 0) @@ -83,7 +83,7 @@ public static class ApiModule } /// 认证中间件:解析 Bearer 令牌或会话 Cookie。需要放在路由之后、端点之前。 - public static IApplicationBuilder UseMonitorApi(this IApplicationBuilder app) + public static IApplicationBuilder UseMoShiroApi(this IApplicationBuilder app) { app.UseExceptionHandler(); app.UseStatusCodePages(); @@ -91,7 +91,7 @@ public static class ApiModule return app; } - public static IEndpointRouteBuilder MapMonitorApi(this IEndpointRouteBuilder app) + public static IEndpointRouteBuilder MapMoShiroApi(this IEndpointRouteBuilder app) { RouteGroupBuilder publicGroup = app.MapGroup("/api/public").AddEndpointFilter(PublicGuard.InvokeAsync); QueryEndpoints.Map(publicGroup); diff --git a/backend/src/Monitor.Backend.Api/Common/Concurrency.cs b/backend/src/MoShiro.Backend.Api/Common/Concurrency.cs similarity index 97% rename from backend/src/Monitor.Backend.Api/Common/Concurrency.cs rename to backend/src/MoShiro.Backend.Api/Common/Concurrency.cs index 1916238..60bc8e7 100644 --- a/backend/src/Monitor.Backend.Api/Common/Concurrency.cs +++ b/backend/src/MoShiro.Backend.Api/Common/Concurrency.cs @@ -1,7 +1,7 @@ using System.Globalization; using Microsoft.AspNetCore.Http; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 并发控制:配置类资源返回 ETag(行版本),PATCH/DELETE 支持 If-Match,不匹配时返回 412。 internal static class Concurrency diff --git a/backend/src/Monitor.Backend.Api/Common/EndpointConventions.cs b/backend/src/MoShiro.Backend.Api/Common/EndpointConventions.cs similarity index 96% rename from backend/src/Monitor.Backend.Api/Common/EndpointConventions.cs rename to backend/src/MoShiro.Backend.Api/Common/EndpointConventions.cs index 9158ec2..f749fd0 100644 --- a/backend/src/Monitor.Backend.Api/Common/EndpointConventions.cs +++ b/backend/src/MoShiro.Backend.Api/Common/EndpointConventions.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; public static class EndpointConventions { diff --git a/backend/src/Monitor.Backend.Api/Common/Guards.cs b/backend/src/MoShiro.Backend.Api/Common/Guards.cs similarity index 90% rename from backend/src/Monitor.Backend.Api/Common/Guards.cs rename to backend/src/MoShiro.Backend.Api/Common/Guards.cs index 9e865c5..0be49b8 100644 --- a/backend/src/Monitor.Backend.Api/Common/Guards.cs +++ b/backend/src/MoShiro.Backend.Api/Common/Guards.cs @@ -1,13 +1,13 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; public static class HttpContextPrincipalExtensions { - private const string Key = "monitor.principal"; + private const string Key = "moshiro.principal"; public static Principal GetPrincipal(this HttpContext http) => http.Items.TryGetValue(Key, out object? value) && value is Principal principal ? principal : Principal.Anonymous; @@ -20,7 +20,7 @@ public static class HttpContextPrincipalExtensions /// public static class PrincipalResolver { - public const string SessionCookie = "monitor_session"; + public const string SessionCookie = "moshiro_session"; public const string CsrfHeader = "X-CSRF-Token"; public static string? BearerOf(HttpContext http) @@ -63,8 +63,8 @@ public static class AdminGuard if (!principal.IsAdmin) { return principal.Scope != ApiScope.None - ? Problems.Create(http, MonitorErrors.Forbidden, "the token scope does not allow this operation") - : Problems.Create(http, MonitorErrors.Unauthorized, "authentication is required"); + ? Problems.Create(http, MoShiroErrors.Forbidden, "the token scope does not allow this operation") + : Problems.Create(http, MoShiroErrors.Unauthorized, "authentication is required"); } if (principal.Kind == PrincipalKind.Session && !HttpMethods.IsGet(http.Request.Method) && !HttpMethods.IsHead(http.Request.Method) && !HttpMethods.IsOptions(http.Request.Method)) @@ -72,7 +72,7 @@ public static class AdminGuard string? csrf = http.Request.Headers[PrincipalResolver.CsrfHeader]; if (csrf is null || principal.CsrfToken is null || !AuthService.FixedTimeEquals(csrf, principal.CsrfToken)) { - return Problems.Create(http, MonitorErrors.CsrfFailed, "a valid X-CSRF-Token header is required"); + return Problems.Create(http, MoShiroErrors.CsrfFailed, "a valid X-CSRF-Token header is required"); } } @@ -95,7 +95,7 @@ public static class PublicGuard HttpContext http = context.HttpContext; if (!http.GetPrincipal().CanRead && !await http.RequestServices.GetRequiredService().IsSitePublicAsync(http.RequestAborted)) { - return Problems.Create(http, MonitorErrors.SitePrivate, "this site is private; sign in or use a read-only token"); + return Problems.Create(http, MoShiroErrors.SitePrivate, "this site is private; sign in or use a read-only token"); } return await next(context); diff --git a/backend/src/Monitor.Backend.Api/Common/Mappers.cs b/backend/src/MoShiro.Backend.Api/Common/Mappers.cs similarity index 98% rename from backend/src/Monitor.Backend.Api/Common/Mappers.cs rename to backend/src/MoShiro.Backend.Api/Common/Mappers.cs index 98ea0d1..39fd43e 100644 --- a/backend/src/Monitor.Backend.Api/Common/Mappers.cs +++ b/backend/src/MoShiro.Backend.Api/Common/Mappers.cs @@ -1,10 +1,10 @@ using System.Text.Json; using Fleet.Server; -using Monitor.Backend.Analysis; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 应用层模型 → REST DTO。public 层的 DTO 只暴露可以公开的字段。 public static class Mappers diff --git a/backend/src/Monitor.Backend.Api/Common/Problems.cs b/backend/src/MoShiro.Backend.Api/Common/Problems.cs similarity index 71% rename from backend/src/Monitor.Backend.Api/Common/Problems.cs rename to backend/src/MoShiro.Backend.Api/Common/Problems.cs index 841ca91..87576e9 100644 --- a/backend/src/Monitor.Backend.Api/Common/Problems.cs +++ b/backend/src/MoShiro.Backend.Api/Common/Problems.cs @@ -1,10 +1,10 @@ using System.Diagnostics; using Fleet.Core; using Microsoft.AspNetCore.Http; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 错误码到 HTTP 状态的映射:只在 Api 层做一次。 public static class ErrorCodeHttpMap @@ -44,19 +44,19 @@ public static class ErrorCodeHttpMap } } - Add(400, MonitorErrors.ValidationFailed, MonitorErrors.BudgetExceeded, FleetErrors.InvalidParams); - Add(401, MonitorErrors.Unauthorized, MonitorErrors.CsrfFailed, FleetErrors.Unauthorized); - Add(403, MonitorErrors.Forbidden, MonitorErrors.SitePrivate, FleetErrors.Forbidden, FleetErrors.ProofInvalid); + Add(400, MoShiroErrors.ValidationFailed, MoShiroErrors.BudgetExceeded, FleetErrors.InvalidParams); + Add(401, MoShiroErrors.Unauthorized, MoShiroErrors.CsrfFailed, FleetErrors.Unauthorized); + Add(403, MoShiroErrors.Forbidden, MoShiroErrors.SitePrivate, FleetErrors.Forbidden, FleetErrors.ProofInvalid); Add( - 404, MonitorErrors.NotFound, MonitorErrors.AgentNotFound, MonitorErrors.ProbeNotFound, MonitorErrors.TaskNotFound, MonitorErrors.TestNotFound, MonitorErrors.ChunkNotFound, - MonitorErrors.TokenNotFound, MonitorErrors.UnknownKind, MonitorErrors.UnknownPlan, FleetErrors.NotFound); - Add(409, MonitorErrors.NameConflict, MonitorErrors.ProbeRevoked, MonitorErrors.ProbeOffline, MonitorErrors.TestBusy, MonitorErrors.AgentNotActive, MonitorErrors.AgentOffline, FleetErrors.NameConflict, FleetErrors.NodeOffline); - Add(410, MonitorErrors.RawExpired, MonitorErrors.JoinTokenExpired, FleetErrors.JoinTokenExpired); - Add(412, MonitorErrors.PreconditionFailed); - Add(413, MonitorErrors.PayloadTooLarge); - Add(422, MonitorErrors.ProbeRequired, MonitorErrors.RangeTooLarge, MonitorErrors.InvalidStep, MonitorErrors.InvalidRange, MonitorErrors.UnknownMetric, MonitorErrors.UnknownPreset, MonitorErrors.TooManyMetrics, FleetErrors.Unsupported); - Add(429, MonitorErrors.TooManyRequests, MonitorErrors.TooManyStreams); - Add(503, MonitorErrors.StorageUnavailable, FleetErrors.Timeout); + 404, MoShiroErrors.NotFound, MoShiroErrors.AgentNotFound, MoShiroErrors.ProbeNotFound, MoShiroErrors.TaskNotFound, MoShiroErrors.TestNotFound, MoShiroErrors.ChunkNotFound, + MoShiroErrors.TokenNotFound, MoShiroErrors.UnknownKind, MoShiroErrors.UnknownPlan, FleetErrors.NotFound); + Add(409, MoShiroErrors.NameConflict, MoShiroErrors.ProbeRevoked, MoShiroErrors.ProbeOffline, MoShiroErrors.TestBusy, MoShiroErrors.AgentNotActive, MoShiroErrors.AgentOffline, FleetErrors.NameConflict, FleetErrors.NodeOffline); + Add(410, MoShiroErrors.RawExpired, MoShiroErrors.JoinTokenExpired, FleetErrors.JoinTokenExpired); + Add(412, MoShiroErrors.PreconditionFailed); + Add(413, MoShiroErrors.PayloadTooLarge); + Add(422, MoShiroErrors.ProbeRequired, MoShiroErrors.RangeTooLarge, MoShiroErrors.InvalidStep, MoShiroErrors.InvalidRange, MoShiroErrors.UnknownMetric, MoShiroErrors.UnknownPreset, MoShiroErrors.TooManyMetrics, FleetErrors.Unsupported); + Add(429, MoShiroErrors.TooManyRequests, MoShiroErrors.TooManyStreams); + Add(503, MoShiroErrors.StorageUnavailable, FleetErrors.Timeout); map[NotImplemented.Value] = 501; return map; } diff --git a/backend/src/Monitor.Backend.Api/Common/QueryHelpers.cs b/backend/src/MoShiro.Backend.Api/Common/QueryHelpers.cs similarity index 93% rename from backend/src/Monitor.Backend.Api/Common/QueryHelpers.cs rename to backend/src/MoShiro.Backend.Api/Common/QueryHelpers.cs index f6e8ef8..f37b141 100644 --- a/backend/src/Monitor.Backend.Api/Common/QueryHelpers.cs +++ b/backend/src/MoShiro.Backend.Api/Common/QueryHelpers.cs @@ -3,10 +3,10 @@ using System.Text; using Fleet.Core; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; internal static class QueryHelpers { @@ -22,7 +22,7 @@ internal static class QueryHelpers } catch (OperationCanceledException) when (!http.RequestAborted.IsCancellationRequested) { - return Problems.Create(http, MonitorErrors.StorageUnavailable, null); + return Problems.Create(http, MoShiroErrors.StorageUnavailable, null); } } @@ -81,7 +81,7 @@ internal static class QueryHelpers return line.Agent.Agent.Status == Fleet.Server.NodeStatus.Active && (line.Agent.Agent.PublicVisible || PublicGuard.CanSeeHidden(http)) && line.Probe.RevokedAtMs is null ? found - : Result.Fail(MonitorErrors.AgentNotFound, "line not found"); + : Result.Fail(MoShiroErrors.AgentNotFound, "line not found"); } /// 找到可以展示的线路:已激活,并且(对外可见,或者访问者已认证)。否则 404(不暴露被隐藏的线路存在与否)。 @@ -90,6 +90,6 @@ internal static class QueryHelpers 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.Ok(view) - : Result.Fail(MonitorErrors.AgentNotFound, "agent not found"); + : Result.Fail(MoShiroErrors.AgentNotFound, "agent not found"); } } diff --git a/backend/src/Monitor.Backend.Api/Contracts/AdminDtos.cs b/backend/src/MoShiro.Backend.Api/Contracts/AdminDtos.cs similarity index 99% rename from backend/src/Monitor.Backend.Api/Contracts/AdminDtos.cs rename to backend/src/MoShiro.Backend.Api/Contracts/AdminDtos.cs index 45236ab..d01021e 100644 --- a/backend/src/Monitor.Backend.Api/Contracts/AdminDtos.cs +++ b/backend/src/MoShiro.Backend.Api/Contracts/AdminDtos.cs @@ -1,6 +1,6 @@ using System.Text.Json; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// return_session:跨域的前端用——不设 Cookie,把会话令牌放在响应里,之后用 Authorization: Bearer 带上。 public sealed record LoginRequest(string Username, string Password, bool? ReturnSession); diff --git a/backend/src/Monitor.Backend.Api/Contracts/ApiJsonContext.cs b/backend/src/MoShiro.Backend.Api/Contracts/ApiJsonContext.cs similarity index 97% rename from backend/src/Monitor.Backend.Api/Contracts/ApiJsonContext.cs rename to backend/src/MoShiro.Backend.Api/Contracts/ApiJsonContext.cs index 8a355b9..2ce9de8 100644 --- a/backend/src/Monitor.Backend.Api/Contracts/ApiJsonContext.cs +++ b/backend/src/MoShiro.Backend.Api/Contracts/ApiJsonContext.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// /// REST 的 JSON 源生成上下文(snake_case,字段始终存在、未知值写 null,枚举与时间的格式见数据表示规则)。 @@ -80,6 +80,6 @@ namespace Monitor.Backend.Api; [JsonSerializable(typeof(CreateUserRequest))] [JsonSerializable(typeof(ChangePasswordRequest))] [JsonSerializable(typeof(RecomputeDto))] -[JsonSerializable(typeof(Monitor.Protocol.LocalLimits))] +[JsonSerializable(typeof(MoShiro.Protocol.LocalLimits))] [JsonSerializable(typeof(List))] public sealed partial class ApiJsonContext : JsonSerializerContext; diff --git a/backend/src/Monitor.Backend.Api/Contracts/CommonDtos.cs b/backend/src/MoShiro.Backend.Api/Contracts/CommonDtos.cs similarity index 97% rename from backend/src/Monitor.Backend.Api/Contracts/CommonDtos.cs rename to backend/src/MoShiro.Backend.Api/Contracts/CommonDtos.cs index 0095b20..ea982a1 100644 --- a/backend/src/Monitor.Backend.Api/Contracts/CommonDtos.cs +++ b/backend/src/MoShiro.Backend.Api/Contracts/CommonDtos.cs @@ -2,7 +2,7 @@ using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 时间点统一使用 RFC 3339 UTC,以 Z 结尾,精确到毫秒(唯一例外:列式时序里的时间轴 t 是 Unix 毫秒)。 public sealed class Rfc3339Converter : JsonConverter diff --git a/backend/src/Monitor.Backend.Api/Contracts/PublicDtos.cs b/backend/src/MoShiro.Backend.Api/Contracts/PublicDtos.cs similarity index 99% rename from backend/src/Monitor.Backend.Api/Contracts/PublicDtos.cs rename to backend/src/MoShiro.Backend.Api/Contracts/PublicDtos.cs index c52543e..4c1cdf0 100644 --- a/backend/src/Monitor.Backend.Api/Contracts/PublicDtos.cs +++ b/backend/src/MoShiro.Backend.Api/Contracts/PublicDtos.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 汇总:整个时间段由累加器精确合并得出的值(不是各点的平均)。 public sealed record SummaryDto(IReadOnlyDictionary Metrics, IReadOnlyDictionary Samples, double Coverage); diff --git a/backend/src/Monitor.Backend.Api/Monitor.Backend.Api.csproj b/backend/src/MoShiro.Backend.Api/MoShiro.Backend.Api.csproj similarity index 76% rename from backend/src/Monitor.Backend.Api/Monitor.Backend.Api.csproj rename to backend/src/MoShiro.Backend.Api/MoShiro.Backend.Api.csproj index 95eddf2..0111063 100644 --- a/backend/src/Monitor.Backend.Api/Monitor.Backend.Api.csproj +++ b/backend/src/MoShiro.Backend.Api/MoShiro.Backend.Api.csproj @@ -6,6 +6,6 @@ - + diff --git a/backend/src/Monitor.Backend.Api/OpsEndpoints.cs b/backend/src/MoShiro.Backend.Api/OpsEndpoints.cs similarity index 91% rename from backend/src/Monitor.Backend.Api/OpsEndpoints.cs rename to backend/src/MoShiro.Backend.Api/OpsEndpoints.cs index 1e51dbc..75779be 100644 --- a/backend/src/Monitor.Backend.Api/OpsEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/OpsEndpoints.cs @@ -1,10 +1,10 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 运维端点:/healthz、/metrics(admin 令牌)、安装脚本。 public static class OpsEndpoints @@ -40,8 +40,8 @@ public static class OpsEndpoints if (!principal.IsAdmin) { return principal.CanRead - ? Problems.Create(http, MonitorErrors.Forbidden, "an admin token is required") - : Problems.Create(http, MonitorErrors.Unauthorized, "an admin token is required"); + ? Problems.Create(http, MoShiroErrors.Forbidden, "an admin token is required") + : Problems.Create(http, MoShiroErrors.Unauthorized, "an admin token is required"); } return TypedResults.Text(await ops.RenderPrometheusAsync(http.RequestAborted), "text/plain; version=0.0.4"); diff --git a/backend/src/Monitor.Backend.Api/Public/CatalogEndpoints.cs b/backend/src/MoShiro.Backend.Api/Public/CatalogEndpoints.cs similarity index 90% rename from backend/src/Monitor.Backend.Api/Public/CatalogEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Public/CatalogEndpoints.cs index 34f1779..b2f6e9c 100644 --- a/backend/src/Monitor.Backend.Api/Public/CatalogEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Public/CatalogEndpoints.cs @@ -1,10 +1,10 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 目录:由代码里的注册表生成。新增 Kind、方案、指标、分组、模型后,目录自动更新,前端不需要改。 public static class CatalogEndpoints @@ -27,12 +27,12 @@ public static class CatalogEndpoints } private static IResult Kinds(HttpContext http) => - QueryHelpers.ApplyCatalogCaching(http, string.Join(',', Monitor.Protocol.Kinds.All.Select(k => k.Id))) - ?? TypedResults.Json(new PageDto([.. Monitor.Protocol.Kinds.All.Select(Mappers.ToDto)], null), ApiJsonContext.Default.PageDtoKindDto); + QueryHelpers.ApplyCatalogCaching(http, string.Join(',', MoShiro.Protocol.Kinds.All.Select(k => k.Id))) + ?? TypedResults.Json(new PageDto([.. MoShiro.Protocol.Kinds.All.Select(Mappers.ToDto)], null), ApiJsonContext.Default.PageDtoKindDto); private static IResult Plans(HttpContext http) => - QueryHelpers.ApplyCatalogCaching(http, string.Join(',', Monitor.Backend.Application.Plans.All.Select(p => p.Id))) - ?? TypedResults.Json(new PageDto([.. Monitor.Backend.Application.Plans.All.Select(Mappers.ToDto)], null), ApiJsonContext.Default.PageDtoPlanDto); + QueryHelpers.ApplyCatalogCaching(http, string.Join(',', MoShiro.Backend.Application.Plans.All.Select(p => p.Id))) + ?? TypedResults.Json(new PageDto([.. MoShiro.Backend.Application.Plans.All.Select(Mappers.ToDto)], null), ApiJsonContext.Default.PageDtoPlanDto); private static IResult Metrics(HttpContext http) => QueryHelpers.ApplyCatalogCaching(http, string.Join(',', MetricRegistry.All.Select(m => m.Fingerprint))) diff --git a/backend/src/Monitor.Backend.Api/Public/HostEndpoints.cs b/backend/src/MoShiro.Backend.Api/Public/HostEndpoints.cs similarity index 95% rename from backend/src/Monitor.Backend.Api/Public/HostEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Public/HostEndpoints.cs index 1430e74..1dc2031 100644 --- a/backend/src/Monitor.Backend.Api/Public/HostEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Public/HostEndpoints.cs @@ -2,10 +2,10 @@ using Fleet.Core; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// Agent 的主机资源占用:最新值(实时的部分走 SSE 的 hosts 主题)和历史曲线。只有汇总的数字,没有型号和 IP。 public static class HostEndpoints @@ -44,12 +44,12 @@ public static class HostEndpoints AgentView? view = await agents.GetAsync(new NodeId(agent_id), ct); if (view is not { Agent.Status: Fleet.Server.NodeStatus.Active } || !(view.Agent.PublicVisible || PublicGuard.CanSeeHidden(http))) { - return Problems.Create(http, MonitorErrors.AgentNotFound, "agent not found"); + return Problems.Create(http, MoShiroErrors.AgentNotFound, "agent not found"); } if (!RangeResolver.TryParseSpan(range ?? "1h", out long span) || span < Steps.Hour || span > 30 * Steps.Day) { - return Problems.From(http, new FleetError(MonitorErrors.InvalidRange, "range must look like 1h, 6h, 24h or 7d (between 1 hour and 30 days)")); + return Problems.From(http, new FleetError(MoShiroErrors.InvalidRange, "range must look like 1h, 6h, 24h or 7d (between 1 hour and 30 days)")); } long now = time.GetUtcNow().ToUnixTimeMilliseconds(); diff --git a/backend/src/Monitor.Backend.Api/Public/LiveEndpoints.cs b/backend/src/MoShiro.Backend.Api/Public/LiveEndpoints.cs similarity index 99% rename from backend/src/Monitor.Backend.Api/Public/LiveEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Public/LiveEndpoints.cs index 8c6f2cb..b2de354 100644 --- a/backend/src/Monitor.Backend.Api/Public/LiveEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Public/LiveEndpoints.cs @@ -7,10 +7,10 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Primitives; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// /// 实时推送(SSE):先推送当前快照,再推送增量(不补发历史)。SSE 只负责“更快地获得变化”, @@ -67,7 +67,7 @@ public static class LiveEndpoints string client = http.Connection.RemoteIpAddress?.ToString() ?? "unknown"; if (!limiter.TryAcquire(client)) { - return Problems.Create(http, MonitorErrors.TooManyStreams, $"at most {options.MaxSsePerClient} live connections per client"); + return Problems.Create(http, MoShiroErrors.TooManyStreams, $"at most {options.MaxSsePerClient} live connections per client"); } counters.SseOpened(); diff --git a/backend/src/Monitor.Backend.Api/Public/LiveTopics.cs b/backend/src/MoShiro.Backend.Api/Public/LiveTopics.cs similarity index 95% rename from backend/src/Monitor.Backend.Api/Public/LiveTopics.cs rename to backend/src/MoShiro.Backend.Api/Public/LiveTopics.cs index d483eff..c9c3e31 100644 --- a/backend/src/Monitor.Backend.Api/Public/LiveTopics.cs +++ b/backend/src/MoShiro.Backend.Api/Public/LiveTopics.cs @@ -1,9 +1,9 @@ using System.Collections.Concurrent; using Fleet.Core; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; internal enum LiveTopicKind { @@ -46,7 +46,7 @@ internal sealed record LiveTopic(LiveTopicKind Kind, string Raw, string? Range, if (tokens.Count > maxTopics) { - return Result>.Fail(MonitorErrors.TooManyStreams, $"at most {maxTopics} topics per connection"); + return Result>.Fail(MoShiroErrors.TooManyStreams, $"at most {maxTopics} topics per connection"); } var topics = new List(); @@ -83,7 +83,7 @@ internal sealed record LiveTopic(LiveTopicKind Kind, string Raw, string? Range, case "series" when parts.Length == 4: if (!Steps.TryParse(parts[2], out long step) || step > Steps.Minute) { - return Result.Fail(MonitorErrors.InvalidStep, $"{token}: series topics support steps up to 1m; refetch coarser steps over REST"); + return Result.Fail(MoShiroErrors.InvalidStep, $"{token}: series topics support steps up to 1m; refetch coarser steps over REST"); } return Result.Ok(new LiveTopic(LiveTopicKind.Series, token, null, step, parts[3], parts[1], null)); diff --git a/backend/src/Monitor.Backend.Api/Public/NodeEndpoints.cs b/backend/src/MoShiro.Backend.Api/Public/NodeEndpoints.cs similarity index 92% rename from backend/src/Monitor.Backend.Api/Public/NodeEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Public/NodeEndpoints.cs index 35da907..e71ba87 100644 --- a/backend/src/Monitor.Backend.Api/Public/NodeEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Public/NodeEndpoints.cs @@ -1,9 +1,9 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Application; +using MoShiro.Backend.Application; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// /// 节点的展示信息:系统、架构、国家、运营商。只有这几项,没有任何 IP 地址、城市、ASN、经纬度—— @@ -25,7 +25,7 @@ public static class NodeEndpoints /// 这个后端自己的构建信息;没有(本地构建)的字段是 null。 internal static BuildDto Backend(bool withCommit) => - new(Monitor.Protocol.BuildInfo.Version, Empty(Monitor.Protocol.BuildInfo.Tag), withCommit ? Empty(Monitor.Protocol.BuildInfo.Commit) : null, Empty(Monitor.Protocol.BuildInfo.BuiltAt)); + 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; diff --git a/backend/src/Monitor.Backend.Api/Public/QueryEndpoints.cs b/backend/src/MoShiro.Backend.Api/Public/QueryEndpoints.cs similarity index 98% rename from backend/src/Monitor.Backend.Api/Public/QueryEndpoints.cs rename to backend/src/MoShiro.Backend.Api/Public/QueryEndpoints.cs index dcadd8d..9c8be7d 100644 --- a/backend/src/Monitor.Backend.Api/Public/QueryEndpoints.cs +++ b/backend/src/MoShiro.Backend.Api/Public/QueryEndpoints.cs @@ -3,11 +3,11 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Routing; -using Monitor.Backend.Analysis; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Api; +namespace MoShiro.Backend.Api; /// 展示数据的查询端点:参数解析、校验与缓存头,业务都在 Application.Query。 public static class QueryEndpoints @@ -211,13 +211,13 @@ public static class QueryEndpoints TestDetail? detail = await tests.GetAsync(new TestId(test_id), ct); if (detail is null) { - return Problems.Create(http, MonitorErrors.TestNotFound, "test not found"); + return Problems.Create(http, MoShiroErrors.TestNotFound, "test not found"); } Result visible = await QueryHelpers.FindVisibleAgentAsync(http, agents, detail.Test.AgentId.Value, ct); if (!visible.IsSuccess) { - return Problems.Create(http, MonitorErrors.TestNotFound, "test not found"); + return Problems.Create(http, MoShiroErrors.TestNotFound, "test not found"); } return TypedResults.Json(Mappers.ToDto(detail), ApiJsonContext.Default.TestDto); diff --git a/backend/src/Monitor.Backend.Application/Admin/EventService.cs b/backend/src/MoShiro.Backend.Application/Admin/EventService.cs similarity index 91% rename from backend/src/Monitor.Backend.Application/Admin/EventService.cs rename to backend/src/MoShiro.Backend.Application/Admin/EventService.cs index 1c4ff5d..0f59b3b 100644 --- a/backend/src/Monitor.Backend.Application/Admin/EventService.cs +++ b/backend/src/MoShiro.Backend.Application/Admin/EventService.cs @@ -1,6 +1,6 @@ using Fleet.Core; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed class EventService { diff --git a/backend/src/Monitor.Backend.Application/Admin/JoinTokenService.cs b/backend/src/MoShiro.Backend.Application/Admin/JoinTokenService.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Admin/JoinTokenService.cs rename to backend/src/MoShiro.Backend.Application/Admin/JoinTokenService.cs index 813bca0..382267e 100644 --- a/backend/src/Monitor.Backend.Application/Admin/JoinTokenService.cs +++ b/backend/src/MoShiro.Backend.Application/Admin/JoinTokenService.cs @@ -1,6 +1,6 @@ using Fleet.Core; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record CreateJoinTokenRequest(string? Note, IReadOnlyList? Labels, bool AutoApprove, int MaxUses, int ExpiresInHours); diff --git a/backend/src/Monitor.Backend.Application/Admin/OpsService.cs b/backend/src/MoShiro.Backend.Application/Admin/OpsService.cs similarity index 75% rename from backend/src/Monitor.Backend.Application/Admin/OpsService.cs rename to backend/src/MoShiro.Backend.Application/Admin/OpsService.cs index 13ebe0f..913b85a 100644 --- a/backend/src/Monitor.Backend.Application/Admin/OpsService.cs +++ b/backend/src/MoShiro.Backend.Application/Admin/OpsService.cs @@ -1,7 +1,7 @@ using System.Globalization; using System.Text; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 运维:健康检查和 Prometheus 指标(在线数、块入库速率、分析队列长度、重算进度、磁盘占用、SSE 连接数)。 public sealed class OpsService @@ -40,17 +40,17 @@ public sealed class OpsService } RecomputeProgress progress = _recompute.Progress; - Metric("monitor_agents_online", "Agents with an open control connection.", _gateway.OnlineAgents.Count); - Metric("monitor_chunks_ingested_total", "Raw chunks stored.", _counters.ChunksIngested, "counter"); - Metric("monitor_chunks_duplicate_total", "Raw chunks received more than once.", _counters.ChunksDuplicate, "counter"); - Metric("monitor_chunks_discarded_total", "Raw chunks rejected as invalid.", _counters.ChunksDiscarded, "counter"); - Metric("monitor_ingest_bytes_total", "Bytes of raw chunks stored.", _counters.BytesIngested, "counter"); - Metric("monitor_windows_analyzed_total", "Minute windows computed.", _counters.WindowsAnalyzed, "counter"); - Metric("monitor_analysis_queue_length", "Minute windows waiting to be computed.", await _metrics.QueueLengthAsync(ct)); - Metric("monitor_recompute_windows_done", "Windows recomputed by the current backfill.", progress.WindowsDone); - Metric("monitor_recompute_windows_total", "Windows to recompute in the current backfill.", progress.WindowsTotal); - Metric("monitor_raw_bytes", "Disk used by raw segment files.", _raw.TotalBytes); - Metric("monitor_sse_connections", "Open server-sent event connections.", _counters.SseConnections); + Metric("moshiro_agents_online", "Agents with an open control connection.", _gateway.OnlineAgents.Count); + Metric("moshiro_chunks_ingested_total", "Raw chunks stored.", _counters.ChunksIngested, "counter"); + Metric("moshiro_chunks_duplicate_total", "Raw chunks received more than once.", _counters.ChunksDuplicate, "counter"); + Metric("moshiro_chunks_discarded_total", "Raw chunks rejected as invalid.", _counters.ChunksDiscarded, "counter"); + Metric("moshiro_ingest_bytes_total", "Bytes of raw chunks stored.", _counters.BytesIngested, "counter"); + Metric("moshiro_windows_analyzed_total", "Minute windows computed.", _counters.WindowsAnalyzed, "counter"); + Metric("moshiro_analysis_queue_length", "Minute windows waiting to be computed.", await _metrics.QueueLengthAsync(ct)); + Metric("moshiro_recompute_windows_done", "Windows recomputed by the current backfill.", progress.WindowsDone); + Metric("moshiro_recompute_windows_total", "Windows to recompute in the current backfill.", progress.WindowsTotal); + Metric("moshiro_raw_bytes", "Disk used by raw segment files.", _raw.TotalBytes); + Metric("moshiro_sse_connections", "Open server-sent event connections.", _counters.SseConnections); return text.ToString(); } } diff --git a/backend/src/Monitor.Backend.Application/Admin/RawBrowserService.cs b/backend/src/MoShiro.Backend.Application/Admin/RawBrowserService.cs similarity index 88% rename from backend/src/Monitor.Backend.Application/Admin/RawBrowserService.cs rename to backend/src/MoShiro.Backend.Application/Admin/RawBrowserService.cs index b69fa06..e3541b3 100644 --- a/backend/src/Monitor.Backend.Application/Admin/RawBrowserService.cs +++ b/backend/src/MoShiro.Backend.Application/Admin/RawBrowserService.cs @@ -1,7 +1,7 @@ using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 原始数据的检索与下载(管理员)。块过了保留期返回 raw_expired,从来不存在返回 chunk_not_found。 public sealed class RawBrowserService @@ -26,7 +26,7 @@ public sealed class RawBrowserService { byte[]? bytes = await _raw.ReadAsync(meta, ct); return bytes is null - ? Result<(RawChunkMeta, byte[])>.Fail(MonitorErrors.RawExpired, "the raw data has expired") + ? Result<(RawChunkMeta, byte[])>.Fail(MoShiroErrors.RawExpired, "the raw data has expired") : Result<(RawChunkMeta, byte[])>.Ok((meta, bytes)); } @@ -34,8 +34,8 @@ public sealed class RawBrowserService int days = await _settings.GetIntAsync(SettingsService.TestRawDays, ct); long cutoff = _time.GetUtcNow().ToUnixTimeMilliseconds() - (days * 86_400_000L); return ChunkTimestampMs(id.Value) is { } created && created < cutoff - ? Result<(RawChunkMeta, byte[])>.Fail(MonitorErrors.RawExpired, "the raw data has expired") - : Result<(RawChunkMeta, byte[])>.Fail(MonitorErrors.ChunkNotFound, "chunk not found"); + ? Result<(RawChunkMeta, byte[])>.Fail(MoShiroErrors.RawExpired, "the raw data has expired") + : Result<(RawChunkMeta, byte[])>.Fail(MoShiroErrors.ChunkNotFound, "chunk not found"); } /// UUIDv7 的前 48 位是毫秒时间戳。 diff --git a/backend/src/Monitor.Backend.Application/Admin/SettingsService.cs b/backend/src/MoShiro.Backend.Application/Admin/SettingsService.cs similarity index 99% rename from backend/src/Monitor.Backend.Application/Admin/SettingsService.cs rename to backend/src/MoShiro.Backend.Application/Admin/SettingsService.cs index eb05808..1577ec3 100644 --- a/backend/src/Monitor.Backend.Application/Admin/SettingsService.cs +++ b/backend/src/MoShiro.Backend.Application/Admin/SettingsService.cs @@ -2,7 +2,7 @@ using System.Globalization; using System.Text.Json; using Fleet.Core; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record SettingSpec(string Key, string Type, string Default, long Min, long Max, string Description); diff --git a/backend/src/Monitor.Backend.Application/Agents/AgentEventService.cs b/backend/src/MoShiro.Backend.Application/Agents/AgentEventService.cs similarity index 93% rename from backend/src/Monitor.Backend.Application/Agents/AgentEventService.cs rename to backend/src/MoShiro.Backend.Application/Agents/AgentEventService.cs index 957624c..8f50d8b 100644 --- a/backend/src/Monitor.Backend.Application/Agents/AgentEventService.cs +++ b/backend/src/MoShiro.Backend.Application/Agents/AgentEventService.cs @@ -1,9 +1,9 @@ using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; -/// monitor.event:Agent 报告的事件(Probe 连上/断开、端点变化、时钟跳变、缺口、CPU 饱和)。 +/// moshiro.event:Agent 报告的事件(Probe 连上/断开、端点变化、时钟跳变、缺口、CPU 饱和)。 public sealed class AgentEventService { private readonly AgentRuntime _runtime; diff --git a/backend/src/Monitor.Backend.Application/Agents/AgentRuntime.cs b/backend/src/MoShiro.Backend.Application/Agents/AgentRuntime.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Agents/AgentRuntime.cs rename to backend/src/MoShiro.Backend.Application/Agents/AgentRuntime.cs index 98e7738..6fe7134 100644 --- a/backend/src/Monitor.Backend.Application/Agents/AgentRuntime.cs +++ b/backend/src/MoShiro.Backend.Application/Agents/AgentRuntime.cs @@ -1,8 +1,8 @@ using System.Collections.Concurrent; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// Agent 眼中的一个已连接 Probe(Agent 在事件和心跳里上报)。 public sealed record ConnectedProbeInfo(string Id, string? Version, string? Remote, long SinceMs); diff --git a/backend/src/Monitor.Backend.Application/Agents/AgentService.cs b/backend/src/MoShiro.Backend.Application/Agents/AgentService.cs similarity index 99% rename from backend/src/Monitor.Backend.Application/Agents/AgentService.cs rename to backend/src/MoShiro.Backend.Application/Agents/AgentService.cs index 8c95cc2..5b09036 100644 --- a/backend/src/Monitor.Backend.Application/Agents/AgentService.cs +++ b/backend/src/MoShiro.Backend.Application/Agents/AgentService.cs @@ -1,9 +1,9 @@ using System.Text.RegularExpressions; using Fleet.Core; using Fleet.Server; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record AgentView(AgentRecord Agent, bool Online, IReadOnlyList Probes, AgentHeartbeatExtra? Heartbeat, int EndpointChanges, long? HeartbeatAtMs = null, HostSnapshot? Host = null) { diff --git a/backend/src/Monitor.Backend.Application/Agents/HostStatusService.cs b/backend/src/MoShiro.Backend.Application/Agents/HostStatusService.cs similarity index 94% rename from backend/src/Monitor.Backend.Application/Agents/HostStatusService.cs rename to backend/src/MoShiro.Backend.Application/Agents/HostStatusService.cs index 284fa15..2c7c0df 100644 --- a/backend/src/Monitor.Backend.Application/Agents/HostStatusService.cs +++ b/backend/src/MoShiro.Backend.Application/Agents/HostStatusService.cs @@ -1,10 +1,10 @@ using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// -/// monitor.host:Agent 每隔几秒上报的主机资源占用快照。最新值放在内存里并实时推给订阅者;每个 Agent 每分钟存一个样本做历史。 +/// moshiro.host:Agent 每隔几秒上报的主机资源占用快照。最新值放在内存里并实时推给订阅者;每个 Agent 每分钟存一个样本做历史。 /// 快照里没有 CPU 型号、主机名、网卡名和 IP(Agent 根本不采集它们)。 /// public sealed class HostStatusService diff --git a/backend/src/Monitor.Backend.Application/Agents/LinkService.cs b/backend/src/MoShiro.Backend.Application/Agents/LinkService.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Agents/LinkService.cs rename to backend/src/MoShiro.Backend.Application/Agents/LinkService.cs index 63347d9..0ee14ea 100644 --- a/backend/src/Monitor.Backend.Application/Agents/LinkService.cs +++ b/backend/src/MoShiro.Backend.Application/Agents/LinkService.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 某一时刻的「线路」开关:自动连接的总开关,加上每一对(Probe,Agent)的手动设置。 public sealed class LinkSnapshot diff --git a/backend/src/Monitor.Backend.Application/Agents/MonitorFleetHooks.cs b/backend/src/MoShiro.Backend.Application/Agents/MonitorFleetHooks.cs similarity index 90% rename from backend/src/Monitor.Backend.Application/Agents/MonitorFleetHooks.cs rename to backend/src/MoShiro.Backend.Application/Agents/MonitorFleetHooks.cs index 380b9e6..492bc1f 100644 --- a/backend/src/Monitor.Backend.Application/Agents/MonitorFleetHooks.cs +++ b/backend/src/MoShiro.Backend.Application/Agents/MonitorFleetHooks.cs @@ -2,17 +2,17 @@ using System.Text.Json; using Fleet.Core; using Fleet.Rpc; using Fleet.Server; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; -/// Monitor 在 Fleet 之上的接入点:注册之后补全公开地址与端口。 -public sealed class MonitorEnrollmentHook : IEnrollmentHook +/// MoShiro 在 Fleet 之上的接入点:注册之后补全公开地址与端口。 +public sealed class MoShiroEnrollmentHook : IEnrollmentHook { private readonly IAgentStore _agents; private readonly AgentService _service; - public MonitorEnrollmentHook(IAgentStore agents, AgentService service) + public MoShiroEnrollmentHook(IAgentStore agents, AgentService service) { _agents = agents; _service = service; @@ -25,7 +25,7 @@ public sealed class MonitorEnrollmentHook : IEnrollmentHook { try { - meta = raw.Deserialize(MonitorJsonContext.Default.AgentEnrollMeta) ?? meta; + meta = raw.Deserialize(MoShiroJsonContext.Default.AgentEnrollMeta) ?? meta; } catch (JsonException) { @@ -44,7 +44,7 @@ public sealed class MonitorEnrollmentHook : IEnrollmentHook } /// 节点上线、下线、hello、心跳:更新运行时状态,补全 Agent 信息,并推送给 SSE。 -public sealed class MonitorNodeEventSink : INodeEventSink +public sealed class MoShiroNodeEventSink : INodeEventSink { private readonly IAgentStore _agents; private readonly AgentRuntime _runtime; @@ -54,7 +54,7 @@ public sealed class MonitorNodeEventSink : INodeEventSink private readonly NodeInfoService _nodes; private readonly ReleaseService _releases; - public MonitorNodeEventSink(IAgentStore agents, AgentRuntime runtime, IEventStore events, LiveHub live, AgentService service, NodeInfoService nodes, ReleaseService releases) + public MoShiroNodeEventSink(IAgentStore agents, AgentRuntime runtime, IEventStore events, LiveHub live, AgentService service, NodeInfoService nodes, ReleaseService releases) { _releases = releases; _nodes = nodes; @@ -93,7 +93,7 @@ public sealed class MonitorNodeEventSink : INodeEventSink try { AgentRuntimeState state = _runtime.Get(id); - AgentHeartbeatExtra? beat = extra.Deserialize(MonitorJsonContext.Default.AgentHeartbeatExtra); + AgentHeartbeatExtra? beat = extra.Deserialize(MoShiroJsonContext.Default.AgentHeartbeatExtra); state.LastHeartbeat = beat; state.LastHeartbeatAtMs = nodeEvent.AtMs; _releases.RecordStatus(id, beat?.Update); @@ -128,7 +128,7 @@ public sealed class MonitorNodeEventSink : INodeEventSink { try { - ProbeHelloMeta? meta = raw.Deserialize(MonitorJsonContext.Default.ProbeHelloMeta); + ProbeHelloMeta? meta = raw.Deserialize(MoShiroJsonContext.Default.ProbeHelloMeta); await _nodes.SetPlatformAsync(id.Value, NodeKinds.Probe, meta?.Platform, ct); } catch (JsonException) @@ -146,7 +146,7 @@ public sealed class MonitorNodeEventSink : INodeEventSink case NodeEventKind.Heartbeat when nodeEvent.Extra is { } extra: try { - _releases.RecordStatus(id, extra.Deserialize(MonitorJsonContext.Default.ProbeHeartbeatExtra)?.Update); + _releases.RecordStatus(id, extra.Deserialize(MoShiroJsonContext.Default.ProbeHeartbeatExtra)?.Update); } catch (JsonException) { @@ -162,9 +162,9 @@ public sealed class MonitorNodeEventSink : INodeEventSink var kinds = new List(); foreach (string capability in hello.Capabilities) { - if (capability.StartsWith(MonitorCapabilities.KindsPrefix, StringComparison.Ordinal)) + if (capability.StartsWith(MoShiroCapabilities.KindsPrefix, StringComparison.Ordinal)) { - kinds.AddRange(capability[MonitorCapabilities.KindsPrefix.Length..].Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)); + kinds.AddRange(capability[MoShiroCapabilities.KindsPrefix.Length..].Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)); } } @@ -173,7 +173,7 @@ public sealed class MonitorNodeEventSink : INodeEventSink { try { - meta = raw.Deserialize(MonitorJsonContext.Default.AgentHelloMeta) ?? meta; + meta = raw.Deserialize(MoShiroJsonContext.Default.AgentHelloMeta) ?? meta; } catch (JsonException) { diff --git a/backend/src/Monitor.Backend.Application/Agents/ProbeService.cs b/backend/src/MoShiro.Backend.Application/Agents/ProbeService.cs similarity index 93% rename from backend/src/Monitor.Backend.Application/Agents/ProbeService.cs rename to backend/src/MoShiro.Backend.Application/Agents/ProbeService.cs index 8b24e6c..e47df2b 100644 --- a/backend/src/Monitor.Backend.Application/Agents/ProbeService.cs +++ b/backend/src/MoShiro.Backend.Application/Agents/ProbeService.cs @@ -2,9 +2,9 @@ using System.Text.RegularExpressions; using Fleet.Core; using Fleet.Identity; using Fleet.Server; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 本地硬上限:写在 Probe 本机的配置里,面板无法修改(在路由器上建议调低)。 public sealed record ProbeLimits(double MaxTestMbps, long MaxTotalPps); @@ -56,7 +56,7 @@ public sealed partial class ProbeService if ((await _probes.ListAsync(ct)).Any(p => string.Equals(p.Name, finalName, StringComparison.OrdinalIgnoreCase))) { - return Result.Fail(MonitorErrors.NameConflict, $"a probe named {finalName} already exists"); + return Result.Fail(MoShiroErrors.NameConflict, $"a probe named {finalName} already exists"); } using NodeIdentity identity = NodeIdentity.Generate(); @@ -80,7 +80,7 @@ public sealed partial class ProbeService { if (await _probes.GetAsync(id, ct) is not { } probe) { - return Result.Fail(MonitorErrors.ProbeNotFound, "probe not found"); + return Result.Fail(MoShiroErrors.ProbeNotFound, "probe not found"); } string trimmed = name.Trim(); @@ -91,7 +91,7 @@ public sealed partial class ProbeService if ((await _probes.ListAsync(ct)).Any(p => p.Id != id && string.Equals(p.Name, trimmed, StringComparison.OrdinalIgnoreCase))) { - return Result.Fail(MonitorErrors.NameConflict, $"a probe named {trimmed} already exists"); + return Result.Fail(MoShiroErrors.NameConflict, $"a probe named {trimmed} already exists"); } await _probes.SaveAsync(probe with { Name = trimmed }, ct); @@ -103,12 +103,12 @@ public sealed partial class ProbeService { if (await _probes.GetAsync(id, ct) is not { } probe) { - return Result.Fail(MonitorErrors.ProbeNotFound, "probe not found"); + return Result.Fail(MoShiroErrors.ProbeNotFound, "probe not found"); } if (probe.RevokedAtMs is not null) { - return Result.Fail(MonitorErrors.ProbeRevoked, "a revoked probe cannot get a new key; create a new probe instead"); + return Result.Fail(MoShiroErrors.ProbeRevoked, "a revoked probe cannot get a new key; create a new probe instead"); } using NodeIdentity identity = NodeIdentity.Generate(); @@ -124,7 +124,7 @@ public sealed partial class ProbeService { if (await _probes.GetAsync(id, ct) is null) { - return Result.Fail(MonitorErrors.ProbeNotFound, "probe not found"); + return Result.Fail(MoShiroErrors.ProbeNotFound, "probe not found"); } await _probes.RevokeAsync(id, _time.GetUtcNow().ToUnixTimeMilliseconds(), ct); @@ -151,12 +151,12 @@ public sealed partial class ProbeService { if (await _probes.GetAsync(probeId, ct) is null) { - return Result.Fail(MonitorErrors.ProbeNotFound, "probe not found"); + return Result.Fail(MoShiroErrors.ProbeNotFound, "probe not found"); } if (await _agents.GetAsync(agentId, ct) is null) { - return Result.Fail(MonitorErrors.AgentNotFound, "agent not found"); + return Result.Fail(MoShiroErrors.AgentNotFound, "agent not found"); } return await _gateway.DisconnectProbeAsync(agentId, new ProbeId(probeId), ct); diff --git a/backend/src/Monitor.Backend.Application/Analysis/AnalysisScheduler.cs b/backend/src/MoShiro.Backend.Application/Analysis/AnalysisScheduler.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Analysis/AnalysisScheduler.cs rename to backend/src/MoShiro.Backend.Application/Analysis/AnalysisScheduler.cs index e29a1f1..3259509 100644 --- a/backend/src/Monitor.Backend.Application/Analysis/AnalysisScheduler.cs +++ b/backend/src/MoShiro.Backend.Application/Analysis/AnalysisScheduler.cs @@ -1,9 +1,9 @@ using Fleet.Core; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Monitor.Backend.Analysis; +using MoShiro.Backend.Analysis; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 持久路径:分钟窗口就绪(窗口结束 + 宽限,或迟到的块到达)之后从原始块计算 → 写入 metric_1m → 标记降采样脏桶; diff --git a/backend/src/Monitor.Backend.Application/Analysis/MetricRecompute.cs b/backend/src/MoShiro.Backend.Application/Analysis/MetricRecompute.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Analysis/MetricRecompute.cs rename to backend/src/MoShiro.Backend.Application/Analysis/MetricRecompute.cs index 0214343..50893d8 100644 --- a/backend/src/Monitor.Backend.Application/Analysis/MetricRecompute.cs +++ b/backend/src/MoShiro.Backend.Application/Analysis/MetricRecompute.cs @@ -1,9 +1,9 @@ using Fleet.Core; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Monitor.Backend.Analysis; +using MoShiro.Backend.Analysis; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record RecomputeProgress(string State, IReadOnlyList Metrics, long WindowsDone, long WindowsTotal, long? FromMs, long? ToMs); diff --git a/backend/src/Monitor.Backend.Application/Analysis/WindowComputer.cs b/backend/src/MoShiro.Backend.Application/Analysis/WindowComputer.cs similarity index 95% rename from backend/src/Monitor.Backend.Application/Analysis/WindowComputer.cs rename to backend/src/MoShiro.Backend.Application/Analysis/WindowComputer.cs index f5328f2..0d33caa 100644 --- a/backend/src/Monitor.Backend.Application/Analysis/WindowComputer.cs +++ b/backend/src/MoShiro.Backend.Application/Analysis/WindowComputer.cs @@ -1,8 +1,8 @@ using Fleet.Core; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 从原始块重新计算一个窗口(持久路径与回填共用):读取与窗口重叠的块 → 评估 → 取出窗口对应的累加器。 diff --git a/backend/src/Monitor.Backend.Application/ApplicationServiceCollectionExtensions.cs b/backend/src/MoShiro.Backend.Application/ApplicationServiceCollectionExtensions.cs similarity index 91% rename from backend/src/Monitor.Backend.Application/ApplicationServiceCollectionExtensions.cs rename to backend/src/MoShiro.Backend.Application/ApplicationServiceCollectionExtensions.cs index 2ad95a9..569f932 100644 --- a/backend/src/Monitor.Backend.Application/ApplicationServiceCollectionExtensions.cs +++ b/backend/src/MoShiro.Backend.Application/ApplicationServiceCollectionExtensions.cs @@ -2,7 +2,7 @@ using Fleet.Server; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public static class ApplicationServiceCollectionExtensions { @@ -10,7 +10,7 @@ public static class ApplicationServiceCollectionExtensions /// 注册 Application 层的全部服务。需要事先注册端口的实现(存储、)和 。 /// 后台任务按这里的顺序启动: 必须在最前面。 /// - public static IServiceCollection AddMonitorApplication(this IServiceCollection services, BackendOptions options) + public static IServiceCollection AddMoShiroApplication(this IServiceCollection services, BackendOptions options) { services.AddSingleton(options); services.AddHostedService(); @@ -47,8 +47,8 @@ public static class ApplicationServiceCollectionExtensions services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddHostedService(provider => provider.GetRequiredService()); diff --git a/backend/src/Monitor.Backend.Application/Auth/AuthModels.cs b/backend/src/MoShiro.Backend.Application/Auth/AuthModels.cs similarity index 96% rename from backend/src/Monitor.Backend.Application/Auth/AuthModels.cs rename to backend/src/MoShiro.Backend.Application/Auth/AuthModels.cs index 9caf89d..9f438c5 100644 --- a/backend/src/Monitor.Backend.Application/Auth/AuthModels.cs +++ b/backend/src/MoShiro.Backend.Application/Auth/AuthModels.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public enum PrincipalKind { diff --git a/backend/src/Monitor.Backend.Application/Auth/AuthService.cs b/backend/src/MoShiro.Backend.Application/Auth/AuthService.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Auth/AuthService.cs rename to backend/src/MoShiro.Backend.Application/Auth/AuthService.cs index 81e4086..30cad19 100644 --- a/backend/src/Monitor.Backend.Application/Auth/AuthService.cs +++ b/backend/src/MoShiro.Backend.Application/Auth/AuthService.cs @@ -2,9 +2,9 @@ using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 面板用户、Cookie 会话、API 令牌。密码用 PBKDF2-SHA256,令牌和会话只保存 SHA-256。 public sealed partial class AuthService @@ -34,7 +34,7 @@ public sealed partial class AuthService byte[] hash = Hash(password, salt, iterations); if (user is null || !CryptographicOperations.FixedTimeEquals(hash, user.PasswordHash)) { - return Result.Fail(MonitorErrors.Unauthorized, "invalid credentials"); + return Result.Fail(MoShiroErrors.Unauthorized, "invalid credentials"); } byte[] token = RandomNumberGenerator.GetBytes(32); @@ -111,7 +111,7 @@ public sealed partial class AuthService var user = new UserRecord(Ulid.NewPrefixed("usr", _time), username, Hash(password, salt, _options.Pbkdf2Iterations), salt, _options.Pbkdf2Iterations, _time.GetUtcNow().ToUnixTimeMilliseconds()); return await _store.CreateUserAsync(user, ct) ? Result.Ok(user) - : Result.Fail(MonitorErrors.NameConflict, "username already exists"); + : Result.Fail(MoShiroErrors.NameConflict, "username already exists"); } public async ValueTask> ChangePasswordAsync(string userId, string newPassword, CancellationToken ct) diff --git a/backend/src/Monitor.Backend.Application/Auth/LoginRateLimiter.cs b/backend/src/MoShiro.Backend.Application/Auth/LoginRateLimiter.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Auth/LoginRateLimiter.cs rename to backend/src/MoShiro.Backend.Application/Auth/LoginRateLimiter.cs index 134cce6..ca7fede 100644 --- a/backend/src/Monitor.Backend.Application/Auth/LoginRateLimiter.cs +++ b/backend/src/MoShiro.Backend.Application/Auth/LoginRateLimiter.cs @@ -1,6 +1,6 @@ using System.Collections.Concurrent; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 登录限流:每个来源在滑动的一分钟内最多尝试若干次。 public sealed class LoginRateLimiter diff --git a/backend/src/Monitor.Backend.Application/BackendCounters.cs b/backend/src/MoShiro.Backend.Application/BackendCounters.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/BackendCounters.cs rename to backend/src/MoShiro.Backend.Application/BackendCounters.cs index 032831f..28c1036 100644 --- a/backend/src/Monitor.Backend.Application/BackendCounters.cs +++ b/backend/src/MoShiro.Backend.Application/BackendCounters.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 进程内计数器,用于 /metrics(Prometheus 格式)。 public sealed class BackendCounters diff --git a/backend/src/Monitor.Backend.Application/BackendOptions.cs b/backend/src/MoShiro.Backend.Application/BackendOptions.cs similarity index 96% rename from backend/src/Monitor.Backend.Application/BackendOptions.cs rename to backend/src/MoShiro.Backend.Application/BackendOptions.cs index f38727d..4fb34a2 100644 --- a/backend/src/Monitor.Backend.Application/BackendOptions.cs +++ b/backend/src/MoShiro.Backend.Application/BackendOptions.cs @@ -1,9 +1,9 @@ -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// Backend 的可调参数(保留期等也可以通过 settings 改,这里是默认值与硬上限)。 public sealed class BackendOptions { - /// 数据目录:monitor.db 与 raw/。 + /// 数据目录:moshiro.db 与 raw/。 public string DataDirectory { get; set; } = "data"; /// 面板的对外地址(用于生成安装命令)。 diff --git a/backend/src/Monitor.Backend.Application/Ingest/IngestService.cs b/backend/src/MoShiro.Backend.Application/Ingest/IngestService.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Ingest/IngestService.cs rename to backend/src/MoShiro.Backend.Application/Ingest/IngestService.cs index 4bbc381..5b6b8ae 100644 --- a/backend/src/Monitor.Backend.Application/Ingest/IngestService.cs +++ b/backend/src/MoShiro.Backend.Application/Ingest/IngestService.cs @@ -1,9 +1,9 @@ using Fleet.Core; using Microsoft.Extensions.Logging; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 和 都会让节点把消息从发件箱里移除。 diff --git a/backend/src/Monitor.Backend.Application/Live/HotLayer.cs b/backend/src/MoShiro.Backend.Application/Live/HotLayer.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Live/HotLayer.cs rename to backend/src/MoShiro.Backend.Application/Live/HotLayer.cs index 2b921b7..747cf7d 100644 --- a/backend/src/Monitor.Backend.Application/Live/HotLayer.cs +++ b/backend/src/MoShiro.Backend.Application/Live/HotLayer.cs @@ -1,9 +1,9 @@ using System.Collections.Concurrent; using Fleet.Core; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 1 秒精度的内存热层:最近 1 小时的累加器。桶以 编码后的字节保存, diff --git a/backend/src/Monitor.Backend.Application/Live/HotLayerBackfill.cs b/backend/src/MoShiro.Backend.Application/Live/HotLayerBackfill.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Live/HotLayerBackfill.cs rename to backend/src/MoShiro.Backend.Application/Live/HotLayerBackfill.cs index 73dd177..917509c 100644 --- a/backend/src/Monitor.Backend.Application/Live/HotLayerBackfill.cs +++ b/backend/src/MoShiro.Backend.Application/Live/HotLayerBackfill.cs @@ -1,9 +1,9 @@ using Fleet.Core; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 重启后热层为空:从原始块回填最近 1 小时(低优先级、逐块让出)。完成之前查询规划器不会选用热层。 public sealed partial class HotLayerBackfill : BackgroundService diff --git a/backend/src/Monitor.Backend.Application/Live/LiveHub.cs b/backend/src/MoShiro.Backend.Application/Live/LiveHub.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Live/LiveHub.cs rename to backend/src/MoShiro.Backend.Application/Live/LiveHub.cs index f0dc7cc..7f5a1d2 100644 --- a/backend/src/Monitor.Backend.Application/Live/LiveHub.cs +++ b/backend/src/MoShiro.Backend.Application/Live/LiveHub.cs @@ -1,9 +1,9 @@ using System.Collections.Concurrent; using System.Threading.Channels; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 发布到 SSE 订阅者的信号。SSE 只负责“更快地获得变化”,推送的内容都能由 REST 查询重建。 public abstract record LiveSignal; diff --git a/backend/src/Monitor.Backend.Application/Monitor.Backend.Application.csproj b/backend/src/MoShiro.Backend.Application/MoShiro.Backend.Application.csproj similarity index 81% rename from backend/src/Monitor.Backend.Application/Monitor.Backend.Application.csproj rename to backend/src/MoShiro.Backend.Application/MoShiro.Backend.Application.csproj index 611afa2..02dcdf9 100644 --- a/backend/src/Monitor.Backend.Application/Monitor.Backend.Application.csproj +++ b/backend/src/MoShiro.Backend.Application/MoShiro.Backend.Application.csproj @@ -4,7 +4,7 @@ - + diff --git a/backend/src/Monitor.Backend.Application/Models/AgentModels.cs b/backend/src/MoShiro.Backend.Application/Models/AgentModels.cs similarity index 94% rename from backend/src/Monitor.Backend.Application/Models/AgentModels.cs rename to backend/src/MoShiro.Backend.Application/Models/AgentModels.cs index 2b7dd90..b44c53e 100644 --- a/backend/src/Monitor.Backend.Application/Models/AgentModels.cs +++ b/backend/src/MoShiro.Backend.Application/Models/AgentModels.cs @@ -1,7 +1,7 @@ using Fleet.Core; using Fleet.Server; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record AgentRecord( NodeId Id, @@ -45,7 +45,7 @@ public sealed record AgentHello( int? ProbeTcpPort, IReadOnlyList? ProbeUdpPorts); -/// 注册之后 Monitor 的补充:公开地址和端口。 +/// 注册之后 MoShiro 的补充:公开地址和端口。 public sealed record AgentEnrollment(string PublicHost, int ProbeTcpPort, IReadOnlyList ProbeUdpPorts, IReadOnlyList Kinds); public sealed record JoinTokenInfo( diff --git a/backend/src/Monitor.Backend.Application/Models/RawModels.cs b/backend/src/MoShiro.Backend.Application/Models/RawModels.cs similarity index 96% rename from backend/src/Monitor.Backend.Application/Models/RawModels.cs rename to backend/src/MoShiro.Backend.Application/Models/RawModels.cs index 4f2be36..52f133b 100644 --- a/backend/src/Monitor.Backend.Application/Models/RawModels.cs +++ b/backend/src/MoShiro.Backend.Application/Models/RawModels.cs @@ -1,7 +1,7 @@ using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 原始块的索引信息(块本身在段文件里)。 public sealed record RawChunkMeta( diff --git a/backend/src/Monitor.Backend.Application/Models/TaskAndTestModels.cs b/backend/src/MoShiro.Backend.Application/Models/TaskAndTestModels.cs similarity index 93% rename from backend/src/Monitor.Backend.Application/Models/TaskAndTestModels.cs rename to backend/src/MoShiro.Backend.Application/Models/TaskAndTestModels.cs index 7e732a1..6502332 100644 --- a/backend/src/Monitor.Backend.Application/Models/TaskAndTestModels.cs +++ b/backend/src/MoShiro.Backend.Application/Models/TaskAndTestModels.cs @@ -1,8 +1,8 @@ using System.Text.Json; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record TaskRecord( TaskId Id, diff --git a/backend/src/Monitor.Backend.Application/Nodes/IspClassifier.cs b/backend/src/MoShiro.Backend.Application/Nodes/IspClassifier.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Nodes/IspClassifier.cs rename to backend/src/MoShiro.Backend.Application/Nodes/IspClassifier.cs index 46205d9..c0c45c4 100644 --- a/backend/src/Monitor.Backend.Application/Nodes/IspClassifier.cs +++ b/backend/src/MoShiro.Backend.Application/Nodes/IspClassifier.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 把「ASN 和组织名」归成几个常见的国内运营商:mobile / telecom / unicom / broadnet;别的是 other(显示组织名)。 diff --git a/backend/src/Monitor.Backend.Application/Nodes/NodeInfo.cs b/backend/src/MoShiro.Backend.Application/Nodes/NodeInfo.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Nodes/NodeInfo.cs rename to backend/src/MoShiro.Backend.Application/Nodes/NodeInfo.cs index b5212d1..af23b65 100644 --- a/backend/src/Monitor.Backend.Application/Nodes/NodeInfo.cs +++ b/backend/src/MoShiro.Backend.Application/Nodes/NodeInfo.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 一个节点(Agent 或 Probe)用来展示的信息:系统和架构、国家、运营商,以及它自己上报的构建信息(版本、tag、提交、构建时间)。 diff --git a/backend/src/Monitor.Backend.Application/Nodes/NodeInfoService.cs b/backend/src/MoShiro.Backend.Application/Nodes/NodeInfoService.cs similarity index 99% rename from backend/src/Monitor.Backend.Application/Nodes/NodeInfoService.cs rename to backend/src/MoShiro.Backend.Application/Nodes/NodeInfoService.cs index 9a9d3ea..09930ab 100644 --- a/backend/src/Monitor.Backend.Application/Nodes/NodeInfoService.cs +++ b/backend/src/MoShiro.Backend.Application/Nodes/NodeInfoService.cs @@ -1,9 +1,9 @@ using System.Collections.Concurrent; using System.Net; using System.Net.Sockets; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 节点的展示信息:系统和架构(节点自报),国家和运营商(Backend 用节点的来源地址查一次)。 diff --git a/backend/src/Monitor.Backend.Application/Ports/IAgentGateway.cs b/backend/src/MoShiro.Backend.Application/Ports/IAgentGateway.cs similarity index 96% rename from backend/src/Monitor.Backend.Application/Ports/IAgentGateway.cs rename to backend/src/MoShiro.Backend.Application/Ports/IAgentGateway.cs index a022297..ed855df 100644 --- a/backend/src/Monitor.Backend.Application/Ports/IAgentGateway.cs +++ b/backend/src/MoShiro.Backend.Application/Ports/IAgentGateway.cs @@ -1,7 +1,7 @@ using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// Application 通往 Agent 连接的端口(由 Gateway 实现):下发状态变化、发起按需测试。 diff --git a/backend/src/Monitor.Backend.Application/Ports/IAuthStore.cs b/backend/src/MoShiro.Backend.Application/Ports/IAuthStore.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Ports/IAuthStore.cs rename to backend/src/MoShiro.Backend.Application/Ports/IAuthStore.cs index 02c7e35..235dcf3 100644 --- a/backend/src/Monitor.Backend.Application/Ports/IAuthStore.cs +++ b/backend/src/MoShiro.Backend.Application/Ports/IAuthStore.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record UserRecord(string Id, string Username, byte[] PasswordHash, byte[] PasswordSalt, int Iterations, long CreatedAtMs); diff --git a/backend/src/Monitor.Backend.Application/Ports/StorePorts.cs b/backend/src/MoShiro.Backend.Application/Ports/StorePorts.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Ports/StorePorts.cs rename to backend/src/MoShiro.Backend.Application/Ports/StorePorts.cs index b600021..a126798 100644 --- a/backend/src/Monitor.Backend.Application/Ports/StorePorts.cs +++ b/backend/src/MoShiro.Backend.Application/Ports/StorePorts.cs @@ -1,8 +1,8 @@ using Fleet.Core; using Fleet.Server; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public interface IAgentStore { @@ -137,7 +137,7 @@ public interface IEventStore /// 主机资源占用的历史:每个 Agent 每分钟一个样本。 public interface IHostStore { - ValueTask SaveAsync(NodeId agent, long minuteMs, Monitor.Protocol.HostSnapshot snapshot, CancellationToken ct); + ValueTask SaveAsync(NodeId agent, long minuteMs, MoShiro.Protocol.HostSnapshot snapshot, CancellationToken ct); ValueTask> ReadAsync(NodeId agent, long fromMs, long toMs, CancellationToken ct); diff --git a/backend/src/Monitor.Backend.Application/Query/Bucketing.cs b/backend/src/MoShiro.Backend.Application/Query/Bucketing.cs similarity index 96% rename from backend/src/Monitor.Backend.Application/Query/Bucketing.cs rename to backend/src/MoShiro.Backend.Application/Query/Bucketing.cs index b959fd3..0eaae6d 100644 --- a/backend/src/Monitor.Backend.Application/Query/Bucketing.cs +++ b/backend/src/MoShiro.Backend.Application/Query/Bucketing.cs @@ -1,6 +1,6 @@ -using Monitor.Backend.Analysis; +using MoShiro.Backend.Analysis; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 把源行合并成查询步长的桶:计数相加、直方图逐桶相加,所以结果是精确的,不是各点的平均。 public sealed class BucketedRows diff --git a/backend/src/Monitor.Backend.Application/Query/Lines.cs b/backend/src/MoShiro.Backend.Application/Query/Lines.cs similarity index 92% rename from backend/src/Monitor.Backend.Application/Query/Lines.cs rename to backend/src/MoShiro.Backend.Application/Query/Lines.cs index 53240c1..8c07a0b 100644 --- a/backend/src/Monitor.Backend.Application/Query/Lines.cs +++ b/backend/src/MoShiro.Backend.Application/Query/Lines.cs @@ -1,7 +1,7 @@ using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 一条线路 = 一对(Agent,Probe)。存储里它的序列是 line:<probe_id>,对外的 id 是 <agent_id>~<probe_id>。 public readonly record struct LineKey(NodeId Agent, ProbeId Probe) @@ -68,7 +68,7 @@ public sealed class LineService { if (!LineKey.TryParse(id, out LineKey key)) { - return Result.Fail(MonitorErrors.AgentNotFound, "line not found"); + return Result.Fail(MoShiroErrors.AgentNotFound, "line not found"); } agentPart = key.Agent.Value; @@ -78,7 +78,7 @@ public sealed class LineService AgentView? agent = await _agents.GetAsync(new NodeId(agentPart), ct); if (agent is null) { - return Result.Fail(MonitorErrors.AgentNotFound, "line not found"); + return Result.Fail(MoShiroErrors.AgentNotFound, "line not found"); } IReadOnlyList probes = await _probes.ListAsync(ct); @@ -88,7 +88,7 @@ public sealed class LineService probe = probes.FirstOrDefault(p => p.Id == probePart); if (probe is null) { - return Result.Fail(MonitorErrors.ProbeNotFound, "probe not found"); + return Result.Fail(MoShiroErrors.ProbeNotFound, "probe not found"); } } else @@ -96,7 +96,7 @@ public sealed class LineService ProbeRecord[] active = [.. probes.Where(p => p.RevokedAtMs is null)]; if (active.Length != 1) { - return Result.Fail(MonitorErrors.ProbeRequired, active.Length == 0 ? "there is no active probe" : "several probes exist: use ~ as the line id"); + return Result.Fail(MoShiroErrors.ProbeRequired, active.Length == 0 ? "there is no active probe" : "several probes exist: use ~ as the line id"); } probe = active[0]; diff --git a/backend/src/Monitor.Backend.Application/Query/MetricSelection.cs b/backend/src/MoShiro.Backend.Application/Query/MetricSelection.cs similarity index 89% rename from backend/src/Monitor.Backend.Application/Query/MetricSelection.cs rename to backend/src/MoShiro.Backend.Application/Query/MetricSelection.cs index ca74d91..e3b34f1 100644 --- a/backend/src/Monitor.Backend.Application/Query/MetricSelection.cs +++ b/backend/src/MoShiro.Backend.Application/Query/MetricSelection.cs @@ -1,8 +1,8 @@ using Fleet.Core; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 请求的指标:导出 id(rtt.p95)与评分 id(score.mc)。 public sealed record MetricSelection(IReadOnlyList ExportIds, IReadOnlyList ScoreModelIds) @@ -21,7 +21,7 @@ public sealed record MetricSelection(IReadOnlyList ExportIds, IReadOnlyL PresetDef? preset = MetricRegistry.FindPreset(presetId); if (preset is null) { - return Result.Fail(MonitorErrors.UnknownPreset, $"unknown preset {presetId}"); + return Result.Fail(MoShiroErrors.UnknownPreset, $"unknown preset {presetId}"); } ids.AddRange(preset.MetricIds); @@ -36,7 +36,7 @@ public sealed record MetricSelection(IReadOnlyList ExportIds, IReadOnlyL ids = [.. ids.Distinct(StringComparer.Ordinal)]; if (ids.Count > maxMetrics) { - return Result.Fail(MonitorErrors.TooManyMetrics, $"at most {maxMetrics} metrics per request"); + return Result.Fail(MoShiroErrors.TooManyMetrics, $"at most {maxMetrics} metrics per request"); } var exports = new List(); @@ -48,7 +48,7 @@ public sealed record MetricSelection(IReadOnlyList ExportIds, IReadOnlyL string model = id["score.".Length..]; if (ModelRegistry.Find(model) is null) { - return Result.Fail(MonitorErrors.UnknownMetric, $"unknown metric {id}"); + return Result.Fail(MoShiroErrors.UnknownMetric, $"unknown metric {id}"); } scores.Add(model); @@ -59,7 +59,7 @@ public sealed record MetricSelection(IReadOnlyList ExportIds, IReadOnlyL } else { - return Result.Fail(MonitorErrors.UnknownMetric, $"unknown metric {id}"); + return Result.Fail(MoShiroErrors.UnknownMetric, $"unknown metric {id}"); } } diff --git a/backend/src/Monitor.Backend.Application/Query/QueryResults.cs b/backend/src/MoShiro.Backend.Application/Query/QueryResults.cs similarity index 95% rename from backend/src/Monitor.Backend.Application/Query/QueryResults.cs rename to backend/src/MoShiro.Backend.Application/Query/QueryResults.cs index 996a527..6392195 100644 --- a/backend/src/Monitor.Backend.Application/Query/QueryResults.cs +++ b/backend/src/MoShiro.Backend.Application/Query/QueryResults.cs @@ -1,7 +1,7 @@ using Fleet.Core; -using Monitor.Backend.Analysis; +using MoShiro.Backend.Analysis; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record SummaryResult( IReadOnlyDictionary Values, diff --git a/backend/src/Monitor.Backend.Application/Query/QueryService.cs b/backend/src/MoShiro.Backend.Application/Query/QueryService.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Query/QueryService.cs rename to backend/src/MoShiro.Backend.Application/Query/QueryService.cs index a082026..d484acb 100644 --- a/backend/src/Monitor.Backend.Application/Query/QueryService.cs +++ b/backend/src/MoShiro.Backend.Application/Query/QueryService.cs @@ -1,9 +1,9 @@ using System.Text.Json; using Fleet.Core; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 展示数据查询:任意时间段、自动步长、数据分层与现场合并、精确汇总、列式结果。 @@ -185,7 +185,7 @@ public sealed class QueryService if (!MetricRegistry.TryFindExport(exportId, out _, out _)) { - return Result.Fail(MonitorErrors.UnknownMetric, $"unknown metric {exportId}"); + return Result.Fail(MoShiroErrors.UnknownMetric, $"unknown metric {exportId}"); } Result<(QueryRange Range, SourcePlan Plan)> planned = Plan(request, "1h"); @@ -229,7 +229,7 @@ public sealed class QueryService MetricDef? def = MetricRegistry.Find(metricId); if (def is null || def.Kind != AccKind.Histogram) { - return Result.Fail(MonitorErrors.UnknownMetric, $"{metricId} is not a histogram metric"); + return Result.Fail(MoShiroErrors.UnknownMetric, $"{metricId} is not a histogram metric"); } Result<(QueryRange Range, SourcePlan Plan)> planned = Plan(request, "15m"); @@ -273,7 +273,7 @@ public sealed class QueryService MetricDef? def = MetricRegistry.Find(metricId); if (def is null || def.Kind != AccKind.Histogram) { - return Result.Fail(MonitorErrors.UnknownMetric, $"{metricId} is not a histogram metric"); + return Result.Fail(MoShiroErrors.UnknownMetric, $"{metricId} is not a histogram metric"); } Result<(QueryRange Range, SourcePlan Plan)> planned = Plan(request, "6h"); diff --git a/backend/src/Monitor.Backend.Application/Query/RangeResolver.cs b/backend/src/MoShiro.Backend.Application/Query/RangeResolver.cs similarity index 92% rename from backend/src/Monitor.Backend.Application/Query/RangeResolver.cs rename to backend/src/MoShiro.Backend.Application/Query/RangeResolver.cs index b5a0558..68e0921 100644 --- a/backend/src/Monitor.Backend.Application/Query/RangeResolver.cs +++ b/backend/src/MoShiro.Backend.Application/Query/RangeResolver.cs @@ -1,9 +1,9 @@ using System.Globalization; using System.Text.RegularExpressions; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// now(默认)或 latest:相对时间段(range=)以当前时间还是以这条线路最后一个样本为终点。后者让离线的线路显示它最后一段数据,而不是空图。 public sealed record RangeRequest(string? Range, DateTimeOffset? From, DateTimeOffset? To, string? Step, string? TimeZone, string? Anchor = null); @@ -63,7 +63,7 @@ public sealed partial class RangeResolver { if (!TryParseSpan(request.Range ?? defaultRange, out long span)) { - return Result.Fail(MonitorErrors.InvalidRange, "range must look like 5m, 6h or 7d"); + return Result.Fail(MoShiroErrors.InvalidRange, "range must look like 5m, 6h or 7d"); } to = nowMs; @@ -73,12 +73,12 @@ public sealed partial class RangeResolver if (from >= to) { - return Result.Fail(MonitorErrors.InvalidRange, "from must be earlier than to"); + return Result.Fail(MoShiroErrors.InvalidRange, "from must be earlier than to"); } if (to - from > MaxSpanMs) { - return Result.Fail(MonitorErrors.RangeTooLarge, "the range is longer than 400 days"); + return Result.Fail(MoShiroErrors.RangeTooLarge, "the range is longer than 400 days"); } long step; @@ -88,14 +88,14 @@ public sealed partial class RangeResolver } else if (!Steps.TryParse(request.Step, out step)) { - return Result.Fail(MonitorErrors.InvalidStep, "step must be one of: " + string.Join(", ", Steps.Common.Select(Steps.Format))); + return Result.Fail(MoShiroErrors.InvalidStep, "step must be one of: " + string.Join(", ", Steps.Common.Select(Steps.Format))); } var range = new QueryRange(Steps.FloorTo(from, step), Steps.CeilTo(to, step), step, relative, from, to); if (range.Points > _options.MaxPointsPerSeries) { long suggested = Steps.Common.FirstOrDefault(s => (Steps.CeilTo(to, s) - Steps.FloorTo(from, s)) / s <= _options.MaxPointsPerSeries, Steps.Day); - return Result.Fail(MonitorErrors.RangeTooLarge, $"{range.Points} points exceed the limit of {_options.MaxPointsPerSeries}; use step={Steps.Format(suggested)} or a shorter range"); + return Result.Fail(MoShiroErrors.RangeTooLarge, $"{range.Points} points exceed the limit of {_options.MaxPointsPerSeries}; use step={Steps.Format(suggested)} or a shorter range"); } return Result.Ok(range); diff --git a/backend/src/Monitor.Backend.Application/Query/RowLoader.cs b/backend/src/MoShiro.Backend.Application/Query/RowLoader.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Query/RowLoader.cs rename to backend/src/MoShiro.Backend.Application/Query/RowLoader.cs index e9f397e..4f29b51 100644 --- a/backend/src/Monitor.Backend.Application/Query/RowLoader.cs +++ b/backend/src/MoShiro.Backend.Application/Query/RowLoader.cs @@ -1,8 +1,8 @@ using Fleet.Core; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public readonly record struct SourceRow(long Start, MetricSet Set, bool Partial); @@ -92,7 +92,7 @@ public sealed class RowLoader case DataSource.Raw: if (!_gate.TryEnter()) { - return Result>.Fail(MonitorErrors.TooManyRequests, "too many queries are reading raw data; retry shortly or use a coarser step"); + return Result>.Fail(MoShiroErrors.TooManyRequests, "too many queries are reading raw data; retry shortly or use a coarser step"); } try diff --git a/backend/src/Monitor.Backend.Application/Query/SourcePlanner.cs b/backend/src/MoShiro.Backend.Application/Query/SourcePlanner.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Query/SourcePlanner.cs rename to backend/src/MoShiro.Backend.Application/Query/SourcePlanner.cs index 4e3df11..4e4de46 100644 --- a/backend/src/Monitor.Backend.Application/Query/SourcePlanner.cs +++ b/backend/src/MoShiro.Backend.Application/Query/SourcePlanner.cs @@ -1,4 +1,4 @@ -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public enum DataSource { diff --git a/backend/src/Monitor.Backend.Application/Query/Steps.cs b/backend/src/MoShiro.Backend.Application/Query/Steps.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Query/Steps.cs rename to backend/src/MoShiro.Backend.Application/Query/Steps.cs index b1830f1..a0f250e 100644 --- a/backend/src/Monitor.Backend.Application/Query/Steps.cs +++ b/backend/src/MoShiro.Backend.Application/Query/Steps.cs @@ -1,6 +1,6 @@ using System.Globalization; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 常用步长:1s 2s 5s 10s 15s 30s 1m 2m 5m 10m 15m 30m 1h 2h 3h 6h 12h 1d。 public static class Steps diff --git a/backend/src/Monitor.Backend.Application/Retention/RetentionService.cs b/backend/src/MoShiro.Backend.Application/Retention/RetentionService.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Retention/RetentionService.cs rename to backend/src/MoShiro.Backend.Application/Retention/RetentionService.cs index 2b2db9c..85448fb 100644 --- a/backend/src/Monitor.Backend.Application/Retention/RetentionService.cs +++ b/backend/src/MoShiro.Backend.Application/Retention/RetentionService.cs @@ -1,7 +1,7 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 保留清理:原始段文件(持续任务与按需测试保留期不同)、各层指标、事件。保留期来自 settings,可以在线修改。 public sealed partial class RetentionService : BackgroundService diff --git a/backend/src/Monitor.Backend.Application/StartupTasks.cs b/backend/src/MoShiro.Backend.Application/StartupTasks.cs similarity index 96% rename from backend/src/Monitor.Backend.Application/StartupTasks.cs rename to backend/src/MoShiro.Backend.Application/StartupTasks.cs index 318fe29..3716e30 100644 --- a/backend/src/Monitor.Backend.Application/StartupTasks.cs +++ b/backend/src/MoShiro.Backend.Application/StartupTasks.cs @@ -1,6 +1,6 @@ using Microsoft.Extensions.Hosting; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 启动时最先执行:截断没有索引记录的段文件尾部、创建初始管理员、创建默认的线路任务模板。 diff --git a/backend/src/Monitor.Backend.Application/Tasks/EffectiveTasks.cs b/backend/src/MoShiro.Backend.Application/Tasks/EffectiveTasks.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Tasks/EffectiveTasks.cs rename to backend/src/MoShiro.Backend.Application/Tasks/EffectiveTasks.cs index 504ce09..ae996ef 100644 --- a/backend/src/Monitor.Backend.Application/Tasks/EffectiveTasks.cs +++ b/backend/src/MoShiro.Backend.Application/Tasks/EffectiveTasks.cs @@ -1,7 +1,7 @@ using System.Text.Json; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record EffectiveTask( TaskId Id, diff --git a/backend/src/Monitor.Backend.Application/Tasks/TaskPlanner.cs b/backend/src/MoShiro.Backend.Application/Tasks/TaskPlanner.cs similarity index 96% rename from backend/src/Monitor.Backend.Application/Tasks/TaskPlanner.cs rename to backend/src/MoShiro.Backend.Application/Tasks/TaskPlanner.cs index 526bb98..8a21a96 100644 --- a/backend/src/Monitor.Backend.Application/Tasks/TaskPlanner.cs +++ b/backend/src/MoShiro.Backend.Application/Tasks/TaskPlanner.cs @@ -2,9 +2,9 @@ using System.Security.Cryptography; using System.Text.Json; using Fleet.Core; using Fleet.Server; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record DesiredTaskSet(long Version, TaskSet Document); @@ -65,7 +65,7 @@ public sealed class TaskPlanner : IDisposable document.Peers.Add(new PeerSpec { ProbeId = new ProbeId(probe.Id), PublicKey = Convert.ToBase64String(probe.PublicKey) }); } - string hash = Convert.ToHexStringLower(SHA256.HashData(JsonSerializer.SerializeToUtf8Bytes(document, MonitorJsonContext.Default.TaskSet))); + string hash = Convert.ToHexStringLower(SHA256.HashData(JsonSerializer.SerializeToUtf8Bytes(document, MoShiroJsonContext.Default.TaskSet))); await _gate.WaitAsync(ct); try diff --git a/backend/src/Monitor.Backend.Application/Tasks/TaskService.cs b/backend/src/MoShiro.Backend.Application/Tasks/TaskService.cs similarity index 96% rename from backend/src/Monitor.Backend.Application/Tasks/TaskService.cs rename to backend/src/MoShiro.Backend.Application/Tasks/TaskService.cs index 00547e9..6bafbfd 100644 --- a/backend/src/Monitor.Backend.Application/Tasks/TaskService.cs +++ b/backend/src/MoShiro.Backend.Application/Tasks/TaskService.cs @@ -2,9 +2,9 @@ using System.Net; using System.Text.Json; using Fleet.Core; using Fleet.Server; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record TaskInput( string Scope, @@ -97,7 +97,7 @@ public sealed class TaskService TaskRecord? current = await _tasks.GetAsync(id, ct); if (current is null) { - return Result.Fail(MonitorErrors.TaskNotFound, "task not found"); + return Result.Fail(MoShiroErrors.TaskNotFound, "task not found"); } IReadOnlyDictionary parameters = patch.Params ?? current.Params; @@ -178,7 +178,7 @@ public sealed class TaskService KindSpec? spec = Kinds.Find(kind); if (spec is null) { - return Result.Fail(MonitorErrors.UnknownKind, $"unknown kind {kind}"); + return Result.Fail(MoShiroErrors.UnknownKind, $"unknown kind {kind}"); } Scope wanted = scope == EffectiveTasks.LineScope ? Scope.Line : Scope.Target; @@ -206,7 +206,7 @@ public sealed class TaskService if (agentId is { } id && await _agents.GetAsync(id, ct) is null) { - return Result.Fail(MonitorErrors.AgentNotFound, "agent not found"); + return Result.Fail(MoShiroErrors.AgentNotFound, "agent not found"); } if (scope == EffectiveTasks.TargetScope) @@ -259,7 +259,7 @@ public sealed class TaskService long bits = EffectiveTasks.ContinuousLineBudget(EffectiveTasks.Compute(after, agent with { Kinds = [] }, filterByAgentKinds: false)); if (bits > ProtocolLimits.MaxLineBudgetBitsPerSecond) { - return Result.Fail(MonitorErrors.BudgetExceeded, $"continuous tasks for {agent.Name} would use {bits / 1000} kbps (limit {ProtocolLimits.MaxLineBudgetBitsPerSecond / 1000} kbps)"); + return Result.Fail(MoShiroErrors.BudgetExceeded, $"continuous tasks for {agent.Name} would use {bits / 1000} kbps (limit {ProtocolLimits.MaxLineBudgetBitsPerSecond / 1000} kbps)"); } } @@ -270,7 +270,7 @@ public sealed class TaskService long bits = EffectiveTasks.ContinuousLineBudget(EffectiveTasks.Compute(after, virtualAgent, filterByAgentKinds: false)); if (bits > ProtocolLimits.MaxLineBudgetBitsPerSecond) { - return Result.Fail(MonitorErrors.BudgetExceeded, $"continuous line templates would use {bits / 1000} kbps (limit {ProtocolLimits.MaxLineBudgetBitsPerSecond / 1000} kbps)"); + return Result.Fail(MoShiroErrors.BudgetExceeded, $"continuous line templates would use {bits / 1000} kbps (limit {ProtocolLimits.MaxLineBudgetBitsPerSecond / 1000} kbps)"); } } diff --git a/backend/src/Monitor.Backend.Application/Tests/Plans.cs b/backend/src/MoShiro.Backend.Application/Tests/Plans.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Tests/Plans.cs rename to backend/src/MoShiro.Backend.Application/Tests/Plans.cs index 31a6a87..2d4d1e1 100644 --- a/backend/src/Monitor.Backend.Application/Tests/Plans.cs +++ b/backend/src/MoShiro.Backend.Application/Tests/Plans.cs @@ -1,8 +1,8 @@ using System.Text.Json; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed record PhaseSpec(string Kind, IReadOnlyDictionary Overrides, int DurationSeconds); diff --git a/backend/src/Monitor.Backend.Application/Tests/TestFinalizer.cs b/backend/src/MoShiro.Backend.Application/Tests/TestFinalizer.cs similarity index 97% rename from backend/src/Monitor.Backend.Application/Tests/TestFinalizer.cs rename to backend/src/MoShiro.Backend.Application/Tests/TestFinalizer.cs index c095a2d..def6e09 100644 --- a/backend/src/Monitor.Backend.Application/Tests/TestFinalizer.cs +++ b/backend/src/MoShiro.Backend.Application/Tests/TestFinalizer.cs @@ -1,10 +1,10 @@ using Fleet.Core; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// /// 后台任务:给已成功结束的测试算结果(所有阶段的块到达之后,或结束一分钟后以现有的块为准), diff --git a/backend/src/Monitor.Backend.Application/Tests/TestModels.cs b/backend/src/MoShiro.Backend.Application/Tests/TestModels.cs similarity index 94% rename from backend/src/Monitor.Backend.Application/Tests/TestModels.cs rename to backend/src/MoShiro.Backend.Application/Tests/TestModels.cs index c983179..e41669c 100644 --- a/backend/src/Monitor.Backend.Application/Tests/TestModels.cs +++ b/backend/src/MoShiro.Backend.Application/Tests/TestModels.cs @@ -1,8 +1,8 @@ using System.Text.Json; using System.Text.Json.Serialization; -using Monitor.Backend.Analysis; +using MoShiro.Backend.Analysis; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; public sealed class StoredTestMetrics { diff --git a/backend/src/Monitor.Backend.Application/Tests/TestService.cs b/backend/src/MoShiro.Backend.Application/Tests/TestService.cs similarity index 94% rename from backend/src/Monitor.Backend.Application/Tests/TestService.cs rename to backend/src/MoShiro.Backend.Application/Tests/TestService.cs index d0dfaad..b0af831 100644 --- a/backend/src/Monitor.Backend.Application/Tests/TestService.cs +++ b/backend/src/MoShiro.Backend.Application/Tests/TestService.cs @@ -1,10 +1,10 @@ using System.Text.Json; using Fleet.Core; using Fleet.Server; -using Monitor.Backend.Analysis; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 按需测试(once):校验与排队、下发给 Agent、状态更新、结果查询。 public sealed class TestService @@ -33,18 +33,18 @@ public sealed class TestService PlanSpec? plan = Plans.Find(request.Plan); if (plan is null) { - return Result.Fail(MonitorErrors.UnknownPlan, $"unknown plan {request.Plan}"); + return Result.Fail(MoShiroErrors.UnknownPlan, $"unknown plan {request.Plan}"); } AgentRecord? agent = await _agents.GetAsync(agentId, ct); if (agent is null) { - return Result.Fail(MonitorErrors.AgentNotFound, "agent not found"); + return Result.Fail(MoShiroErrors.AgentNotFound, "agent not found"); } if (agent.Status != NodeStatus.Active) { - return Result.Fail(MonitorErrors.AgentNotActive, "agent is not active"); + return Result.Fail(MoShiroErrors.AgentNotActive, "agent is not active"); } // Agent 在 hello 里声明了它支持的采集方法:方案里有它不支持的就不下发(否则要等到阶段开始才失败) @@ -62,17 +62,17 @@ public sealed class TestService if (!_gateway.IsOnline(agentId)) { - return Result.Fail(MonitorErrors.AgentOffline, "agent is offline"); + return Result.Fail(MoShiroErrors.AgentOffline, "agent is offline"); } if (!(_runtime.TryGet(agentId, out AgentRuntimeState? state) && state.IsConnected(probeId.Value))) { - return Result.Fail(MonitorErrors.ProbeOffline, $"probe {probeId.Value} has no session with this agent"); + return Result.Fail(MoShiroErrors.ProbeOffline, $"probe {probeId.Value} has no session with this agent"); } if (await _tests.HasActiveAsync(agentId, probeId, ct)) { - return Result.Fail(MonitorErrors.TestBusy, "another test is already running on this line"); + return Result.Fail(MoShiroErrors.TestBusy, "another test is already running on this line"); } var testId = new TestId(Ulid.NewPrefixed(TestId.Prefix, _time)); @@ -96,7 +96,7 @@ public sealed class TestService TestRecord? test = await _tests.GetAsync(id, ct); if (test is null) { - return Result.Fail(MonitorErrors.TestNotFound, "test not found"); + return Result.Fail(MoShiroErrors.TestNotFound, "test not found"); } if (IsTerminal(test.Status)) @@ -115,7 +115,7 @@ public sealed class TestService return Result.Ok(await _tests.GetAsync(id, ct) ?? test); } - /// monitor.test.status:只接受该测试所属 Agent 的汇报。 + /// moshiro.test.status:只接受该测试所属 Agent 的汇报。 public async ValueTask OnStatusAsync(NodeId agent, TestStatusParams status, CancellationToken ct) { TestRecord? test = await _tests.GetAsync(status.TestId, ct); @@ -244,7 +244,7 @@ public sealed class TestService long bits = kind.BudgetBitsPerSecond(resolved.Values!); if (limitMbps is > 0 && bits > limitMbps * 1_000_000) { - return Result>.Fail(MonitorErrors.BudgetExceeded, $"{phase.Kind} needs {bits / 1_000_000.0:0.#} Mbit/s but the agent allows {limitMbps} Mbit/s"); + return Result>.Fail(MoShiroErrors.BudgetExceeded, $"{phase.Kind} needs {bits / 1_000_000.0:0.#} Mbit/s but the agent allows {limitMbps} Mbit/s"); } int duration = resolved.Values!.Values.TryGetValue("duration_s", out JsonElement d) && d.TryGetInt64(out long seconds) ? (int)seconds : Math.Max(1, (int)Math.Round(phase.DurationSeconds * phaseScale)); diff --git a/backend/src/Monitor.Backend.Application/Updates/ReleaseService.cs b/backend/src/MoShiro.Backend.Application/Updates/ReleaseService.cs similarity index 98% rename from backend/src/Monitor.Backend.Application/Updates/ReleaseService.cs rename to backend/src/MoShiro.Backend.Application/Updates/ReleaseService.cs index ad1e055..39cc37b 100644 --- a/backend/src/Monitor.Backend.Application/Updates/ReleaseService.cs +++ b/backend/src/MoShiro.Backend.Application/Updates/ReleaseService.cs @@ -3,9 +3,9 @@ using System.Diagnostics.CodeAnalysis; using System.Text.Json; using System.Text.RegularExpressions; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 面板记下的、CI 签名的发布清单(只留每个组件最新的一份)。Manifest 是签名对象的原始文本,面板一个字节也不改。 public sealed record ReleaseOffer(string Component, long Seq, string Tag, string Version, string Digest, string Manifest, string Signature); @@ -42,7 +42,7 @@ public sealed partial class ReleaseService ReleaseOffer? current = await GetAsync(offer.Component, ct); if (current is not null && offer.Seq <= current.Seq) { - return Result.Fail(MonitorErrors.NameConflict, $"a release with seq {current.Seq} or newer is already registered"); + return Result.Fail(MoShiroErrors.NameConflict, $"a release with seq {current.Seq} or newer is already registered"); } await _settings.SetAsync(Key(offer.Component, "manifest"), offer.Manifest, ct); diff --git a/backend/src/Monitor.Backend.Application/ValidationError.cs b/backend/src/MoShiro.Backend.Application/ValidationError.cs similarity index 85% rename from backend/src/Monitor.Backend.Application/ValidationError.cs rename to backend/src/MoShiro.Backend.Application/ValidationError.cs index c1468f9..fb2d2a7 100644 --- a/backend/src/Monitor.Backend.Application/ValidationError.cs +++ b/backend/src/MoShiro.Backend.Application/ValidationError.cs @@ -1,11 +1,11 @@ using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.Backend.Application; +namespace MoShiro.Backend.Application; /// 校验失败,带逐字段的原因(键是 JSON 字段路径)。Api 层把它映射成 problem+json 的 errors。 public sealed record ValidationError(string Message, IReadOnlyDictionary Fields) - : FleetError(MonitorErrors.ValidationFailed, Message) + : FleetError(MoShiroErrors.ValidationFailed, Message) { public static ValidationError Single(string field, string message) => new("Validation failed", new Dictionary { [field] = message }); diff --git a/backend/src/Monitor.Backend.Gateway/ConnectionShutdown.cs b/backend/src/MoShiro.Backend.Gateway/ConnectionShutdown.cs similarity index 97% rename from backend/src/Monitor.Backend.Gateway/ConnectionShutdown.cs rename to backend/src/MoShiro.Backend.Gateway/ConnectionShutdown.cs index 83227d4..07a6c56 100644 --- a/backend/src/Monitor.Backend.Gateway/ConnectionShutdown.cs +++ b/backend/src/MoShiro.Backend.Gateway/ConnectionShutdown.cs @@ -2,7 +2,7 @@ using Fleet.Server; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Monitor.Backend.Gateway; +namespace MoShiro.Backend.Gateway; /// /// 宿主开始停止时先关闭所有 Agent 的长连接(Close 握手,不发 revoked:Agent 会重连)。 diff --git a/backend/src/Monitor.Backend.Gateway/FleetGateway.cs b/backend/src/MoShiro.Backend.Gateway/FleetGateway.cs similarity index 72% rename from backend/src/Monitor.Backend.Gateway/FleetGateway.cs rename to backend/src/MoShiro.Backend.Gateway/FleetGateway.cs index 89aaa98..d8fae4d 100644 --- a/backend/src/Monitor.Backend.Gateway/FleetGateway.cs +++ b/backend/src/MoShiro.Backend.Gateway/FleetGateway.cs @@ -1,10 +1,10 @@ using Fleet.Core; using Fleet.Server; using Microsoft.Extensions.DependencyInjection; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Gateway; +namespace MoShiro.Backend.Gateway; /// /// Application 通往 Agent 连接的端口的实现,建立在 Fleet.Server.Link 的在线表之上。 @@ -37,26 +37,26 @@ public sealed class FleetGateway : IAgentGateway public async ValueTask> RunTestAsync(NodeId agent, TestRunParams run, CancellationToken ct) { Result result = await Connections.RequestAsync( - agent, MonitorMethods.TestRun, run, MonitorJsonContext.Default.TestRunParams, MonitorJsonContext.Default.TestRunResult, ct); + agent, MoShiroMethods.TestRun, run, MoShiroJsonContext.Default.TestRunParams, MoShiroJsonContext.Default.TestRunResult, ct); if (!result.TryGet(out TestRunResult? accepted, out FleetError? error)) { - return Result.Fail(error.Code == FleetErrors.NodeOffline ? MonitorErrors.AgentOffline : error.Code, error.Message); + return Result.Fail(error.Code == FleetErrors.NodeOffline ? MoShiroErrors.AgentOffline : error.Code, error.Message); } - return accepted.Accepted ? Result.Ok(true) : Result.Fail(MonitorErrors.TestBusy, "the agent did not accept the test"); + return accepted.Accepted ? Result.Ok(true) : Result.Fail(MoShiroErrors.TestBusy, "the agent did not accept the test"); } public async ValueTask CancelTestAsync(NodeId agent, TestId test, CancellationToken ct) => await Connections.RequestAsync( - agent, MonitorMethods.TestCancel, new TestCancelParams { TestId = test }, MonitorJsonContext.Default.TestCancelParams, MonitorJsonContext.Default.TestRunResult, ct); + agent, MoShiroMethods.TestCancel, new TestCancelParams { TestId = test }, MoShiroJsonContext.Default.TestCancelParams, MoShiroJsonContext.Default.TestRunResult, ct); public async ValueTask> DisconnectProbeAsync(NodeId agent, ProbeId probe, CancellationToken ct) { Result result = await Connections.RequestAsync( - agent, MonitorMethods.ProbeDisconnect, new ProbeDisconnectParams { ProbeId = probe }, MonitorJsonContext.Default.ProbeDisconnectParams, MonitorJsonContext.Default.TestRunResult, ct); + agent, MoShiroMethods.ProbeDisconnect, new ProbeDisconnectParams { ProbeId = probe }, MoShiroJsonContext.Default.ProbeDisconnectParams, MoShiroJsonContext.Default.TestRunResult, ct); if (!result.TryGet(out TestRunResult? done, out FleetError? error)) { - return Result.Fail(error.Code == FleetErrors.NodeOffline ? MonitorErrors.AgentOffline : error.Code, error.Message); + return Result.Fail(error.Code == FleetErrors.NodeOffline ? MoShiroErrors.AgentOffline : error.Code, error.Message); } return Result.Ok(done.Accepted); @@ -65,8 +65,8 @@ public sealed class FleetGateway : IAgentGateway public ValueTask DisconnectAsync(NodeId agent, string reason, CancellationToken ct) => Connections.DisconnectAsync(agent, reason, ct); public async ValueTask NotifyUpdateOfferAsync(NodeId node, string manifest, string signature, CancellationToken ct) => - await Connections.NotifyAsync(node, MonitorMethods.UpdateOffer, new UpdateOfferParams { Manifest = manifest, Signature = signature }, MonitorJsonContext.Default.UpdateOfferParams, ct); + await Connections.NotifyAsync(node, MoShiroMethods.UpdateOffer, new UpdateOfferParams { Manifest = manifest, Signature = signature }, MoShiroJsonContext.Default.UpdateOfferParams, ct); public async ValueTask NotifyUpdateApplyAsync(NodeId node, CancellationToken ct) => - await Connections.NotifyAsync(node, MonitorMethods.UpdateApply, new UpdateOfferParams(), MonitorJsonContext.Default.UpdateOfferParams, ct); + await Connections.NotifyAsync(node, MoShiroMethods.UpdateApply, new UpdateOfferParams(), MoShiroJsonContext.Default.UpdateOfferParams, ct); } diff --git a/backend/src/Monitor.Backend.Gateway/GatewayServiceCollectionExtensions.cs b/backend/src/MoShiro.Backend.Gateway/GatewayServiceCollectionExtensions.cs similarity index 63% rename from backend/src/Monitor.Backend.Gateway/GatewayServiceCollectionExtensions.cs rename to backend/src/MoShiro.Backend.Gateway/GatewayServiceCollectionExtensions.cs index b8701aa..8cdb3ac 100644 --- a/backend/src/Monitor.Backend.Gateway/GatewayServiceCollectionExtensions.cs +++ b/backend/src/MoShiro.Backend.Gateway/GatewayServiceCollectionExtensions.cs @@ -2,18 +2,18 @@ using Fleet.Core; using Fleet.Rpc; using Fleet.Server; using Microsoft.Extensions.DependencyInjection; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Gateway; +namespace MoShiro.Backend.Gateway; public static class GatewayServiceCollectionExtensions { /// - /// 在 Fleet.Server 之上接入 Monitor:期望状态(TaskSet)、RawChunk 收件箱、monitor.* 方法、注册挂钩和节点事件。 - /// 需要事先注册 和 ,并在 AddMonitorApplication 之后调用。 + /// 在 Fleet.Server 之上接入 MoShiro:期望状态(TaskSet)、RawChunk 收件箱、moshiro.* 方法、注册挂钩和节点事件。 + /// 需要事先注册 和 ,并在 AddMoShiroApplication 之后调用。 /// - public static IServiceCollection AddMonitorGateway(this IServiceCollection services) + public static IServiceCollection AddMoShiroGateway(this IServiceCollection services) { services.AddSingleton(); services.AddHostedService(); @@ -22,24 +22,24 @@ public static class GatewayServiceCollectionExtensions .AddState() .AddState() .AddInbox() - .MapMethods(MapMonitorMethods); + .MapMethods(MapMoShiroMethods); return services; } - private static void MapMonitorMethods(RpcRouter router, IServiceProvider services) + private static void MapMoShiroMethods(RpcRouter router, IServiceProvider services) { router .OnNotify( - MonitorMethods.Event, - MonitorJsonContext.Default.AgentEventParams, + MoShiroMethods.Event, + MoShiroJsonContext.Default.AgentEventParams, (context, parameters, ct) => services.GetRequiredService().OnEventAsync(context.Node.Id, parameters, ct)) .OnNotify( - MonitorMethods.Host, - MonitorJsonContext.Default.HostSnapshot, + MoShiroMethods.Host, + MoShiroJsonContext.Default.HostSnapshot, (context, snapshot, ct) => services.GetRequiredService().OnHostAsync(context.Node.Id, snapshot, ct)) .OnNotify( - MonitorMethods.TestStatus, - MonitorJsonContext.Default.TestStatusParams, + MoShiroMethods.TestStatus, + MoShiroJsonContext.Default.TestStatusParams, (context, parameters, ct) => services.GetRequiredService().OnStatusAsync(context.Node.Id, parameters, ct)); } } diff --git a/backend/src/Monitor.Backend.Gateway/Monitor.Backend.Gateway.csproj b/backend/src/MoShiro.Backend.Gateway/MoShiro.Backend.Gateway.csproj similarity index 79% rename from backend/src/Monitor.Backend.Gateway/Monitor.Backend.Gateway.csproj rename to backend/src/MoShiro.Backend.Gateway/MoShiro.Backend.Gateway.csproj index e9f9ceb..d57222a 100644 --- a/backend/src/Monitor.Backend.Gateway/Monitor.Backend.Gateway.csproj +++ b/backend/src/MoShiro.Backend.Gateway/MoShiro.Backend.Gateway.csproj @@ -4,7 +4,7 @@ true - + diff --git a/backend/src/Monitor.Backend.Gateway/ProbeAgentsStateProvider.cs b/backend/src/MoShiro.Backend.Gateway/ProbeAgentsStateProvider.cs similarity index 86% rename from backend/src/Monitor.Backend.Gateway/ProbeAgentsStateProvider.cs rename to backend/src/MoShiro.Backend.Gateway/ProbeAgentsStateProvider.cs index e3f95de..d8f4697 100644 --- a/backend/src/Monitor.Backend.Gateway/ProbeAgentsStateProvider.cs +++ b/backend/src/MoShiro.Backend.Gateway/ProbeAgentsStateProvider.cs @@ -1,10 +1,10 @@ using System.Text.Json; using Fleet.Rpc; using Fleet.Server; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Gateway; +namespace MoShiro.Backend.Gateway; /// 期望状态:为每个 Probe 下发要连接的 Agent 列表(地址、端口、证书指纹)。Agent 集合变化时由 NotifyAllChanged 一起重算推送。 public sealed class ProbeAgentsStateProvider : IStateProvider @@ -26,7 +26,7 @@ public sealed class ProbeAgentsStateProvider : IStateProvider } ProbeAgentList list = await _agents.ProbeAgentsAsync(node.Id.Value, ct); - return new StateDocument(list.Version, JsonSerializer.SerializeToElement(list, MonitorJsonContext.Default.ProbeAgentList)); + return new StateDocument(list.Version, JsonSerializer.SerializeToElement(list, MoShiroJsonContext.Default.ProbeAgentList)); } public ValueTask OnAppliedAsync(NodeRecord node, long version, StateSyncResult result, CancellationToken ct) => ValueTask.CompletedTask; diff --git a/backend/src/Monitor.Backend.Gateway/RawChunkInbox.cs b/backend/src/MoShiro.Backend.Gateway/RawChunkInbox.cs similarity index 84% rename from backend/src/Monitor.Backend.Gateway/RawChunkInbox.cs rename to backend/src/MoShiro.Backend.Gateway/RawChunkInbox.cs index 9aaedc8..5860d9e 100644 --- a/backend/src/Monitor.Backend.Gateway/RawChunkInbox.cs +++ b/backend/src/MoShiro.Backend.Gateway/RawChunkInbox.cs @@ -1,8 +1,8 @@ using Fleet.Server; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Gateway; +namespace MoShiro.Backend.Gateway; /// /// RawChunk 收件箱(二进制通道 16):持久化之后才返回,Fleet 随后才回复 ACK,按 chunk_id 去重。 @@ -17,7 +17,7 @@ public sealed class RawChunkInbox : IInbox _ingest = ingest; } - public byte Channel => MonitorChannels.RawChunk; + public byte Channel => MoShiroChannels.RawChunk; public async ValueTask HandleAsync(NodeRecord node, Guid msgId, ReadOnlyMemory payload, CancellationToken ct) => await _ingest.IngestAsync(node.Id, msgId, payload, ct) switch diff --git a/backend/src/Monitor.Backend.Gateway/TaskSetStateProvider.cs b/backend/src/MoShiro.Backend.Gateway/TaskSetStateProvider.cs similarity index 92% rename from backend/src/Monitor.Backend.Gateway/TaskSetStateProvider.cs rename to backend/src/MoShiro.Backend.Gateway/TaskSetStateProvider.cs index 6f7bfcc..e257f5a 100644 --- a/backend/src/Monitor.Backend.Gateway/TaskSetStateProvider.cs +++ b/backend/src/MoShiro.Backend.Gateway/TaskSetStateProvider.cs @@ -2,10 +2,10 @@ using System.Text.Json; using System.Text.Json.Serialization; using Fleet.Rpc; using Fleet.Server; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Gateway; +namespace MoShiro.Backend.Gateway; /// /// 期望状态:为每个 Agent 下发完整的 快照(有效任务集 + Probe 公钥)。 @@ -32,7 +32,7 @@ public sealed class TaskSetStateProvider : IStateProvider } DesiredTaskSet? desired = await _planner.GetDesiredAsync(node.Id, ct); - return desired is null ? null : new StateDocument(desired.Version, JsonSerializer.SerializeToElement(desired.Document, MonitorJsonContext.Default.TaskSet)); + return desired is null ? null : new StateDocument(desired.Version, JsonSerializer.SerializeToElement(desired.Document, MoShiroJsonContext.Default.TaskSet)); } public async ValueTask OnAppliedAsync(NodeRecord node, long version, StateSyncResult result, CancellationToken ct) diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/Monitor.Backend.Storage.Sqlite.csproj b/backend/src/MoShiro.Backend.Storage.Sqlite/MoShiro.Backend.Storage.Sqlite.csproj similarity index 60% rename from backend/src/Monitor.Backend.Storage.Sqlite/Monitor.Backend.Storage.Sqlite.csproj rename to backend/src/MoShiro.Backend.Storage.Sqlite/MoShiro.Backend.Storage.Sqlite.csproj index 88d4c26..c816f7d 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/Monitor.Backend.Storage.Sqlite.csproj +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/MoShiro.Backend.Storage.Sqlite.csproj @@ -3,10 +3,10 @@ true - + - + diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/Schema.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/Schema.cs similarity index 99% rename from backend/src/Monitor.Backend.Storage.Sqlite/Schema.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/Schema.cs index a1276dd..69b20f4 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/Schema.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/Schema.cs @@ -1,6 +1,6 @@ using Microsoft.Data.Sqlite; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; /// 表结构。版本记录在 PRAGMA user_version;以后的迁移是按版本号追加的内置 SQL。 internal static class Schema diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/Sql.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/Sql.cs similarity index 98% rename from backend/src/Monitor.Backend.Storage.Sqlite/Sql.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/Sql.cs index 6819ac9..d6751c1 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/Sql.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/Sql.cs @@ -1,6 +1,6 @@ using Microsoft.Data.Sqlite; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; /// 手写的参数化 SQL 的小帮手:禁止字符串拼接值,所有值都经过参数。 internal static class Sql diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteAgentStore.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteAgentStore.cs similarity index 94% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteAgentStore.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteAgentStore.cs index 9685b25..1774315 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteAgentStore.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteAgentStore.cs @@ -1,14 +1,14 @@ using Fleet.Core; using Fleet.Server; using Microsoft.Data.Sqlite; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; /// -/// Agent 表同时是 Fleet 的节点表:实现 (Monitor 的视图)和 (注册与认证)。 -/// 加入令牌的校验也在这里,和 Monitor 的其他数据放在同一个 monitor.db 里,由同一个单写入者写入。 +/// Agent 表同时是 Fleet 的节点表:实现 (MoShiro 的视图)和 (注册与认证)。 +/// 加入令牌的校验也在这里,和 MoShiro 的其他数据放在同一个 moshiro.db 里,由同一个单写入者写入。 /// public sealed class SqliteAgentStore : IAgentStore, IFleetStore { @@ -47,17 +47,17 @@ public sealed class SqliteAgentStore : IAgentStore, IFleetStore AgentRecord? current = GetInternal(c, id); if (current is null) { - return Result.Fail(MonitorErrors.AgentNotFound, "agent not found"); + return Result.Fail(MoShiroErrors.AgentNotFound, "agent not found"); } if (expectedRowVersion is { } expected && expected != current.RowVersion) { - return Result.Fail(MonitorErrors.PreconditionFailed, "the agent was modified by someone else"); + return Result.Fail(MoShiroErrors.PreconditionFailed, "the agent was modified by someone else"); } if (patch.Name is { } name && name != current.Name && current.Status != NodeStatus.Pending && NameTaken(c, name, id)) { - return Result.Fail(MonitorErrors.NameConflict, "another agent already uses this name"); + return Result.Fail(MoShiroErrors.NameConflict, "another agent already uses this name"); } c.Exec( @@ -74,12 +74,12 @@ public sealed class SqliteAgentStore : IAgentStore, IFleetStore AgentRecord? current = GetInternal(c, id); if (current is null) { - return Result.Fail(MonitorErrors.AgentNotFound, "agent not found"); + return Result.Fail(MoShiroErrors.AgentNotFound, "agent not found"); } if (status != NodeStatus.Pending && NameTaken(c, current.Name, id)) { - return Result.Fail(MonitorErrors.NameConflict, "another agent already uses this name; rename it or take over the existing node"); + return Result.Fail(MoShiroErrors.NameConflict, "another agent already uses this name; rename it or take over the existing node"); } c.Exec("UPDATE agents SET status = @status, row_version = row_version + 1 WHERE id = @id", ("@id", id.Value), ("@status", StatusText(status))); @@ -92,13 +92,13 @@ public sealed class SqliteAgentStore : IAgentStore, IFleetStore AgentRecord? pending = GetInternal(c, pendingId); if (pending is null || pending.Status != NodeStatus.Pending) { - return Result.Fail(MonitorErrors.AgentNotFound, "no pending agent with this id"); + return Result.Fail(MoShiroErrors.AgentNotFound, "no pending agent with this id"); } string? existingId = c.Scalar("SELECT id FROM agents WHERE name = @name AND status <> 'pending' AND id <> @id", ("@name", pending.Name), ("@id", pendingId.Value)); if (existingId is null) { - return Result.Fail(MonitorErrors.AgentNotFound, "there is no established agent with this name to take over"); + return Result.Fail(MoShiroErrors.AgentNotFound, "there is no established agent with this name to take over"); } // 旧记录换成新公钥,历史数据保留;待审批记录删除 diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteAuthStore.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteAuthStore.cs similarity index 98% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteAuthStore.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteAuthStore.cs index 683f477..b9a7092 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteAuthStore.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteAuthStore.cs @@ -1,7 +1,7 @@ using Microsoft.Data.Sqlite; -using Monitor.Backend.Application; +using MoShiro.Backend.Application; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; public sealed class SqliteAuthStore : IAuthStore { diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteConfigStores.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteConfigStores.cs similarity index 97% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteConfigStores.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteConfigStores.cs index 96e0f55..e62854b 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteConfigStores.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteConfigStores.cs @@ -1,10 +1,10 @@ using System.Text.Json; using Fleet.Core; using Microsoft.Data.Sqlite; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; public sealed class SqliteJoinTokenStore : IJoinTokenStore { @@ -132,12 +132,12 @@ public sealed class SqliteTaskStore : ITaskStore TaskRecord? current = c.QueryOne($"SELECT {Columns} FROM tasks WHERE id = @id", Read, ("@id", task.Id.Value)); if (current is null) { - return Result.Fail(MonitorErrors.TaskNotFound, "task not found"); + return Result.Fail(MoShiroErrors.TaskNotFound, "task not found"); } if (expectedRowVersion is { } expected && expected != current.RowVersion) { - return Result.Fail(MonitorErrors.PreconditionFailed, "the task was modified by someone else"); + return Result.Fail(MoShiroErrors.PreconditionFailed, "the task was modified by someone else"); } c.Exec( diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteDatabase.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteDatabase.cs similarity index 98% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteDatabase.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteDatabase.cs index a433ffc..e7a2217 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteDatabase.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteDatabase.cs @@ -1,7 +1,7 @@ using System.Threading.Channels; using Microsoft.Data.Sqlite; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; /// /// 连接与单写入者:所有写操作经过一个有界 Channel,由一个后台循环依次执行(每个操作一个事务); @@ -27,7 +27,7 @@ public sealed class SqliteDatabase : IDisposable, IAsyncDisposable RawDirectory = Path.Combine(DataDirectory, "raw"); Directory.CreateDirectory(RawDirectory); - string path = Path.Combine(DataDirectory, "monitor.db"); + string path = Path.Combine(DataDirectory, "moshiro.db"); _readConnectionString = new SqliteConnectionStringBuilder { DataSource = path, Mode = SqliteOpenMode.ReadOnly, Pooling = true }.ToString(); _writer = new SqliteConnection(new SqliteConnectionStringBuilder { DataSource = path, Mode = SqliteOpenMode.ReadWriteCreate, Pooling = false }.ToString()); diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteHostStore.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteHostStore.cs similarity index 95% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteHostStore.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteHostStore.cs index 06d9c89..3aded0d 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteHostStore.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteHostStore.cs @@ -1,9 +1,9 @@ using Fleet.Core; using Microsoft.Data.Sqlite; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; public sealed class SqliteHostStore : IHostStore { diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteMetricStore.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteMetricStore.cs similarity index 99% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteMetricStore.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteMetricStore.cs index b2cd990..155faf1 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteMetricStore.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteMetricStore.cs @@ -1,9 +1,9 @@ using Fleet.Core; using Microsoft.Data.Sqlite; -using Monitor.Backend.Analysis; -using Monitor.Backend.Application; +using MoShiro.Backend.Analysis; +using MoShiro.Backend.Application; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; /// 指标窗口的通用存储:每个桶一行,内容是 指标 id → 累加器状态(对本层不透明,只在合并和补丁时解码)。 public sealed class SqliteMetricStore : IMetricStore diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteNodeMetaStore.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteNodeMetaStore.cs similarity index 96% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteNodeMetaStore.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteNodeMetaStore.cs index 4dc92dc..c2d8c63 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteNodeMetaStore.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteNodeMetaStore.cs @@ -1,7 +1,7 @@ using Microsoft.Data.Sqlite; -using Monitor.Backend.Application; +using MoShiro.Backend.Application; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; public sealed class SqliteNodeMetaStore : INodeMetaStore { diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteRawStore.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteRawStore.cs similarity index 99% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteRawStore.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteRawStore.cs index 9787003..a667d99 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteRawStore.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteRawStore.cs @@ -2,10 +2,10 @@ using System.Text; using System.Text.RegularExpressions; using Fleet.Core; using Microsoft.Data.Sqlite; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; /// /// 原始块的存储:块原样追加写入段文件(块本身带 crc 并且自描述),SQLite 只记录 (segment, offset, length)。 diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteStorageHealth.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteStorageHealth.cs similarity index 93% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteStorageHealth.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteStorageHealth.cs index 67dc4c7..083d294 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteStorageHealth.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteStorageHealth.cs @@ -1,7 +1,7 @@ using Microsoft.Data.Sqlite; -using Monitor.Backend.Application; +using MoShiro.Backend.Application; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; public sealed class SqliteStorageHealth : IStorageHealth { diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteTestStore.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteTestStore.cs similarity index 98% rename from backend/src/Monitor.Backend.Storage.Sqlite/SqliteTestStore.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/SqliteTestStore.cs index fb59d69..b763b41 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/SqliteTestStore.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/SqliteTestStore.cs @@ -1,9 +1,9 @@ using Fleet.Core; using Microsoft.Data.Sqlite; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; public sealed class SqliteTestStore : ITestStore { diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/StorageJson.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/StorageJson.cs similarity index 95% rename from backend/src/Monitor.Backend.Storage.Sqlite/StorageJson.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/StorageJson.cs index 3259e7a..51b9490 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/StorageJson.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/StorageJson.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; [JsonSerializable(typeof(List))] [JsonSerializable(typeof(List))] diff --git a/backend/src/Monitor.Backend.Storage.Sqlite/StorageServiceCollectionExtensions.cs b/backend/src/MoShiro.Backend.Storage.Sqlite/StorageServiceCollectionExtensions.cs similarity index 91% rename from backend/src/Monitor.Backend.Storage.Sqlite/StorageServiceCollectionExtensions.cs rename to backend/src/MoShiro.Backend.Storage.Sqlite/StorageServiceCollectionExtensions.cs index ee7402a..290fda9 100644 --- a/backend/src/Monitor.Backend.Storage.Sqlite/StorageServiceCollectionExtensions.cs +++ b/backend/src/MoShiro.Backend.Storage.Sqlite/StorageServiceCollectionExtensions.cs @@ -1,13 +1,13 @@ using Fleet.Server; using Microsoft.Extensions.DependencyInjection; -using Monitor.Backend.Application; +using MoShiro.Backend.Application; -namespace Monitor.Backend.Storage.Sqlite; +namespace MoShiro.Backend.Storage.Sqlite; public static class StorageServiceCollectionExtensions { /// 注册 SQLite + 段文件存储:实现 Application 的全部存储端口,同时实现 Fleet 的 。 - public static IServiceCollection AddMonitorSqlite(this IServiceCollection services, string dataDirectory) + public static IServiceCollection AddMoShiroSqlite(this IServiceCollection services, string dataDirectory) { services.AddSingleton(_ => new SqliteDatabase(dataDirectory)); services.AddSingleton(); diff --git a/backend/src/Monitor.Backend/BackendHost.cs b/backend/src/MoShiro.Backend/BackendHost.cs similarity index 79% rename from backend/src/Monitor.Backend/BackendHost.cs rename to backend/src/MoShiro.Backend/BackendHost.cs index dd14010..3b42a1a 100644 --- a/backend/src/Monitor.Backend/BackendHost.cs +++ b/backend/src/MoShiro.Backend/BackendHost.cs @@ -3,20 +3,20 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Monitor.Backend.Api; -using Monitor.Backend.Application; -using Monitor.Backend.Gateway; -using Monitor.Backend.Storage.Sqlite; +using MoShiro.Backend.Api; +using MoShiro.Backend.Application; +using MoShiro.Backend.Gateway; +using MoShiro.Backend.Storage.Sqlite; -namespace Monitor.Backend; +namespace MoShiro.Backend; /// -/// 组合根:在这里显式注册所有层。配置来自 appsettings.json、环境变量(Monitor__DataDirectory 等)和命令行。 +/// 组合根:在这里显式注册所有层。配置来自 appsettings.json、环境变量(MoShiro__DataDirectory 等)和命令行。 /// 测试用 在真实端口上启动整个后端。 /// public static class BackendHost { - public const string ConfigurationSection = "Monitor"; + public const string ConfigurationSection = "MoShiro"; public const int MaxRequestBodyBytes = 64 * 1024; public static WebApplication Build(string[] args, Action? configureOptions = null, TimeProvider? time = null) @@ -37,7 +37,7 @@ public static class BackendHost IServiceCollection services = builder.Services; services.AddSingleton(time ?? TimeProvider.System); - services.AddMonitorSqlite(options.DataDirectory); + services.AddMoShiroSqlite(options.DataDirectory); // 国家和运营商:Backend 用节点的来源地址查一次(Probe、Agent 不访问任何外部服务);地址留空就不查 if (string.IsNullOrWhiteSpace(options.GeoLookupUrl)) { @@ -48,16 +48,16 @@ public static class BackendHost services.AddSingleton(new HttpGeoLookup(options.GeoLookupUrl)); } - services.AddMonitorApplication(options); - services.AddMonitorGateway(); - services.AddMonitorApi(); + 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.UseMonitorCors(options.CorsOrigins); - app.UseMonitorApi(); - app.MapMonitorApi(); + app.UseMoShiroCors(options.CorsOrigins); + app.UseMoShiroApi(); + app.MapMoShiroApi(); app.MapFleetEnrollment("/api/agent/v1/enroll"); app.MapFleetLink("/api/agent/v1/rpc"); return app; diff --git a/backend/src/Monitor.Backend/HttpGeoLookup.cs b/backend/src/MoShiro.Backend/HttpGeoLookup.cs similarity index 93% rename from backend/src/Monitor.Backend/HttpGeoLookup.cs rename to backend/src/MoShiro.Backend/HttpGeoLookup.cs index d8b50e2..234b699 100644 --- a/backend/src/Monitor.Backend/HttpGeoLookup.cs +++ b/backend/src/MoShiro.Backend/HttpGeoLookup.cs @@ -1,7 +1,7 @@ using System.Text.Json; -using Monitor.Backend.Application; +using MoShiro.Backend.Application; -namespace Monitor.Backend; +namespace MoShiro.Backend; /// /// 用 IP 归属查询服务(GET {地址}/lookup?ip=…)查国家和运营商。 @@ -14,7 +14,7 @@ public sealed class HttpGeoLookup : IGeoLookup, IDisposable public HttpGeoLookup(string baseUrl) { _http = new HttpClient { BaseAddress = new Uri(baseUrl.TrimEnd('/') + "/"), Timeout = TimeSpan.FromSeconds(6) }; - _http.DefaultRequestHeaders.UserAgent.ParseAdd("MyMonitor"); + _http.DefaultRequestHeaders.UserAgent.ParseAdd("MoShiro"); } public async ValueTask LookupAsync(string host, CancellationToken ct) @@ -66,7 +66,7 @@ public sealed class HttpGeoLookup : IGeoLookup, IDisposable public void Dispose() => _http.Dispose(); } -/// 不查(Monitor__GeoLookupUrl 留空)。 +/// 不查(MoShiro__GeoLookupUrl 留空)。 public sealed class NoGeoLookup : IGeoLookup { public ValueTask LookupAsync(string host, CancellationToken ct) => ValueTask.FromResult(null); diff --git a/backend/src/Monitor.Backend/Monitor.Backend.csproj b/backend/src/MoShiro.Backend/MoShiro.Backend.csproj similarity index 85% rename from backend/src/Monitor.Backend/Monitor.Backend.csproj rename to backend/src/MoShiro.Backend/MoShiro.Backend.csproj index 93afdac..5492665 100644 --- a/backend/src/Monitor.Backend/Monitor.Backend.csproj +++ b/backend/src/MoShiro.Backend/MoShiro.Backend.csproj @@ -3,8 +3,8 @@ Exe - monitor-backend - Monitor.Backend + moshiro-backend + MoShiro.Backend true true Size @@ -28,9 +28,9 @@ - - - + + + diff --git a/backend/src/Monitor.Backend/Program.cs b/backend/src/MoShiro.Backend/Program.cs similarity index 65% rename from backend/src/Monitor.Backend/Program.cs rename to backend/src/MoShiro.Backend/Program.cs index 2a3a592..2d22be8 100644 --- a/backend/src/Monitor.Backend/Program.cs +++ b/backend/src/MoShiro.Backend/Program.cs @@ -1,3 +1,3 @@ -using Monitor.Backend; +using MoShiro.Backend; await BackendHost.Build(args).RunAsync(); diff --git a/backend/src/Monitor.Backend/StaticSqlite.targets b/backend/src/MoShiro.Backend/StaticSqlite.targets similarity index 90% rename from backend/src/Monitor.Backend/StaticSqlite.targets rename to backend/src/MoShiro.Backend/StaticSqlite.targets index e1c17d8..1a6f75a 100644 --- a/backend/src/Monitor.Backend/StaticSqlite.targets +++ b/backend/src/MoShiro.Backend/StaticSqlite.targets @@ -14,20 +14,20 @@ '$(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)." /> - <_SqliteCache>$([System.IO.Path]::GetFullPath('$(BaseIntermediateOutputPath)sqlite/$(MonitorSqliteSourceVersion)/')) - <_SqliteArchive>$(_SqliteCache)sqlite-amalgamation-$(MonitorSqliteSourceVersion).zip - <_SqliteSource>$(_SqliteCache)sqlite-amalgamation-$(MonitorSqliteSourceVersion)/sqlite3.c + <_SqliteCache>$([System.IO.Path]::GetFullPath('$(BaseIntermediateOutputPath)sqlite/$(MoShiroSqliteSourceVersion)/')) + <_SqliteArchive>$(_SqliteCache)sqlite-amalgamation-$(MoShiroSqliteSourceVersion).zip + <_SqliteSource>$(_SqliteCache)sqlite-amalgamation-$(MoShiroSqliteSourceVersion)/sqlite3.c <_SqliteObjectDirectory>$(_SqliteCache)$(RuntimeIdentifier)/$(UseAotAnywhere)/ <_SqliteObject>$(_SqliteObjectDirectory)e_sqlite3.o <_SqliteObject Condition="$(RuntimeIdentifier.StartsWith('win'))">$(_SqliteObjectDirectory)e_sqlite3.obj - - @@ -45,7 +45,7 @@ <_SqliteCompiler Condition="'$(UseAotAnywhere)' == 'true'">"$(_AotAnywhereZigExe)" cc -target $(TargetTriple) <_SqliteCompiler Condition="'$(_SqliteUseMsvc)' == 'true'">cl - + - - + + diff --git a/backend/tests/Monitor.Backend.Analysis.Tests/ModelAndTestEvaluatorTests.cs b/backend/tests/MoShiro.Backend.Analysis.Tests/ModelAndTestEvaluatorTests.cs similarity index 98% rename from backend/tests/Monitor.Backend.Analysis.Tests/ModelAndTestEvaluatorTests.cs rename to backend/tests/MoShiro.Backend.Analysis.Tests/ModelAndTestEvaluatorTests.cs index 535351e..487311f 100644 --- a/backend/tests/Monitor.Backend.Analysis.Tests/ModelAndTestEvaluatorTests.cs +++ b/backend/tests/MoShiro.Backend.Analysis.Tests/ModelAndTestEvaluatorTests.cs @@ -1,8 +1,8 @@ using Fleet.Core; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Analysis.Tests; +namespace MoShiro.Backend.Analysis.Tests; public sealed class ModelAndTestEvaluatorTests { diff --git a/backend/tests/Monitor.Backend.Analysis.Tests/OpTests.cs b/backend/tests/MoShiro.Backend.Analysis.Tests/OpTests.cs similarity index 99% rename from backend/tests/Monitor.Backend.Analysis.Tests/OpTests.cs rename to backend/tests/MoShiro.Backend.Analysis.Tests/OpTests.cs index 5fc1c18..850e2d1 100644 --- a/backend/tests/Monitor.Backend.Analysis.Tests/OpTests.cs +++ b/backend/tests/MoShiro.Backend.Analysis.Tests/OpTests.cs @@ -1,8 +1,8 @@ using Fleet.Core; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Analysis.Tests; +namespace MoShiro.Backend.Analysis.Tests; public sealed class OpTests { diff --git a/backend/tests/Monitor.Backend.Tests/AgentEndToEndTests.cs b/backend/tests/MoShiro.Backend.Tests/AgentEndToEndTests.cs similarity index 99% rename from backend/tests/Monitor.Backend.Tests/AgentEndToEndTests.cs rename to backend/tests/MoShiro.Backend.Tests/AgentEndToEndTests.cs index 423762d..7f2e0ec 100644 --- a/backend/tests/Monitor.Backend.Tests/AgentEndToEndTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/AgentEndToEndTests.cs @@ -1,9 +1,9 @@ using System.Text.Json.Nodes; -using Monitor.Measurement; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Measurement; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// 真实的后端 + 真实的 Agent(进程内)+ 假 Probe:覆盖 Agent 与 Backend 的链路、Probe 与 Agent 的点对点会话和数据面。 [Collection("backend")] diff --git a/backend/tests/Monitor.Backend.Tests/AgentHarness.cs b/backend/tests/MoShiro.Backend.Tests/AgentHarness.cs similarity index 96% rename from backend/tests/Monitor.Backend.Tests/AgentHarness.cs rename to backend/tests/MoShiro.Backend.Tests/AgentHarness.cs index 0fff698..e83a6d8 100644 --- a/backend/tests/Monitor.Backend.Tests/AgentHarness.cs +++ b/backend/tests/MoShiro.Backend.Tests/AgentHarness.cs @@ -3,11 +3,11 @@ using Fleet.Core; using Fleet.Enrollment.Client; using Fleet.Hosting; using Fleet.Identity; -using Monitor.Agent; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Agent; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// /// 进程内的真实 Agent:用 注册(和 fleet-enroll 同一份代码)、写出身份目录、 @@ -43,7 +43,7 @@ public sealed class AgentHarness : IAsyncDisposable public static async Task StartAsync(BackendFixture backend, Action? configure = null, string? name = null) { - string directory = Path.Combine(Path.GetTempPath(), "monitor-agent-" + Guid.NewGuid().ToString("N")); + string directory = Path.Combine(Path.GetTempPath(), "moshiro-agent-" + Guid.NewGuid().ToString("N")); string token = await backend.CreateJoinTokenAsync(); using var http = new HttpClient(); Result enrolled = await EnrollmentClient.EnrollAsync(http, backend.BaseAddress, token, name ?? backend.UniqueName("agent"), directory, AgentApp.Version, null, TimeProvider.System, CancellationToken.None); diff --git a/backend/tests/Monitor.Backend.Tests/AotSmokeTests.cs b/backend/tests/MoShiro.Backend.Tests/AotSmokeTests.cs similarity index 96% rename from backend/tests/Monitor.Backend.Tests/AotSmokeTests.cs rename to backend/tests/MoShiro.Backend.Tests/AotSmokeTests.cs index 5c434d4..86204ec 100644 --- a/backend/tests/Monitor.Backend.Tests/AotSmokeTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/AotSmokeTests.cs @@ -1,24 +1,24 @@ using System.Net.Http.Headers; using System.Text.Json.Nodes; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// /// 对一个正在运行的 NativeAOT 发布产物跑一遍真实的 Agent 流程(注册、WebSocket、状态同步、二进制收件箱、查询、SSE、按需测试)。 -/// 只有设置了 MONITOR_AOT_URL 才会运行: -/// dotnet publish backend/src/Monitor.Backend -r win-x64 -p:PublishAot=true,启动产物,再设置该环境变量后运行本测试。 +/// 只有设置了 MOSHIRO_AOT_URL 才会运行: +/// dotnet publish backend/src/MoShiro.Backend -r win-x64 -p:PublishAot=true,启动产物,再设置该环境变量后运行本测试。 /// 管理员凭据与测试夹具相同(用户 admin,口令见 )。 /// public sealed class AotSmokeTests { - private static string? Url => Environment.GetEnvironmentVariable("MONITOR_AOT_URL"); + private static string? Url => Environment.GetEnvironmentVariable("MOSHIRO_AOT_URL"); [Fact] public async Task TheNativeBinary_ServesTheWholeAgentWorkflow() { - Assert.SkipUnless(Url is not null, "set MONITOR_AOT_URL to the address of a running NativeAOT build to run this test"); + Assert.SkipUnless(Url is not null, "set MOSHIRO_AOT_URL to the address of a running NativeAOT build to run this test"); var baseAddress = new Uri(Url!); using var http = new HttpClient { BaseAddress = baseAddress }; diff --git a/backend/tests/Monitor.Backend.Tests/ApiBasicsTests.cs b/backend/tests/MoShiro.Backend.Tests/ApiBasicsTests.cs similarity index 98% rename from backend/tests/Monitor.Backend.Tests/ApiBasicsTests.cs rename to backend/tests/MoShiro.Backend.Tests/ApiBasicsTests.cs index 06dbe59..6774085 100644 --- a/backend/tests/Monitor.Backend.Tests/ApiBasicsTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/ApiBasicsTests.cs @@ -2,7 +2,7 @@ using System.Net; using System.Net.Http.Headers; using System.Text.Json.Nodes; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; [Collection("backend")] public sealed class ApiBasicsTests @@ -217,8 +217,8 @@ public sealed class ApiBasicsTests using HttpResponseMessage allowed = await _backend.Admin.GetAsync("/metrics"); string text = await allowed.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, allowed.StatusCode); - Assert.Contains("monitor_agents_online", text); - Assert.Contains("monitor_analysis_queue_length", text); + Assert.Contains("moshiro_agents_online", text); + Assert.Contains("moshiro_analysis_queue_length", text); } [Fact] diff --git a/backend/tests/Monitor.Backend.Tests/ArchitectureTests.cs b/backend/tests/MoShiro.Backend.Tests/ArchitectureTests.cs similarity index 81% rename from backend/tests/Monitor.Backend.Tests/ArchitectureTests.cs rename to backend/tests/MoShiro.Backend.Tests/ArchitectureTests.cs index cf81a17..83096a4 100644 --- a/backend/tests/Monitor.Backend.Tests/ArchitectureTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/ArchitectureTests.cs @@ -1,6 +1,6 @@ using System.Xml.Linq; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// /// 依赖规则(docs/project-layout.md 第 3 节):由测试在构建期强制,等价于文档里的 eng/check-deps。 @@ -17,7 +17,8 @@ public sealed class ArchitectureTests private static string FindRoot() { string? dir = AppContext.BaseDirectory; - while (dir is not null && !File.Exists(Path.Combine(dir, "global.json"))) + // backend/ 目录的标志:BannedSymbols.txt 只在这里(global.json 和 NuGet 版本表已经挪到仓库根目录) + while (dir is not null && !File.Exists(Path.Combine(dir, "BannedSymbols.txt"))) { dir = Path.GetDirectoryName(dir); } @@ -48,17 +49,17 @@ public sealed class ArchitectureTests private static bool IsFleet(Project p) => p.Name.StartsWith("Fleet.", StringComparison.Ordinal) && !IsTest(p); [Fact] - public void Fleet_NeverReferencesMonitor_InProjectsOrCode() + public void Fleet_NeverReferencesMoShiro_InProjectsOrCode() { foreach (Project project in LoadProjects().Where(IsFleet)) { - Assert.DoesNotContain(project.ProjectReferences, r => r.StartsWith("Monitor.", StringComparison.Ordinal)); + Assert.DoesNotContain(project.ProjectReferences, r => r.StartsWith("MoShiro.", StringComparison.Ordinal)); foreach (string file in Directory.EnumerateFiles(project.Directory, "*.cs", SearchOption.AllDirectories).Where(f => !f.Contains(Path.DirectorySeparatorChar + "obj" + Path.DirectorySeparatorChar, StringComparison.Ordinal))) { string text = File.ReadAllText(file); - Assert.False(text.Contains("using Monitor.", StringComparison.Ordinal) || text.Contains("namespace Monitor.", StringComparison.Ordinal), $"{file} refers to Monitor.*"); - Assert.False(text.Contains("monitor.", StringComparison.Ordinal) && text.Contains("\"monitor.", StringComparison.Ordinal), $"{file} hard-codes a Monitor method or channel name"); - Assert.False(text.Contains("7443", StringComparison.Ordinal), $"{file} hard-codes a Monitor port"); + Assert.False(text.Contains("using MoShiro.", StringComparison.Ordinal) || text.Contains("namespace MoShiro.", StringComparison.Ordinal), $"{file} refers to MoShiro.*"); + Assert.False(text.Contains("moshiro.", StringComparison.Ordinal) && text.Contains("\"moshiro.", StringComparison.Ordinal), $"{file} hard-codes a MoShiro method or channel name"); + Assert.False(text.Contains("7443", StringComparison.Ordinal), $"{file} hard-codes a MoShiro port"); } } } @@ -66,7 +67,7 @@ public sealed class ArchitectureTests [Fact] public void NodeSideLibraries_HaveNoRuntimePackages_AndUseTheNodeBanList() { - string[] nodeSide = ["Fleet.Core", "Fleet.Identity", "Fleet.Rpc", "Monitor.Protocol", "Monitor.Backend.Analysis"]; + string[] nodeSide = ["Fleet.Core", "Fleet.Identity", "Fleet.Rpc", "MoShiro.Protocol", "MoShiro.Backend.Analysis"]; foreach (Project project in LoadProjects().Where(p => nodeSide.Contains(p.Name))) { Assert.All(project.Packages, package => Assert.Contains(package, s_allowedAnalyzers)); @@ -83,8 +84,8 @@ public sealed class ArchitectureTests public void Protocol_DependsOnlyOnFleetCoreAndRpc_AndAnalysisOnlyOnProtocol() { List projects = LoadProjects(); - Assert.Equal(["Fleet.Core", "Fleet.Rpc"], projects.Single(p => p.Name == "Monitor.Protocol").ProjectReferences.Order().ToArray()); - Assert.Equal(["Monitor.Protocol"], projects.Single(p => p.Name == "Monitor.Backend.Analysis").ProjectReferences.ToArray()); + Assert.Equal(["Fleet.Core", "Fleet.Rpc"], projects.Single(p => p.Name == "MoShiro.Protocol").ProjectReferences.Order().ToArray()); + Assert.Equal(["MoShiro.Protocol"], projects.Single(p => p.Name == "MoShiro.Backend.Analysis").ProjectReferences.ToArray()); } [Fact] @@ -94,19 +95,19 @@ public sealed class ArchitectureTests Project Get(string name) => projects.Single(p => p.Name == name); // Agent 是纯采集进程:不引用后端的任何层,也不引用 Fleet 的服务端库 - Project agent = Get("Monitor.Agent"); - Assert.DoesNotContain(agent.ProjectReferences, r => r.StartsWith("Monitor.Backend", StringComparison.Ordinal) || r.StartsWith("Fleet.Server", StringComparison.Ordinal) || r.StartsWith("Fleet.Enrollment", StringComparison.Ordinal)); - Assert.Equal(["Fleet.Hosting", "Fleet.Link", "Monitor.Measurement"], agent.ProjectReferences.Order().ToArray()); + Project agent = Get("MoShiro.Agent"); + Assert.DoesNotContain(agent.ProjectReferences, r => r.StartsWith("MoShiro.Backend", StringComparison.Ordinal) || r.StartsWith("Fleet.Server", StringComparison.Ordinal) || r.StartsWith("Fleet.Enrollment", StringComparison.Ordinal)); + Assert.Equal(["Fleet.Hosting", "Fleet.Link", "MoShiro.Measurement"], agent.ProjectReferences.Order().ToArray()); // Probe 同理,并且不认识 Backend 和 Agent - Project probe = Get("Monitor.Probe"); - Assert.Equal(["Fleet.Hosting", "Fleet.Link", "Monitor.Measurement"], probe.ProjectReferences.Order().ToArray()); + Project probe = Get("MoShiro.Probe"); + Assert.Equal(["Fleet.Hosting", "Fleet.Link", "MoShiro.Measurement"], probe.ProjectReferences.Order().ToArray()); // 两个节点的共享库只依赖协议 - Assert.Equal(["Monitor.Protocol"], Get("Monitor.Measurement").ProjectReferences.ToArray()); + Assert.Equal(["MoShiro.Protocol"], Get("MoShiro.Measurement").ProjectReferences.ToArray()); // 节点一侧的库没有运行时依赖包,并使用节点禁用列表(不能用 HttpClient、Process、写文件;唯一的写文件豁免在 ConfigStore) - foreach (string name in new[] { "Fleet.Link", "Fleet.Hosting", "Monitor.Measurement", "Monitor.Agent", "Monitor.Probe" }) + foreach (string name in new[] { "Fleet.Link", "Fleet.Hosting", "MoShiro.Measurement", "MoShiro.Agent", "MoShiro.Probe" }) { Project project = Get(name); Assert.All(project.Packages, package => Assert.Contains(package, s_allowedAnalyzers)); @@ -126,7 +127,7 @@ public sealed class ArchitectureTests { // 采集层(协议、积木、Agent、Probe、Fleet)只认识机制(传输、节奏、方向、时间戳)和原始列; // REALITY、Hysteria2、Minecraft 这些业务概念以及由原语编排成的测试方案只存在于 Backend。 - string[] collectionRoots = ["shared/Monitor.Protocol", "shared/Monitor.Measurement", "agent/src", "probe/src", "fleet/src"]; + string[] collectionRoots = ["shared/MoShiro.Protocol", "shared/MoShiro.Measurement", "agent/src", "probe/src", "fleet/src"]; string[] forbidden = ["reality", "hysteria", "hy2", "minecraft", "brutal", "PlanSpec", "PhaseSpec"]; foreach (string root in collectionRoots) { @@ -142,7 +143,7 @@ public sealed class ArchitectureTests } // 派生量(丢包率、RTT、抖动)由 Backend 的分析层算:采集层的积木不引用分析层 - Assert.DoesNotContain(LoadProjects().Single(p => p.Name == "Monitor.Measurement").ProjectReferences, r => r.Contains("Analysis", StringComparison.Ordinal)); + Assert.DoesNotContain(LoadProjects().Single(p => p.Name == "MoShiro.Measurement").ProjectReferences, r => r.Contains("Analysis", StringComparison.Ordinal)); } [Fact] @@ -152,22 +153,22 @@ public sealed class ArchitectureTests Project Get(string name) => projects.Single(p => p.Name == name); // Api 不能引用 Storage(也不引用 Gateway):只调用 Application - Assert.DoesNotContain(Get("Monitor.Backend.Api").ProjectReferences, r => r.Contains("Storage", StringComparison.Ordinal) || r.Contains("Gateway", StringComparison.Ordinal)); - Assert.Equal(["Monitor.Backend.Application"], Get("Monitor.Backend.Api").ProjectReferences.ToArray()); + Assert.DoesNotContain(Get("MoShiro.Backend.Api").ProjectReferences, r => r.Contains("Storage", StringComparison.Ordinal) || r.Contains("Gateway", StringComparison.Ordinal)); + Assert.Equal(["MoShiro.Backend.Application"], Get("MoShiro.Backend.Api").ProjectReferences.ToArray()); // Application 不依赖任何下游层 - Assert.DoesNotContain(Get("Monitor.Backend.Application").ProjectReferences, r => r.Contains("Storage", StringComparison.Ordinal) || r.Contains("Api", StringComparison.Ordinal) || r.Contains("Gateway", StringComparison.Ordinal)); + Assert.DoesNotContain(Get("MoShiro.Backend.Application").ProjectReferences, r => r.Contains("Storage", StringComparison.Ordinal) || r.Contains("Api", StringComparison.Ordinal) || r.Contains("Gateway", StringComparison.Ordinal)); // Gateway 只通过 Application 与 Fleet.Server 工作 - Assert.DoesNotContain(Get("Monitor.Backend.Gateway").ProjectReferences, r => r.Contains("Storage", StringComparison.Ordinal) || r.Contains("Backend.Api", StringComparison.Ordinal)); + Assert.DoesNotContain(Get("MoShiro.Backend.Gateway").ProjectReferences, r => r.Contains("Storage", StringComparison.Ordinal) || r.Contains("Backend.Api", StringComparison.Ordinal)); // Storage 实现 Application 的端口,不认识 Api 和 Gateway - Assert.DoesNotContain(Get("Monitor.Backend.Storage.Sqlite").ProjectReferences, r => r.Contains("Backend.Api", StringComparison.Ordinal) || r.Contains("Gateway", StringComparison.Ordinal)); + Assert.DoesNotContain(Get("MoShiro.Backend.Storage.Sqlite").ProjectReferences, r => r.Contains("Backend.Api", StringComparison.Ordinal) || r.Contains("Gateway", StringComparison.Ordinal)); // 只有宿主(组合根)认识所有层 Assert.Equivalent( - new[] { "Monitor.Backend.Api", "Monitor.Backend.Gateway", "Monitor.Backend.Storage.Sqlite" }, - Get("Monitor.Backend").ProjectReferences.ToArray()); + new[] { "MoShiro.Backend.Api", "MoShiro.Backend.Gateway", "MoShiro.Backend.Storage.Sqlite" }, + Get("MoShiro.Backend").ProjectReferences.ToArray()); } [Fact] @@ -175,7 +176,7 @@ public sealed class ArchitectureTests { string[] allowed = [ - "Microsoft.CodeAnalysis.BannedApiAnalyzers", "Microsoft.Data.Sqlite", "Microsoft.AspNetCore.OpenApi", + "Microsoft.CodeAnalysis.BannedApiAnalyzers", "Microsoft.Data.Sqlite", "SQLitePCLRaw.lib.e_sqlite3", "Microsoft.AspNetCore.OpenApi", "Microsoft.Extensions.ApiDescription.Server", "xunit.v3", "Microsoft.Extensions.TimeProvider.Testing", ]; foreach (Project project in LoadProjects()) @@ -187,7 +188,7 @@ public sealed class ArchitectureTests [Fact] public void ApplicationAndApi_NeverTouchSqliteOrTheFileSystemDirectly() { - foreach (string layer in new[] { "Monitor.Backend.Application", "Monitor.Backend.Api", "Monitor.Backend.Gateway", "Monitor.Backend.Analysis" }) + foreach (string layer in new[] { "MoShiro.Backend.Application", "MoShiro.Backend.Api", "MoShiro.Backend.Gateway", "MoShiro.Backend.Analysis" }) { string dir = Path.Combine(s_root, "src", layer); foreach (string file in Directory.EnumerateFiles(dir, "*.cs", SearchOption.AllDirectories).Where(f => !f.Contains(Path.DirectorySeparatorChar + "obj" + Path.DirectorySeparatorChar, StringComparison.Ordinal))) @@ -204,7 +205,7 @@ public sealed class ArchitectureTests public void NoProductionCode_BuildsSqlByConcatenatingValues() { // 手写的参数化 SQL:只有表名可以来自常量;值一律通过参数 - string dir = Path.Combine(s_root, "src", "Monitor.Backend.Storage.Sqlite"); + string dir = Path.Combine(s_root, "src", "MoShiro.Backend.Storage.Sqlite"); foreach (string file in Directory.EnumerateFiles(dir, "*.cs", SearchOption.AllDirectories).Where(f => !f.Contains(Path.DirectorySeparatorChar + "obj" + Path.DirectorySeparatorChar, StringComparison.Ordinal))) { string text = File.ReadAllText(file); diff --git a/backend/tests/Monitor.Backend.Tests/BackendFixture.cs b/backend/tests/MoShiro.Backend.Tests/BackendFixture.cs similarity index 96% rename from backend/tests/Monitor.Backend.Tests/BackendFixture.cs rename to backend/tests/MoShiro.Backend.Tests/BackendFixture.cs index 86c2970..47120ab 100644 --- a/backend/tests/Monitor.Backend.Tests/BackendFixture.cs +++ b/backend/tests/MoShiro.Backend.Tests/BackendFixture.cs @@ -5,10 +5,10 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.Extensions.DependencyInjection; -using Monitor.Backend.Application; -using Monitor.TestSupport; +using MoShiro.Backend.Application; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// /// 在真实的 Kestrel 端口上启动整个后端(真实的 SQLite 与段文件,只是用临时目录和较快的轮询), @@ -58,7 +58,7 @@ public class BackendFixture : IAsyncLifetime public async ValueTask InitializeAsync() { - DataDirectory = Path.Combine(Path.GetTempPath(), "monitor-tests-" + Guid.NewGuid().ToString("N")); + DataDirectory = Path.Combine(Path.GetTempPath(), "moshiro-tests-" + Guid.NewGuid().ToString("N")); await StartAsync(); _adminToken = await CreateAdminTokenAsync(); CreateClients(); @@ -100,7 +100,7 @@ public class BackendFixture : IAsyncLifetime public async Task ReconnectAsync(AgentSimulator previous) { AgentSimulator agent = AgentSimulator.Restore(previous.ExportedKey, previous.NodeId); - agent.ProbeForChunks = new Monitor.Protocol.ProbeId(DefaultProbeId); + agent.ProbeForChunks = new MoShiro.Protocol.ProbeId(DefaultProbeId); _agents.Add(agent); await agent.ConnectAsync(BaseAddress); return agent; @@ -129,7 +129,7 @@ public class BackendFixture : IAsyncLifetime { string token = await CreateJoinTokenAsync(autoApprove); AgentSimulator agent = await AgentSimulator.EnrollAsync(Anonymous, token, name ?? UniqueName("agent"), kinds); - agent.ProbeForChunks = new Monitor.Protocol.ProbeId(DefaultProbeId); + agent.ProbeForChunks = new MoShiro.Protocol.ProbeId(DefaultProbeId); _agents.Add(agent); await agent.ConnectAsync(BaseAddress, hello, kinds); return agent; diff --git a/backend/tests/Monitor.Backend.Tests/EnrollmentAndTaskSetTests.cs b/backend/tests/MoShiro.Backend.Tests/EnrollmentAndTaskSetTests.cs similarity index 99% rename from backend/tests/Monitor.Backend.Tests/EnrollmentAndTaskSetTests.cs rename to backend/tests/MoShiro.Backend.Tests/EnrollmentAndTaskSetTests.cs index 6bb7d7e..b97414e 100644 --- a/backend/tests/Monitor.Backend.Tests/EnrollmentAndTaskSetTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/EnrollmentAndTaskSetTests.cs @@ -1,9 +1,9 @@ using System.Net; using System.Text.Json.Nodes; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; [Collection("backend")] public sealed class EnrollmentAndTaskSetTests @@ -150,7 +150,7 @@ public sealed class EnrollmentAndTaskSetTests RawChunk chunk = ChunkFactory.UdpEchoClean(agent.NodeId, TimeProvider.System.GetUtcNow().ToUnixTimeMilliseconds() - 30_000); chunk.Header.AgentId = agent.NodeId; - await agent.SendBinaryAsync(Fleet.Rpc.OutboxFrame.Build(MonitorChannels.RawChunk, chunk.Header.ChunkId.Value, RawChunkCodec.Encode(chunk))); + await agent.SendBinaryAsync(Fleet.Rpc.OutboxFrame.Build(MoShiroChannels.RawChunk, chunk.Header.ChunkId.Value, RawChunkCodec.Encode(chunk))); await Task.Delay(300); JsonNode chunks = await _backend.GetJsonAsync(_backend.Admin, "/api/admin/raw/chunks?agent_id=" + agent.NodeId.Value); Assert.Empty(chunks["items"]!.AsArray()); diff --git a/backend/tests/Monitor.Backend.Tests/HostTests.cs b/backend/tests/MoShiro.Backend.Tests/HostTests.cs similarity index 98% rename from backend/tests/Monitor.Backend.Tests/HostTests.cs rename to backend/tests/MoShiro.Backend.Tests/HostTests.cs index d6ba7ce..ca4ea9b 100644 --- a/backend/tests/Monitor.Backend.Tests/HostTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/HostTests.cs @@ -1,9 +1,9 @@ using System.Text.Json.Nodes; -using Monitor.Agent; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Agent; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; public sealed class HostSamplerTests { diff --git a/backend/tests/Monitor.Backend.Tests/IngestAndQueryTests.cs b/backend/tests/MoShiro.Backend.Tests/IngestAndQueryTests.cs similarity index 99% rename from backend/tests/Monitor.Backend.Tests/IngestAndQueryTests.cs rename to backend/tests/MoShiro.Backend.Tests/IngestAndQueryTests.cs index 6b6292b..3a4b065 100644 --- a/backend/tests/Monitor.Backend.Tests/IngestAndQueryTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/IngestAndQueryTests.cs @@ -2,10 +2,10 @@ using System.Net; using System.Net.Http.Headers; using System.Text.Json.Nodes; using Fleet.Core; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; [Collection("backend")] public sealed class IngestAndQueryTests @@ -120,11 +120,11 @@ public sealed class IngestAndQueryTests var ack = new TaskCompletionSource(); byte[] corrupt = RawChunkCodec.Encode(ChunkFactory.UdpEchoClean(agent.NodeId, start)); corrupt[^1] ^= 0xFF; - await agent.SendBinaryAsync(Fleet.Rpc.OutboxFrame.Build(MonitorChannels.RawChunk, garbage.Value, corrupt)); + await agent.SendBinaryAsync(Fleet.Rpc.OutboxFrame.Build(MoShiroChannels.RawChunk, garbage.Value, corrupt)); // 冒名的块:agent_id 与认证的节点不一致 RawChunk spoofed = ChunkFactory.UdpEchoClean(new NodeId("agt_someone_else"), start); - await agent.SendBinaryAsync(Fleet.Rpc.OutboxFrame.Build(MonitorChannels.RawChunk, spoofed.Header.ChunkId.Value, RawChunkCodec.Encode(spoofed))); + await agent.SendBinaryAsync(Fleet.Rpc.OutboxFrame.Build(MoShiroChannels.RawChunk, spoofed.Header.ChunkId.Value, RawChunkCodec.Encode(spoofed))); await BackendFixture.EventuallyAsync(async () => { diff --git a/backend/tests/Monitor.Backend.Tests/LinkTests.cs b/backend/tests/MoShiro.Backend.Tests/LinkTests.cs similarity index 98% rename from backend/tests/Monitor.Backend.Tests/LinkTests.cs rename to backend/tests/MoShiro.Backend.Tests/LinkTests.cs index 5877c34..15b2020 100644 --- a/backend/tests/Monitor.Backend.Tests/LinkTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/LinkTests.cs @@ -1,8 +1,8 @@ using System.Net; using System.Text.Json.Nodes; -using Monitor.TestSupport; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; [Collection("probe-e2e")] public sealed class LinkTests diff --git a/backend/tests/Monitor.Backend.Tests/LiveTests.cs b/backend/tests/MoShiro.Backend.Tests/LiveTests.cs similarity index 98% rename from backend/tests/Monitor.Backend.Tests/LiveTests.cs rename to backend/tests/MoShiro.Backend.Tests/LiveTests.cs index f29d959..c875df6 100644 --- a/backend/tests/Monitor.Backend.Tests/LiveTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/LiveTests.cs @@ -1,10 +1,10 @@ using System.Net; using System.Text.Json.Nodes; using Fleet.Core; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; [Collection("backend")] public sealed class LiveTests diff --git a/backend/tests/Monitor.Backend.Tests/LoginRateLimitTests.cs b/backend/tests/MoShiro.Backend.Tests/LoginRateLimitTests.cs similarity index 98% rename from backend/tests/Monitor.Backend.Tests/LoginRateLimitTests.cs rename to backend/tests/MoShiro.Backend.Tests/LoginRateLimitTests.cs index ef1dee7..ddd5a91 100644 --- a/backend/tests/Monitor.Backend.Tests/LoginRateLimitTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/LoginRateLimitTests.cs @@ -1,7 +1,7 @@ using System.Net; using System.Text.Json.Nodes; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// 登录限流按来源地址计,会影响同一地址上的其他登录,所以用独立的后端实例。 public sealed class LoginRateLimitTests : IClassFixture diff --git a/backend/tests/Monitor.Backend.Tests/Monitor.Backend.Tests.csproj b/backend/tests/MoShiro.Backend.Tests/MoShiro.Backend.Tests.csproj similarity index 67% rename from backend/tests/Monitor.Backend.Tests/Monitor.Backend.Tests.csproj rename to backend/tests/MoShiro.Backend.Tests/MoShiro.Backend.Tests.csproj index d36d4b8..8409a4f 100644 --- a/backend/tests/Monitor.Backend.Tests/Monitor.Backend.Tests.csproj +++ b/backend/tests/MoShiro.Backend.Tests/MoShiro.Backend.Tests.csproj @@ -8,11 +8,11 @@ - - - + + + - + diff --git a/backend/tests/Monitor.Backend.Tests/NodeInfoTests.cs b/backend/tests/MoShiro.Backend.Tests/NodeInfoTests.cs similarity index 99% rename from backend/tests/Monitor.Backend.Tests/NodeInfoTests.cs rename to backend/tests/MoShiro.Backend.Tests/NodeInfoTests.cs index b9ecaf2..0bb40dc 100644 --- a/backend/tests/Monitor.Backend.Tests/NodeInfoTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/NodeInfoTests.cs @@ -2,10 +2,10 @@ using System.Text.Json; using System.Text.Json.Nodes; using System.Text.RegularExpressions; using Microsoft.Extensions.Time.Testing; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; public sealed partial class NodeInfoTests { diff --git a/backend/tests/Monitor.Backend.Tests/OnDemandTestsTests.cs b/backend/tests/MoShiro.Backend.Tests/OnDemandTestsTests.cs similarity index 99% rename from backend/tests/Monitor.Backend.Tests/OnDemandTestsTests.cs rename to backend/tests/MoShiro.Backend.Tests/OnDemandTestsTests.cs index f344ee8..66f200a 100644 --- a/backend/tests/Monitor.Backend.Tests/OnDemandTestsTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/OnDemandTestsTests.cs @@ -1,10 +1,10 @@ using System.Net; using System.Text.Json.Nodes; using Fleet.Core; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; [Collection("backend")] public sealed class OnDemandTestsTests @@ -233,7 +233,7 @@ public sealed class OnDemandTestsTests Assert.Equal("line:" + _backend.DefaultProbeId, item["series"]!.GetValue()); using HttpResponseMessage download = await _backend.Admin.GetAsync("/api/admin/raw/chunks/" + chunk.Header.ChunkId); - Assert.Equal("application/vnd.monitor.rawchunk", download.Content.Headers.ContentType!.MediaType); + Assert.Equal("application/vnd.moshiro.rawchunk", download.Content.Headers.ContentType!.MediaType); RawChunk decoded = RawChunkCodec.Decode(await download.Content.ReadAsByteArrayAsync()).Value; Assert.Equal(chunk.Header.ChunkId, decoded.Header.ChunkId); Assert.Equal(100, decoded.Find("msg")!.Count); diff --git a/backend/tests/Monitor.Backend.Tests/OpenApiConformanceTests.cs b/backend/tests/MoShiro.Backend.Tests/OpenApiConformanceTests.cs similarity index 99% rename from backend/tests/Monitor.Backend.Tests/OpenApiConformanceTests.cs rename to backend/tests/MoShiro.Backend.Tests/OpenApiConformanceTests.cs index 955c80d..7d9fdc0 100644 --- a/backend/tests/Monitor.Backend.Tests/OpenApiConformanceTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/OpenApiConformanceTests.cs @@ -1,7 +1,7 @@ using System.Text.Json.Nodes; using System.Text.RegularExpressions; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// /// 对照 docs/api-guidelines.md 检查运行时生成的 OpenAPI 文档:operationId、路径风格、错误响应格式、字段命名。 diff --git a/backend/tests/Monitor.Backend.Tests/OperationsAndSecurityTests.cs b/backend/tests/MoShiro.Backend.Tests/OperationsAndSecurityTests.cs similarity index 98% rename from backend/tests/Monitor.Backend.Tests/OperationsAndSecurityTests.cs rename to backend/tests/MoShiro.Backend.Tests/OperationsAndSecurityTests.cs index 4485688..c7b6215 100644 --- a/backend/tests/Monitor.Backend.Tests/OperationsAndSecurityTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/OperationsAndSecurityTests.cs @@ -5,12 +5,12 @@ using Fleet.Core; using Fleet.Rpc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -using Monitor.Backend.Analysis; -using Monitor.Backend.Application; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Backend.Analysis; +using MoShiro.Backend.Application; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; [Collection("backend")] public sealed class OperationsAndSecurityTests @@ -169,7 +169,7 @@ public sealed class OperationsAndSecurityTests await agent.SendBinaryAsync(OutboxFrame.Build(99, Guid.NewGuid(), [1])); // 没有注册的通道 // 节点不能调用任何“执行”类的方法:Fleet 根本没有这样的路由 - foreach (string method in new[] { "fleet.exec", "fleet.shell", "monitor.exec", "monitor.write_file", "fleet.update" }) + foreach (string method in new[] { "fleet.exec", "fleet.shell", "moshiro.exec", "moshiro.write_file", "fleet.update" }) { RpcMessage reply = await agent.RequestRawAsync(method); Assert.Equal("fleet_unsupported", reply.Error!.Data!.Code); diff --git a/backend/tests/Monitor.Backend.Tests/PersistenceTests.cs b/backend/tests/MoShiro.Backend.Tests/PersistenceTests.cs similarity index 97% rename from backend/tests/Monitor.Backend.Tests/PersistenceTests.cs rename to backend/tests/MoShiro.Backend.Tests/PersistenceTests.cs index 6a8c000..9c60385 100644 --- a/backend/tests/Monitor.Backend.Tests/PersistenceTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/PersistenceTests.cs @@ -1,8 +1,8 @@ using System.Text.Json.Nodes; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// 重启后端:数据、身份和令牌都必须还在;热层从原始块回填;段文件尾部没有索引的数据被截断。 public sealed class PersistenceTests : IAsyncLifetime diff --git a/backend/tests/Monitor.Backend.Tests/PlanTests.cs b/backend/tests/MoShiro.Backend.Tests/PlanTests.cs similarity index 86% rename from backend/tests/Monitor.Backend.Tests/PlanTests.cs rename to backend/tests/MoShiro.Backend.Tests/PlanTests.cs index 352345a..4aeb1f9 100644 --- a/backend/tests/Monitor.Backend.Tests/PlanTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/PlanTests.cs @@ -1,8 +1,8 @@ using System.Text.Json; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; public sealed class PlanTests { diff --git a/backend/tests/Monitor.Backend.Tests/ProbeEndToEndTests.cs b/backend/tests/MoShiro.Backend.Tests/ProbeEndToEndTests.cs similarity index 99% rename from backend/tests/Monitor.Backend.Tests/ProbeEndToEndTests.cs rename to backend/tests/MoShiro.Backend.Tests/ProbeEndToEndTests.cs index 21562d1..2d34f5a 100644 --- a/backend/tests/Monitor.Backend.Tests/ProbeEndToEndTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/ProbeEndToEndTests.cs @@ -1,6 +1,6 @@ using System.Text.Json.Nodes; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// 真实的后端 + 真实的 Agent + 真实的 Probe(都在进程内,回环网络)。 [Collection("probe-e2e")] diff --git a/backend/tests/Monitor.Backend.Tests/ProbeHarness.cs b/backend/tests/MoShiro.Backend.Tests/ProbeHarness.cs similarity index 93% rename from backend/tests/Monitor.Backend.Tests/ProbeHarness.cs rename to backend/tests/MoShiro.Backend.Tests/ProbeHarness.cs index 95b354e..e10cbcb 100644 --- a/backend/tests/Monitor.Backend.Tests/ProbeHarness.cs +++ b/backend/tests/MoShiro.Backend.Tests/ProbeHarness.cs @@ -1,9 +1,9 @@ using System.Text; using System.Text.Json.Nodes; using Fleet.Core; -using Monitor.Probe; +using MoShiro.Probe; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// 进程内的真实 Probe:用后端生成的身份文件(和面板下载的 probe.json 同一份)启动 。 public sealed class ProbeHarness : IAsyncDisposable @@ -31,7 +31,7 @@ public sealed class ProbeHarness : IAsyncDisposable JsonNode created = await backend.CreateProbeAsync(); string json = created.ToJsonString(); - string directory = Path.Combine(Path.GetTempPath(), "monitor-probe-" + Guid.NewGuid().ToString("N")); + string directory = Path.Combine(Path.GetTempPath(), "moshiro-probe-" + Guid.NewGuid().ToString("N")); System.IO.Directory.CreateDirectory(directory); string path = Path.Combine(directory, "probe.json"); await File.WriteAllTextAsync(path, json, Encoding.UTF8); diff --git a/backend/tests/Monitor.Backend.Tests/QueryPlanningTests.cs b/backend/tests/MoShiro.Backend.Tests/QueryPlanningTests.cs similarity index 92% rename from backend/tests/Monitor.Backend.Tests/QueryPlanningTests.cs rename to backend/tests/MoShiro.Backend.Tests/QueryPlanningTests.cs index 8c9d41e..259aa3d 100644 --- a/backend/tests/Monitor.Backend.Tests/QueryPlanningTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/QueryPlanningTests.cs @@ -1,10 +1,10 @@ using Fleet.Core; using Microsoft.Extensions.Time.Testing; -using Monitor.Backend.Analysis; -using Monitor.Backend.Application; -using Monitor.Protocol; +using MoShiro.Backend.Analysis; +using MoShiro.Backend.Application; +using MoShiro.Protocol; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// 时间段、步长与数据源的规划:与 docs/query.md 里的表格逐行对应。 public sealed class QueryPlanningTests @@ -127,18 +127,18 @@ public sealed class QueryPlanningTests { Result result = Resolver.Resolve(new RangeRequest(range, null, null, null, null), s_now); Assert.False(result.IsSuccess); - Assert.Contains(result.Error.Code, new[] { MonitorErrors.InvalidRange, MonitorErrors.RangeTooLarge }); + Assert.Contains(result.Error.Code, new[] { MoShiroErrors.InvalidRange, MoShiroErrors.RangeTooLarge }); } [Fact] public void RangeResolver_EnforcesThePointLimit_AndSuggestsAStep() { Result result = Resolver.Resolve(new RangeRequest("30d", null, null, "1m", null), s_now); - Assert.Equal(MonitorErrors.RangeTooLarge, result.Error.Code); + Assert.Equal(MoShiroErrors.RangeTooLarge, result.Error.Code); Assert.Contains("step=", result.Error.Message); - Assert.Equal(MonitorErrors.InvalidStep, Resolver.Resolve(new RangeRequest("1h", null, null, "7s", null), s_now).Error.Code); - Assert.Equal(MonitorErrors.InvalidRange, Resolver.Resolve(new RangeRequest(null, DateTimeOffset.FromUnixTimeMilliseconds(s_now), DateTimeOffset.FromUnixTimeMilliseconds(s_now), null, null), s_now).Error.Code); - Assert.Equal(MonitorErrors.ValidationFailed, Resolver.Resolve(new RangeRequest("1h", DateTimeOffset.FromUnixTimeMilliseconds(s_now - Hour), null, null, null), s_now).Error.Code); + Assert.Equal(MoShiroErrors.InvalidStep, Resolver.Resolve(new RangeRequest("1h", null, null, "7s", null), s_now).Error.Code); + Assert.Equal(MoShiroErrors.InvalidRange, Resolver.Resolve(new RangeRequest(null, DateTimeOffset.FromUnixTimeMilliseconds(s_now), DateTimeOffset.FromUnixTimeMilliseconds(s_now), null, null), s_now).Error.Code); + Assert.Equal(MoShiroErrors.ValidationFailed, Resolver.Resolve(new RangeRequest("1h", DateTimeOffset.FromUnixTimeMilliseconds(s_now - Hour), null, null, null), s_now).Error.Code); } [Fact] @@ -147,7 +147,7 @@ public sealed class QueryPlanningTests Assert.True(Resolver.Resolve(new RangeRequest("1h", null, null, null, "UTC"), s_now).IsSuccess); Assert.True(Resolver.Resolve(new RangeRequest("1h", null, null, null, null), s_now).IsSuccess); Result shanghai = Resolver.Resolve(new RangeRequest("7d", null, null, "1d", "Asia/Shanghai"), s_now); - Assert.Equal(MonitorErrors.ValidationFailed, shanghai.Error.Code); + Assert.Equal(MoShiroErrors.ValidationFailed, shanghai.Error.Code); Assert.IsType(shanghai.Error); } @@ -209,10 +209,10 @@ public sealed class QueryPlanningTests Assert.Equal(selection.ExportIds.Count, selection.ExportIds.Distinct().Count()); Assert.True(selection.WantsScores); - Assert.Equal(MonitorErrors.UnknownMetric, MetricSelection.Resolve("nope", null, 100).Error.Code); - Assert.Equal(MonitorErrors.UnknownMetric, MetricSelection.Resolve("score.nope", null, 100).Error.Code); - Assert.Equal(MonitorErrors.UnknownPreset, MetricSelection.Resolve(null, "nope", 100).Error.Code); - Assert.Equal(MonitorErrors.TooManyMetrics, MetricSelection.Resolve(null, "udp", 3).Error.Code); + Assert.Equal(MoShiroErrors.UnknownMetric, MetricSelection.Resolve("nope", null, 100).Error.Code); + Assert.Equal(MoShiroErrors.UnknownMetric, MetricSelection.Resolve("score.nope", null, 100).Error.Code); + Assert.Equal(MoShiroErrors.UnknownPreset, MetricSelection.Resolve(null, "nope", 100).Error.Code); + Assert.Equal(MoShiroErrors.TooManyMetrics, MetricSelection.Resolve(null, "udp", 3).Error.Code); } [Fact] diff --git a/backend/tests/Monitor.Backend.Tests/SseClient.cs b/backend/tests/MoShiro.Backend.Tests/SseClient.cs similarity index 99% rename from backend/tests/Monitor.Backend.Tests/SseClient.cs rename to backend/tests/MoShiro.Backend.Tests/SseClient.cs index f20f160..6d6b70f 100644 --- a/backend/tests/Monitor.Backend.Tests/SseClient.cs +++ b/backend/tests/MoShiro.Backend.Tests/SseClient.cs @@ -1,7 +1,7 @@ using System.Collections.Concurrent; using System.Text.Json.Nodes; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; public sealed record SseEvent(string Name, JsonNode? Data); diff --git a/backend/tests/Monitor.Backend.Tests/StorageTests.cs b/backend/tests/MoShiro.Backend.Tests/StorageTests.cs similarity index 97% rename from backend/tests/Monitor.Backend.Tests/StorageTests.cs rename to backend/tests/MoShiro.Backend.Tests/StorageTests.cs index e0dff17..ec98bcf 100644 --- a/backend/tests/Monitor.Backend.Tests/StorageTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/StorageTests.cs @@ -2,20 +2,20 @@ using System.Text; using Fleet.Core; using Fleet.Server; using Microsoft.Data.Sqlite; -using Monitor.Backend.Analysis; -using Monitor.Backend.Application; -using Monitor.Backend.Storage.Sqlite; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Backend.Analysis; +using MoShiro.Backend.Application; +using MoShiro.Backend.Storage.Sqlite; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; /// 存储层:段文件与索引、指标窗口、队列、节点与令牌。直接使用真实的 SQLite 和临时目录。 public sealed class StorageTests : IDisposable { private static readonly NodeId s_agent = new("agt_storage"); - private readonly string _dir = Path.Combine(Path.GetTempPath(), "monitor-storage-" + Guid.NewGuid().ToString("N")); + private readonly string _dir = Path.Combine(Path.GetTempPath(), "moshiro-storage-" + Guid.NewGuid().ToString("N")); private readonly SqliteDatabase _db; public StorageTests() @@ -269,7 +269,7 @@ public sealed class StorageTests : IDisposable Assert.True((await ((IFleetStore)store).CreateNodeAsync(Node("agt_4", "hk", NodeStatus.Pending), default)).IsSuccess); Result approve = await store.SetStatusAsync(new NodeId("agt_3"), NodeStatus.Active, default); - Assert.Equal(MonitorErrors.NameConflict, approve.Error.Code); + Assert.Equal(MoShiroErrors.NameConflict, approve.Error.Code); // 接管:保留旧 ID 与历史,换成新公钥,删除待审批记录 Result takeover = await store.TakeoverAsync(new NodeId("agt_3"), default); @@ -277,7 +277,7 @@ public sealed class StorageTests : IDisposable Assert.Equal(new byte[] { 1, 2, 3 }, takeover.Value.PublicKey); Assert.Null(await store.GetAsync(new NodeId("agt_3"), default)); Assert.Equal(NodeStatus.Pending, (await store.GetAsync(new NodeId("agt_4"), default))!.Status); - Assert.Equal(MonitorErrors.AgentNotFound, (await store.TakeoverAsync(new NodeId("agt_1"), default)).Error.Code); // 只有 pending 能接管别人 + Assert.Equal(MoShiroErrors.AgentNotFound, (await store.TakeoverAsync(new NodeId("agt_1"), default)).Error.Code); // 只有 pending 能接管别人 } [Fact] @@ -288,12 +288,12 @@ public sealed class StorageTests : IDisposable AgentRecord current = (await store.GetAsync(new NodeId("agt_1"), default))!; Result stale = await store.PatchAsync(current.Id, new AgentPatch { Labels = ["x"] }, current.RowVersion + 5, default); - Assert.Equal(MonitorErrors.PreconditionFailed, stale.Error.Code); + Assert.Equal(MoShiroErrors.PreconditionFailed, stale.Error.Code); Result ok = await store.PatchAsync(current.Id, new AgentPatch { Labels = ["x"] }, current.RowVersion, default); Assert.Equal(current.RowVersion + 1, ok.Value.RowVersion); Assert.Equal(["x"], ok.Value.Labels); Assert.Equal("hk", ok.Value.Name); // 没写的字段不动 - Assert.Equal(MonitorErrors.AgentNotFound, (await store.PatchAsync(new NodeId("agt_x"), new AgentPatch(), null, default)).Error.Code); + Assert.Equal(MoShiroErrors.AgentNotFound, (await store.PatchAsync(new NodeId("agt_x"), new AgentPatch(), null, default)).Error.Code); } [Fact] @@ -368,11 +368,11 @@ public sealed class StorageTests : IDisposable [Fact] public void Schema_RefusesADatabaseFromANewerBuild() { - string dir = Path.Combine(Path.GetTempPath(), "monitor-schema-" + Guid.NewGuid().ToString("N")); + string dir = Path.Combine(Path.GetTempPath(), "moshiro-schema-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(dir); try { - using (var connection = new SqliteConnection($"Data Source={Path.Combine(dir, "monitor.db")}")) + using (var connection = new SqliteConnection($"Data Source={Path.Combine(dir, "moshiro.db")}")) { connection.Open(); connection.Exec("PRAGMA user_version = 99"); diff --git a/backend/tests/Monitor.Backend.Tests/UpdateTests.cs b/backend/tests/MoShiro.Backend.Tests/UpdateTests.cs similarity index 93% rename from backend/tests/Monitor.Backend.Tests/UpdateTests.cs rename to backend/tests/MoShiro.Backend.Tests/UpdateTests.cs index caf8443..75c438b 100644 --- a/backend/tests/Monitor.Backend.Tests/UpdateTests.cs +++ b/backend/tests/MoShiro.Backend.Tests/UpdateTests.cs @@ -1,15 +1,20 @@ using System.Net; using System.Text.Json.Nodes; -using Monitor.Protocol; -using Monitor.TestSupport; +using MoShiro.Protocol; +using MoShiro.TestSupport; -namespace Monitor.Backend.Tests; +namespace MoShiro.Backend.Tests; [Collection("probe-e2e")] public sealed class UpdateTests { private const string Digest = "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; + // 每个用例取自己的 seq(单调递增):共用的后端只接受比已登记的更大的 seq,用例的先后顺序不能影响结果 + private static long s_seq = TimeProvider.System.GetUtcNow().ToUnixTimeSeconds() * 1000; + + private static long NextSeq() => Interlocked.Add(ref s_seq, 100); + private readonly BackendFixture _backend; public UpdateTests(BackendFixture backend) @@ -19,7 +24,7 @@ public sealed class UpdateTests // 面板不验签(节点宿主机上的更新器验),所以测试里签名随便写一个格式对的 private static string Manifest(string component, long seq, string digest = Digest) => - $$"""{"schema":1,"component":"{{component}}","channel":"dev","image":"registry.example/monitor-dev/monitor-{{component}}","digest":"{{digest}}","tag":"dev-{{seq}}","version":"0.1.1","commit":"abc","built_at":"2026-10-06T00:00:00Z","seq":{{seq}}}"""; + $$"""{"schema":1,"component":"{{component}}","channel":"dev","image":"registry.example/moshiro-dev/moshiro-{{component}}","digest":"{{digest}}","tag":"dev-{{seq}}","version":"0.1.1","commit":"abc","built_at":"2026-10-06T00:00:00Z","seq":{{seq}}}"""; private async Task PublishAsync(string manifest, string signature = "MEUCIQDc") => await _backend.Admin.PostAsync("/api/admin/releases", BackendFixture.Json(new JsonObject { ["manifest"] = manifest, ["signature"] = signature })); @@ -27,7 +32,7 @@ public sealed class UpdateTests [Fact] public async Task Release_IsForwardedByteForByte_ToOnlineNodesOfThatComponent_AndToNodesThatConnectLater() { - long seq = TimeProvider.System.GetUtcNow().ToUnixTimeSeconds() * 1000; + long seq = NextSeq(); await using AgentSimulator online = await _backend.ConnectAgentAsync(); string manifest = Manifest("agent", seq); @@ -53,7 +58,7 @@ public sealed class UpdateTests [Fact] public async Task Release_Registration_RefusesBadManifests_StaleSeq_AndNeedsAnAdmin() { - long seq = TimeProvider.System.GetUtcNow().ToUnixTimeSeconds() * 1000 + 5; + long seq = NextSeq(); Assert.Equal(HttpStatusCode.BadRequest, (await PublishAsync("{not json")).StatusCode); Assert.Equal(HttpStatusCode.BadRequest, (await PublishAsync(Manifest("agent", seq, digest: "sha256:short"))).StatusCode); Assert.Equal(HttpStatusCode.BadRequest, (await PublishAsync(Manifest("backend", seq))).StatusCode); @@ -84,7 +89,7 @@ public sealed class UpdateTests return client; } - long seq = TimeProvider.System.GetUtcNow().ToUnixTimeSeconds() * 1000 + 50; + long seq = NextSeq(); using HttpClient release = Client(await NewTokenAsync("release")); using HttpClient read = Client(await NewTokenAsync("read")); var body = BackendFixture.Json(new JsonObject { ["manifest"] = Manifest("probe", seq), ["signature"] = "MEUC" }); diff --git a/backend/tests/Monitor.TestSupport/AgentSimulator.cs b/backend/tests/MoShiro.TestSupport/AgentSimulator.cs similarity index 92% rename from backend/tests/Monitor.TestSupport/AgentSimulator.cs rename to backend/tests/MoShiro.TestSupport/AgentSimulator.cs index 4e7ca32..15b0d30 100644 --- a/backend/tests/Monitor.TestSupport/AgentSimulator.cs +++ b/backend/tests/MoShiro.TestSupport/AgentSimulator.cs @@ -7,9 +7,9 @@ using System.Text.Json.Nodes; using Fleet.Core; using Fleet.Identity; using Fleet.Rpc; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.TestSupport; +namespace MoShiro.TestSupport; /// /// 一个会说 Fleet 协议的假 Agent:用加入令牌注册 → 连接 → 签名认证 → hello → 接收期望状态 → 上传原始块并等待 ACK。 @@ -48,7 +48,7 @@ public sealed class AgentSimulator : IAsyncDisposable public ConcurrentQueue TestRuns { get; } = new(); - /// 面板发来的发布清单(monitor.update.offer)和更新请求(monitor.update.apply)。 + /// 面板发来的发布清单(moshiro.update.offer)和更新请求(moshiro.update.apply)。 public ConcurrentQueue UpdateOffers { get; } = new(); private int _updateApplies; @@ -63,7 +63,7 @@ public sealed class AgentSimulator : IAsyncDisposable public string? CloseReason { get; private set; } - /// 收到 monitor.test.run 时的应答:默认接受。 + /// 收到 moshiro.test.run 时的应答:默认接受。 public Func TestRunHandler { get; set; } = _ => (true, null); public byte[] PublicKey => _identity.PublicKeySpki; @@ -144,11 +144,11 @@ public sealed class AgentSimulator : IAsyncDisposable ProbeUdpPorts = [7443], LocalLimits = new LocalLimits { MaxTotalMbps = 200, MaxTotalPps = 20_000, MaxConcurrentTests = 1 }, }, - MonitorJsonContext.Default.AgentHelloMeta); + MoShiroJsonContext.Default.AgentHelloMeta); var hello = new HelloParams { NodeVersion = "0.0.1-sim", - Capabilities = [MonitorCapabilities.Base, MonitorCapabilities.KindsPrefix + string.Join(',', kinds ?? ["udp_echo", "tcp_echo", "udp_train", "connect", "hold", "tcp_bulk", "icmp_echo"])], + Capabilities = [MoShiroCapabilities.Base, MoShiroCapabilities.KindsPrefix + string.Join(',', kinds ?? ["udp_echo", "tcp_echo", "udp_train", "connect", "hold", "tcp_bulk", "icmp_echo"])], NowUtcMs = TimeProvider.System.GetUtcNow().ToUnixTimeMilliseconds(), Meta = meta, }; @@ -170,7 +170,7 @@ public sealed class AgentSimulator : IAsyncDisposable Guid id = chunk.Header.ChunkId.Value; var ack = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); _acks[id] = ack; - await SendBinaryAsync(OutboxFrame.Build(MonitorChannels.RawChunk, id, bytes)); + await SendBinaryAsync(OutboxFrame.Build(MoShiroChannels.RawChunk, id, bytes)); return await ack.Task.WaitAsync(timeout ?? TimeSpan.FromSeconds(10)); } @@ -182,24 +182,24 @@ public sealed class AgentSimulator : IAsyncDisposable public Task SendEventAsync(string kind, string? detail = null) => SendAsync(RpcMessage.Notification( - MonitorMethods.Event, + MoShiroMethods.Event, new AgentEventParams { Kind = kind, AtUtcMs = TimeProvider.System.GetUtcNow().ToUnixTimeMilliseconds(), Detail = detail }, - MonitorJsonContext.Default.AgentEventParams)); + MoShiroJsonContext.Default.AgentEventParams)); public Task SendHostAsync(HostSnapshot snapshot) => - SendAsync(RpcMessage.Notification(MonitorMethods.Host, snapshot, MonitorJsonContext.Default.HostSnapshot)); + SendAsync(RpcMessage.Notification(MoShiroMethods.Host, snapshot, MoShiroJsonContext.Default.HostSnapshot)); public Task SendTestStatusAsync(TestId test, string status, int? phase = null, string? errorCode = null) => SendAsync(RpcMessage.Notification( - MonitorMethods.TestStatus, + MoShiroMethods.TestStatus, new TestStatusParams { TestId = test, Status = status, Phase = phase, ErrorCode = errorCode }, - MonitorJsonContext.Default.TestStatusParams)); + MoShiroJsonContext.Default.TestStatusParams)); /// 像节点的更新器报告的那样,随心跳上报更新状态。 public Task SendUpdateStatusAsync(UpdateStatus status) => SendAsync(RpcMessage.Notification( FleetMethods.Heartbeat, - new HeartbeatParams { Extra = JsonSerializer.SerializeToElement(new AgentHeartbeatExtra { Update = status }, MonitorJsonContext.Default.AgentHeartbeatExtra) }, + new HeartbeatParams { Extra = JsonSerializer.SerializeToElement(new AgentHeartbeatExtra { Update = status }, MoShiroJsonContext.Default.AgentHeartbeatExtra) }, FleetRpcContext.Default.HeartbeatParams)); public async Task RequestRawAsync(string method, JsonElement? parameters = null) => await RequestAsync(method, parameters); @@ -383,7 +383,7 @@ public sealed class AgentSimulator : IAsyncDisposable StateSyncParams sync = message.Params!.Value.Deserialize(FleetRpcContext.Default.StateSyncParams)!; if (sync.Type == TaskSet.StateType) { - TaskSets.Enqueue(sync.Doc.Deserialize(MonitorJsonContext.Default.TaskSet)!); + TaskSets.Enqueue(sync.Doc.Deserialize(MoShiroJsonContext.Default.TaskSet)!); } var result = new StateSyncResult { AppliedVersion = sync.Version, Rejected = [.. RejectNextState] }; @@ -403,19 +403,19 @@ public sealed class AgentSimulator : IAsyncDisposable case FleetMethods.Revoked: Revoked = true; break; - case MonitorMethods.UpdateOffer: - UpdateOffers.Enqueue(message.Params!.Value.Deserialize(MonitorJsonContext.Default.UpdateOfferParams)!); + case MoShiroMethods.UpdateOffer: + UpdateOffers.Enqueue(message.Params!.Value.Deserialize(MoShiroJsonContext.Default.UpdateOfferParams)!); break; - case MonitorMethods.UpdateApply: + case MoShiroMethods.UpdateApply: Interlocked.Increment(ref _updateApplies); break; - case MonitorMethods.TestRun: - TestRunParams run = message.Params!.Value.Deserialize(MonitorJsonContext.Default.TestRunParams)!; + case MoShiroMethods.TestRun: + TestRunParams run = message.Params!.Value.Deserialize(MoShiroJsonContext.Default.TestRunParams)!; TestRuns.Enqueue(run); (bool accepted, string? errorCode) = TestRunHandler(run); if (accepted) { - await SendAsync(RpcMessage.Success(message.Id!.Value, new TestRunResult { Accepted = true }, MonitorJsonContext.Default.TestRunResult)); + await SendAsync(RpcMessage.Success(message.Id!.Value, new TestRunResult { Accepted = true }, MoShiroJsonContext.Default.TestRunResult)); } else { @@ -423,10 +423,10 @@ public sealed class AgentSimulator : IAsyncDisposable } break; - case MonitorMethods.TestCancel: - TestCancelParams cancel = message.Params!.Value.Deserialize(MonitorJsonContext.Default.TestCancelParams)!; + case MoShiroMethods.TestCancel: + TestCancelParams cancel = message.Params!.Value.Deserialize(MoShiroJsonContext.Default.TestCancelParams)!; TestCancels.Enqueue(cancel.TestId); - await SendAsync(RpcMessage.Success(message.Id!.Value, new TestRunResult { Accepted = true }, MonitorJsonContext.Default.TestRunResult)); + await SendAsync(RpcMessage.Success(message.Id!.Value, new TestRunResult { Accepted = true }, MoShiroJsonContext.Default.TestRunResult)); break; } } diff --git a/backend/tests/Monitor.TestSupport/AgentWire.cs b/backend/tests/MoShiro.TestSupport/AgentWire.cs similarity index 98% rename from backend/tests/Monitor.TestSupport/AgentWire.cs rename to backend/tests/MoShiro.TestSupport/AgentWire.cs index 685f307..a3fbf6e 100644 --- a/backend/tests/Monitor.TestSupport/AgentWire.cs +++ b/backend/tests/MoShiro.TestSupport/AgentWire.cs @@ -3,7 +3,7 @@ using System.Text.Json; using Fleet.Core; using Fleet.Rpc; -namespace Monitor.TestSupport; +namespace MoShiro.TestSupport; public sealed record AuthAttempt(bool Ok, string? Status, string? ErrorCode, string? CloseReason); diff --git a/backend/tests/Monitor.TestSupport/ChunkFactory.cs b/backend/tests/MoShiro.TestSupport/ChunkFactory.cs similarity index 99% rename from backend/tests/Monitor.TestSupport/ChunkFactory.cs rename to backend/tests/MoShiro.TestSupport/ChunkFactory.cs index 2a01dab..3f51c50 100644 --- a/backend/tests/Monitor.TestSupport/ChunkFactory.cs +++ b/backend/tests/MoShiro.TestSupport/ChunkFactory.cs @@ -1,8 +1,8 @@ using System.Text.Json; using Fleet.Core; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.TestSupport; +namespace MoShiro.TestSupport; /// 每一个回显包的设定:上行或下行丢失,以及两个方向的单向时延(微秒)。 public readonly record struct EchoPacket(bool LostUp, bool LostDown, long OwdUpUs, long OwdDownUs, long ProcessUs = 50); diff --git a/backend/tests/Monitor.TestSupport/Monitor.TestSupport.csproj b/backend/tests/MoShiro.TestSupport/MoShiro.TestSupport.csproj similarity index 77% rename from backend/tests/Monitor.TestSupport/Monitor.TestSupport.csproj rename to backend/tests/MoShiro.TestSupport/MoShiro.TestSupport.csproj index ae60e1e..56e8167 100644 --- a/backend/tests/Monitor.TestSupport/Monitor.TestSupport.csproj +++ b/backend/tests/MoShiro.TestSupport/MoShiro.TestSupport.csproj @@ -3,7 +3,7 @@ false - + diff --git a/backend/tests/Monitor.TestSupport/ProbeSimulator.cs b/backend/tests/MoShiro.TestSupport/ProbeSimulator.cs similarity index 96% rename from backend/tests/Monitor.TestSupport/ProbeSimulator.cs rename to backend/tests/MoShiro.TestSupport/ProbeSimulator.cs index d2734a1..972bc58 100644 --- a/backend/tests/Monitor.TestSupport/ProbeSimulator.cs +++ b/backend/tests/MoShiro.TestSupport/ProbeSimulator.cs @@ -8,9 +8,9 @@ using Fleet.Core; using Fleet.Identity; using Fleet.Link; using Fleet.Rpc; -using Monitor.Protocol; +using MoShiro.Protocol; -namespace Monitor.TestSupport; +namespace MoShiro.TestSupport; /// /// 假 Probe:通过真实的点对点握手(TLS 固定证书 + 签名 + ECDH)连接真实的 Agent,接收 line_task_set, @@ -104,7 +104,7 @@ public sealed class ProbeSimulator : IAsyncDisposable for (int i = 0; i < rounds; i++) { long t0 = NowUs(); - Result reply = await _rpc!.RequestAsync(MonitorMethods.Clock, new ClockParams { ProbeMonoUs = t0 }, MonitorJsonContext.Default.ClockParams, MonitorJsonContext.Default.ClockResult, CancellationToken.None); + Result reply = await _rpc!.RequestAsync(MoShiroMethods.Clock, new ClockParams { ProbeMonoUs = t0 }, MoShiroJsonContext.Default.ClockParams, MoShiroJsonContext.Default.ClockResult, CancellationToken.None); long t1 = NowUs(); long roundTrip = t1 - t0; if (reply.IsSuccess && roundTrip < bestRoundTrip) @@ -214,7 +214,7 @@ public sealed class ProbeSimulator : IAsyncDisposable Guid id = fragment.Header.ChunkId.Value; var ack = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); _acks[id] = ack; - await _rpc!.SendBinaryAsync(OutboxFrame.Build(MonitorChannels.ColumnBlock, id, RawChunkCodec.Encode(fragment)), ct); + await _rpc!.SendBinaryAsync(OutboxFrame.Build(MoShiroChannels.ColumnBlock, id, RawChunkCodec.Encode(fragment)), ct); if (waitForAck) { await ack.Task.WaitAsync(TimeSpan.FromSeconds(10), ct); @@ -322,24 +322,24 @@ public sealed class ProbeSimulator : IAsyncDisposable { if (sync.Type == LineTaskSet.StateType) { - probe._taskSets.Enqueue(sync.Doc.Deserialize(MonitorJsonContext.Default.LineTaskSet)!); + probe._taskSets.Enqueue(sync.Doc.Deserialize(MoShiroJsonContext.Default.LineTaskSet)!); } return ValueTask.FromResult(Result.Ok(new StateSyncResult { AppliedVersion = sync.Version })); }) .On( - MonitorMethods.TestPhase, - MonitorJsonContext.Default.TestPhaseStartParams, - MonitorJsonContext.Default.TestPhaseStartResult, + MoShiroMethods.TestPhase, + MoShiroJsonContext.Default.TestPhaseStartParams, + MoShiroJsonContext.Default.TestPhaseStartResult, async (probe, start, ct) => Result.Ok(new TestPhaseStartResult { Accepted = await probe.StartPhaseAsync(start, ct) })) .On( - MonitorMethods.TestPhaseEnd, - MonitorJsonContext.Default.TestPhaseEndParams, - MonitorJsonContext.Default.TestPhaseEndResult, + MoShiroMethods.TestPhaseEnd, + MoShiroJsonContext.Default.TestPhaseEndParams, + MoShiroJsonContext.Default.TestPhaseEndResult, async (probe, end, ct) => Result.Ok(new TestPhaseEndResult { Fragments = await probe.EndPhaseAsync(end, ct) })) .OnNotify( - MonitorMethods.TestAbort, - MonitorJsonContext.Default.TestAbortParams, + MoShiroMethods.TestAbort, + MoShiroJsonContext.Default.TestAbortParams, (probe, abort, _) => { probe.Aborts.Enqueue(abort.TestId); diff --git a/ci/Monitor.Tar/Monitor.Tar.csproj b/ci/MoShiro.Tar/MoShiro.Tar.csproj similarity index 100% rename from ci/Monitor.Tar/Monitor.Tar.csproj rename to ci/MoShiro.Tar/MoShiro.Tar.csproj diff --git a/ci/Monitor.Tar/Program.cs b/ci/MoShiro.Tar/Program.cs similarity index 96% rename from ci/Monitor.Tar/Program.cs rename to ci/MoShiro.Tar/Program.cs index a66e340..65587dc 100644 --- a/ci/Monitor.Tar/Program.cs +++ b/ci/MoShiro.Tar/Program.cs @@ -3,7 +3,7 @@ using System.IO.Compression; if (args.Length < 3) { - Console.Error.WriteLine("usage: Monitor.Tar ..."); + Console.Error.WriteLine("usage: MoShiro.Tar ..."); return 2; } diff --git a/ci/build-main-amd64.sh b/ci/build-main-amd64.sh index 68b1b1d..649dc5d 100644 --- a/ci/build-main-amd64.sh +++ b/ci/build-main-amd64.sh @@ -23,7 +23,7 @@ esac root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" registry="${ZOT_REGISTRY:-registry.oeo.one}" -repository="$registry/monitor-dev/monitor-$component" +repository="$registry/moshiro-dev/moshiro-$component" work="$root/.release/main-amd64-build" base_home="/home/justme/woodpecker/buildah-home/main-amd64-build-$component" short_sha="${CI_COMMIT_SHA:0:12}" @@ -44,12 +44,12 @@ export HOME="$base_home" export BUILDAH_HOME="$base_home" export REGISTRY_AUTH_FILE="$work/$component-auth.json" context="$work/$component" -local_image="localhost/monitor-$component:main-amd64-check" +local_image="localhost/moshiro-$component:main-amd64-check" python3 "$root/ci/stage-node-image.py" "$component" "$context" buildah bud --layers --network host --tls-verify=true --arch amd64 \ --build-arg APP_VERSION=main \ - --build-arg "MONITOR_TAG=$dev_tag" --build-arg "MONITOR_COMMIT=${CI_COMMIT_SHA:0:10}" --build-arg "MONITOR_BUILT_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + --build-arg "MOSHIRO_TAG=$dev_tag" --build-arg "MOSHIRO_COMMIT=${CI_COMMIT_SHA:0:10}" --build-arg "MOSHIRO_BUILT_AT=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ -f "$context/Containerfile" \ -t "$local_image" "$context" diff --git a/ci/index-backend-image.sh b/ci/index-backend-image.sh index aff521b..793d15b 100644 --- a/ci/index-backend-image.sh +++ b/ci/index-backend-image.sh @@ -11,7 +11,7 @@ version="${CI_COMMIT_TAG#v}" registry="${ZOT_REGISTRY:-registry.oeo.one}" scheme="${ZOT_SCHEME:-https}" -image="monitor/monitor-backend" +image="moshiro/moshiro-backend" auth_file="$(mktemp)" chmod 600 "$auth_file" trap 'rm -f "$auth_file"' EXIT diff --git a/ci/package-cross-platform.ps1 b/ci/package-cross-platform.ps1 index 32c02be..71327a4 100644 --- a/ci/package-cross-platform.ps1 +++ b/ci/package-cross-platform.ps1 @@ -15,14 +15,14 @@ if ($version -ne $projectVersion) { throw "Tag version $version does not match project version $projectVersion." } -$tarProject = Join-Path $PSScriptRoot 'Monitor.Tar\Monitor.Tar.csproj' -$tarTool = Join-Path $PSScriptRoot 'Monitor.Tar\bin\Release\net10.0\Monitor.Tar.dll' +$tarProject = Join-Path $PSScriptRoot 'MoShiro.Tar\MoShiro.Tar.csproj' +$tarTool = Join-Path $PSScriptRoot 'MoShiro.Tar\bin\Release\net10.0\MoShiro.Tar.dll' & dotnet build $tarProject -c Release --nologo if ($LASTEXITCODE -ne 0) { throw 'Could not build the cross-platform tar helper.' } $giteaBase = if ($env:GITEA_BASE) { $env:GITEA_BASE.TrimEnd('/') } else { 'http://localhost:3100' } -$netrc = Join-Path $env:TEMP ("monitor-gitea-$([guid]::NewGuid().ToString('N')).netrc") +$netrc = Join-Path $env:TEMP ("moshiro-gitea-$([guid]::NewGuid().ToString('N')).netrc") $giteaHost = ([Uri]$giteaBase).Host Set-Content -LiteralPath $netrc -Value "machine $giteaHost login justme password $($env:GITEA_TOKEN)" -Encoding ascii -NoNewline @@ -61,11 +61,11 @@ try { $stage = Join-Path $root ".release\stage\$($target.Rid)\$role" $null = New-Item -ItemType Directory -Force -Path $stage $extension = if ($target.Windows) { '.exe' } else { '' } - Copy-Item -LiteralPath (Join-Path (Join-Path $root ".release\publish\$($target.Rid)\$role") "monitor-$role$extension") -Destination $stage + Copy-Item -LiteralPath (Join-Path (Join-Path $root ".release\publish\$($target.Rid)\$role") "moshiro-$role$extension") -Destination $stage Copy-Item -LiteralPath (Join-Path $root 'LICENSE') -Destination $stage Copy-Item -LiteralPath (Join-Path $root "backend\$role\README.md") -Destination $stage - $executables = @("monitor-$role$extension") + $executables = @("moshiro-$role$extension") if ($role -eq 'agent') { $enrollName = if ($target.Windows) { 'fleet-enroll.exe' } else { 'fleet-enroll' } Copy-Item -LiteralPath (Join-Path $enrollDirectory $enrollName) -Destination $stage @@ -76,12 +76,12 @@ try { $executables += 'install.sh' $systemd = Join-Path $stage 'systemd' $null = New-Item -ItemType Directory -Force -Path $systemd - Copy-Item -LiteralPath (Join-Path $root "packaging/systemd/monitor-$role.service") -Destination $systemd + Copy-Item -LiteralPath (Join-Path $root "packaging/systemd/moshiro-$role.service") -Destination $systemd if ($role -eq 'probe') { $openwrt = Join-Path $stage 'openwrt' $null = New-Item -ItemType Directory -Force -Path $openwrt - Copy-Item -LiteralPath (Join-Path $root 'packaging/openwrt/monitor-probe.init') -Destination $openwrt - Copy-Item -LiteralPath (Join-Path $root 'packaging/openwrt/monitor.keep') -Destination $openwrt + Copy-Item -LiteralPath (Join-Path $root 'packaging/openwrt/moshiro-probe.init') -Destination $openwrt + Copy-Item -LiteralPath (Join-Path $root 'packaging/openwrt/moshiro.keep') -Destination $openwrt } } elseif ($target.Os -eq 'macos') { @@ -94,7 +94,7 @@ consumer install. '@ | Set-Content -LiteralPath (Join-Path $stage 'MACOS-SECURITY.txt') -Encoding utf8 } - $archiveName = if ($target.Windows) { "monitor-$role-v$version-windows-$($target.Arch).zip" } else { "monitor-$role-v$version-$($target.Os)-$($target.Arch).tar.gz" } + $archiveName = if ($target.Windows) { "moshiro-$role-v$version-windows-$($target.Arch).zip" } else { "moshiro-$role-v$version-$($target.Os)-$($target.Arch).tar.gz" } $archive = Join-Path $packageRoot $archiveName if ($target.Windows) { Compress-Archive -Path (Join-Path $stage '*') -DestinationPath $archive -CompressionLevel Optimal -Force @@ -115,7 +115,7 @@ consumer install. param([string]$File, [string]$Base, [string]$PackageVersion, [string]$Netrc) $ErrorActionPreference = 'Stop' $name = [IO.Path]::GetFileName($File) -$url = "$Base/api/packages/justme/generic/monitor-node/$PackageVersion/$name" +$url = "$Base/api/packages/justme/generic/moshiro-node/$PackageVersion/$name" $status = & curl.exe --silent --show-error --retry 3 --netrc-file $Netrc --upload-file $File --output NUL --write-out '%{http_code}' $url if ($LASTEXITCODE -ne 0) { throw "Gitea package upload failed for $name (curl exit $LASTEXITCODE)." diff --git a/ci/publish-gitea-release.sh b/ci/publish-gitea-release.sh index 80dabea..55cc612 100644 --- a/ci/publish-gitea-release.sh +++ b/ci/publish-gitea-release.sh @@ -16,7 +16,7 @@ gitea_host="${gitea_base#https://}" gitea_host="${gitea_host#http://}" gitea_host="${gitea_host%%/*}" gitea_host="${gitea_host%%:*}" -api="$gitea_base/api/v1/repos/justme/MyMonitor" +api="$gitea_base/api/v1/repos/justme/MoShiro" tmp="$(mktemp -d)" netrc="$tmp/netrc" release_json="$tmp/release.json" @@ -26,8 +26,8 @@ printf 'machine %s login justme password %s\n' "$gitea_host" "$GITEA_TOKEN" > "$ chmod 600 "$netrc" trap 'rm -rf "$tmp"' EXIT -release_body="Agent and Probe builds: Linux glibc and musl (x64, arm64), macOS (x64, arm64), and Windows (x64, arm64). Linux glibc Agent and Probe OCI images: registry.oeo.one/monitor/monitor-agent:$version and registry.oeo.one/monitor/monitor-probe:$version (linux/amd64 and linux/arm64). Backend OCI image: registry.oeo.one/monitor/monitor-backend:$version (linux/amd64 and linux/arm64). macOS binaries are not Developer ID signed or notarized." -payload="$(printf '{"tag_name":"%s","target_commitish":"%s","name":"MyMonitor %s","body":"%s","draft":false,"prerelease":false}' \ +release_body="Agent and Probe builds: Linux glibc and musl (x64, arm64), macOS (x64, arm64), and Windows (x64, arm64). Linux glibc Agent and Probe OCI images: registry.oeo.one/moshiro/moshiro-agent:$version and registry.oeo.one/moshiro/moshiro-probe:$version (linux/amd64 and linux/arm64). Backend OCI image: registry.oeo.one/moshiro/moshiro-backend:$version (linux/amd64 and linux/arm64). macOS binaries are not Developer ID signed or notarized." +payload="$(printf '{"tag_name":"%s","target_commitish":"%s","name":"MoShiro %s","body":"%s","draft":false,"prerelease":false}' \ "$tag" "${CI_COMMIT_SHA:-}" "$tag" "$release_body")" release_status="$(curl --silent --show-error --retry 3 --netrc-file "$netrc" \ --output "$release_json" --write-out '%{http_code}' "$api/releases/tags/$tag")" @@ -60,28 +60,28 @@ curl --fail-with-body --silent --show-error --retry 3 --netrc-file "$netrc" \ "$api/releases/$release_id/assets" -o "$assets_json" assets=( - "monitor-agent-v$version-linux-amd64.tar.gz" - "monitor-agent-v$version-linux-arm64.tar.gz" - "monitor-probe-v$version-linux-amd64.tar.gz" - "monitor-probe-v$version-linux-arm64.tar.gz" - "monitor-agent-v$version-linux-musl-amd64.tar.gz" - "monitor-probe-v$version-linux-musl-amd64.tar.gz" - "monitor-agent-v$version-linux-musl-arm64.tar.gz" - "monitor-probe-v$version-linux-musl-arm64.tar.gz" - "monitor-agent-v$version-macos-x64.tar.gz" - "monitor-probe-v$version-macos-x64.tar.gz" - "monitor-agent-v$version-macos-arm64.tar.gz" - "monitor-probe-v$version-macos-arm64.tar.gz" - "monitor-agent-v$version-windows-amd64.zip" - "monitor-agent-v$version-windows-arm64.zip" - "monitor-probe-v$version-windows-amd64.zip" - "monitor-probe-v$version-windows-arm64.zip" + "moshiro-agent-v$version-linux-amd64.tar.gz" + "moshiro-agent-v$version-linux-arm64.tar.gz" + "moshiro-probe-v$version-linux-amd64.tar.gz" + "moshiro-probe-v$version-linux-arm64.tar.gz" + "moshiro-agent-v$version-linux-musl-amd64.tar.gz" + "moshiro-probe-v$version-linux-musl-amd64.tar.gz" + "moshiro-agent-v$version-linux-musl-arm64.tar.gz" + "moshiro-probe-v$version-linux-musl-arm64.tar.gz" + "moshiro-agent-v$version-macos-x64.tar.gz" + "moshiro-probe-v$version-macos-x64.tar.gz" + "moshiro-agent-v$version-macos-arm64.tar.gz" + "moshiro-probe-v$version-macos-arm64.tar.gz" + "moshiro-agent-v$version-windows-amd64.zip" + "moshiro-agent-v$version-windows-arm64.zip" + "moshiro-probe-v$version-windows-amd64.zip" + "moshiro-probe-v$version-windows-arm64.zip" ) upload_release_asset() { local name="$1" file="$tmp/$1" upload_response="$tmp/$1.upload.json" status curl --fail-with-body --silent --show-error --retry 3 --netrc-file "$netrc" \ - "$gitea_base/api/packages/justme/generic/monitor-node/$version/$name" -o "$file" + "$gitea_base/api/packages/justme/generic/moshiro-node/$version/$name" -o "$file" status="$(curl --silent --show-error --retry 3 --netrc-file "$netrc" \ --request POST --header 'Content-Type: application/octet-stream' --data-binary "@$file" \ --output "$upload_response" --write-out '%{http_code}' \ @@ -111,4 +111,4 @@ for pid in "${pids[@]}"; do wait "$pid" done -echo "published Gitea Release $tag: https://git.oeo.one/justme/MyMonitor/releases/tag/$tag" +echo "published Gitea Release $tag: https://git.oeo.one/justme/MoShiro/releases/tag/$tag" diff --git a/ci/release-cross-platform.ps1 b/ci/release-cross-platform.ps1 index d048fd0..2d3d60b 100644 --- a/ci/release-cross-platform.ps1 +++ b/ci/release-cross-platform.ps1 @@ -43,8 +43,8 @@ if ($RuntimeIdentifier -in @('win-x64', 'win-arm64')) { } $project = switch ($Component) { - 'agent' { 'agent/src/Monitor.Agent' } - 'probe' { 'probe/src/Monitor.Probe' } + 'agent' { 'agent/src/MoShiro.Agent' } + 'probe' { 'probe/src/MoShiro.Probe' } 'fleet-enroll' { 'fleet/tools/fleet-enroll' } } $output = Join-Path $root ".release\publish\$RuntimeIdentifier\$Component" @@ -52,9 +52,9 @@ $buildRoot = Join-Path $root ".release\build\$RuntimeIdentifier-$Component" $null = New-Item -ItemType Directory -Force -Path $output # 构建信息:程序里显示的 tag、提交、构建时间 -$env:MONITOR_TAG = if ($env:CI_COMMIT_TAG) { $env:CI_COMMIT_TAG } else { "main-$($env:CI_COMMIT_SHA.Substring(0, 10))" } -$env:MONITOR_COMMIT = $env:CI_COMMIT_SHA.Substring(0, 10) -$env:MONITOR_BUILT_AT = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') +$env:MOSHIRO_TAG = if ($env:CI_COMMIT_TAG) { $env:CI_COMMIT_TAG } else { "main-$($env:CI_COMMIT_SHA.Substring(0, 10))" } +$env:MOSHIRO_COMMIT = $env:CI_COMMIT_SHA.Substring(0, 10) +$env:MOSHIRO_BUILT_AT = (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') Push-Location $backend try { diff --git a/ci/release-linux.sh b/ci/release-linux.sh index f7e34f8..e801990 100644 --- a/ci/release-linux.sh +++ b/ci/release-linux.sh @@ -40,25 +40,25 @@ if [[ -n "$tag" && "$version" != "$project_version" ]]; then fi registry="${ZOT_REGISTRY:-registry.oeo.one}" -image="${ZOT_IMAGE_REPOSITORY:-$registry/monitor/monitor-backend}" +image="${ZOT_IMAGE_REPOSITORY:-$registry/moshiro/moshiro-backend}" output="$root/.release/linux-$arch/backend" build_root="$root/.release/build/linux-$arch-backend" container_context="$root/.release/container/linux-$arch" mkdir -p "$output" "$build_root" "$container_context/app" "$container_context/data" # 构建信息:tag 发布用 tag,main 构建用 main-<提交> -export MONITOR_TAG="${MONITOR_TAG:-${tag:-main-${CI_COMMIT_SHA:0:10}}}" -export MONITOR_COMMIT="${MONITOR_COMMIT:-${CI_COMMIT_SHA:0:10}}" -export MONITOR_BUILT_AT="${MONITOR_BUILT_AT:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}" +export MOSHIRO_TAG="${MOSHIRO_TAG:-${tag:-main-${CI_COMMIT_SHA:0:10}}}" +export MOSHIRO_COMMIT="${MOSHIRO_COMMIT:-${CI_COMMIT_SHA:0:10}}" +export MOSHIRO_BUILT_AT="${MOSHIRO_BUILT_AT:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}" -(cd "$root/backend" && dotnet publish src/Monitor.Backend \ +(cd "$root/backend" && dotnet publish src/MoShiro.Backend \ -m:3 -c Release -r "$rid" --self-contained true \ -p:DebugType=none -p:DebugSymbols=false \ -p:PublishAot=true -p:UseAotAnywhere=true -p:SqliteStaticLink=true -p:OpenApiGenerateDocuments=false \ --artifacts-path "$build_root" -o "$output") -[[ -x "$output/monitor-backend" ]] || { echo "NativeAOT Backend executable is missing" >&2; exit 1; } -[[ "$(wc -c < "$output/monitor-backend")" -gt 2000000 ]] || { echo "Backend output is an apphost, not a NativeAOT executable" >&2; exit 1; } -install -m 0755 "$output/monitor-backend" "$container_context/app/monitor-backend" +[[ -x "$output/moshiro-backend" ]] || { echo "NativeAOT Backend executable is missing" >&2; exit 1; } +[[ "$(wc -c < "$output/moshiro-backend")" -gt 2000000 ]] || { echo "Backend output is an apphost, not a NativeAOT executable" >&2; exit 1; } +install -m 0755 "$output/moshiro-backend" "$container_context/app/moshiro-backend" : > "$container_context/data/.keep" # Woodpecker's local backend isolates HOME per workflow. Keep Buildah's image @@ -68,7 +68,7 @@ buildah_home="${BUILDAH_HOME:-/home/justme/woodpecker/buildah-home/$arch}" mkdir -p "$buildah_home" export HOME="$buildah_home" -local_image="localhost/monitor-backend:$version-$arch" +local_image="localhost/moshiro-backend:$version-$arch" buildah bud --tls-verify=true --arch "$arch" \ --build-arg "APP_VERSION=$version" \ -f "$root/packaging/container/Backend.Containerfile" \ diff --git a/ci/release-node-images.sh b/ci/release-node-images.sh index 95eaa7e..e6c1cd9 100644 --- a/ci/release-node-images.sh +++ b/ci/release-node-images.sh @@ -28,7 +28,7 @@ gitea_host="${gitea_host#http://}" gitea_host="${gitea_host%%/*}" gitea_host="${gitea_host%%:*}" registry="${ZOT_REGISTRY:-registry.oeo.one}" -image_root="$registry/monitor" +image_root="$registry/moshiro" work="$root/.release/node-images" netrc="$work/netrc" buildah_home="/home/justme/woodpecker/buildah-home/node-images" @@ -56,23 +56,23 @@ done build_arch_image() { local component="$1" arch="$2" suffix="$3" - local filename="monitor-$component-v$version-linux-$suffix.tar.gz" + local filename="moshiro-$component-v$version-linux-$suffix.tar.gz" local context="$work/$component-$arch" local archive="$work/$filename" local containerfile="$root/packaging/container/${component^}.Containerfile" - local image="$image_root/monitor-$component" - local local_image="localhost/monitor-$component:$version-$arch" + local image="$image_root/moshiro-$component" + local local_image="localhost/moshiro-$component:$version-$arch" curl --fail-with-body --silent --show-error --retry 3 --netrc-file "$netrc" \ - "$gitea_base/api/packages/justme/generic/monitor-node/$version/$filename" -o "$archive" + "$gitea_base/api/packages/justme/generic/moshiro-node/$version/$filename" -o "$archive" mkdir -p "$context/app" "$context/config" if [[ "$component" == agent ]]; then - tar -xzf "$archive" -C "$work" monitor-agent fleet-enroll + tar -xzf "$archive" -C "$work" moshiro-agent fleet-enroll install -m 0755 "$work/fleet-enroll" "$context/app/fleet-enroll" else - tar -xzf "$archive" -C "$work" "monitor-$component" + tar -xzf "$archive" -C "$work" "moshiro-$component" fi - install -m 0755 "$work/monitor-$component" "$context/app/monitor-$component" + install -m 0755 "$work/moshiro-$component" "$context/app/moshiro-$component" : > "$context/config/.keep" buildah bud --tls-verify=true --arch "$arch" \ @@ -95,8 +95,8 @@ build_arch_image() { } publish_index() { - local component="$1" image="$image_root/monitor-$component" - local manifest="localhost/monitor-$component:$version-multiarch" + local component="$1" image="$image_root/moshiro-$component" + local manifest="localhost/moshiro-$component:$version-multiarch" buildah manifest rm "$manifest" >/dev/null 2>&1 || true buildah manifest create "$manifest" >/dev/null buildah manifest add "$manifest" "docker://$image:$version-amd64" >/dev/null diff --git a/compose.yaml b/compose.yaml index 1b83feb..a6471c3 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,18 +1,18 @@ services: backend: - image: registry.oeo.one/monitor/monitor-backend:${MONITOR_VERSION:-0.1.1} - container_name: monitor-backend + image: registry.oeo.one/moshiro/moshiro-backend:${MOSHIRO_VERSION:-0.1.1} + container_name: moshiro-backend restart: unless-stopped init: true ports: - "127.0.0.1:8080:8080" environment: ASPNETCORE_HTTP_PORTS: "8080" - Monitor__DataDirectory: /data - Monitor__InitialAdminUser: ${MONITOR_ADMIN_USER:-admin} - Monitor__InitialAdminPassword: "${MONITOR_ADMIN_PASSWORD:?Set MONITOR_ADMIN_PASSWORD in the environment}" + MoShiro__DataDirectory: /data + MoShiro__InitialAdminUser: ${MOSHIRO_ADMIN_USER:-admin} + MoShiro__InitialAdminPassword: "${MOSHIRO_ADMIN_PASSWORD:?Set MOSHIRO_ADMIN_PASSWORD in the environment}" volumes: - - monitor-data:/data + - moshiro-data:/data read_only: true tmpfs: - /tmp:rw,noexec,nosuid,size=64m,mode=1777 @@ -23,4 +23,4 @@ services: stop_grace_period: 30s volumes: - monitor-data: + moshiro-data: diff --git a/docs/analysis.md b/docs/analysis.md index aa2545c..9785a89 100644 --- a/docs/analysis.md +++ b/docs/analysis.md @@ -135,7 +135,7 @@ chunk 入库 ─┬─> 流式路径:按 1s 桶计算累加器 → 热层环 ## 9. 项目结构 ```text -backend/src/Monitor.Backend.Analysis/ 依赖:Monitor.Protocol、Fleet.Core(纯计算,没有 I/O) +backend/src/MoShiro.Backend.Analysis/ 依赖:MoShiro.Protocol、Fleet.Core(纯计算,没有 I/O) ├─ Accumulators/ Counter Ratio Sum Min Max Histogram RunLength Series + AccumulatorCodec ├─ Ops/ Rtt Loss OwdVar LossRuns Reorder Gap KernelDelta Rate PhaseMs Outcome ChangePoint ├─ Metrics/ LinkMetrics TcpMetrics UdpTrainMetrics ConnectMetrics …(只包含声明) @@ -144,4 +144,4 @@ backend/src/Monitor.Backend.Analysis/ 依赖:Monitor.Protocol、Fleet.Core └─ Clock/ ClockDriftFit(估计两端的时钟偏移和漂移) ``` -分析库没有 I/O,可以直接用于离线 CLI `tools/monitor-analyze`,对下载的原始块做实验。 +分析库没有 I/O,可以直接用于离线 CLI `tools/moshiro-analyze`,对下载的原始块做实验。 diff --git a/docs/api-guidelines.md b/docs/api-guidelines.md index 266736d..cac57ce 100644 --- a/docs/api-guidelines.md +++ b/docs/api-guidelines.md @@ -16,7 +16,7 @@ web:openapi-typescript 生成类型,调用方的类型错误会直接暴露 - 端点**必须**声明精确的返回类型,例如 `Results, NotFound>`,不能返回 `IResult` 或匿名对象,否则 OpenAPI 文档会不准确。 - 每个端点都必须设置 `WithName("agents_list")`(即 operationId,snake_case、`资源_动作`)、`WithSummary`、`WithTags`。 -- 请求和响应 DTO 放在 `Monitor.Backend.Api/Contracts/`,并注册到 Backend 的 JSON 源生成上下文。**不要直接暴露 `Monitor.Protocol` 中的线协议类型**,因为 REST 与线协议的演进节奏不同。 +- 请求和响应 DTO 放在 `MoShiro.Backend.Api/Contracts/`,并注册到 Backend 的 JSON 源生成上下文。**不要直接暴露 `MoShiro.Protocol` 中的线协议类型**,因为 REST 与线协议的演进节奏不同。 - **结构强类型,指标弱类型**:资源结构(Agent、任务、测试等)必须是强类型 DTO;而**指标值和评分**统一使用字典 `metrics: { "": number }`、`scores: { "": number }`,键的含义、单位、版本由 `/api/public/catalog/*` 给出。这样新增指标或模型不需要改 OpenAPI,也不需要改前端类型。 ## 2. 版本与兼容性 diff --git a/docs/api.md b/docs/api.md index 3c21298..1a1c182 100644 --- a/docs/api.md +++ b/docs/api.md @@ -95,7 +95,7 @@ `GET /api/public/about`:`{show_build, backend}`。`show_build` 关着时 `backend` 是 `null`;打开后 `backend` 是 `{version, tag, built_at}`(后端自己的版本、tag、构建时间,不含提交号)。 - 系统和架构是节点自报的:Agent 和 Probe 都在各自连面板时的 `fleet.hello` 里自报。只有粗粒度的名字,没有主机名、内核版本、CPU 型号。 -- 国家和运营商由 **Backend** 用节点的来源地址向 IP 归属服务查一次(`Monitor__GeoLookupUrl`,缺省 `https://ip.007995.xyz`,留空就不查):Probe 用 Agent 看到的来源 IP,Agent 用它的公开地址。**Probe 和 Agent 不访问任何外部服务。** 只查公网地址(回环、内网、CGNAT、链路本地一律不发出去);同一个地址一周内只查一次,失败 10 分钟后再试;查到的只留国家代码和运营商,地址只存在 Backend 内部的 `node_meta.geo_host`,不对外。 +- 国家和运营商由 **Backend** 用节点的来源地址向 IP 归属服务查一次(`MoShiro__GeoLookupUrl`,缺省 `https://ip.007995.xyz`,留空就不查):Probe 用 Agent 看到的来源 IP,Agent 用它的公开地址。**Probe 和 Agent 不访问任何外部服务。** 只查公网地址(回环、内网、CGNAT、链路本地一律不发出去);同一个地址一周内只查一次,失败 10 分钟后再试;查到的只留国家代码和运营商,地址只存在 Backend 内部的 `node_meta.geo_host`,不对外。 ### 2.4 测试结果与目录 @@ -105,7 +105,7 @@ ### 2.5 跨域访问 -默认前端和 Backend 同源(Cookie 会话)。前端在别的来源时(比如本机跑前端、连线上的 Backend),Backend 设 `Monitor__CorsOrigins`(逗号分隔的来源,或 `*`;默认空 = 不允许)。只对 `/api/*` 生效,响应带 `Access-Control-Allow-Origin`,预检请求(`OPTIONS`)返回 204,允许的头是 `Authorization, Content-Type, X-CSRF-Token`。**不带凭据**,Cookie 不会跨域,所以跨域的调用只能用 `Authorization: Bearer `:展示端用只读令牌(站点私有时需要),管理端用 admin 范围的令牌(`/api/admin/auth/me` 对令牌同样可用)。SSE 在跨域时前端用 fetch 读流,因为 `EventSource` 带不了请求头。 +默认前端和 Backend 同源(Cookie 会话)。前端在别的来源时(比如本机跑前端、连线上的 Backend),Backend 设 `MoShiro__CorsOrigins`(逗号分隔的来源,或 `*`;默认空 = 不允许)。只对 `/api/*` 生效,响应带 `Access-Control-Allow-Origin`,预检请求(`OPTIONS`)返回 204,允许的头是 `Authorization, Content-Type, X-CSRF-Token`。**不带凭据**,Cookie 不会跨域,所以跨域的调用只能用 `Authorization: Bearer `:展示端用只读令牌(站点私有时需要),管理端用 admin 范围的令牌(`/api/admin/auth/me` 对令牌同样可用)。SSE 在跨域时前端用 fetch 读流,因为 `EventSource` 带不了请求头。 ## 3. Admin API @@ -130,7 +130,7 @@ | POST | `/api/admin/lines/{line_id}/tests` | `{plan, params?}` → **202** + `Location: /api/public/tests/{id}`;Probe 离线时返回 409 `probe_offline`,节点繁忙时返回 409 `test_busy` | | POST | `/api/admin/tests/{id}/cancel` | | | GET | `/api/admin/raw/chunks?agent_id=&kind=&from=&to=&test_id=` | 原始块元数据 | -| GET | `/api/admin/raw/chunks/{chunk_id}` | 下载原始块(`application/vnd.monitor.rawchunk`);过期返回 410 `raw_expired` | +| GET | `/api/admin/raw/chunks/{chunk_id}` | 下载原始块(`application/vnd.moshiro.rawchunk`);过期返回 410 `raw_expired` | | GET | `/api/admin/events?agent_id=&kind=&from=&to=` | 事件 | | GET | `/api/admin/analysis/recompute` | 指标重算进度 | | GET/POST/DELETE | `/api/admin/api-tokens` | 作用域为 `read`、`admin` 或 `release`(只能登记发布清单,给 CI 用,什么都读不了);明文只显示一次 | @@ -157,7 +157,7 @@ | 方法 | 路径 | 说明 | | --- | --- | --- | | POST | `/api/agent/v1/enroll` | 由 `MapFleetEnrollment` 提供(使用加入令牌认证),见 [fleet/link.md](fleet/link.md) 第 3 节 | -| GET | `/api/agent/v1/rpc` | 由 `MapFleetLink` 提供,升级为 WebSocket;Monitor 的方法见 [protocol.md](protocol.md) | +| GET | `/api/agent/v1/rpc` | 由 `MapFleetLink` 提供,升级为 WebSocket;MoShiro 的方法见 [protocol.md](protocol.md) | | GET | `/fleet/releases/{app}/{channel}/latest.json`、`/fleet/releases/{app}/{version}/…` | 由 `MapFleetReleases` 提供的公开发布源(清单和制品),供 `fleet-updater` 轮询;也可以改用 GitHub Releases | ## 5. 运维端点 diff --git a/docs/architecture.md b/docs/architecture.md index b503a87..7c5d6ba 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -53,13 +53,13 @@ | 主题 | 要点 | 文档 | | --- | --- | --- | -| 节点框架 | 注册、身份、连接、RPC、可靠上报、状态同步、宿主、更新都由与业务无关的 **Fleet** 提供;Monitor 只写业务,其他产品也能复用 | [fleet/overview.md](fleet/overview.md) | +| 节点框架 | 注册、身份、连接、RPC、可靠上报、状态同步、宿主、更新都由与业务无关的 **Fleet** 提供;MoShiro 只写业务,其他产品也能复用 | [fleet/overview.md](fleet/overview.md) | | 注册与身份 | 使用 `fleet-enroll` 和加入令牌自动注册,之后用签名认证;Probe 用自己的身份直连面板,Agent 列表由面板下发 | [enrollment.md](enrollment.md) | -| 更新 | 只接受发布密钥签名的清单,更新策略由节点本地决定,失败自动回滚。容器节点(Agent、Probe)已实现:CI 对镜像 digest 签名,宿主机上的 `monitor-update` 验签、按 digest 拉取、重启;纯二进制的 `fleet-updater` 还只是设计 | [deployment.md](deployment.md)、[fleet/update.md](fleet/update.md) | +| 更新 | 只接受发布密钥签名的清单,更新策略由节点本地决定,失败自动回滚。容器节点(Agent、Probe)已实现:CI 对镜像 digest 签名,宿主机上的 `moshiro-update` 验签、按 digest 拉取、重启;纯二进制的 `fleet-updater` 还只是设计 | [deployment.md](deployment.md)、[fleet/update.md](fleet/update.md) | | 任务模型 | `Task = {kind, target, params, schedule}`;持续采集、按需测试、目标任务统一建模;下发“期望任务集”,由节点自行调和 | [measurement.md](measurement.md) | | 采集扩展 | Kind 由积木组合声明;采集密度靠参数调整;原始块自描述 | [measurement.md](measurement.md) | | 统计扩展 | 指标注册制:少数几种累加器 + 统计算子;一行 `MetricDef` 就是一个新指标 | [analysis.md](analysis.md) | -| 协议 | 控制链路使用 Fleet(JSON-RPC 2.0 + 二进制通道);Monitor 只定义 `monitor.*` 方法、`TaskSet` 状态文档和 UDP/TCP 数据面 | [protocol.md](protocol.md) | +| 协议 | 控制链路使用 Fleet(JSON-RPC 2.0 + 二进制通道);MoShiro 只定义 `moshiro.*` 方法、`TaskSet` 状态文档和 UDP/TCP 数据面 | [protocol.md](protocol.md) | | 存储 | 原始块追加写入段文件,SQLite 记录偏移量;指标窗口通用存储并降采样 | [storage.md](storage.md) | | 展示查询 | 任意时间段(相对或绝对);自动步长(每条曲线最多约 720 个点);1s 内存热层(1 小时)加上 10s/1m/5m/1h 各层;累加器现场合并,汇总精确;列式响应;SSE 实时跟随 | [query.md](query.md) | | API | `/api/public`(只读,可设为公开)、`/api/admin`(登录)、`/api/agent`(注册与 RPC);实时数据用 SSE | [api.md](api.md) | @@ -70,7 +70,7 @@ CI ──签名的发布清单(镜像 digest)──▶ Backend ──原样转发(offer)──▶ Agent / Probe 进程 │ 只写进数据目录的 update/ ▼ -宿主机 monitor-update(root):用本机公钥验签 → 核对组件、仓库和 seq → podman pull 仓库@digest → 重启 → 不健康就回滚 +宿主机 moshiro-update(root):用本机公钥验签 → 核对组件、仓库和 seq → podman pull 仓库@digest → 重启 → 不健康就回滚 │ 状态写进只读的 update-status/ ▼ 节点随心跳上报更新状态 ──▶ Backend ──▶ 管理端(有新版本时点「更新」) @@ -97,13 +97,13 @@ Agent / Probe 能做的 执行编译在二进制中的 Kind;监听和访问 - **本地硬上限**写在节点本机的配置文件中,Backend 下发的任务如果超出,节点直接拒绝:允许访问的目标网段(默认为空,即不开放目标任务)、总码率和包速率上限、允许监听的端口。 - **构建期强制**:常驻节点进程使用 `BannedSymbols.Node.txt`,禁用 `System.Diagnostics.Process`、`Assembly.Load*`、`NativeLibrary.Load`、`HttpClient`,以及 `ConfigStore` 以外的文件写入 API,详见 [project-layout.md](project-layout.md) 第 7 节。 -- **权限分离**:注册(`fleet-enroll`,一次性运行)、采集(`monitor-agent` / `monitor-probe`)、更新是不同的进程。容器节点里,采集进程在容器内以 UID 1654 运行(只读文件系统、不带额外能力),更新由宿主机上 root 运行的 `monitor-update` 完成:它只读取节点放进 `update/` 的普通文件、复制到自己的临时目录后验签,状态写在节点只读的 `update-status/`;采集进程改写不了自己的二进制,更新器也读不到节点身份私钥。纯二进制安装的 `fleet-updater` 还只是设计。 +- **权限分离**:注册(`fleet-enroll`,一次性运行)、采集(`moshiro-agent` / `moshiro-probe`)、更新是不同的进程。容器节点里,采集进程在容器内以 UID 1654 运行(只读文件系统、不带额外能力),更新由宿主机上 root 运行的 `moshiro-update` 完成:它只读取节点放进 `update/` 的普通文件、复制到自己的临时目录后验签,状态写在节点只读的 `update-status/`;采集进程改写不了自己的二进制,更新器也读不到节点身份私钥。纯二进制安装的 `fleet-updater` 还只是设计。 - **容器运行**:Agent、Probe 的镜像基于 Alpine(musl,NativeAOT),宿主机用 rootful podman 加 systemd 运行:UID/GID 1654、只读文件系统、`--cap-drop all`、`no-new-privileges`、`/tmp` 用 tmpfs;配置和身份放在挂载的数据目录里。 - **最小权限运行**:非 root 用户;只在需要时授予 `CAP_NET_RAW`(ICMP);默认端口都高于 1024,不需要 `CAP_NET_BIND_SERVICE`,只有在 Agent 本地显式开启 443 时才授予。 - **身份**:节点使用本地生成的 ECDSA P-256 密钥对签名认证(Probe 的密钥由面板生成、只返回一次,同一把用来连面板和连 Agent),Backend 只存公钥,数据库泄露也无法冒充节点。 - **防放大**:未认证的包静默丢弃;回复长度与请求相等;每个流按声明速率限速;使用重放窗口。 - **容器里的主机指标**:容器里的 Agent 通过只读挂载宿主机的 `/proc`、`/sys`、根目录和 `/etc/os-release`(环境变量 `HOST_PROC`、`HOST_SYS`、`HOST_ROOT`)读取宿主机的资源占用和系统名;读不到的项返回空值,不会退回去读容器自己的数据。Probe 只需要挂载 `/etc/os-release`。 -- **自身状态**:节点上报进程内的计数(会话数、包速率、队列、丢弃数);Agent 另外每隔几秒用 `monitor.host` 上报一份主机资源占用的汇总数字(可以在 `agent.json` 里用 `reporting.host_stats = false` 整个关掉),最新值实时推给展示页,Backend 每分钟存一个样本(默认保留 7 天,`retention.host_days`)。 +- **自身状态**:节点上报进程内的计数(会话数、包速率、队列、丢弃数);Agent 另外每隔几秒用 `moshiro.host` 上报一份主机资源占用的汇总数字(可以在 `agent.json` 里用 `reporting.host_stats = false` 整个关掉),最新值实时推给展示页,Backend 每分钟存一个样本(默认保留 7 天,`retention.host_days`)。 ## 6. 可扩展性目标 @@ -119,7 +119,7 @@ Kind 目录编译在二进制中,节点不接受远程下发代码(安全边 ## 7. 可靠性与资源 -- Probe:每个 Agent 未交付的原始列 ≤ 8 MB;Agent:上传队列 ≤ 64 MB,满时丢弃最旧的块,并通过 `monitor.event(gap)` 上报缺口。 +- Probe:每个 Agent 未交付的原始列 ≤ 8 MB;Agent:上传队列 ≤ 64 MB,满时丢弃最旧的块,并通过 `moshiro.event(gap)` 上报缺口。 - 至少一次投递:Backend 持久化之后才回复 ACK,按 `chunk_id` 去重。 - 节点重启会丢失未上传的数据,并体现为数据缺口。 - 窗口时间以 Agent 时钟为准;时钟偏差超过 5 秒时记录告警事件。 @@ -144,7 +144,7 @@ Kind 目录编译在二进制中,节点不接受远程下发代码(安全边 | D13 | Probe/Agent 运行时只依赖 BCL;.NET 10 NativeAOT | 轻量 | | D14 | 节点机制抽成与业务无关的 Fleet 框架,放在同一仓库的 `backend/fleet/` 目录,暂不独立(由用户确认;不设拆分时间表,需要时再评估;不使用 PublicApiAnalyzers) | 可复用;`samples/EchoNode` 作为第二个使用者,防止过度设计 | | D15 | 注册独立为 `fleet-enroll` 工具;常驻进程不包含注册代码 | 常驻进程去掉 HttpClient,边界更纯 | -| D16 | 更新与业务进程分离:发布密钥签名、本地策略、健康确认与回滚。容器节点已实现(宿主机 `monitor-update`,清单里是镜像 digest);纯二进制的 `fleet-updater` 待做 | 面板被攻破时也无法推送恶意二进制;可以同时管理多个产品 | +| D16 | 更新与业务进程分离:发布密钥签名、本地策略、健康确认与回滚。容器节点已实现(宿主机 `moshiro-update`,清单里是镜像 digest);纯二进制的 `fleet-updater` 待做 | 面板被攻破时也无法推送恶意二进制;可以同时管理多个产品 | | D17 | Probe 支持 OpenWrt:正式支持 `linux-musl-x64`、`linux-musl-arm64`;armv7 视工具链验证结果决定;MIPS 不支持,改为在局域网设备上运行 Probe | 由用户确认;NativeAOT 不支持 MIPS | | D18 | 默认测量端口不使用 443:控制 7443/tcp,UDP 数据 7443/udp,TCP 数据 7444/tcp;443 只在 Agent 本地显式开启时才允许使用 | 由用户确认;避免与 VPS 上的真实服务冲突;结果会记录实际端口 | | D19 | 展示查询最细 1s:最近 1 小时来自内存热层,更早的数据来自 10s/1m/5m/1h 各层,现场合并;时间段内的汇总由累加器精确合并得出 | 由用户确认;5 分钟、15 分钟这类视图足够精细且快 | diff --git a/docs/coding-style.md b/docs/coding-style.md index d3a95c2..37e7049 100644 --- a/docs/coding-style.md +++ b/docs/coding-style.md @@ -5,7 +5,7 @@ ## 1. 格式与命名(`.editorconfig` 强制) - 使用 Allman 大括号(左大括号独占一行),四空格缩进,不使用 Tab;`if`/`for` 等语句必须加大括号。 -- 使用文件作用域 namespace;namespace 与目录一致(`Monitor.Agent.Sessions` 对应 `Sessions/`)。 +- 使用文件作用域 namespace;namespace 与目录一致(`MoShiro.Agent.Sessions` 对应 `Sessions/`)。 - `using` 放在文件顶部、namespace 之外,`System.*` 排在最前面,其余按字母排序。 - 始终显式写出可见性,并且放在修饰符的第一位;`static readonly` 的顺序固定。 @@ -82,8 +82,8 @@ ## 9.1 Fleet 的通用性 -- `backend/fleet/**` 不能引用任何 `Monitor.*`,也不能出现产品相关的概念、命名或默认值(例如端口 7443、`monitor` 字样),由 `scripts/check-deps` 和代码评审把关。 -- Fleet 的每个公开 API 都要在 `samples/EchoNode` 或 `EchoServer` 中有用法。新增的公开 API 如果只有 Monitor 使用,应先放在 Monitor 中,等出现第二个使用者后再下沉到 Fleet。 +- `backend/fleet/**` 不能引用任何 `MoShiro.*`,也不能出现产品相关的概念、命名或默认值(例如端口 7443、`moshiro` 字样),由 `scripts/check-deps` 和代码评审把关。 +- Fleet 的每个公开 API 都要在 `samples/EchoNode` 或 `EchoServer` 中有用法。新增的公开 API 如果只有 MoShiro 使用,应先放在 MoShiro 中,等出现第二个使用者后再下沉到 Fleet。 - Fleet 永远不提供 exec、shell、文件读写或远程下发代码的方法,这条规则不接受例外。 - 公开 API 的变更记录在 `PublicAPI.Unshipped.txt` 中;PR 描述需要说明是否属于破坏性变更。 @@ -107,5 +107,5 @@ ## 12. 提交与评审 - 提交信息使用 `<范围>: <摘要>` 格式,范围取值为 `probe`、`agent`、`backend`、`shared`、`web`、`docs`、`scripts`。 -- 修改 `backend/shared/Monitor.Protocol` 的 PR 必须说明兼容性影响(新增字段、行为变化、需要升级版本)。 +- 修改 `backend/shared/MoShiro.Protocol` 的 PR 必须说明兼容性影响(新增字段、行为变化、需要升级版本)。 - 修改 `backend/openapi/v1.json` 的 PR 必须按照 [api-guidelines.md](api-guidelines.md) 第 2 节判断是否属于破坏性变更。 diff --git a/docs/deployment.md b/docs/deployment.md index c66a03d..cbc1fb2 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -6,10 +6,10 @@ ```text scripts/publish.sh → backend/artifacts/publish/// -scripts/package.sh → backend/artifacts/packages/monitor---.tar.gz(附 .sha256) +scripts/package.sh → backend/artifacts/packages/moshiro---.tar.gz(附 .sha256) ``` -构建信息(程序里显示的 tag、提交、构建时间):`publish.sh` 会用 `git describe --tags --always --dirty`、`git rev-parse` 和当前时间自动设置环境变量 `MONITOR_TAG`、`MONITOR_COMMIT`、`MONITOR_BUILT_AT`,直接用 `dotnet publish` 或 CI 构建时自己设置它们(容器镜像的 `*.NativeBuild.Containerfile` 用同名的 `--build-arg`,CI 脚本会传);不设置就是空,本地构建照常可重复。版本号取自 `backend/Directory.Build.props` 的 `Version`。前端的信息由 `web/build-info.mjs` 在构建时写入(版本取自 `web/package.json`)。 +构建信息(程序里显示的 tag、提交、构建时间):`publish.sh` 会用 `git describe --tags --always --dirty`、`git rev-parse` 和当前时间自动设置环境变量 `MOSHIRO_TAG`、`MOSHIRO_COMMIT`、`MOSHIRO_BUILT_AT`,直接用 `dotnet publish` 或 CI 构建时自己设置它们(容器镜像的 `*.NativeBuild.Containerfile` 用同名的 `--build-arg`,CI 脚本会传);不设置就是空,本地构建照常可重复。版本号取自 `backend/Directory.Build.props` 的 `Version`。前端的信息由 `web/build-info.mjs` 在构建时写入(版本取自 `web/package.json`)。 | rid | 目标 | 构建方式 | | --- | --- | --- | @@ -24,15 +24,15 @@ macOS 的 Apple Silicon 产物带临时 ad-hoc 签名,Intel 产物未签名。 ## Backend 容器 -Backend 使用 OCI 标准镜像,通过 `registry.oeo.one/monitor/monitor-backend:` 分发,支持 `linux/amd64` 和 `linux/arm64`。容器使用 musl NativeAOT 单文件程序,基底为 `mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine`,以非 root 用户运行,在 `8080/tcp` 提供 HTTP 服务;数据库和原始数据统一写入 `/data`。程序启用 InvariantGlobalization,无需 .NET 运行时或 ICU;时间查询使用 UTC。SQLite 从固定版本的官方源码编译并静态链接,不再随镜像携带 `libe_sqlite3.so`。将 `/data` 挂载为持久卷,并在反向代理处配置 HTTPS。 +Backend 使用 OCI 标准镜像,通过 `registry.oeo.one/moshiro/moshiro-backend:` 分发,支持 `linux/amd64` 和 `linux/arm64`。容器使用 musl NativeAOT 单文件程序,基底为 `mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine`,以非 root 用户运行,在 `8080/tcp` 提供 HTTP 服务;数据库和原始数据统一写入 `/data`。程序启用 InvariantGlobalization,无需 .NET 运行时或 ICU;时间查询使用 UTC。SQLite 从固定版本的官方源码编译并静态链接,不再随镜像携带 `libe_sqlite3.so`。将 `/data` 挂载为持久卷,并在反向代理处配置 HTTPS。 -在部署目录保存此仓库的 `compose.yaml`,先通过部署平台的环境变量或密钥管理设置 `MONITOR_ADMIN_PASSWORD`(可选设置 `MONITOR_ADMIN_USER`、`MONITOR_VERSION`),然后启动: +在部署目录保存此仓库的 `compose.yaml`,先通过部署平台的环境变量或密钥管理设置 `MOSHIRO_ADMIN_PASSWORD`(可选设置 `MOSHIRO_ADMIN_USER`、`MOSHIRO_VERSION`),然后启动: ```sh docker compose up -d ``` -Compose 将容器端口只绑定到宿主机 `127.0.0.1:8080`,适合由同机 HTTPS 反向代理转发;数据保存在 Docker 命名卷 `monitor-data`。首次启动成功创建管理员后,改密应在管理端完成。 +Compose 将容器端口只绑定到宿主机 `127.0.0.1:8080`,适合由同机 HTTPS 反向代理转发;数据保存在 Docker 命名卷 `moshiro-data`。首次启动成功创建管理员后,改密应在管理端完成。 Backend 的 NativeAOT 发布默认启用 `SqliteStaticLink`,支持 Linux glibc/musl、macOS、Windows 的 x64/arm64 RID;跨平台构建使用 `-p:UseAotAnywhere=true`。SQLite 源码版本、下载年份和 SHA-256 统一配置在根目录 `Directory.Packages.props`,构建会校验下载文件并按 RID 缓存原生对象。普通 JIT 开发构建仍使用 NuGet 原生库。发布 Backend 时设置 `-p:OpenApiGenerateDocuments=false`,API 文档在普通开发构建中生成。 @@ -50,30 +50,30 @@ Pull request 和 `dev` push 会运行 Backend tests;通过后,独立的 `web ### main 开发镜像 -`main` 上只有提交信息包含 `[CI]` 的 push 才构建镜像。合并 PR 时,请把 `[CI]` 放入 PR 标题或合并提交标题。Backend、Agent、Probe 的 Linux/amd64 镜像会并行构建,并推送到同一个 Zot Registry 下独立的 `monitor-dev/` 仓库: +`main` 上只有提交信息包含 `[CI]` 的 push 才构建镜像。合并 PR 时,请把 `[CI]` 放入 PR 标题或合并提交标题。Backend、Agent、Probe 的 Linux/amd64 镜像会并行构建,并推送到同一个 Zot Registry 下独立的 `moshiro-dev/` 仓库: | 镜像 | 滚动标签 | 固定提交标签 | | --- | --- | --- | -| Backend | `registry.oeo.one/monitor-dev/monitor-backend:latest` | `registry.oeo.one/monitor-dev/monitor-backend:dev-<12位SHA>` | -| Agent | `registry.oeo.one/monitor-dev/monitor-agent:latest` | `registry.oeo.one/monitor-dev/monitor-agent:dev-<12位SHA>` | -| Probe | `registry.oeo.one/monitor-dev/monitor-probe:latest` | `registry.oeo.one/monitor-dev/monitor-probe:dev-<12位SHA>` | +| Backend | `registry.oeo.one/moshiro-dev/moshiro-backend:latest` | `registry.oeo.one/moshiro-dev/moshiro-backend:dev-<12位SHA>` | +| Agent | `registry.oeo.one/moshiro-dev/moshiro-agent:latest` | `registry.oeo.one/moshiro-dev/moshiro-agent:dev-<12位SHA>` | +| Probe | `registry.oeo.one/moshiro-dev/moshiro-probe:latest` | `registry.oeo.one/moshiro-dev/moshiro-probe:dev-<12位SHA>` | -Dev 镜像目前仅支持 amd64;Agent/Probe 在 `sdk:10.0-alpine-aot` 中构建 `linux-musl-x64` 产物,运行基底为 `runtime-deps:10.0-alpine`。它们不创建 Gitea Release,也不修改正式版 `monitor/` 仓库中的标签。普通 main push 不会构建镜像。 +Dev 镜像目前仅支持 amd64;Agent/Probe 在 `sdk:10.0-alpine-aot` 中构建 `linux-musl-x64` 产物,运行基底为 `runtime-deps:10.0-alpine`。它们不创建 Gitea Release,也不修改正式版 `moshiro/` 仓库中的标签。普通 main push 不会构建镜像。 ### 正式版发布 -推送匹配项目版本的 `vMAJOR.MINOR.PATCH` tag 会触发完整跨平台构建、正式 OCI 镜像推送和 Gitea Release。正式镜像使用 `registry.oeo.one/monitor/` 路径;Agent、Probe 提供 amd64 与 arm64 多架构标签,稳定版本更新正式仓库自己的 `latest`。这与 `monitor-dev/` 的 dev `latest` 相互独立。 +推送匹配项目版本的 `vMAJOR.MINOR.PATCH` tag 会触发完整跨平台构建、正式 OCI 镜像推送和 Gitea Release。正式镜像使用 `registry.oeo.one/moshiro/` 路径;Agent、Probe 提供 amd64 与 arm64 多架构标签,稳定版本更新正式仓库自己的 `latest`。这与 `moshiro-dev/` 的 dev `latest` 相互独立。 -Agent 和 Probe 镜像分别发布为 `registry.oeo.one/monitor/monitor-agent:` 与 `registry.oeo.one/monitor/monitor-probe:`,包含 amd64、arm64 多架构索引;也可指定 `:-amd64` 或 `:-arm64`。稳定版本同时更新 `latest`。镜像以非 root 用户(UID/GID 1654)运行,默认读取 `/etc/monitor/agent.json` 或 `/etc/monitor/probe.json`。运行容器时挂载对应配置目录;Probe 还会在该目录写入 `agents.json`,因此目录需可由 1654 用户写入。Agent、Probe 需使用宿主网络以保持节点端口和测量流量行为,并按需添加 `NET_RAW` 能力以执行 ICMP 测量: +Agent 和 Probe 镜像分别发布为 `registry.oeo.one/moshiro/moshiro-agent:` 与 `registry.oeo.one/moshiro/moshiro-probe:`,包含 amd64、arm64 多架构索引;也可指定 `:-amd64` 或 `:-arm64`。稳定版本同时更新 `latest`。镜像以非 root 用户(UID/GID 1654)运行,默认读取 `/etc/moshiro/agent.json` 或 `/etc/moshiro/probe.json`。运行容器时挂载对应配置目录;Probe 还会在该目录写入 `agents.json`,因此目录需可由 1654 用户写入。Agent、Probe 需使用宿主网络以保持节点端口和测量流量行为,并按需添加 `NET_RAW` 能力以执行 ICMP 测量: ```sh -docker run -d --name monitor-agent --restart unless-stopped --network host \ - --cap-add NET_RAW -v "$PWD/agent-config:/etc/monitor" \ - registry.oeo.one/monitor/monitor-agent: +docker run -d --name moshiro-agent --restart unless-stopped --network host \ + --cap-add NET_RAW -v "$PWD/agent-config:/etc/moshiro" \ + registry.oeo.one/moshiro/moshiro-agent: -docker run -d --name monitor-probe --restart unless-stopped --network host \ - --cap-add NET_RAW -v "$PWD/probe-config:/etc/monitor" \ - registry.oeo.one/monitor/monitor-probe: +docker run -d --name moshiro-probe --restart unless-stopped --network host \ + --cap-add NET_RAW -v "$PWD/probe-config:/etc/moshiro" \ + registry.oeo.one/moshiro/moshiro-probe: ``` 宿主机配置目录应允许 UID/GID 1654 读写;Probe 需要写权限来更新 `agents.json`。也可通过 Docker Compose 配置相同的网络、卷和能力。 @@ -86,8 +86,8 @@ Agent 和 Probe 的默认发布配置:NativeAOT、完整裁剪、`Optimization | 程序 | linux-musl-x64 | linux-x64 | win-x64 | | --- | --- | --- | --- | -| monitor-probe | 7.7 MB | 7.7 MB | 5.6 MB | -| monitor-agent | 8.4 MB | 8.4 MB | 7.3 MB | +| moshiro-probe | 7.7 MB | 7.7 MB | 5.6 MB | +| moshiro-agent | 8.4 MB | 8.4 MB | 7.3 MB | | fleet-enroll | 6.4 MB | 6.4 MB | — | Linux 上比 Windows 大,是因为 .NET 的加密、压缩、网络本机库被静态链接进来。tar.gz 压缩后 Probe 约 3.6 MB。 @@ -108,31 +108,31 @@ Linux 上比 Windows 大,是因为 .NET 的加密、压缩、网络本机库 | 位置 | 内容 | 所有者 | | --- | --- | --- | -| `/usr/lib/monitor/` | 二进制 | root,0755:采集进程不能改写自己的可执行文件 | -| `/etc/monitor/` | `agent.json` 或 `probe.json`、身份(`node.json`、`node.key`、`tls.pfx`)、`agents.json` | `monitor` 用户,0750 | +| `/usr/lib/moshiro/` | 二进制 | root,0755:采集进程不能改写自己的可执行文件 | +| `/etc/moshiro/` | `agent.json` 或 `probe.json`、身份(`node.json`、`node.key`、`tls.pfx`)、`agents.json` | `moshiro` 用户,0750 | -安装脚本会:检查 OpenSSL、创建 `monitor` 用户(`useradd`、busybox `adduser`,OpenWrt 没有这些时直接写 `/etc/passwd`)、安装二进制和服务文件;缺少配置时只安装、不启动,并打印下一步。 +安装脚本会:检查 OpenSSL、创建 `moshiro` 用户(`useradd`、busybox `adduser`,OpenWrt 没有这些时直接写 `/etc/passwd`)、安装二进制和服务文件;缺少配置时只安装、不启动,并打印下一步。 ### systemd(`packaging/systemd/*.service`) -以 `monitor` 用户运行,沙箱:`NoNewPrivileges`、`ProtectSystem=strict`、`ProtectHome`、`PrivateTmp/Devices`、`ProtectKernel*`、`RestrictAddressFamilies=AF_INET AF_INET6`、`RestrictNamespaces`、`MemoryDenyWriteExecute`(NativeAOT 不 JIT)、`SystemCallArchitectures=native`,`MemoryMax`(Agent 128 MB、Probe 64 MB)。 +以 `moshiro` 用户运行,沙箱:`NoNewPrivileges`、`ProtectSystem=strict`、`ProtectHome`、`PrivateTmp/Devices`、`ProtectKernel*`、`RestrictAddressFamilies=AF_INET AF_INET6`、`RestrictNamespaces`、`MemoryDenyWriteExecute`(NativeAOT 不 JIT)、`SystemCallArchitectures=native`,`MemoryMax`(Agent 128 MB、Probe 64 MB)。 -- **Agent** 只保留 `CAP_NET_RAW`(ICMP 目标任务用),`/etc/monitor` 只读;Probe 没有任何 capability,只对 `agents.json` 所在的目录可写。 +- **Agent** 只保留 `CAP_NET_RAW`(ICMP 目标任务用),`/etc/moshiro` 只读;Probe 没有任何 capability,只对 `agents.json` 所在的目录可写。 - 监听 1024 以下的端口(例如把数据面放到 443)需要在 drop-in 里加 `AmbientCapabilities=CAP_NET_BIND_SERVICE` 和对应的 `CapabilityBoundingSet`。默认端口是 7443/tcp+udp(Probe 控制通道和 UDP 数据面)、7444/tcp。 ### OpenWrt(`packaging/openwrt/`) -只支持 Probe(Agent 面向服务器)。`install.sh probe` 安装 `/etc/init.d/monitor-probe`(procd,崩溃自动重启,日志进 logd)并写入 `/lib/upgrade/keep.d/monitor`,sysupgrade 时保留 `/etc/monitor/`。 +只支持 Probe(Agent 面向服务器)。`install.sh probe` 安装 `/etc/init.d/moshiro-probe`(procd,崩溃自动重启,日志进 logd)并写入 `/lib/upgrade/keep.d/moshiro`,sysupgrade 时保留 `/etc/moshiro/`。 OpenWrt 默认不带 OpenSSL:`opkg install libopenssl3`(较新的快照和 24.10 之后用 `apk add libopenssl3`)。闪存很小时注意:二进制 7.7 MB,配置只在 Agent 列表变化时才写。路由器上建议把 `probe.json` 的 `limits.max_test_mbps` 调低。 ## 3. 验证 -`scripts/smoke-linux.sh` 在 Linux 容器里用发布的二进制跑完整链路(后端 → 注册 → Agent → Probe → 数据落库),`MODE=install` 用打包产物和 `install.sh` 安装、以 `monitor` 用户运行。`scripts/smoke-systemd.sh` 在 systemd 容器里验证服务单元。已经验证过: +`scripts/smoke-linux.sh` 在 Linux 容器里用发布的二进制跑完整链路(后端 → 注册 → Agent → Probe → 数据落库),`MODE=install` 用打包产物和 `install.sh` 安装、以 `moshiro` 用户运行。`scripts/smoke-systemd.sh` 在 systemd 容器里验证服务单元。已经验证过: - Alpine 3.22(musl)、Debian 12(glibc):直接运行和 `install.sh` 安装都通; - OpenWrt(官方 rootfs,busybox,无 `install`/`useradd`/`su`):安装、建用户、卸载、二进制启动和 OpenSSL 自检; -- systemd(Debian 12):两个服务 active,Agent 只有 `CAP_NET_RAW`、Probe 没有 capability,`NoNewPrivs`、seccomp 生效,Agent 无法写 `/etc/monitor`,没有重启和错误日志。 +- systemd(Debian 12):两个服务 active,Agent 只有 `CAP_NET_RAW`、Probe 没有 capability,`NoNewPrivs`、seccomp 生效,Agent 无法写 `/etc/moshiro`,没有重启和错误日志。 没有验证的:arm64 构建、真正的 OpenWrt 设备(有 procd 和真实的内存/闪存限制)、跨公网的真实线路。 @@ -172,20 +172,20 @@ OpenWrt 默认不带 OpenSSL:`opkg install libopenssl3`(较新的快照和 2 - **Backend 通过隧道暴露**:隧道把一个公网域名转到家宽机器的 `29181`;Backend 监听 `http://0.0.0.0:29181`(只写一个监听地址,同时写 `0.0.0.0` 和 `[::]` 会报地址已被占用),家宽路由器的防火墙不放行这个端口,公网只能经隧道进来。Agent 用 `fleet-enroll --server https://<公网域名>` 注册,之后用 WSS 连回 Backend。 - **经隧道注册之后,检查 Agent 的 `public_host`**:Backend 看到的来源地址是隧道的出口,不是 VPS 的地址,要改成 VPS 的真实地址,Probe 才连得上。 -- **Probe 直连面板**:`probe.json` 里的 `server` 就是面板地址(取自 `Monitor__PublicUrl`,没配就用创建它时的请求地址),Probe 用它连面板,Agent 列表由面板下发;先注册还是先创建 Probe 都可以。 +- **Probe 直连面板**:`probe.json` 里的 `server` 就是面板地址(取自 `MoShiro__PublicUrl`,没配就用创建它时的请求地址),Probe 用它连面板,Agent 列表由面板下发;先注册还是先创建 Probe 都可以。 - **小 VPS 把 `limits.max_total_mbps` 调低**(试跑时用 100);Agent 常驻约 23 MB,VPS 上原有的服务不受影响,结束后删除 `/opt/…`、停掉进程即可,没有留下任何东西。 - 家宽的 IPv6 前缀会在路由器重新拨号(比如停电)后变化,SSH 地址要跟着换;面板走隧道的域名,不受影响。 - 本地电脑没有直连 VPS 的路径时,用家宽机器当跳板(`SSH_ASKPASS` + `SSH_ASKPASS_REQUIRE=force`,密码放环境变量,不写进文件)。 **常驻(开机自启)**: -- 家宽机器(没有 root 时):`~/.config/systemd/user/monitor-backend.service` 和 `monitor-probe.service`,`EnvironmentFile` 指向放配置的 `backend.env`,`Restart=always`,`systemctl --user enable --now …`,再用 `sudo loginctl enable-linger <用户>` 让它们不登录也能起来。Probe 的命令行是 `monitor-probe --config `(默认路径是 `/etc/monitor/probe.json`)。 -- VPS:`/etc/systemd/system/monitor-agent.service`,`Restart=always`,加 `NoNewPrivileges`、`ProtectSystem=strict`、`ReadWritePaths=/opt/monitor`、`ProtectHome`、`PrivateTmp`。这是不走安装脚本的手动方式;正式安装用上面的 `packaging/systemd`。 -- 日志进 journal:`journalctl -u monitor-agent`、`journalctl --user -u monitor-probe`。重启 Backend 用 `systemctl` 而不是手动再起一个进程,否则会端口冲突。 +- 家宽机器(没有 root 时):`~/.config/systemd/user/moshiro-backend.service` 和 `moshiro-probe.service`,`EnvironmentFile` 指向放配置的 `backend.env`,`Restart=always`,`systemctl --user enable --now …`,再用 `sudo loginctl enable-linger <用户>` 让它们不登录也能起来。Probe 的命令行是 `moshiro-probe --config `(默认路径是 `/etc/moshiro/probe.json`)。 +- VPS:`/etc/systemd/system/moshiro-agent.service`,`Restart=always`,加 `NoNewPrivileges`、`ProtectSystem=strict`、`ReadWritePaths=/opt/moshiro`、`ProtectHome`、`PrivateTmp`。这是不走安装脚本的手动方式;正式安装用上面的 `packaging/systemd`。 +- 日志进 journal:`journalctl -u moshiro-agent`、`journalctl --user -u moshiro-probe`。重启 Backend 用 `systemctl` 而不是手动再起一个进程,否则会端口冲突。 -**国家和运营商**:Backend 用 Probe、Agent 的来源地址向 IP 归属服务查一次,展示在国旗和运营商图标上(`Monitor__GeoLookupUrl`,缺省 `https://ip.007995.xyz`;留空就不查;这个服务只供公益使用,署名和使用条款由部署的人自己遵守)。Probe、Agent 自己不访问外部服务,所以客户的防火墙审计里不会多出出站连接;Backend 发出去的只有公网 IP(内网地址不发)。 +**国家和运营商**:Backend 用 Probe、Agent 的来源地址向 IP 归属服务查一次,展示在国旗和运营商图标上(`MoShiro__GeoLookupUrl`,缺省 `https://ip.007995.xyz`;留空就不查;这个服务只供公益使用,署名和使用条款由部署的人自己遵守)。Probe、Agent 自己不访问外部服务,所以客户的防火墙审计里不会多出出站连接;Backend 发出去的只有公网 IP(内网地址不发)。 -**从别处看这个面板**:本机跑前端,在页面里把数据源指向这个域名,用 API 令牌访问,Backend 设 `Monitor__CorsOrigins` 放行前端的来源(见 [web/README.md](../web/README.md))。 +**从别处看这个面板**:本机跑前端,在页面里把数据源指向这个域名,用 API 令牌访问,Backend 设 `MoShiro__CorsOrigins` 放行前端的来源(见 [web/README.md](../web/README.md))。 实测(Probe 在广东移动家宽,Agent 在日本 IIJ): @@ -203,24 +203,24 @@ OpenWrt 默认不带 OpenSSL:`opkg install libopenssl3`(较新的快照和 2 ## 容器部署(Docker / Podman 共用命名 volume) -镜像和 Compose 配置共用。普通用户执行 Podman 即为 rootless,使用命名 volume 不需要 `keep-id` 或手动 `chown`。Agent 的配置、原有身份和缓存保存在 `monitor-agent-config`,Probe 保存在 `monitor-probe-config`,更新状态使用独立的 `monitor--status` volume,在业务容器内只读。不会重新生成已有身份。更新/重建容器不删除 volume;不要使用 `compose down -v`,该参数会删除数据。 +镜像和 Compose 配置共用。普通用户执行 Podman 即为 rootless,使用命名 volume 不需要 `keep-id` 或手动 `chown`。Agent 的配置、原有身份和缓存保存在 `moshiro-agent-config`,Probe 保存在 `moshiro-probe-config`,更新状态使用独立的 `moshiro--status` volume,在业务容器内只读。不会重新生成已有身份。更新/重建容器不删除 volume;不要使用 `compose down -v`,该参数会删除数据。 在 `packaging/compose/agent` 下首次注册,并写配置(下列 `podman` 可替换为 `docker`): ```sh podman compose run --rm --entrypoint /usr/local/bin/fleet-enroll agent \ - --server https:// --join --name --identity-dir /etc/monitor/agent-id -podman compose run --rm -T --entrypoint /bin/sh agent -c 'cat > /etc/monitor/agent.json' <<'JSON' -{"fleet":{"server":"https://","identity_dir":"/etc/monitor/agent-id"},"listen":{"bind":"0.0.0.0"}} + --server https:// --join --name --identity-dir /etc/moshiro/agent-id +podman compose run --rm -T --entrypoint /bin/sh agent -c 'cat > /etc/moshiro/agent.json' <<'JSON' +{"fleet":{"server":"https://","identity_dir":"/etc/moshiro/agent-id"},"listen":{"bind":"0.0.0.0"}} JSON podman compose up -d ``` -Probe 在 `packaging/compose/probe` 下,将面板下载的身份文件通过标准输入导入 volume:`podman compose run --rm -T --entrypoint /bin/sh probe -c 'umask 077; cat > /etc/monitor/probe.json' < probe.json`,再 `podman compose up -d`。私钥权限为 600。已有部署迁移时,应把原配置与身份原样复制进 volume,不重新注册或轮换密钥。Docker 与 Podman 各自管理 volume,切换引擎不会自动共享数据。 +Probe 在 `packaging/compose/probe` 下,将面板下载的身份文件通过标准输入导入 volume:`podman compose run --rm -T --entrypoint /bin/sh probe -c 'umask 077; cat > /etc/moshiro/probe.json' < probe.json`,再 `podman compose up -d`。私钥权限为 600。已有部署迁移时,应把原配置与身份原样复制进 volume,不重新注册或轮换密钥。Docker 与 Podman 各自管理 volume,切换引擎不会自动共享数据。 -纯 Compose 使用 `compose pull && compose up -d` 更新镜像;面板自动更新使用下述 systemd 单元和更新器。Rootless Podman 使用 `monitor--rootless.service`,安装到 `~/.config/systemd/user/`,镜像文件为 `~/.config/monitor/.image`;rootful Podman 使用 `monitor--container.service`,Docker 使用 `monitor--docker.service`,安装到 `/etc/systemd/system/`,镜像文件为 `/etc/monitor-update/.image`。所有单元均使用相同的配置和状态 volume 名称。自动启动分别使用 `systemctl --user enable --now ` 或 `sudo systemctl enable --now `。Rootless 在退出登录后继续运行需管理员执行一次 `loginctl enable-linger <用户名>`。 +纯 Compose 使用 `compose pull && compose up -d` 更新镜像;面板自动更新使用下述 systemd 单元和更新器。Rootless Podman 使用 `moshiro--rootless.service`,安装到 `~/.config/systemd/user/`,镜像文件为 `~/.config/moshiro/.image`;rootful Podman 使用 `moshiro--container.service`,Docker 使用 `moshiro--docker.service`,安装到 `/etc/systemd/system/`,镜像文件为 `/etc/moshiro-update/.image`。所有单元均使用相同的配置和状态 volume 名称。自动启动分别使用 `systemctl --user enable --now ` 或 `sudo systemctl enable --now `。Rootless 在退出登录后继续运行需管理员执行一次 `loginctl enable-linger <用户名>`。 -Backend 的 `packaging/compose/backend/compose.yaml` 使用 `monitor-backend-data` 保存数据库和原始数据,设置 `MONITOR_INITIAL_ADMIN_PASSWORD` 后即可启动。首次安装 Podman 与用户 subuid/subgid 映射需要管理员权限,之后普通用户运行无需 sudo。 +Backend 的 `packaging/compose/backend/compose.yaml` 使用 `moshiro-backend-data` 保存数据库和原始数据,设置 `MOSHIRO_INITIAL_ADMIN_PASSWORD` 后即可启动。首次安装 Podman 与用户 subuid/subgid 映射需要管理员权限,之后普通用户运行无需 sudo。 ### Agent 的系统指标挂载 @@ -247,16 +247,16 @@ Rootless Podman 普通用户安装示例(先将对应 rootless 服务单元复 ```sh sh packaging/update/install-updater.sh agent --user \ - --volume monitor-agent-config --status-volume monitor-agent-status \ - --helper-image registry.oeo.one/monitor/monitor-agent: \ - --image-repo registry.oeo.one/monitor/monitor-agent \ - --unit monitor-agent-rootless.service --policy auto + --volume moshiro-agent-config --status-volume moshiro-agent-status \ + --helper-image registry.oeo.one/moshiro/moshiro-agent: \ + --image-repo registry.oeo.one/moshiro/moshiro-agent \ + --unit moshiro-agent-rootless.service --policy auto ``` -使用 Docker 时以管理员运行相同安装命令,去掉 `--user`,加 `--engine docker`,单元选择 `monitor-agent-docker.service`。rootful Podman 去掉 `--user`,单元选择 `monitor-agent-container.service`。Probe 替换角色名。初始化对应 `.image` 为 `IMAGE=<当前镜像引用>` 后启动容器单元。辅助镜像可用本机已有的 digest 引用,避免标签变化。Docker rootless 更新尚未适配。 +使用 Docker 时以管理员运行相同安装命令,去掉 `--user`,加 `--engine docker`,单元选择 `moshiro-agent-docker.service`。rootful Podman 去掉 `--user`,单元选择 `moshiro-agent-container.service`。Probe 替换角色名。初始化对应 `.image` 为 `IMAGE=<当前镜像引用>` 后启动容器单元。辅助镜像可用本机已有的 digest 引用,避免标签变化。Docker rootless 更新尚未适配。 命名 volume 的更新服务由 systemd timer 每 30 秒检查一次。`--policy auto` 验签后自动应用,默认 `manual` 等待面板写入应用请求。清单必须通过 ECDSA P-256 签名校验,组件、镜像仓库和递增 seq 都必须匹配本机配置;镜像按签名清单中的 digest 拉取。更新后观察服务 20 秒,启动失败或崩溃循环会恢复旧镜像引用并重启。无效签名、重放清单、拉取失败不会切换当前镜像。同一组件的更新通过 flock 串行处理。 -更新器依赖 Linux、systemd、OpenSSL、util-linux/flock 和所选引擎。用户部署把配置、公钥和镜像引用放在 `~/.config/monitor/`、版本记录放在 `~/.local/state/monitor-update/`;系统部署使用 `/etc/monitor-update/` 和 `/var/lib/monitor-update/`。私有仓库的 `--authfile` 对 Podman 使用其认证文件,对 Docker 使用标准 `config.json`,不改写全局 Docker 配置。旧 `--data-dir` 安装方式保留兼容,但新部署统一使用 `--volume`。 +更新器依赖 Linux、systemd、OpenSSL、util-linux/flock 和所选引擎。用户部署把配置、公钥和镜像引用放在 `~/.config/moshiro/`、版本记录放在 `~/.local/state/moshiro-update/`;系统部署使用 `/etc/moshiro-update/` 和 `/var/lib/moshiro-update/`。私有仓库的 `--authfile` 对 Podman 使用其认证文件,对 Docker 使用标准 `config.json`,不改写全局 Docker 配置。旧 `--data-dir` 安装方式保留兼容,但新部署统一使用 `--volume`。 发布私钥只放在 Woodpecker 的 `release_signing_key` secret;发布公钥位于 `packaging/update/release-key.pub.pem`。CI 的 `release_api_token` 只有发布登记权限,`RELEASE_API_URL` 指向面板。面板保存并转发签名清单,Agent/Probe 将它与更新请求写进配置 volume;更新器验签后才调用容器引擎和 systemd。管理端仍能看到可更新、更新中、已回滚和无效清单状态。纯二进制更新器尚未实现。 diff --git a/docs/enrollment.md b/docs/enrollment.md index 1338b2c..b03e4e6 100644 --- a/docs/enrollment.md +++ b/docs/enrollment.md @@ -1,6 +1,6 @@ -# Monitor 的注册与身份 +# MoShiro 的注册与身份 -通用的注册、身份、认证机制由 Fleet 提供,见 [fleet/link.md](fleet/link.md) 第 2~3 节。本文只描述 **Monitor 在 Fleet 之上的约定**:Agent 注册后如何自动接入测量、Probe 的身份以及 Agent 列表同步,以及节点本地的硬上限。 +通用的注册、身份、认证机制由 Fleet 提供,见 [fleet/link.md](fleet/link.md) 第 2~3 节。本文只描述 **MoShiro 在 Fleet 之上的约定**:Agent 注册后如何自动接入测量、Probe 的身份以及 Agent 列表同步,以及节点本地的硬上限。 ## 1. 身份一览 @@ -10,7 +10,7 @@ | Probe | Fleet 节点身份(同时用于连面板和连 Agent) | 面板生成 `probe.json`(可以有多个 Probe,每个独立吊销) | 公钥 | | 面板用户 | 账号 + 密码(PBKDF2-SHA256) | 面板 | 密码哈希 | | API 令牌 | 随机高熵令牌,作用域为 `read` 或 `admin` | 面板 | SHA-256 | -| 发布签名 | ECDSA P-256 发布密钥 | CI(Woodpecker 密钥 `release_signing_key`)或离线环境 | 只在节点宿主机的更新器里配置公钥(容器节点是 `monitor-update`,见 [deployment.md](deployment.md);纯二进制方案的 `fleet-updater` 还只是设计),**面板不保存私钥,也不验签** | +| 发布签名 | ECDSA P-256 发布密钥 | CI(Woodpecker 密钥 `release_signing_key`)或离线环境 | 只在节点宿主机的更新器里配置公钥(容器节点是 `moshiro-update`,见 [deployment.md](deployment.md);纯二进制方案的 `fleet-updater` 还只是设计),**面板不保存私钥,也不验签** | ## 2. Agent 接入流程 @@ -20,14 +20,14 @@ curl -fsSL https://panel/install.sh | sh -s -- --join jt_xxx --name jp-1 install.sh(只做安装,不包含任何远程控制功能;下面的更新器部分是纯二进制方案的设计,还没有实现,容器节点的做法见 deployment.md) - ├─ 下载 monitor-agent、fleet-enroll、fleet-updater,并验证发布签名 - ├─ 创建系统用户:monitor(运行 Agent)、fleet-update(运行更新器) - ├─ fleet-enroll --server https://panel --join jt_xxx --name jp-1 --identity-dir /etc/monitor - │ └─ 注册元数据(Monitor 定义):{ probe_tcp_port, probe_udp_ports, public_host?, kinds[] } + ├─ 下载 moshiro-agent、fleet-enroll、fleet-updater,并验证发布签名 + ├─ 创建系统用户:moshiro(运行 Agent)、fleet-update(运行更新器) + ├─ fleet-enroll --server https://panel --join jt_xxx --name jp-1 --identity-dir /etc/moshiro + │ └─ 注册元数据(MoShiro 定义):{ probe_tcp_port, probe_udp_ports, public_host?, kinds[] } ├─ 写入 agent.json(本地硬上限)和 /etc/fleet/updater.json - └─ 启用 monitor-agent.service 和 fleet-updater.service + └─ 启用 moshiro-agent.service 和 fleet-updater.service -面板收到 OnEnrolled(Monitor 挂钩) +面板收到 OnEnrolled(MoShiro 挂钩) ├─ public_host 未提供时,取注册请求的来源 IP ├─ 按“线路任务模板”为该 Agent 计算有效任务集(TaskSet) └─ 面板把新的 Agent 列表作为期望状态推给所有 Probe → Probe 自动连接新 Agent @@ -58,11 +58,11 @@ Probe 启动 - **哪些 Probe 连哪些 Agent 由面板决定,始终是 Probe 主动拨出**:设置 `fleet.auto_link`(默认开)打开时,所有未吊销的 Probe 和所有 Agent 两两连;关闭时只连手动选中的。每一对还可以在管理端 Probe 页的「线路」矩阵里手动强制开或关(`PUT /api/admin/links/{probe_id}/{agent_id}`),手动设置优先于自动连接。结果同时用在 Probe 的 Agent 列表、Agent 的 `peers` 和线路目录(关掉的线路从总览里消失,历史数据还在)。 - 吊销 Probe:在面板上重新生成身份,旧公钥立即从所有 Agent 的期望状态中移除,旧会话随之断开。 -## 4. Agent 本地配置(`/etc/monitor/agent.json`,面板无法修改) +## 4. Agent 本地配置(`/etc/moshiro/agent.json`,面板无法修改) ```json { - "fleet": { "server": "https://panel.example.com", "identity_dir": "/etc/monitor" }, + "fleet": { "server": "https://panel.example.com", "identity_dir": "/etc/moshiro" }, "listen": { "control_port": 7443, "udp_ports": [7443], "tcp_ports": [7444] }, "limits": { "max_total_mbps": 200, @@ -70,7 +70,7 @@ Probe 启动 "allowed_target_cidrs": [], "max_concurrent_tests": 1 }, - "fleet_policy": { "allow_methods": ["monitor.test.run", "monitor.test.cancel"] } + "fleet_policy": { "allow_methods": ["moshiro.test.run", "moshiro.test.cancel"] } } ``` @@ -101,4 +101,4 @@ Probe 启动 { "reporting": { "host_stats": true, "host_interval_s": 2 } } ``` -`host_stats` 为 true(默认)时,Agent 每隔 `host_interval_s` 秒用 `monitor.host` 上报一份主机资源占用的汇总数字(CPU、内存、根分区、网卡累计流量与网速、运行时长;没有型号、主机名、IP);设为 false 就一个字也不上报。 +`host_stats` 为 true(默认)时,Agent 每隔 `host_interval_s` 秒用 `moshiro.host` 上报一份主机资源占用的汇总数字(CPU、内存、根分区、网卡累计流量与网速、运行时长;没有型号、主机名、IP);设为 false 就一个字也不上报。 diff --git a/docs/fleet/link.md b/docs/fleet/link.md index 6238f40..735cbf2 100644 --- a/docs/fleet/link.md +++ b/docs/fleet/link.md @@ -49,7 +49,7 @@ ## 4. RPC(Fleet.Rpc) -- 信封采用 JSON-RPC 2.0;方法名为 `领域.动作`。`fleet.*` 保留给框架,产品使用自己的前缀,例如 `monitor.*`。 +- 信封采用 JSON-RPC 2.0;方法名为 `领域.动作`。`fleet.*` 保留给框架,产品使用自己的前缀,例如 `moshiro.*`。 - 二进制帧:`u8 channel | 正文`。channel `0` 到 `15` 保留给框架,产品从 `16` 开始注册自己的二进制通道。 - 错误:`error.data.code` 为 snake_case 字符串,框架的错误码以 `fleet_` 开头,产品可以扩展。 - **与传输方式无关**:同一套路由既可以跑在 wss 上,也可以跑在 TLS 帧(`u32 长度 | u8 类型 | 正文`)上。 @@ -86,7 +86,7 @@ connect(wss) → fleet.challenge → fleet.auth → fleet.hello → 状态同步 - 投递语义为**至少一次**:每条消息都带有 `msg_id`(UUIDv7),服务端按此去重。 - 在途数据按字节限制(默认 4 MiB),保证服务端慢时不会把内存撑爆。 - 丢弃消息时会累计缺口计数,通过 `OnGap` 回调通知产品,由产品决定如何上报。 -- 默认只保存在内存中,不落盘。产品如果需要持久化,可以自行实现 `IOutboxStore`(Monitor 不使用)。 +- 默认只保存在内存中,不落盘。产品如果需要持久化,可以自行实现 `IOutboxStore`(MoShiro 不使用)。 ## 7. 期望状态同步(State Sync) @@ -134,4 +134,4 @@ public interface IFleetStore } ``` -产品可以使用 `Fleet.Server.Sqlite`,也可以把这些表放进自己的数据库中。Monitor 的做法是把它们放进自己的 `monitor.db`,并由同一个单写入者负责写入。 +产品可以使用 `Fleet.Server.Sqlite`,也可以把这些表放进自己的数据库中。MoShiro 的做法是把它们放进自己的 `moshiro.db`,并由同一个单写入者负责写入。 diff --git a/docs/fleet/overview.md b/docs/fleet/overview.md index ff8ab79..1580fed 100644 --- a/docs/fleet/overview.md +++ b/docs/fleet/overview.md @@ -1,8 +1,8 @@ # Fleet:通用节点框架 -> **实现状态**:`Fleet.Update`、`Fleet.Server.Releases`、`fleet-updater`、`fleet-release` 还只是设计;容器节点的更新目前由宿主机上的 `monitor-update` 脚本和 Monitor 的 `ReleaseService` 完成(见 [deployment.md](../deployment.md))。其余组件已实现。 +> **实现状态**:`Fleet.Update`、`Fleet.Server.Releases`、`fleet-updater`、`fleet-release` 还只是设计;容器节点的更新目前由宿主机上的 `moshiro-update` 脚本和 MoShiro 的 `ReleaseService` 完成(见 [deployment.md](../deployment.md))。其余组件已实现。 -> 名称暂定。Fleet 与业务无关,Monitor 是它的第一个使用者。 +> 名称暂定。Fleet 与业务无关,MoShiro 是它的第一个使用者。 ## 1. 定位 @@ -10,7 +10,7 @@ ```text ┌──────────────────────────── 产品层(各产品自己写) ─────────────────────────────┐ -│ Monitor: Protocol(Kind/任务) · Measurement(积木) · Agent · Probe · Backend │ +│ MoShiro: Protocol(Kind/任务) · Measurement(积木) · Agent · Probe · Backend │ │ 其他产品: YourApp.Node · YourApp.Server │ └──────────────────────────────────┬─────────────────────────────────────────────┘ │ 只依赖 Fleet;Fleet 不认识任何产品 @@ -29,14 +29,14 @@ ## 2. 设计原则 -1. **与业务无关**:Fleet 中不出现任何产品概念。产品通过扩展点接入:元数据类型、RPC 方法、发件箱消息类型、期望状态文档类型。`scripts/check-deps` 强制规定 `backend/fleet/**` 不能引用 `Monitor.*`。 +1. **与业务无关**:Fleet 中不出现任何产品概念。产品通过扩展点接入:元数据类型、RPC 方法、发件箱消息类型、期望状态文档类型。`scripts/check-deps` 强制规定 `backend/fleet/**` 不能引用 `MoShiro.*`。 2. **安全默认值**: - Fleet **永远不提供** exec、shell、文件读写、远程下发代码这类方法; - 节点只响应本地注册过的方法,本地策略 `allow_methods` 还可以进一步收窄; - 更新必须通过离线密钥签名验证,面板即使被攻破也推不出恶意二进制。 3. **权限分离**:注册(`fleet-enroll`,一次性运行)、常驻业务进程、更新(`fleet-updater`)是三个独立的进程,使用不同的系统用户,各自只拥有最小权限。 4. **NativeAOT 优先**:节点侧只依赖 BCL;泛型扩展点通过产品传入的 `JsonTypeInfo` 实现序列化,不使用反射。 -5. **只抽取真正用到的**:每项能力都必须同时被 Monitor 和 `samples/EchoNode` 使用,防止过度设计。 +5. **只抽取真正用到的**:每项能力都必须同时被 MoShiro 和 `samples/EchoNode` 使用,防止过度设计。 ## 3. 组件 @@ -67,15 +67,15 @@ fleet/ 以后可以原样拆成独立仓库并发 │ ├─ Fleet.Enrollment.Client/ │ └─ Fleet.Server.Enrollment/ Fleet.Server.Link/ Fleet.Server.Releases/ Fleet.Server.Sqlite/ ├─ tools/ fleet-enroll/ fleet-updater/ fleet-release/ -├─ samples/ EchoNode/ EchoServer/ 最小示例:不依赖 Monitor 的第二个使用者 +├─ samples/ EchoNode/ EchoServer/ 最小示例:不依赖 MoShiro 的第二个使用者 ├─ tests/ └─ docs → 仓库 docs/fleet/ ``` ## 5. 演进策略 -- **现阶段**(已确认,暂不独立):放在 monitor 仓库的 `backend/fleet/` 目录中,通过项目引用使用,一处修改两边同时编译。 -- **拆分条件**:公开 API 连续两个里程碑没有破坏性变更,并且 `samples` 能覆盖全部能力。满足后拆成独立仓库,按 semver 发布 NuGet 包,Monitor 改为包引用。 +- **现阶段**(已确认,暂不独立):放在 MoShiro 仓库的 `backend/fleet/` 目录中,通过项目引用使用,一处修改两边同时编译。 +- **拆分条件**:公开 API 连续两个里程碑没有破坏性变更,并且 `samples` 能覆盖全部能力。满足后拆成独立仓库,按 semver 发布 NuGet 包,MoShiro 改为包引用。 - **公开 API 审查**:`backend/fleet/src/*` 的 public 类型使用 `PublicAPI.Shipped.txt` / `PublicAPI.Unshipped.txt` 跟踪(使用 `Microsoft.CodeAnalysis.PublicApiAnalyzers`,只在构建期生效),任何变更都会在 PR 中显示出来。 ## 6. 产品接入一览 diff --git a/docs/fleet/update.md b/docs/fleet/update.md index 58311b8..f379c5e 100644 --- a/docs/fleet/update.md +++ b/docs/fleet/update.md @@ -1,6 +1,6 @@ # Fleet:通用更新(Fleet.Update / fleet-updater) -> **实现状态**:容器节点(Agent、Probe)的更新已经实现,见 [deployment.md](../deployment.md) 的「容器节点的更新」:同样的信任模型(离线发布密钥签名、本机配置公钥和仓库、`seq` 防重放、面板只通知和请求),清单里是镜像 digest,更新器是宿主机上的 `monitor-update`。本文下面描述的纯二进制方案(`Fleet.Update`、`fleet-updater`、`fleet-release`、健康信标)还没有实现。 +> **实现状态**:容器节点(Agent、Probe)的更新已经实现,见 [deployment.md](../deployment.md) 的「容器节点的更新」:同样的信任模型(离线发布密钥签名、本机配置公钥和仓库、`seq` 防重放、面板只通知和请求),清单里是镜像 digest,更新器是宿主机上的 `moshiro-update`。本文下面描述的纯二进制方案(`Fleet.Update`、`fleet-updater`、`fleet-release`、健康信标)还没有实现。 ## 1. 原则 @@ -30,15 +30,15 @@ "check_interval_s": 3600, "apps": [ { - "id": "monitor-agent", - "sources": ["https://panel.example.com/fleet/releases", "https://github.com/org/monitor/releases/download"], + "id": "moshiro-agent", + "sources": ["https://panel.example.com/fleet/releases", "https://github.com/org/moshiro/releases/download"], "channel": "stable", "policy": "notify", "rid": "linux-x64", - "install_dir": "/opt/monitor-agent", + "install_dir": "/opt/moshiro-agent", "keep_versions": 2, - "service": { "kind": "systemd", "name": "monitor-agent" }, - "health": { "kind": "beacon", "path": "/run/fleet/monitor-agent.beacon", "timeout_s": 60 } + "service": { "kind": "systemd", "name": "moshiro-agent" }, + "health": { "kind": "beacon", "path": "/run/fleet/moshiro-agent.beacon", "timeout_s": 60 } } ] } @@ -53,16 +53,16 @@ ```json { "schema": 1, - "app": "monitor-agent", + "app": "moshiro-agent", "channel": "stable", "version": "0.4.2", "released_at": "2026-10-01T00:00:00Z", "min_from": "0.3.0", "artifacts": [ - { "rid": "linux-x64", "url": "monitor-agent-0.4.2-linux-x64.tar.gz", "sha256": "…", "size": 4120334 }, - { "rid": "linux-arm64", "url": "monitor-agent-0.4.2-linux-arm64.tar.gz", "sha256": "…", "size": 3987112 }, - { "rid": "linux-musl-arm64", "url": "monitor-agent-0.4.2-linux-musl-arm64.tar.gz", "sha256": "…", "size": 3990021 }, - { "rid": "win-x64", "url": "monitor-agent-0.4.2-win-x64.zip", "sha256": "…", "size": 4455010 } + { "rid": "linux-x64", "url": "moshiro-agent-0.4.2-linux-x64.tar.gz", "sha256": "…", "size": 4120334 }, + { "rid": "linux-arm64", "url": "moshiro-agent-0.4.2-linux-arm64.tar.gz", "sha256": "…", "size": 3987112 }, + { "rid": "linux-musl-arm64", "url": "moshiro-agent-0.4.2-linux-musl-arm64.tar.gz", "sha256": "…", "size": 3990021 }, + { "rid": "win-x64", "url": "moshiro-agent-0.4.2-win-x64.zip", "sha256": "…", "size": 4455010 } ], "notes_url": "https://…/CHANGELOG#0.4.2", "key_id": "rel-2026a", diff --git a/docs/measurement.md b/docs/measurement.md index 541d903..f8f7cd6 100644 --- a/docs/measurement.md +++ b/docs/measurement.md @@ -3,7 +3,7 @@ ## 1. 原则 - **只采集原始数据**:逐包、逐消息、逐事件,TCP 另加周期性的内核采样;不计算任何统计,解释全部放在 [analysis.md](analysis.md)。 -- **一处声明,处处生效**:采集方法(Kind)由积木组合**声明**而成。Probe 和 Agent 共用同一套积木(`backend/shared/Monitor.Measurement`)。 +- **一处声明,处处生效**:采集方法(Kind)由积木组合**声明**而成。Probe 和 Agent 共用同一套积木(`backend/shared/MoShiro.Measurement`)。 - **密度即参数**:频率、包大小、采样间隔全部是任务参数,由 API 下发,不需要改代码。 ## 2. 任务模型 @@ -26,7 +26,7 @@ schedule continuous 持续运行,按时间切块 ## 3. Kind 目录:积木组合 -### 3.1 积木(`Monitor.Measurement`,只有新增积木才需要写代码) +### 3.1 积木(`MoShiro.Measurement`,只有新增积木才需要写代码) | 类别 | 积木 | 参数示例 | | --- | --- | --- | @@ -39,7 +39,7 @@ schedule continuous 持续运行,按时间切块 **两种角色互相独立**:连接角色(Probe 永远是拨号方,适配 NAT)与数据角色(发送端、接收端、回显端,由 `direction` 决定)无关。每种积木只实现一次,Probe 和 Agent 共用。 -### 3.2 Kind 声明(`Monitor.Protocol/Catalog/Kinds`) +### 3.2 Kind 声明(`MoShiro.Protocol/Catalog/Kinds`) ```csharp public static readonly KindSpec TcpEcho = new( @@ -109,7 +109,7 @@ RawChunk - **列定义写在块头中**:新增列或新增 Kind 时,**不需要升级 `container_version`**。只有容器格式本身变化时才升级。Backend 可以通用地解码任何块,不认识的列会被保留,但会被分析层忽略。 - **切块规则**:持续任务每 **10 秒**切一块,或者记录数达到上限(默认 50 000)时提前切块。这样采集密度提高后,单块大小仍然有界,实时显示和持久化也共用同一条链路。 - 按需测试按阶段切块,阶段内同样受记录数上限约束。 -- 编解码器位于 `Monitor.Protocol/Raw`,Probe、Agent、Backend、离线工具使用同一份代码。 +- 编解码器位于 `MoShiro.Protocol/Raw`,Probe、Agent、Backend、离线工具使用同一份代码。 ## 5. 列的归属与合并 @@ -131,12 +131,12 @@ RawChunk 新增一种记录流只需要写声明,不需要写合并代码。Probe 的列在规定时间内没有送达时,目前 Agent 带着已有的数据继续(不上传只有 Agent 一侧的 `partial` 块,见已知缺口)。 -## 6. 代码结构(`backend/shared/Monitor.Measurement`) +## 6. 代码结构(`backend/shared/MoShiro.Measurement`) 同一种采集方法的两端是**一对角色**写在同一个文件里:拨号方(Probe 永远是拨号方,适配 NAT)和监听方(Agent)。两端共用包的构造和校验、时钟、行表和合并;Probe 和 Agent 只负责组装自己那一侧。 ```text -Monitor.Measurement/ 依赖:Monitor.Protocol(仅 BCL,零 NuGet) +MoShiro.Measurement/ 依赖:MoShiro.Protocol(仅 BCL,零 NuGet) ├─ Core/ │ ├─ Contracts.cs IBlock、BlockSpec、BlockEnv、DataSession、IAdmission、IFragmentSink…… │ ├─ RowStore.cs 本侧记录的行:只含本侧拥有的列,按键索引的环形缓冲,热路径不分配 diff --git a/docs/project-layout.md b/docs/project-layout.md index 4ba2efa..d7f1e34 100644 --- a/docs/project-layout.md +++ b/docs/project-layout.md @@ -3,8 +3,8 @@ ## 1. 目标 1. **三个独立项目加一个前端**:Probe、Agent、Backend 各自拥有解决方案,可以单独构建、测试和发布;Web 是独立的 Vite 项目(`web/`)。 -2. **通用能力只写一次**:TCP/UDP/TLS/ICMP 采集积木(类似 iperf3 的能力,但只记录原始数据)放在 `Monitor.Measurement` 中,Probe 和 Agent 共用;采集方法(Kind)由积木组合声明而成。 -3. **节点机制通用化**:注册、身份、连接、RPC、可靠上报、状态同步、宿主、更新,由与业务无关的 **Fleet** 框架提供(见 [fleet/overview.md](fleet/overview.md))。Monitor 只写业务,其他产品也可以复用 Fleet。 +2. **通用能力只写一次**:TCP/UDP/TLS/ICMP 采集积木(类似 iperf3 的能力,但只记录原始数据)放在 `MoShiro.Measurement` 中,Probe 和 Agent 共用;采集方法(Kind)由积木组合声明而成。 +3. **节点机制通用化**:注册、身份、连接、RPC、可靠上报、状态同步、宿主、更新,由与业务无关的 **Fleet** 框架提供(见 [fleet/overview.md](fleet/overview.md))。MoShiro 只写业务,其他产品也可以复用 Fleet。 4. **改一处,整条链路受益**:协议、原始数据格式、测试方案、指标、错误码、版本号、编译设置、代码风格都只有**一个真源**。改动之后,下游要么自动更新,要么在编译期或 CI 中直接报错。 5. **模块化**:Probe/Agent 由可插拔的模块组成;Backend 按层分成多个项目,层之间的依赖在编译期强制。 6. **Probe/Agent 轻量**:运行时只依赖 BCL 和仓库内的库,不引用任何 NuGet 包。 @@ -12,45 +12,45 @@ ## 2. 仓库布局 ```text -monitor/ +moshiro/ ├─ README.md .gitignore ├─ docs/ docs/fleet/ ├─ scripts/ # publish / package / smoke / stability 等脚本(check-deps 等检查也放这里) ├─ packaging/ # install.sh、systemd 单元、OpenWrt 文件 ├─ web/ # 前端:Vite + React + TypeScript(自写),只依赖 backend/openapi/v1.json │ -├─ global.json Directory.Packages.props Monitor.slnx # SDK、NuGet 版本和全部 .NET 项目入口 +├─ global.json Directory.Packages.props MoShiro.slnx # SDK、NuGet 版本和全部 .NET 项目入口 ├─ .editorconfig BannedSymbols.txt # 风格与禁用 API(构建期强制) ├─ BannedSymbols.Node.txt # 仅用于常驻节点进程:纯采集边界 │ -├─ ci/Monitor.Tar/ # CI 归档工具,也加入根解决方案 +├─ ci/MoShiro.Tar/ # CI 归档工具,也加入根解决方案 └─ backend/ # 服务和节点 C# 代码(构建产物在 backend/artifacts/) - ├─ Directory.Build.props Monitor.slnx # 后端编译设置和后端目录解决方案 - ├─ fleet/ # 通用节点框架(不认识 Monitor,以后可以拆成独立仓库) + ├─ Directory.Build.props MoShiro.slnx # 后端编译设置和后端目录解决方案 + ├─ fleet/ # 通用节点框架(不认识 MoShiro,以后可以拆成独立仓库) │ ├─ src/ Fleet.Core Fleet.Identity Fleet.Rpc Fleet.Link Fleet.Hosting Fleet.Update │ │ Fleet.Enrollment.Client Fleet.Server.{Enrollment,Link,Releases,Sqlite} │ ├─ tools/ fleet-enroll fleet-updater fleet-release │ ├─ samples/ EchoNode EchoServer │ └─ tests/ - ├─ shared/ # Monitor 自己的共享库 - │ ├─ Monitor.Protocol/ # 契约真源:Kind/Plan 目录、任务集、monitor.* 方法、UDP 包、RawChunk、错误码 - │ ├─ Monitor.Measurement/ # 采集引擎:积木、Recorder、任务调和(见 measurement.md) + ├─ shared/ # MoShiro 自己的共享库 + │ ├─ MoShiro.Protocol/ # 契约真源:Kind/Plan 目录、任务集、moshiro.* 方法、UDP 包、RawChunk、错误码 + │ ├─ MoShiro.Measurement/ # 采集引擎:积木、Recorder、任务调和(见 measurement.md) │ └─ tests/ - ├─ probe/ src/Monitor.Probe/ tests/ # 家宽端采集器 - ├─ agent/ src/Monitor.Agent/ tests/ # VPS 端采集器 + ├─ probe/ src/MoShiro.Probe/ tests/ # 家宽端采集器 + ├─ agent/ src/MoShiro.Agent/ tests/ # VPS 端采集器 ├─ src/ # Backend(面板) - │ ├─ Monitor.Backend/ # 宿主与组合根(Program.cs) - │ ├─ Monitor.Backend.Api/ # API 层:HTTP 端点、DTO、错误映射 - │ ├─ Monitor.Backend.Gateway/ # 在 Fleet.Server.Link 上注册 Monitor 的方法、状态与收件箱 - │ ├─ Monitor.Backend.Application/ # 用例层 + 端口接口 - │ ├─ Monitor.Backend.Analysis/ # 分析(纯计算,见 analysis.md) - │ └─ Monitor.Backend.Storage.Sqlite/ # 端口接口的实现,同时实现 IFleetStore + │ ├─ MoShiro.Backend/ # 宿主与组合根(Program.cs) + │ ├─ MoShiro.Backend.Api/ # API 层:HTTP 端点、DTO、错误映射 + │ ├─ MoShiro.Backend.Gateway/ # 在 Fleet.Server.Link 上注册 MoShiro 的方法、状态与收件箱 + │ ├─ MoShiro.Backend.Application/ # 用例层 + 端口接口 + │ ├─ MoShiro.Backend.Analysis/ # 分析(纯计算,见 analysis.md) + │ └─ MoShiro.Backend.Storage.Sqlite/ # 端口接口的实现,同时实现 IFleetStore ├─ tests/ ├─ openapi/v1.json # 构建生成并提交 - └─ Monitor.Backend.slnx + └─ MoShiro.Backend.slnx ``` -节点机器上的发布物是三个独立进程,使用不同的系统用户:`monitor-agent`(或 `monitor-probe`)、`fleet-enroll`(一次性运行)、`fleet-updater`(常驻或定时运行)。 +节点机器上的发布物是三个独立进程,使用不同的系统用户:`moshiro-agent`(或 `moshiro-probe`)、`fleet-enroll`(一次性运行)、`fleet-updater`(常驻或定时运行)。 ## 3. 依赖关系 @@ -65,21 +65,21 @@ monitor/ │ └─────┬──────┘ │ │ ▼ ▼ ▼ ▼ ┌──────────────────────────────────┐ ┌─────────────────────────┐ - │ Monitor.Protocol │ │ Fleet.Server.* │ + │ MoShiro.Protocol │ │ Fleet.Server.* │ └────────────────┬─────────────────┘ └───────────┬─────────────┘ ▼ ▼ ┌──────────────────────────────────────────────────────────────────┐ │ Fleet(节点侧):Core · Identity · Rpc · Link · Hosting │ └──────────────────────────────────────────────────────────────────┘ - 反向依赖一律禁止:fleet/** ✗→ Monitor.* + 反向依赖一律禁止:fleet/** ✗→ MoShiro.* ``` 简要来说: ```text -Probe, Agent ──> Measurement ──> Monitor.Protocol ──> Fleet.Core / Fleet.Rpc +Probe, Agent ──> Measurement ──> MoShiro.Protocol ──> Fleet.Core / Fleet.Rpc Probe, Agent ──> Fleet.Link / Fleet.Hosting / Fleet.Identity -Backend.* ──> Monitor.Protocol + Fleet.Server.* (不引用 Measurement) +Backend.* ──> MoShiro.Protocol + Fleet.Server.* (不引用 Measurement) fleet-enroll ──> Fleet.Enrollment.Client ──> Fleet.Identity / Core fleet-updater ──> Fleet.Update ──> Fleet.Core (不引用 Link,也不读取节点身份) Web ──> openapi/v1.json @@ -87,12 +87,12 @@ Web ──> openapi/v1.json | 项目 | 允许依赖 | 禁止 | | --- | --- | --- | -| `Fleet.*`(节点侧) | BCL、其他节点侧 Fleet 库 | 任何 NuGet 运行时包;任何 `Monitor.*` | -| `Fleet.Server.*` | ASP.NET Core、`Microsoft.Data.Sqlite`(仅 Sqlite 项目)、节点侧 Fleet 库 | 任何 `Monitor.*` | -| `Monitor.Protocol` | Fleet.Core、Fleet.Rpc | 任何 I/O、套接字、日志 | -| `Monitor.Measurement` | Monitor.Protocol、Fleet.Core | NuGet;日志(只通过计数接收器上报);读取配置;统计或解释逻辑 | +| `Fleet.*`(节点侧) | BCL、其他节点侧 Fleet 库 | 任何 NuGet 运行时包;任何 `MoShiro.*` | +| `Fleet.Server.*` | ASP.NET Core、`Microsoft.Data.Sqlite`(仅 Sqlite 项目)、节点侧 Fleet 库 | 任何 `MoShiro.*` | +| `MoShiro.Protocol` | Fleet.Core、Fleet.Rpc | 任何 I/O、套接字、日志 | +| `MoShiro.Measurement` | MoShiro.Protocol、Fleet.Core | NuGet;日志(只通过计数接收器上报);读取配置;统计或解释逻辑 | | Probe / Agent | 上述库,以及 Fleet.Link / Hosting / Identity | NuGet 运行时包;彼此互相引用;Fleet.Update;Fleet.Enrollment.Client | -| Backend.* | Monitor.Protocol、Fleet.Server.*,以及第 5.2 节列出的包 | Measurement、EF Core 等依赖反射的库 | +| Backend.* | MoShiro.Protocol、Fleet.Server.*,以及第 5.2 节列出的包 | Measurement、EF Core 等依赖反射的库 | 分析器类包(`PrivateAssets="all"`)不受限制。`scripts/check-deps` 在 CI 中检查上述规则。 @@ -102,28 +102,28 @@ Web ──> openapi/v1.json 组件、扩展点与接入方式见 [fleet/overview.md](fleet/overview.md),连接细节见 [fleet/link.md](fleet/link.md),更新见 [fleet/update.md](fleet/update.md)。 -> **实现状态**:`Fleet.Core`、`Fleet.Identity`、`Fleet.Rpc`、`Fleet.Link`、`Fleet.Hosting`、`Fleet.Enrollment.Client`、`Fleet.Server.*`(Abstractions、Enrollment、Link)和 `fleet-enroll` 已实现。`Fleet.Update`、`Fleet.Server.Releases`、`fleet-updater`、`fleet-release` 还只是设计(纯二进制方式的更新);容器节点的更新是宿主机上的 `monitor-update` 脚本和面板的 `ReleaseService`,见 [deployment.md](deployment.md)。原来的 `Monitor.Common` 和 `Monitor.NodeHost` 已经并入 Fleet: +> **实现状态**:`Fleet.Core`、`Fleet.Identity`、`Fleet.Rpc`、`Fleet.Link`、`Fleet.Hosting`、`Fleet.Enrollment.Client`、`Fleet.Server.*`(Abstractions、Enrollment、Link)和 `fleet-enroll` 已实现。`Fleet.Update`、`Fleet.Server.Releases`、`fleet-updater`、`fleet-release` 还只是设计(纯二进制方式的更新);容器节点的更新是宿主机上的 `moshiro-update` 脚本和面板的 `ReleaseService`,见 [deployment.md](deployment.md)。原来的 `MoShiro.Common` 和 `MoShiro.NodeHost` 已经并入 Fleet: | 原位置 | 现位置 | | --- | --- | -| `Monitor.Common`(Result、缓冲区、VarInt、有界队列、重放窗口、退避、ID、令牌哈希) | `Fleet.Core` | -| `Monitor.NodeHost`(模块宿主、日志、配置、ConfigStore、服务外壳) | `Fleet.Hosting` | +| `MoShiro.Common`(Result、缓冲区、VarInt、有界队列、重放窗口、退避、ID、令牌哈希) | `Fleet.Core` | +| `MoShiro.NodeHost`(模块宿主、日志、配置、ConfigStore、服务外壳) | `Fleet.Hosting` | | 节点密钥与签名 | `Fleet.Identity` | | JSON-RPC 信封与路由 | `Fleet.Rpc` | | Agent 注册 | `Fleet.Enrollment.Client` + `fleet-enroll` | -### 4.2 Monitor.Protocol(Monitor 的契约真源) +### 4.2 MoShiro.Protocol(MoShiro 的契约真源) ```text -Monitor.Protocol/ -├─ ProtocolVersion ProtocolLimits MonitorErrorCode(在 Fleet 错误码基础上扩展) +MoShiro.Protocol/ +├─ ProtocolVersion ProtocolLimits MoShiroErrorCode(在 Fleet 错误码基础上扩展) ├─ Ids/ AgentId(= Fleet NodeId)、ProbeId、TaskId、TestId、ChunkId、StreamId ├─ Catalog/ │ ├─ Kinds/ KindSpec 声明(积木组合 + ParamSpec + 记录列 + 预算) │ ├─ Plans/ 多阶段测试方案 │ └─ ParamSpec 参数定义(类型、默认值、上下限),节点与 Backend 共用同一套校验 ├─ Tasks/ TaskSet(Fleet 期望状态的文档类型)、调和结果 -├─ Rpc/ monitor.* 方法名、params/result、二进制通道号(从 16 开始) +├─ Rpc/ moshiro.* 方法名、params/result、二进制通道号(从 16 开始) ├─ Wire/ UDP 包、数据连接首帧 ├─ Raw/ 自描述 RawChunk:头部、列类型、列编解码、Brotli、crc32c └─ Json/ AgentRpcContext、ProbeRpcContext(按信道拆分,便于裁剪) @@ -131,7 +131,7 @@ Monitor.Protocol/ 累加器、直方图等统计类型**不在 Protocol 中**,只属于 `Backend.Analysis`。 -### 4.3 Monitor.Measurement(采集引擎) +### 4.3 MoShiro.Measurement(采集引擎) 包含: @@ -147,14 +147,14 @@ Monitor.Protocol/ ### 5.1 Agent 与 Probe:组装 -节点的组装点是 `AgentApp` 和 `ProbeApp`:在构造函数里**显式组装**,不使用 DI 容器,也不做反射扫描;没有全局状态,测试可以在同一进程里启动多个。连接、认证、重连、发件箱、状态同步都由 Fleet 提供,Monitor 只写业务: +节点的组装点是 `AgentApp` 和 `ProbeApp`:在构造函数里**显式组装**,不使用 DI 容器,也不做反射扫描;没有全局状态,测试可以在同一进程里启动多个。连接、认证、重连、发件箱、状态同步都由 Fleet 提供,MoShiro 只写业务: ```text AgentApp Probe(ProbeApp) FleetLink(到面板) FleetLink(到面板) - 状态 TaskSet、方法 monitor.test.* 状态 probe_agents(Agent 列表)、hello 带系统和构建信息 - 发件箱 RawChunk(通道 16) 心跳带更新器的状态;monitor.update.* 通知 - 心跳带更新器的状态;monitor.update.* AgentDirectory → 每个 Agent 一个 AgentConnection(点对点会话) + 状态 TaskSet、方法 moshiro.test.* 状态 probe_agents(Agent 列表)、hello 带系统和构建信息 + 发件箱 RawChunk(通道 16) 心跳带更新器的状态;moshiro.update.* 通知 + 心跳带更新器的状态;moshiro.update.* AgentDirectory → 每个 Agent 一个 AgentConnection(点对点会话) PeerListener / PeerHub(Probe 会话) 会话内:线路任务集 line_task_set 的调和、角色、列块发件箱(通道 17) UdpMux / TcpAcceptor(数据端口) TaskManager / TestRunner / ChunkAssembler @@ -163,7 +163,7 @@ AgentApp Probe(ProbeApp) 模块之间通过构造函数传入的接口或 `Channel` 通信,禁止通过静态全局状态共享数据。 -**新增 RPC 方法**:在 `Monitor.Protocol/Rpc` 中定义 params/result,然后在组装处加一行 `.On(Methods.X, HandleX)`。 +**新增 RPC 方法**:在 `MoShiro.Protocol/Rpc` 中定义 params/result,然后在组装处加一行 `.On(Methods.X, HandleX)`。 ### 5.2 Backend:分层与 API 层 @@ -172,7 +172,7 @@ AgentApp Probe(ProbeApp) │ │ ▲ ┌──────────────▼───────────────┐ ┌───────────▼──────────┐ │ │ Backend.Api │ │ Backend.Gateway │ │ - │ Public/ Admin/ │ │ 注册 monitor.* 方法 │ │ + │ Public/ Admin/ │ │ 注册 moshiro.* 方法 │ │ │ 认证(Cookie/CSRF/令牌) │ │ TaskSet 状态提供者 │ │ │ 错误映射 · OpenAPI · SSE 端点 │ │ RawChunk 收件箱 │ │ └──────────────┬───────────────┘ └───────────┬──────────┘ │ @@ -187,7 +187,7 @@ AgentApp Probe(ProbeApp) │ 实现端口 ┌───────────────────────────┴─────────────────────────────┐ │ Backend.Storage.Sqlite:段文件 + SQLite(只做读写) │ - │ 同时实现 IFleetStore(Fleet 的节点和令牌表放在 monitor.db 中)│ + │ 同时实现 IFleetStore(Fleet 的节点和令牌表放在 moshiro.db 中)│ └─────────────────────────────────────────────────────────┘ 端口:IAgentStore、ITaskStore、IRawStore、IMetricStore、ITestStore、IAuthStore @@ -198,16 +198,16 @@ AgentApp Probe(ProbeApp) - **Api 不能引用 Storage**(编译期保证);Api 和 Gateway 只调用 Application。 - Application 返回 `Result`。**错误码到 HTTP 状态的映射只在 Api 层做一次**(`ErrorCodeHttpMap`);到 JSON-RPC 错误的映射由 Fleet.Rpc 统一完成。 - Api 层按调用方分目录:`Public/`、`Admin/`,公共部分放在 `Common/`(分页、ETag、认证过滤器、ProblemFactory、`EndpointConventions`)。每类资源一个端点文件,新增资源时在 `ApiModule.Map` 中加一行。 -- 注册端点、签名认证、连接注册表、状态推送、收件箱 ACK、发布通道都来自 Fleet(`MapFleetEnrollment`、`MapFleetLink`、`MapFleetReleases`)。Monitor 只提供: +- 注册端点、签名认证、连接注册表、状态推送、收件箱 ACK、发布通道都来自 Fleet(`MapFleetEnrollment`、`MapFleetLink`、`MapFleetReleases`)。MoShiro 只提供: - `IFleetStore` 的实现; - `TaskSet` 的状态提供者; - `RawChunk` 的收件箱; - - `monitor.*` 方法。 + - `moshiro.*` 方法。 - public 层的 DTO 单独定义,只暴露可以公开的字段,并统一经过“可见性过滤器”。 - 请求校验:简单字段约束使用 .NET 10 内置的 Minimal API 校验;任务参数统一用 `ParamSpec` 校验(与节点共用);跨字段规则放在 Application 层。 - Backend 使用 ASP.NET Core 自带的 DI 容器,只在组合根显式注册。 -Backend.Analysis 只依赖 Monitor.Protocol 和 Fleet.Core,没有 I/O,可以单独做成离线 CLI 使用。 +Backend.Analysis 只依赖 MoShiro.Protocol 和 Fleet.Core,没有 I/O,可以单独做成离线 CLI 使用。 Backend 允许的包:ASP.NET Core 共享框架、`Microsoft.Data.Sqlite`、`Microsoft.AspNetCore.OpenApi`、`Microsoft.Extensions.ApiDescription.Server`(仅构建期使用)。 @@ -221,11 +221,11 @@ Backend 允许的包:ASP.NET Core 共享框架、`Microsoft.Data.Sqlite`、`Mi | 原始数据格式 | `Protocol/Raw`(自描述) | 新增列不需要升级版本;四处使用同一份编解码器 | | 新增统计指标 | `Analysis/Metrics` 中加 1 行 `MetricDef` | 存储、降采样、API、SSE、目录全部自动处理;回填 30 天历史 | | 服务评分 | `Analysis/Models` | 查询时计算,立即对全部历史生效 | -| 新增 RPC 能力 | `Monitor.Protocol/Rpc` + 组装处加 1 行 | 通过 Fleet 的 capabilities 协商,旧节点不受影响 | -| 注册、认证、重连、发件箱、状态同步 | `backend/fleet/` | Monitor 和所有其他产品同时受益 | +| 新增 RPC 能力 | `MoShiro.Protocol/Rpc` + 组装处加 1 行 | 通过 Fleet 的 capabilities 协商,旧节点不受影响 | +| 注册、认证、重连、发件箱、状态同步 | `backend/fleet/` | MoShiro 和所有其他产品同时受益 | | 更新机制 | `Fleet.Update` + `fleet-updater` | 所有产品共用;产品只提供发布清单 | | REST DTO 与端点 | `Backend.Api` | 生成 OpenAPI,CI 检查 diff,前端的 TS 类型随之更新 | -| 错误码 | Fleet 错误码 + `MonitorErrorCode` | REST、JSON-RPC、OpenAPI、TS 全部一致 | +| 错误码 | Fleet 错误码 + `MoShiroErrorCode` | REST、JSON-RPC、OpenAPI、TS 全部一致 | | 版本、编译设置、风格、禁用 API | `backend/` 下的 props、`.editorconfig`、`BannedSymbols*.txt` | 所有项目 | ## 7. 编译设置 @@ -334,10 +334,10 @@ M0 阶段先测出基线,之后作为 CI 的回归门槛(超出 10% 即失 | C 库 | musl:使用 `linux-musl-*` 目标发布 | | TLS | .NET 在 Linux 上依赖 OpenSSL,而 OpenWrt 默认使用 mbedTLS/wolfSSL。需要安装 `libopenssl3`(安装脚本自动检查并提示)。启动时自检,缺少时明确报错,不会静默降级 | | 全球化 | 已启用 `InvariantGlobalization`,不依赖 ICU | -| 服务管理 | procd:提供 `/etc/init.d/monitor-probe`(`procd_set_param respawn`,前台运行,日志输出到 logd);`Fleet.Hosting.ServiceShell` 在 procd 下不需要 `sd_notify` | -| 存储 | 闪存很小,而且需要避免频繁写入:二进制放在 `/usr/lib/monitor/`,配置和身份放在 `/etc/monitor/`(sysupgrade 时通过 `/lib/upgrade/keep.d/` 保留);测量数据本来就不落盘;`ConfigStore` 只在 Agent 列表变化时写入 | +| 服务管理 | procd:提供 `/etc/init.d/moshiro-probe`(`procd_set_param respawn`,前台运行,日志输出到 logd);`Fleet.Hosting.ServiceShell` 在 procd 下不需要 `sd_notify` | +| 存储 | 闪存很小,而且需要避免频繁写入:二进制放在 `/usr/lib/moshiro/`,配置和身份放在 `/etc/moshiro/`(sysupgrade 时通过 `/lib/upgrade/keep.d/` 保留);测量数据本来就不落盘;`ConfigStore` 只在 Agent 列表变化时写入 | | 内存 | 预算 ≤ 32 MB,适合 ≥ 256 MB 内存的路由器;在本地配置中限制重负载测试的码率(`limits.max_test_mbps`),防止路由器 CPU 成为瓶颈,反过来影响测量结果 | -| 测量偏差 | Probe 运行在网关上时,自己没有 NAT;一旦路由器 CPU 饱和,结果就会失真。因此 Probe 在 `monitor.event` 中上报自身的 CPU 繁忙标记(仅进程级别),分析层据此标注置信说明 | +| 测量偏差 | Probe 运行在网关上时,自己没有 NAT;一旦路由器 CPU 饱和,结果就会失真。因此 Probe 在 `moshiro.event` 中上报自身的 CPU 繁忙标记(仅进程级别),分析层据此标注置信说明 | | 打包 | 提供 `tar.gz` 和 procd 脚本;包格式(ipk 或 apk)按目标 OpenWrt 版本提供 | | 更新 | `fleet-updater` 使用 procd 适配器;`keep_versions = 1`,下载前检查剩余空间,避免写满闪存 | diff --git a/docs/protocol.md b/docs/protocol.md index 9c8f7e3..0352ece 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -1,35 +1,35 @@ # 线协议 -Monitor 的两条控制链路都建立在 Fleet 之上: +MoShiro 的两条控制链路都建立在 Fleet 之上: - **Agent ↔ Backend**:Fleet 连接服务端(wss),见 [fleet/link.md](fleet/link.md); - **Probe ↔ Agent**:Fleet 节点间点对点会话(TLS),见 [fleet/link.md](fleet/link.md) 第 8 节。 -认证、心跳、重连、能力协商、可靠发件箱、期望状态同步、JSON-RPC 信封都由 Fleet 负责。本文只定义 **Monitor 自己的内容**:`monitor.*` 方法、状态文档、二进制通道,以及 Fleet 之外的数据面(UDP 包和数据连接)。所有类型都放在 `Monitor.Protocol` 中。 +认证、心跳、重连、能力协商、可靠发件箱、期望状态同步、JSON-RPC 信封都由 Fleet 负责。本文只定义 **MoShiro 自己的内容**:`moshiro.*` 方法、状态文档、二进制通道,以及 Fleet 之外的数据面(UDP 包和数据连接)。所有类型都放在 `MoShiro.Protocol` 中。 ## 1. Fleet 能力的映射 -| Monitor 需要的能力 | 使用的 Fleet 机制 | Monitor 提供的内容 | +| MoShiro 需要的能力 | 使用的 Fleet 机制 | MoShiro 提供的内容 | | --- | --- | --- | | 下发任务 | 期望状态 `fleet.state.sync` | 文档类型 `TaskSet`,包括 `tasks[]`、`peers`(允许连这个 Agent 的 Probe 公钥,已按线路开关过滤) | | 下发 Agent 列表给 Probe | 期望状态 `fleet.state.sync`(Probe 直连面板) | 文档类型 `probe_agents`:`version`、`agents[]`(`agent_id`、`host`、`tcp_port`、`udp_ports`、`spki`),已按线路开关过滤;Agent 集合或线路开关变化时重新推送 | -| 更新 | 通知 `monitor.update.offer` / `monitor.update.apply`(B→A、B→P),心跳附加字段 `update` | `offer` 带 CI 签名的发布清单原文和签名,节点只写进数据目录;`apply` 请求更新;`update` 是宿主机更新器的状态(`state`、`current`、`available`、`error`、`at`),见 [deployment.md](deployment.md) | +| 更新 | 通知 `moshiro.update.offer` / `moshiro.update.apply`(B→A、B→P),心跳附加字段 `update` | `offer` 带 CI 签名的发布清单原文和签名,节点只写进数据目录;`apply` 请求更新;`update` 是宿主机更新器的状态(`state`、`current`、`available`、`error`、`at`),见 [deployment.md](deployment.md) | | 上报原始块 | 发件箱,二进制通道 **16** | `RawChunk`(自描述,见 [measurement.md](measurement.md) 第 4 节),`msg_id = chunk_id` | | Probe 交付列块 | 点对点会话的发件箱,二进制通道 **17** | 列块:`u32 stream_id \| u32 first_seq \| u32 count \| 列数据(Brotli)` | | 节点自身状态 | `fleet.heartbeat` 的附加字段 | Agent:`sessions`、`probes[]`、`pps_in/out`、`dropped_invalid`、`dropped_rate_limited`、`queue_bytes`、`update`;Probe:只有 `update` | -| 版本与能力 | `fleet.hello` | capabilities 包括 `monitor.kinds:<列表>`、`monitor.blocks:<列表>`;Agent 附加 `platform`(系统、架构、版本、tag、提交、构建时间)、`tls_spki`、`probe_ports`、`local_limits` 摘要;Probe 附加 `platform` | +| 版本与能力 | `fleet.hello` | capabilities 包括 `moshiro.kinds:<列表>`、`moshiro.blocks:<列表>`;Agent 附加 `platform`(系统、架构、版本、tag、提交、构建时间)、`tls_spki`、`probe_ports`、`local_limits` 摘要;Probe 附加 `platform` | -## 2. `monitor.*` 方法 +## 2. `moshiro.*` 方法 ### Agent ↔ Backend | 方法 | 方向 | 类型 | 参数与结果 | | --- | --- | --- | --- | -| `monitor.test.run` | B→A | 请求 | `test_id`、`probe_id`(在哪个 Probe 上跑)、`plan`、`phases[]` → `accepted`,或错误 `test_busy`、`probe_offline` | -| `monitor.probe.disconnect` | B→A | 请求 | `probe_id` → `accepted`(Agent 是否真的有这个会话);Agent 关闭该 Probe 的会话 | -| `monitor.test.cancel` | B→A | 请求 | `test_id` | -| `monitor.test.status` | A→B | 通知 | `test_id`、`status`(`running`、`phase_done`、`succeeded`、`failed`、`aborted`)、`phase?`、`error_code?` | -| `monitor.event` | A→B | 通知 | `kind`(`probe_connected`(`detail` 是 `probe_id`,`probe` 里带版本、远端地址和连接时间)、`probe_disconnected`、`endpoint_changed`、`session_rejected`、`clock_step`、`gap`、`cpu_saturated`(节点进程 CPU 饱和,可能影响测量,由 Probe 或 Agent 上报))、`at_utc`、`detail` | +| `moshiro.test.run` | B→A | 请求 | `test_id`、`probe_id`(在哪个 Probe 上跑)、`plan`、`phases[]` → `accepted`,或错误 `test_busy`、`probe_offline` | +| `moshiro.probe.disconnect` | B→A | 请求 | `probe_id` → `accepted`(Agent 是否真的有这个会话);Agent 关闭该 Probe 的会话 | +| `moshiro.test.cancel` | B→A | 请求 | `test_id` | +| `moshiro.test.status` | A→B | 通知 | `test_id`、`status`(`running`、`phase_done`、`succeeded`、`failed`、`aborted`)、`phase?`、`error_code?` | +| `moshiro.event` | A→B | 通知 | `kind`(`probe_connected`(`detail` 是 `probe_id`,`probe` 里带版本、远端地址和连接时间)、`probe_disconnected`、`endpoint_changed`、`session_rejected`、`clock_step`、`gap`、`cpu_saturated`(节点进程 CPU 饱和,可能影响测量,由 Probe 或 Agent 上报))、`at_utc`、`detail` | 心跳的附加字段里有 `probes[]`:Agent 当前连着的每个 Probe(`id`、`version`、`remote`、`since_utc_ms`),每次都是完整快照,Backend 靠它纠正错过的连接事件。点对点握手的认证消息里可以带 Probe 的 `version`(只用于展示)。块头里的 `probe_id` 以 Agent 认证过的会话为准,Probe 自报的值会被覆盖。 @@ -38,10 +38,10 @@ Monitor 的两条控制链路都建立在 Fleet 之上: | 方法 | 方向 | 类型 | 参数与结果 | | --- | --- | --- | --- | | `fleet.state.sync`(文档类型 `line_task_set`) | A→P | 请求 | 这条线路的任务(`id`、`kind`、`params`、`stream_id`、`port`)和 Agent 的数据面端口 | -| `monitor.clock` | P→A | 请求 | `probe_mono_us` → `agent_mono_us`;Probe 按往返中点估计两端单调时钟的偏移(取最小往返的一次),记入块头 `probe_offset_us` | -| `monitor.test.phase` | A→P | 请求 | 测试的一个阶段:`test_id`、`phase`、`kind`、`params`、`stream_id`、`duration_s`、`port` → `accepted`;Probe 在回复之前准备好自己一侧的角色(单向数据流:先发几个探活包让 Agent 学到源地址) | -| `monitor.test.phase_end` | A→P | 请求 | `sent_count`(Agent 发出的包数)→ `fragments`:Probe 收尾,把列块交给 Agent,回复交出的个数;Agent 等全部列块合并上传之后才进入下一阶段 | -| `monitor.test.abort` | A→P | 通知 | `test_id` | +| `moshiro.clock` | P→A | 请求 | `probe_mono_us` → `agent_mono_us`;Probe 按往返中点估计两端单调时钟的偏移(取最小往返的一次),记入块头 `probe_offset_us` | +| `moshiro.test.phase` | A→P | 请求 | 测试的一个阶段:`test_id`、`phase`、`kind`、`params`、`stream_id`、`duration_s`、`port` → `accepted`;Probe 在回复之前准备好自己一侧的角色(单向数据流:先发几个探活包让 Agent 学到源地址) | +| `moshiro.test.phase_end` | A→P | 请求 | `sent_count`(Agent 发出的包数)→ `fragments`:Probe 收尾,把列块交给 Agent,回复交出的个数;Agent 等全部列块合并上传之后才进入下一阶段 | +| `moshiro.test.abort` | A→P | 通知 | `test_id` | | `fleet.outbox.ack` | 双向 | 通知 | Probe 的列块(通道 17)是至少一次投递,Agent 每收到一个就确认,重复到达的只处理一次 | 会话密钥不需要单独的方法:点对点握手(TLS 固定证书 → `peer.challenge` → Probe 用身份私钥签 `(peer_id, nonce, client_pub, server_pub)` → 两端各自 ECDH + HKDF)直接得到 `session_id` 和 `session_key`,`peer.auth` 的应答只回显 `session_id` 用来互相确认。 @@ -58,7 +58,7 @@ Probe 只记录自己一侧的列,Agent 在数据面记录另一侧,由 Agen 单块最多 `MaxRecordsPerChunk`(50 000)条记录:Probe 必须把大的阶段按序号范围切成多个列块(例如 100 Mbit/s、1000 B 的 10 秒阶段是 125 000 个包 → 4 个列块),`phase_end` 的应答报告总块数。块头里 Probe 必须带上 `agent_id`(它知道自己在和哪个 Agent 通信)。 -新增方法只需要在 `Monitor.Protocol/Rpc` 中定义,并在节点组装处加一行 `.On(...)`。旧节点会通过 capabilities 协商自动避开不支持的方法。 +新增方法只需要在 `MoShiro.Protocol/Rpc` 中定义,并在节点组装处加一行 `.On(...)`。旧节点会通过 capabilities 协商自动避开不支持的方法。 ## 3. 数据面(不属于 Fleet) @@ -95,7 +95,7 @@ Probe 只记录自己一侧的列,Agent 在数据面记录另一侧,由 Agen ## 4. 版本演进 - Fleet 层的兼容规则见 [fleet/link.md](fleet/link.md)。 -- `monitor.*` 方法:新增方法或可选字段不需要升级版本,接收方忽略未知字段。 +- `moshiro.*` 方法:新增方法或可选字段不需要升级版本,接收方忽略未知字段。 - RawChunk:块头自描述,新增列或新增 Kind 不需要升级 `container_version`;只有容器格式变化时才升级。 - UDP 包和数据连接首帧的布局变化时,必须升级 `protocol_version`,并更新黄金字节测试。 - Agent 同时支持当前版本和上一个版本的 Probe;Backend 能解码保留期内所有的 `container_version`。 diff --git a/docs/storage.md b/docs/storage.md index bc6afd1..bdea426 100644 --- a/docs/storage.md +++ b/docs/storage.md @@ -1,12 +1,12 @@ # Backend 存储 -实现位于 `Monitor.Backend.Storage.Sqlite`,负责实现 `Backend.Application` 中定义的端口接口,**只做读写,不含业务逻辑**。降采样和分析由 Application 调用 Analysis 完成。 +实现位于 `MoShiro.Backend.Storage.Sqlite`,负责实现 `Backend.Application` 中定义的端口接口,**只做读写,不含业务逻辑**。降采样和分析由 Application 调用 Analysis 完成。 ## 1. 目录布局 ```text data/ -├─ monitor.db # SQLite:配置、身份、原始块索引、指标、测试结果 +├─ moshiro.db # SQLite:配置、身份、原始块索引、指标、测试结果 └─ raw/ └─ 2026-09-27/ # 按 UTC 日期分目录,保留期满整目录删除 ├─ agt_01J…/ # 每条线路或每个 Agent 一个目录 @@ -28,7 +28,7 @@ data/ ## 3. 表结构 -`agents`、`join_tokens` 以及公钥和状态版本字段,同时作为 Fleet 的 `IFleetStore` 存储(由 `Monitor.Backend.Storage.Sqlite` 实现),和 Monitor 的其他数据放在同一个 `monitor.db` 中,由同一个单写入者写入。发布与灰度相关的表(`fleet_releases`、`fleet_rollouts`)由 `Fleet.Server.Releases` 自带的迁移脚本创建(职责见 [fleet/update.md](fleet/update.md) 第 6 节)。 +`agents`、`join_tokens` 以及公钥和状态版本字段,同时作为 Fleet 的 `IFleetStore` 存储(由 `MoShiro.Backend.Storage.Sqlite` 实现),和 MoShiro 的其他数据放在同一个 `moshiro.db` 中,由同一个单写入者写入。发布与灰度相关的表(`fleet_releases`、`fleet_rollouts`)由 `Fleet.Server.Releases` 自带的迁移脚本创建(职责见 [fleet/update.md](fleet/update.md) 第 6 节)。 ```sql -- 身份与注册 ------------------------------------------------------------- diff --git a/packaging/compose/agent/compose.yaml b/packaging/compose/agent/compose.yaml index 567d78b..26bdbdf 100644 --- a/packaging/compose/agent/compose.yaml +++ b/packaging/compose/agent/compose.yaml @@ -3,15 +3,15 @@ # 首次注册、配置导入和自动更新见 docs/deployment.md。 services: agent: - image: ${MONITOR_IMAGE:-registry.oeo.one/monitor/monitor-agent}:${MONITOR_VERSION:-0.1.1} - container_name: monitor-agent + image: ${MOSHIRO_IMAGE:-registry.oeo.one/moshiro/moshiro-agent}:${MOSHIRO_VERSION:-0.1.1} + container_name: moshiro-agent restart: unless-stopped init: true # Probe 要直连 Agent 的 7443(TCP+UDP)和 7444(TCP),用宿主网络,不做端口映射 network_mode: host volumes: - - agent-config:/etc/monitor - - agent-status:/etc/monitor/update-status:ro + - agent-config:/etc/moshiro + - agent-status:/etc/moshiro/update-status:ro - /etc/os-release:/etc/os-release:ro # 系统目录只读,不加 :z/:Z;SELinux 隔离在容器级别禁用。 - /proc:/host/proc:ro @@ -36,6 +36,6 @@ services: volumes: agent-config: - name: monitor-agent-config + name: moshiro-agent-config agent-status: - name: monitor-agent-status + name: moshiro-agent-status diff --git a/packaging/compose/backend/compose.yaml b/packaging/compose/backend/compose.yaml index 0e1be0c..0cd9867 100644 --- a/packaging/compose/backend/compose.yaml +++ b/packaging/compose/backend/compose.yaml @@ -1,15 +1,15 @@ # Docker / Podman 共用,数据库和原始数据保存在命名 volume 中。 services: backend: - image: ${MONITOR_IMAGE:-registry.oeo.one/monitor/monitor-backend}:${MONITOR_VERSION:-0.1.1} - container_name: monitor-backend + image: ${MOSHIRO_IMAGE:-registry.oeo.one/moshiro/moshiro-backend}:${MOSHIRO_VERSION:-0.1.1} + container_name: moshiro-backend restart: unless-stopped ports: - "127.0.0.1:8080:8080" environment: - Monitor__InitialAdminPassword: ${MONITOR_INITIAL_ADMIN_PASSWORD:?Set MONITOR_INITIAL_ADMIN_PASSWORD} + MoShiro__InitialAdminPassword: ${MOSHIRO_INITIAL_ADMIN_PASSWORD:?Set MOSHIRO_INITIAL_ADMIN_PASSWORD} volumes: - backend-data:/data volumes: backend-data: - name: monitor-backend-data + name: moshiro-backend-data diff --git a/packaging/compose/probe/compose.yaml b/packaging/compose/probe/compose.yaml index 98aea62..7aac5a7 100644 --- a/packaging/compose/probe/compose.yaml +++ b/packaging/compose/probe/compose.yaml @@ -3,14 +3,14 @@ # 首次注册、配置导入和自动更新见 docs/deployment.md。 services: probe: - image: ${MONITOR_IMAGE:-registry.oeo.one/monitor/monitor-probe}:${MONITOR_VERSION:-0.1.1} - container_name: monitor-probe + image: ${MOSHIRO_IMAGE:-registry.oeo.one/moshiro/moshiro-probe}:${MOSHIRO_VERSION:-0.1.1} + container_name: moshiro-probe restart: unless-stopped init: true network_mode: host volumes: - - probe-config:/etc/monitor - - probe-status:/etc/monitor/update-status:ro + - probe-config:/etc/moshiro + - probe-status:/etc/moshiro/update-status:ro - /etc/os-release:/etc/os-release:ro read_only: true tmpfs: @@ -27,6 +27,6 @@ services: volumes: probe-config: - name: monitor-probe-config + name: moshiro-probe-config probe-status: - name: monitor-probe-status + name: moshiro-probe-status diff --git a/packaging/container/Agent.Containerfile b/packaging/container/Agent.Containerfile index 32dd036..15156ec 100644 --- a/packaging/container/Agent.Containerfile +++ b/packaging/container/Agent.Containerfile @@ -1,17 +1,17 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ARG APP_VERSION=unknown -LABEL org.opencontainers.image.title="Monitor Agent" \ - org.opencontainers.image.description="MyMonitor node agent for Linux" \ +LABEL org.opencontainers.image.title="MoShiro Agent" \ + org.opencontainers.image.description="MoShiro node agent for Linux" \ org.opencontainers.image.licenses="Apache-2.0" \ org.opencontainers.image.version="$APP_VERSION" -COPY --chown=1654:1654 app/monitor-agent /usr/local/bin/monitor-agent +COPY --chown=1654:1654 app/moshiro-agent /usr/local/bin/moshiro-agent COPY --chown=1654:1654 app/fleet-enroll /usr/local/bin/fleet-enroll -COPY --chown=1654:1654 config/ /etc/monitor/ +COPY --chown=1654:1654 config/ /etc/moshiro/ USER 1654:1654 -WORKDIR /etc/monitor -VOLUME ["/etc/monitor"] -ENTRYPOINT ["/usr/local/bin/monitor-agent"] -CMD ["--config", "/etc/monitor/agent.json"] +WORKDIR /etc/moshiro +VOLUME ["/etc/moshiro"] +ENTRYPOINT ["/usr/local/bin/moshiro-agent"] +CMD ["--config", "/etc/moshiro/agent.json"] diff --git a/packaging/container/Agent.NativeBuild.Containerfile b/packaging/container/Agent.NativeBuild.Containerfile index 4f81658..ef818a6 100644 --- a/packaging/container/Agent.NativeBuild.Containerfile +++ b/packaging/container/Agent.NativeBuild.Containerfile @@ -3,16 +3,16 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine-aot AS build WORKDIR /src/backend COPY restore/backend/ ./ # restore 也要带 PublishAot:不然不会还原 ILCompiler,之后 --no-restore 的发布就悄悄变成「裁剪过的框架依赖程序」 -RUN dotnet restore agent/src/Monitor.Agent -r linux-musl-x64 -p:PublishAot=true --artifacts-path /artifacts \ +RUN dotnet restore agent/src/MoShiro.Agent -r linux-musl-x64 -p:PublishAot=true --artifacts-path /artifacts \ && dotnet restore fleet/tools/fleet-enroll -r linux-musl-x64 -p:PublishAot=true --artifacts-path /artifacts COPY source/backend/ ./ # 构建信息:CI 通过 --build-arg 传入;不传就是空(放在 restore 之后,每次构建都变的时间不会让依赖还原的缓存失效) -ARG MONITOR_TAG= -ARG MONITOR_COMMIT= -ARG MONITOR_BUILT_AT= -ENV MONITOR_TAG=$MONITOR_TAG MONITOR_COMMIT=$MONITOR_COMMIT MONITOR_BUILT_AT=$MONITOR_BUILT_AT -RUN dotnet publish agent/src/Monitor.Agent -m:3 -c Release -r linux-musl-x64 \ +ARG MOSHIRO_TAG= +ARG MOSHIRO_COMMIT= +ARG MOSHIRO_BUILT_AT= +ENV MOSHIRO_TAG=$MOSHIRO_TAG MOSHIRO_COMMIT=$MOSHIRO_COMMIT MOSHIRO_BUILT_AT=$MOSHIRO_BUILT_AT +RUN dotnet publish agent/src/MoShiro.Agent -m:3 -c Release -r linux-musl-x64 \ --self-contained true --no-restore -p:PublishAot=true -p:UseAotAnywhere=false \ -p:UseAppHost=true -p:StripSymbols=true \ -p:DebugType=none -p:DebugSymbols=false --artifacts-path /artifacts -o /out/agent \ @@ -21,23 +21,23 @@ RUN dotnet publish agent/src/Monitor.Agent -m:3 -c Release -r linux-musl-x64 \ -p:UseAppHost=true -p:StripSymbols=true \ -p:DebugType=none -p:DebugSymbols=false --artifacts-path /artifacts -o /out/enroll # 原生程序有几 MB;几十 KB 的是只会去找 .dll 的启动器 -RUN test -x /out/agent/monitor-agent && test -x /out/enroll/fleet-enroll \ - && test "$(stat -c%s /out/agent/monitor-agent)" -gt 2000000 && test "$(stat -c%s /out/enroll/fleet-enroll)" -gt 2000000 +RUN test -x /out/agent/moshiro-agent && test -x /out/enroll/fleet-enroll \ + && test "$(stat -c%s /out/agent/moshiro-agent)" -gt 2000000 && test "$(stat -c%s /out/enroll/fleet-enroll)" -gt 2000000 FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ARG APP_VERSION=main -LABEL org.opencontainers.image.title="Monitor Agent" \ - org.opencontainers.image.description="MyMonitor node agent for Linux" \ +LABEL org.opencontainers.image.title="MoShiro Agent" \ + org.opencontainers.image.description="MoShiro node agent for Linux" \ org.opencontainers.image.licenses="Apache-2.0" \ org.opencontainers.image.version="$APP_VERSION" -COPY --chown=1654:1654 --from=build /out/agent/monitor-agent /usr/local/bin/monitor-agent +COPY --chown=1654:1654 --from=build /out/agent/moshiro-agent /usr/local/bin/moshiro-agent COPY --chown=1654:1654 --from=build /out/enroll/fleet-enroll /usr/local/bin/fleet-enroll -COPY --chown=1654:1654 config/ /etc/monitor/ +COPY --chown=1654:1654 config/ /etc/moshiro/ USER 1654:1654 -WORKDIR /etc/monitor -VOLUME ["/etc/monitor"] -ENTRYPOINT ["/usr/local/bin/monitor-agent"] -CMD ["--config", "/etc/monitor/agent.json"] +WORKDIR /etc/moshiro +VOLUME ["/etc/moshiro"] +ENTRYPOINT ["/usr/local/bin/moshiro-agent"] +CMD ["--config", "/etc/moshiro/agent.json"] diff --git a/packaging/container/Backend.Containerfile b/packaging/container/Backend.Containerfile index 26d6101..d0c8f5b 100644 --- a/packaging/container/Backend.Containerfile +++ b/packaging/container/Backend.Containerfile @@ -1,20 +1,20 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ARG APP_VERSION=unknown -LABEL org.opencontainers.image.title="Monitor Backend" \ +LABEL org.opencontainers.image.title="MoShiro Backend" \ org.opencontainers.image.description="Self-hosted network path quality monitoring backend" \ org.opencontainers.image.licenses="Apache-2.0" \ org.opencontainers.image.version="$APP_VERSION" WORKDIR /app -COPY --chown=1654:1654 app/monitor-backend /app/monitor-backend +COPY --chown=1654:1654 app/moshiro-backend /app/moshiro-backend COPY --chown=1654:1654 data/.keep /data/.keep ENV ASPNETCORE_HTTP_PORTS=8080 \ - Monitor__DataDirectory=/data \ + MoShiro__DataDirectory=/data \ DOTNET_EnableDiagnostics=0 USER 1654:1654 VOLUME ["/data"] EXPOSE 8080 -ENTRYPOINT ["/app/monitor-backend"] +ENTRYPOINT ["/app/moshiro-backend"] diff --git a/packaging/container/Probe.Containerfile b/packaging/container/Probe.Containerfile index 8f198b7..8ca719e 100644 --- a/packaging/container/Probe.Containerfile +++ b/packaging/container/Probe.Containerfile @@ -1,16 +1,16 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ARG APP_VERSION=unknown -LABEL org.opencontainers.image.title="Monitor Probe" \ - org.opencontainers.image.description="MyMonitor network measurement probe for Linux" \ +LABEL org.opencontainers.image.title="MoShiro Probe" \ + org.opencontainers.image.description="MoShiro network measurement probe for Linux" \ org.opencontainers.image.licenses="Apache-2.0" \ org.opencontainers.image.version="$APP_VERSION" -COPY --chown=1654:1654 app/monitor-probe /usr/local/bin/monitor-probe -COPY --chown=1654:1654 config/ /etc/monitor/ +COPY --chown=1654:1654 app/moshiro-probe /usr/local/bin/moshiro-probe +COPY --chown=1654:1654 config/ /etc/moshiro/ USER 1654:1654 -WORKDIR /etc/monitor -VOLUME ["/etc/monitor"] -ENTRYPOINT ["/usr/local/bin/monitor-probe"] -CMD ["--config", "/etc/monitor/probe.json"] +WORKDIR /etc/moshiro +VOLUME ["/etc/moshiro"] +ENTRYPOINT ["/usr/local/bin/moshiro-probe"] +CMD ["--config", "/etc/moshiro/probe.json"] diff --git a/packaging/container/Probe.NativeBuild.Containerfile b/packaging/container/Probe.NativeBuild.Containerfile index 76abe65..387e83a 100644 --- a/packaging/container/Probe.NativeBuild.Containerfile +++ b/packaging/container/Probe.NativeBuild.Containerfile @@ -3,35 +3,35 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine-aot AS build WORKDIR /src/backend COPY restore/backend/ ./ # restore 也要带 PublishAot:不然不会还原 ILCompiler,之后 --no-restore 的发布就悄悄变成「裁剪过的框架依赖程序」 -RUN dotnet restore probe/src/Monitor.Probe -r linux-musl-x64 -p:PublishAot=true --artifacts-path /artifacts +RUN dotnet restore probe/src/MoShiro.Probe -r linux-musl-x64 -p:PublishAot=true --artifacts-path /artifacts COPY source/backend/ ./ # 构建信息:CI 通过 --build-arg 传入;不传就是空(放在 restore 之后,每次构建都变的时间不会让依赖还原的缓存失效) -ARG MONITOR_TAG= -ARG MONITOR_COMMIT= -ARG MONITOR_BUILT_AT= -ENV MONITOR_TAG=$MONITOR_TAG MONITOR_COMMIT=$MONITOR_COMMIT MONITOR_BUILT_AT=$MONITOR_BUILT_AT -RUN dotnet publish probe/src/Monitor.Probe -m:3 -c Release -r linux-musl-x64 \ +ARG MOSHIRO_TAG= +ARG MOSHIRO_COMMIT= +ARG MOSHIRO_BUILT_AT= +ENV MOSHIRO_TAG=$MOSHIRO_TAG MOSHIRO_COMMIT=$MOSHIRO_COMMIT MOSHIRO_BUILT_AT=$MOSHIRO_BUILT_AT +RUN dotnet publish probe/src/MoShiro.Probe -m:3 -c Release -r linux-musl-x64 \ --self-contained true --no-restore -p:PublishAot=true -p:UseAotAnywhere=false \ -p:UseAppHost=true -p:StripSymbols=true \ -p:DebugType=none -p:DebugSymbols=false --artifacts-path /artifacts -o /out/probe # 原生程序有几 MB;几十 KB 的是只会去找 .dll 的启动器 -RUN test -x /out/probe/monitor-probe \ - && test "$(stat -c%s /out/probe/monitor-probe)" -gt 2000000 +RUN test -x /out/probe/moshiro-probe \ + && test "$(stat -c%s /out/probe/moshiro-probe)" -gt 2000000 FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine ARG APP_VERSION=main -LABEL org.opencontainers.image.title="Monitor Probe" \ - org.opencontainers.image.description="MyMonitor network measurement probe for Linux" \ +LABEL org.opencontainers.image.title="MoShiro Probe" \ + org.opencontainers.image.description="MoShiro network measurement probe for Linux" \ org.opencontainers.image.licenses="Apache-2.0" \ org.opencontainers.image.version="$APP_VERSION" -COPY --chown=1654:1654 --from=build /out/probe/monitor-probe /usr/local/bin/monitor-probe -COPY --chown=1654:1654 config/ /etc/monitor/ +COPY --chown=1654:1654 --from=build /out/probe/moshiro-probe /usr/local/bin/moshiro-probe +COPY --chown=1654:1654 config/ /etc/moshiro/ USER 1654:1654 -WORKDIR /etc/monitor -VOLUME ["/etc/monitor"] -ENTRYPOINT ["/usr/local/bin/monitor-probe"] -CMD ["--config", "/etc/monitor/probe.json"] +WORKDIR /etc/moshiro +VOLUME ["/etc/moshiro"] +ENTRYPOINT ["/usr/local/bin/moshiro-probe"] +CMD ["--config", "/etc/moshiro/probe.json"] diff --git a/packaging/install.sh b/packaging/install.sh index 05d7d73..569f9b5 100644 --- a/packaging/install.sh +++ b/packaging/install.sh @@ -1,18 +1,18 @@ #!/bin/sh -# Installs monitor-agent or monitor-probe from an extracted release directory (the directory this script lives in). +# Installs moshiro-agent or moshiro-probe from an extracted release directory (the directory this script lives in). # POSIX sh: runs on Debian/Ubuntu/Alpine/OpenWrt (busybox). # # ./install.sh agent --server https://panel.example.com --join --name hk-1 # ./install.sh probe [--probe-json /path/to/probe.json] # ./install.sh uninstall agent|probe [--purge] # -# Binaries go to /usr/lib/monitor (root-owned: the collector cannot rewrite its own executable); -# config and identity go to /etc/monitor (owned by the unprivileged `monitor` user). +# Binaries go to /usr/lib/moshiro (root-owned: the collector cannot rewrite its own executable); +# config and identity go to /etc/moshiro (owned by the unprivileged `moshiro` user). set -eu -PREFIX=/usr/lib/monitor -CONFIG=/etc/monitor -USER_NAME=monitor +PREFIX=/usr/lib/moshiro +CONFIG=/etc/moshiro +USER_NAME=moshiro HERE="$(cd "$(dirname "$0")" && pwd)" # busybox on OpenWrt has no `install` @@ -95,22 +95,22 @@ install_role() { if [ "$have_user" -eq 1 ]; then chown "$USER_NAME" "$CONFIG"; fi chmod 0750 "$CONFIG" - install_binary "monitor-$role" + install_binary "moshiro-$role" if [ "$role" = agent ]; then install_binary fleet-enroll; fi say "installed binaries to $PREFIX" init="$(init_system)" case "$init" in systemd) - put 0644 "$HERE/systemd/monitor-$role.service" "/etc/systemd/system/monitor-$role.service" - if [ "$have_user" -eq 0 ]; then sed -i '/^User=/d;/^Group=/d' "/etc/systemd/system/monitor-$role.service"; fi + put 0644 "$HERE/systemd/moshiro-$role.service" "/etc/systemd/system/moshiro-$role.service" + if [ "$have_user" -eq 0 ]; then sed -i '/^User=/d;/^Group=/d' "/etc/systemd/system/moshiro-$role.service"; fi systemctl daemon-reload ;; procd) [ "$role" = probe ] || die "the agent is meant for servers; on OpenWrt only the probe is supported" - put 0755 "$HERE/openwrt/monitor-probe.init" /etc/init.d/monitor-probe + put 0755 "$HERE/openwrt/moshiro-probe.init" /etc/init.d/moshiro-probe mkdir -p /lib/upgrade/keep.d - put 0644 "$HERE/openwrt/monitor.keep" /lib/upgrade/keep.d/monitor ;; - *) echo "warning: no systemd or procd found: start $PREFIX/monitor-$role --config $CONFIG/$role.json with your own supervisor" >&2 ;; + put 0644 "$HERE/openwrt/moshiro.keep" /lib/upgrade/keep.d/moshiro ;; + *) echo "warning: no systemd or procd found: start $PREFIX/moshiro-$role --config $CONFIG/$role.json with your own supervisor" >&2 ;; esac ready=0 @@ -136,18 +136,18 @@ install_role() { if [ "$ready" -eq 1 ] && [ "$no_start" -eq 0 ]; then case "$init" in - systemd) systemctl enable --now "monitor-$role" ;; - procd) /etc/init.d/monitor-probe enable; /etc/init.d/monitor-probe restart ;; + systemd) systemctl enable --now "moshiro-$role" ;; + procd) /etc/init.d/moshiro-probe enable; /etc/init.d/moshiro-probe restart ;; esac - say "monitor-$role is installed" + say "moshiro-$role is installed" else say "installed, not started yet. Next:" if [ "$role" = agent ]; then echo " $PREFIX/fleet-enroll --server --join --name --identity-dir $CONFIG (as the '$USER_NAME' user)" - echo " write $CONFIG/agent.json (see README.md), then: systemctl enable --now monitor-agent" + echo " write $CONFIG/agent.json (see README.md), then: systemctl enable --now moshiro-agent" else echo " save the panel's probe identity (POST /api/admin/probe/identity) as $CONFIG/probe.json (mode 0600, owner $USER_NAME)" - echo " then: systemctl enable --now monitor-probe (OpenWrt: /etc/init.d/monitor-probe enable && /etc/init.d/monitor-probe start)" + echo " then: systemctl enable --now moshiro-probe (OpenWrt: /etc/init.d/moshiro-probe enable && /etc/init.d/moshiro-probe start)" fi fi } @@ -157,15 +157,15 @@ uninstall() { if [ "${2:-}" = "--purge" ]; then purge=1; fi case "$(init_system)" in systemd) - systemctl disable --now "monitor-$role" 2>/dev/null || true - rm -f "/etc/systemd/system/monitor-$role.service" + systemctl disable --now "moshiro-$role" 2>/dev/null || true + rm -f "/etc/systemd/system/moshiro-$role.service" systemctl daemon-reload ;; procd) - /etc/init.d/monitor-probe stop 2>/dev/null || true - /etc/init.d/monitor-probe disable 2>/dev/null || true - rm -f /etc/init.d/monitor-probe /lib/upgrade/keep.d/monitor ;; + /etc/init.d/moshiro-probe stop 2>/dev/null || true + /etc/init.d/moshiro-probe disable 2>/dev/null || true + rm -f /etc/init.d/moshiro-probe /lib/upgrade/keep.d/moshiro ;; esac - rm -f "$PREFIX/monitor-$role" + rm -f "$PREFIX/moshiro-$role" if [ "$role" = agent ]; then rm -f "$PREFIX/fleet-enroll"; fi rmdir "$PREFIX" 2>/dev/null || true if [ "$purge" -eq 1 ]; then diff --git a/packaging/openwrt/monitor.keep b/packaging/openwrt/monitor.keep deleted file mode 100644 index 0e84b1b..0000000 --- a/packaging/openwrt/monitor.keep +++ /dev/null @@ -1 +0,0 @@ -/etc/monitor/ diff --git a/packaging/openwrt/monitor-probe.init b/packaging/openwrt/moshiro-probe.init similarity index 65% rename from packaging/openwrt/monitor-probe.init rename to packaging/openwrt/moshiro-probe.init index a1a2351..be5cddf 100644 --- a/packaging/openwrt/monitor-probe.init +++ b/packaging/openwrt/moshiro-probe.init @@ -1,16 +1,16 @@ #!/bin/sh /etc/rc.common -# procd service for monitor-probe (OpenWrt). Installed as /etc/init.d/monitor-probe. +# procd service for moshiro-probe (OpenWrt). Installed as /etc/init.d/moshiro-probe. START=95 STOP=10 USE_PROCD=1 -PROG=/usr/lib/monitor/monitor-probe -CONF=/etc/monitor/probe.json +PROG=/usr/lib/moshiro/moshiro-probe +CONF=/etc/moshiro/probe.json start_service() { [ -f "$CONF" ] || { - logger -t monitor-probe "$CONF not found: download it from the panel (POST /api/admin/probe/identity)" + logger -t moshiro-probe "$CONF not found: download it from the panel (POST /api/admin/probe/identity)" return 1 } procd_open_instance @@ -21,6 +21,6 @@ start_service() { procd_set_param stderr 1 procd_set_param limits nofile=4096 # Run unprivileged when the installer could create the user (busybox adduser may be missing) - id monitor >/dev/null 2>&1 && procd_set_param user monitor + id moshiro >/dev/null 2>&1 && procd_set_param user moshiro procd_close_instance } diff --git a/packaging/openwrt/moshiro.keep b/packaging/openwrt/moshiro.keep new file mode 100644 index 0000000..d5a4993 --- /dev/null +++ b/packaging/openwrt/moshiro.keep @@ -0,0 +1 @@ +/etc/moshiro/ diff --git a/packaging/systemd/monitor-probe-container.service b/packaging/systemd/monitor-probe-container.service deleted file mode 100644 index 015f69b..0000000 --- a/packaging/systemd/monitor-probe-container.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=Monitor Probe (Podman container) -After=network-online.target -Wants=network-online.target - -[Service] -EnvironmentFile=/etc/monitor-update/probe.image -Restart=always -RestartSec=5 -TimeoutStopSec=30 -ExecStartPre=-/usr/bin/podman rm -f monitor-probe -ExecStart=/usr/bin/podman run --rm --name monitor-probe --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v monitor-probe-config:/etc/monitor -v monitor-probe-status:/etc/monitor/update-status:ro ${IMAGE} -ExecStop=/usr/bin/podman stop -t 20 monitor-probe - -[Install] -WantedBy=multi-user.target diff --git a/packaging/systemd/monitor-probe-docker.service b/packaging/systemd/monitor-probe-docker.service deleted file mode 100644 index 9d7b06a..0000000 --- a/packaging/systemd/monitor-probe-docker.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=Monitor Probe (Docker container) -After=network-online.target -Wants=network-online.target - -[Service] -EnvironmentFile=/etc/monitor-update/probe.image -Restart=always -RestartSec=5 -TimeoutStopSec=30 -ExecStartPre=-/usr/bin/docker rm -f monitor-probe -ExecStart=/usr/bin/docker run --rm --name monitor-probe --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v monitor-probe-config:/etc/monitor -v monitor-probe-status:/etc/monitor/update-status:ro ${IMAGE} -ExecStop=/usr/bin/docker stop -t 20 monitor-probe - -[Install] -WantedBy=multi-user.target diff --git a/packaging/systemd/monitor-probe-rootless.service b/packaging/systemd/monitor-probe-rootless.service deleted file mode 100644 index 723fce4..0000000 --- a/packaging/systemd/monitor-probe-rootless.service +++ /dev/null @@ -1,16 +0,0 @@ -[Unit] -Description=Monitor Probe (rootless Podman container) -After=network-online.target -Wants=network-online.target - -[Service] -EnvironmentFile=%h/.config/monitor/probe.image -Restart=always -RestartSec=5 -TimeoutStopSec=30 -ExecStartPre=-/usr/bin/podman rm -f monitor-probe -ExecStart=/usr/bin/podman run --rm --name monitor-probe --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v monitor-probe-config:/etc/monitor -v monitor-probe-status:/etc/monitor/update-status:ro ${IMAGE} -ExecStop=/usr/bin/podman stop -t 20 monitor-probe - -[Install] -WantedBy=default.target diff --git a/packaging/systemd/monitor-agent-docker.service b/packaging/systemd/moshiro-agent-container.service similarity index 57% rename from packaging/systemd/monitor-agent-docker.service rename to packaging/systemd/moshiro-agent-container.service index c24724b..d016713 100644 --- a/packaging/systemd/monitor-agent-docker.service +++ b/packaging/systemd/moshiro-agent-container.service @@ -1,16 +1,16 @@ [Unit] -Description=Monitor Agent (Docker container) +Description=MoShiro Agent (Podman container) After=network-online.target Wants=network-online.target [Service] -EnvironmentFile=/etc/monitor-update/agent.image +EnvironmentFile=/etc/moshiro-update/agent.image Restart=always RestartSec=5 TimeoutStopSec=30 -ExecStartPre=-/usr/bin/docker rm -f monitor-agent -ExecStart=/usr/bin/docker run --rm --name monitor-agent --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v /proc:/host/proc:ro -v /sys:/host/sys:ro -v /:/host/root:ro -e HOST_PROC=/host/proc -e HOST_SYS=/host/sys -e HOST_ROOT=/host/root -v monitor-agent-config:/etc/monitor -v monitor-agent-status:/etc/monitor/update-status:ro ${IMAGE} -ExecStop=/usr/bin/docker stop -t 20 monitor-agent +ExecStartPre=-/usr/bin/podman rm -f moshiro-agent +ExecStart=/usr/bin/podman run --rm --name moshiro-agent --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v /proc:/host/proc:ro -v /sys:/host/sys:ro -v /:/host/root:ro -e HOST_PROC=/host/proc -e HOST_SYS=/host/sys -e HOST_ROOT=/host/root -v moshiro-agent-config:/etc/moshiro -v moshiro-agent-status:/etc/moshiro/update-status:ro ${IMAGE} +ExecStop=/usr/bin/podman stop -t 20 moshiro-agent [Install] WantedBy=multi-user.target diff --git a/packaging/systemd/monitor-agent-container.service b/packaging/systemd/moshiro-agent-docker.service similarity index 57% rename from packaging/systemd/monitor-agent-container.service rename to packaging/systemd/moshiro-agent-docker.service index 5f285e1..657c540 100644 --- a/packaging/systemd/monitor-agent-container.service +++ b/packaging/systemd/moshiro-agent-docker.service @@ -1,16 +1,16 @@ [Unit] -Description=Monitor Agent (Podman container) +Description=MoShiro Agent (Docker container) After=network-online.target Wants=network-online.target [Service] -EnvironmentFile=/etc/monitor-update/agent.image +EnvironmentFile=/etc/moshiro-update/agent.image Restart=always RestartSec=5 TimeoutStopSec=30 -ExecStartPre=-/usr/bin/podman rm -f monitor-agent -ExecStart=/usr/bin/podman run --rm --name monitor-agent --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v /proc:/host/proc:ro -v /sys:/host/sys:ro -v /:/host/root:ro -e HOST_PROC=/host/proc -e HOST_SYS=/host/sys -e HOST_ROOT=/host/root -v monitor-agent-config:/etc/monitor -v monitor-agent-status:/etc/monitor/update-status:ro ${IMAGE} -ExecStop=/usr/bin/podman stop -t 20 monitor-agent +ExecStartPre=-/usr/bin/docker rm -f moshiro-agent +ExecStart=/usr/bin/docker run --rm --name moshiro-agent --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v /proc:/host/proc:ro -v /sys:/host/sys:ro -v /:/host/root:ro -e HOST_PROC=/host/proc -e HOST_SYS=/host/sys -e HOST_ROOT=/host/root -v moshiro-agent-config:/etc/moshiro -v moshiro-agent-status:/etc/moshiro/update-status:ro ${IMAGE} +ExecStop=/usr/bin/docker stop -t 20 moshiro-agent [Install] WantedBy=multi-user.target diff --git a/packaging/systemd/monitor-agent-rootless.service b/packaging/systemd/moshiro-agent-rootless.service similarity index 56% rename from packaging/systemd/monitor-agent-rootless.service rename to packaging/systemd/moshiro-agent-rootless.service index 5278a8d..9a53d9e 100644 --- a/packaging/systemd/monitor-agent-rootless.service +++ b/packaging/systemd/moshiro-agent-rootless.service @@ -1,16 +1,16 @@ [Unit] -Description=Monitor Agent (rootless Podman container) +Description=MoShiro Agent (rootless Podman container) After=network-online.target Wants=network-online.target [Service] -EnvironmentFile=%h/.config/monitor/agent.image +EnvironmentFile=%h/.config/moshiro/agent.image Restart=always RestartSec=5 TimeoutStopSec=30 -ExecStartPre=-/usr/bin/podman rm -f monitor-agent -ExecStart=/usr/bin/podman run --rm --name monitor-agent --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v /proc:/host/proc:ro -v /sys:/host/sys:ro -v /:/host/root:ro -e HOST_PROC=/host/proc -e HOST_SYS=/host/sys -e HOST_ROOT=/host/root -v monitor-agent-config:/etc/monitor -v monitor-agent-status:/etc/monitor/update-status:ro ${IMAGE} -ExecStop=/usr/bin/podman stop -t 20 monitor-agent +ExecStartPre=-/usr/bin/podman rm -f moshiro-agent +ExecStart=/usr/bin/podman run --rm --name moshiro-agent --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v /proc:/host/proc:ro -v /sys:/host/sys:ro -v /:/host/root:ro -e HOST_PROC=/host/proc -e HOST_SYS=/host/sys -e HOST_ROOT=/host/root -v moshiro-agent-config:/etc/moshiro -v moshiro-agent-status:/etc/moshiro/update-status:ro ${IMAGE} +ExecStop=/usr/bin/podman stop -t 20 moshiro-agent [Install] WantedBy=default.target diff --git a/packaging/systemd/monitor-agent.service b/packaging/systemd/moshiro-agent.service similarity index 84% rename from packaging/systemd/monitor-agent.service rename to packaging/systemd/moshiro-agent.service index ebcc774..e6e9ea5 100644 --- a/packaging/systemd/monitor-agent.service +++ b/packaging/systemd/moshiro-agent.service @@ -1,18 +1,18 @@ [Unit] -Description=Monitor agent (network line quality collector) +Description=MoShiro agent (network line quality collector) After=network-online.target Wants=network-online.target [Service] Type=exec -User=monitor -Group=monitor -ExecStart=/usr/lib/monitor/monitor-agent --config /etc/monitor/agent.json +User=moshiro +Group=moshiro +ExecStart=/usr/lib/moshiro/moshiro-agent --config /etc/moshiro/agent.json Restart=always RestartSec=5 # The agent is a pure collector: it reads its config and identity, never writes files, never starts processes. -ReadOnlyPaths=/etc/monitor +ReadOnlyPaths=/etc/moshiro NoNewPrivileges=yes ProtectSystem=strict ProtectHome=yes diff --git a/packaging/systemd/moshiro-probe-container.service b/packaging/systemd/moshiro-probe-container.service new file mode 100644 index 0000000..a0aea4b --- /dev/null +++ b/packaging/systemd/moshiro-probe-container.service @@ -0,0 +1,16 @@ +[Unit] +Description=MoShiro Probe (Podman container) +After=network-online.target +Wants=network-online.target + +[Service] +EnvironmentFile=/etc/moshiro-update/probe.image +Restart=always +RestartSec=5 +TimeoutStopSec=30 +ExecStartPre=-/usr/bin/podman rm -f moshiro-probe +ExecStart=/usr/bin/podman run --rm --name moshiro-probe --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v moshiro-probe-config:/etc/moshiro -v moshiro-probe-status:/etc/moshiro/update-status:ro ${IMAGE} +ExecStop=/usr/bin/podman stop -t 20 moshiro-probe + +[Install] +WantedBy=multi-user.target diff --git a/packaging/systemd/moshiro-probe-docker.service b/packaging/systemd/moshiro-probe-docker.service new file mode 100644 index 0000000..c24d6c1 --- /dev/null +++ b/packaging/systemd/moshiro-probe-docker.service @@ -0,0 +1,16 @@ +[Unit] +Description=MoShiro Probe (Docker container) +After=network-online.target +Wants=network-online.target + +[Service] +EnvironmentFile=/etc/moshiro-update/probe.image +Restart=always +RestartSec=5 +TimeoutStopSec=30 +ExecStartPre=-/usr/bin/docker rm -f moshiro-probe +ExecStart=/usr/bin/docker run --rm --name moshiro-probe --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v moshiro-probe-config:/etc/moshiro -v moshiro-probe-status:/etc/moshiro/update-status:ro ${IMAGE} +ExecStop=/usr/bin/docker stop -t 20 moshiro-probe + +[Install] +WantedBy=multi-user.target diff --git a/packaging/systemd/moshiro-probe-rootless.service b/packaging/systemd/moshiro-probe-rootless.service new file mode 100644 index 0000000..186966e --- /dev/null +++ b/packaging/systemd/moshiro-probe-rootless.service @@ -0,0 +1,16 @@ +[Unit] +Description=MoShiro Probe (rootless Podman container) +After=network-online.target +Wants=network-online.target + +[Service] +EnvironmentFile=%h/.config/moshiro/probe.image +Restart=always +RestartSec=5 +TimeoutStopSec=30 +ExecStartPre=-/usr/bin/podman rm -f moshiro-probe +ExecStart=/usr/bin/podman run --rm --name moshiro-probe --network host --read-only --security-opt no-new-privileges --security-opt label=disable --cap-drop all --tmpfs /tmp:rw,noexec,nosuid,size=64m,mode=1777 -v /etc/os-release:/etc/os-release:ro -v moshiro-probe-config:/etc/moshiro -v moshiro-probe-status:/etc/moshiro/update-status:ro ${IMAGE} +ExecStop=/usr/bin/podman stop -t 20 moshiro-probe + +[Install] +WantedBy=default.target diff --git a/packaging/systemd/monitor-probe.service b/packaging/systemd/moshiro-probe.service similarity index 83% rename from packaging/systemd/monitor-probe.service rename to packaging/systemd/moshiro-probe.service index db90db4..aaf9141 100644 --- a/packaging/systemd/monitor-probe.service +++ b/packaging/systemd/moshiro-probe.service @@ -1,19 +1,19 @@ [Unit] -Description=Monitor probe (network line quality measurement origin) +Description=MoShiro probe (network line quality measurement origin) After=network-online.target Wants=network-online.target [Service] Type=exec -User=monitor -Group=monitor -ExecStart=/usr/lib/monitor/monitor-probe --config /etc/monitor/probe.json +User=moshiro +Group=moshiro +ExecStart=/usr/lib/moshiro/moshiro-probe --config /etc/moshiro/probe.json Restart=always RestartSec=5 # The probe is a pure collector: it never starts processes and writes no measurement data. # The only file the probe writes is agents.json (the latest agent list) next to probe.json. -ReadWritePaths=/etc/monitor +ReadWritePaths=/etc/moshiro NoNewPrivileges=yes ProtectSystem=strict ProtectHome=yes diff --git a/packaging/update/install-updater.sh b/packaging/update/install-updater.sh index 0752b7b..bf74bb9 100644 --- a/packaging/update/install-updater.sh +++ b/packaging/update/install-updater.sh @@ -30,8 +30,8 @@ case "$POLICY" in auto|manual) ;; *) echo "--policy must be auto or manual" >&2; case "$ENGINE" in podman|docker) ;; *) echo "--engine must be podman or docker" >&2; exit 2 ;; esac if [ -n "$DATA_VOLUME" ]; then [ -z "$DATA_DIR" ] || { echo "use --volume or --data-dir, not both" >&2; exit 2; } - [ -n "$HELPER_IMAGE" ] || { echo "--volume needs --helper-image (an already pulled Monitor image)" >&2; exit 2; } - STATUS_VOLUME="${STATUS_VOLUME:-monitor-$COMPONENT-status}" + [ -n "$HELPER_IMAGE" ] || { echo "--volume needs --helper-image (an already pulled MoShiro image)" >&2; exit 2; } + STATUS_VOLUME="${STATUS_VOLUME:-moshiro-$COMPONENT-status}" "$ENGINE" image inspect "$HELPER_IMAGE" >/dev/null "$ENGINE" volume inspect "$DATA_VOLUME" >/dev/null 2>&1 || "$ENGINE" volume create "$DATA_VOLUME" >/dev/null "$ENGINE" volume inspect "$STATUS_VOLUME" >/dev/null 2>&1 || "$ENGINE" volume create "$STATUS_VOLUME" >/dev/null @@ -42,15 +42,15 @@ fi if [ "$SERVICE_SCOPE" = user ]; then [ "$(id -u)" -ne 0 ] || { echo "--user must run as the rootless Podman user, without sudo" >&2; exit 1; } [ "$ENGINE" = podman ] || { echo "--user currently supports rootless Podman; Docker uses system services" >&2; exit 2; } - CONF_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/monitor" - STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/monitor-update" + CONF_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/moshiro" + STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/moshiro-update" UNIT_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user" BIN_DIR="$HOME/.local/bin" TARGET=default.target else [ "$(id -u)" -eq 0 ] || { echo "system installation needs root; use --user for rootless Podman" >&2; exit 1; } - CONF_DIR=/etc/monitor-update - STATE_DIR=/var/lib/monitor-update + CONF_DIR=/etc/moshiro-update + STATE_DIR=/var/lib/moshiro-update UNIT_DIR=/etc/systemd/system BIN_DIR=/usr/local/sbin TARGET=multi-user.target @@ -64,8 +64,8 @@ unit_escape() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; } HERE="$(cd "$(dirname "$0")" && pwd)" install -d -m 755 "$CONF_DIR" "$STATE_DIR" "$UNIT_DIR" "$BIN_DIR" -BIN="$BIN_DIR/monitor-update" -install -m 755 "$HERE/monitor-update.sh" "$BIN" +BIN="$BIN_DIR/moshiro-update" +install -m 755 "$HERE/moshiro-update.sh" "$BIN" install -m 644 "$HERE/release-key.pub.pem" "$CONF_DIR/release-key.pub.pem" if [ -n "$DATA_VOLUME" ]; then : # Named volumes are initialized by the image; no host directory or chown needed. @@ -92,49 +92,49 @@ PUBKEY="$CONF_DIR/release-key.pub.pem" chmod 600 "$CONF_DIR/$COMPONENT.conf" if [ -n "$DATA_VOLUME" ]; then - cat > "$UNIT_DIR/monitor-update-$COMPONENT.service" < "$UNIT_DIR/moshiro-update-$COMPONENT.service" < "$UNIT_DIR/monitor-update-$COMPONENT.timer" < "$UNIT_DIR/moshiro-update-$COMPONENT.timer" < "$UNIT_DIR/monitor-update-$action-$COMPONENT.service" < "$UNIT_DIR/moshiro-update-$action-$COMPONENT.service" < "$UNIT_DIR/monitor-update-$action-$COMPONENT.path" < "$UNIT_DIR/moshiro-update-$action-$COMPONENT.path" </dev/null 2>&1 || true - service_ctl enable --now "monitor-update-$COMPONENT.timer" + service_ctl disable --now "moshiro-update-check-$COMPONENT.path" "moshiro-update-apply-$COMPONENT.path" >/dev/null 2>&1 || true + service_ctl enable --now "moshiro-update-$COMPONENT.timer" else - service_ctl disable --now "monitor-update-$COMPONENT.timer" >/dev/null 2>&1 || true - service_ctl enable --now "monitor-update-check-$COMPONENT.path" "monitor-update-apply-$COMPONENT.path" + service_ctl disable --now "moshiro-update-$COMPONENT.timer" >/dev/null 2>&1 || true + service_ctl enable --now "moshiro-update-check-$COMPONENT.path" "moshiro-update-apply-$COMPONENT.path" fi fi echo "updater installed for $COMPONENT (engine: $ENGINE, scope: $SERVICE_SCOPE, policy: $POLICY)" diff --git a/packaging/update/monitor-update.sh b/packaging/update/moshiro-update.sh similarity index 90% rename from packaging/update/monitor-update.sh rename to packaging/update/moshiro-update.sh index 309038c..6ea503a 100644 --- a/packaging/update/monitor-update.sh +++ b/packaging/update/moshiro-update.sh @@ -1,10 +1,10 @@ #!/bin/sh -# Monitor 容器节点(Agent、Probe)的宿主机更新器。用法:monitor-update <组件> 组件 = agent 或 probe +# MoShiro 容器节点(Agent、Probe)的宿主机更新器。用法:moshiro-update <组件> 组件 = agent 或 probe # # 信任模型(防篡改、防中间人): # - 只接受用发布私钥签名的清单(ECDSA P-256 / SHA-256,对清单文件的原始字节签名);公钥放在本机,面板和 Registry 都改不了它。 # - 清单里写的是镜像的 digest:拉取时用 repo@sha256:…,内容寻址,Registry 或链路上的人换不出另一个镜像。 -# - 镜像仓库、组件、服务名都来自本机的配置(/etc/monitor-update/<组件>.conf),清单里写什么都不会改变拉哪个仓库。 +# - 镜像仓库、组件、服务名都来自本机的配置(/etc/moshiro-update/<组件>.conf),清单里写什么都不会改变拉哪个仓库。 # - 清单的 seq 必须比已安装的大(防止旧清单被重放回滚)。 # - 业务进程(Agent、Probe)只能往数据目录里写「清单」和「请求」文件,更新由这个宿主机脚本完成,业务进程不执行任何命令。 # Shell snippets below execute inside helper containers. @@ -13,27 +13,27 @@ set -eu CMD="${1:-}" COMPONENT="${2:-}" -case "$CMD" in check|apply) ;; *) echo "usage: monitor-update " >&2; exit 2 ;; esac +case "$CMD" in check|apply) ;; *) echo "usage: moshiro-update " >&2; exit 2 ;; esac case "$COMPONENT" in agent|probe) ;; *) echo "component must be agent or probe" >&2; exit 2 ;; esac if [ "$(id -u)" -eq 0 ]; then - DEFAULT_CONF_DIR=/etc/monitor-update + DEFAULT_CONF_DIR=/etc/moshiro-update else - DEFAULT_CONF_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/monitor" + DEFAULT_CONF_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/moshiro" fi -CONF="${MONITOR_UPDATE_CONF_DIR:-$DEFAULT_CONF_DIR}/$COMPONENT.conf" +CONF="${MOSHIRO_UPDATE_CONF_DIR:-$DEFAULT_CONF_DIR}/$COMPONENT.conf" [ -r "$CONF" ] || { echo "missing $CONF" >&2; exit 2; } -# 配置:DATA_DIR(容器里 /etc/monitor 对应的宿主机目录)、IMAGE_REPO、UNIT、PUBKEY、POLICY(auto|manual)、AUTHFILE(可选)、 +# 配置:DATA_DIR(容器里 /etc/moshiro 对应的宿主机目录)、IMAGE_REPO、UNIT、PUBKEY、POLICY(auto|manual)、AUTHFILE(可选)、 # STATE_DIR(已安装版本的记录)、ENV_FILE(容器单元读取的 IMAGE=… 文件) # shellcheck disable=SC1090 . "$CONF" : "${IMAGE_REPO:?}" "${UNIT:?}" "${PUBKEY:?}" "${ENV_FILE:?}" POLICY="${POLICY:-manual}" -STATE_DIR="${STATE_DIR:-/var/lib/monitor-update}" +STATE_DIR="${STATE_DIR:-/var/lib/moshiro-update}" ENGINE="${ENGINE:-podman}" SERVICE_SCOPE="${SERVICE_SCOPE:-system}" DATA_VOLUME="${DATA_VOLUME:-}" -STATUS_VOLUME="${STATUS_VOLUME:-monitor-$COMPONENT-status}" +STATUS_VOLUME="${STATUS_VOLUME:-moshiro-$COMPONENT-status}" case "$ENGINE" in podman|docker) ;; *) echo "unsupported engine: $ENGINE" >&2; exit 2 ;; esac case "$SERVICE_SCOPE" in system|user) ;; *) echo "unsupported service scope: $SERVICE_SCOPE" >&2; exit 2 ;; esac service_ctl() { @@ -84,8 +84,8 @@ fetch_offer() { for name in offer.manifest offer.sig; do if [ -n "$DATA_VOLUME" ]; then "$ENGINE" run --pull=never --rm --network none --read-only --cap-drop ALL --security-opt no-new-privileges \ - -v "$DATA_VOLUME:/etc/monitor:ro" --entrypoint /bin/sh "$HELPER_IMAGE" \ - -c 'f="/etc/monitor/update/$1"; if [ -f "$f" ] && [ ! -L "$f" ]; then head -c 8192 "$f"; fi' sh "$name" > "$WORK/$name" + -v "$DATA_VOLUME:/etc/moshiro:ro" --entrypoint /bin/sh "$HELPER_IMAGE" \ + -c 'f="/etc/moshiro/update/$1"; if [ -f "$f" ] && [ ! -L "$f" ]; then head -c 8192 "$f"; fi' sh "$name" > "$WORK/$name" continue fi f="$UPDATE_DIR/$name" @@ -163,7 +163,7 @@ do_check() { do_apply() { if [ -n "$DATA_VOLUME" ]; then "$ENGINE" run --pull=never --rm --network none --read-only --cap-drop ALL --security-opt no-new-privileges \ - -v "$DATA_VOLUME:/etc/monitor" --entrypoint /bin/sh "$HELPER_IMAGE" -c 'rm -f /etc/monitor/update/apply.request' + -v "$DATA_VOLUME:/etc/moshiro" --entrypoint /bin/sh "$HELPER_IMAGE" -c 'rm -f /etc/moshiro/update/apply.request' else rm -f "$UPDATE_DIR/apply.request" fi @@ -200,8 +200,8 @@ case "$CMD" in check) if [ -n "$DATA_VOLUME" ] && [ "$POLICY" != auto ]; then requested="$($ENGINE run --pull=never --rm --network none --read-only --cap-drop ALL --security-opt no-new-privileges \ - -v "$DATA_VOLUME:/etc/monitor:ro" --entrypoint /bin/sh "$HELPER_IMAGE" \ - -c '[ ! -f /etc/monitor/update/apply.request ] || printf yes')" + -v "$DATA_VOLUME:/etc/moshiro:ro" --entrypoint /bin/sh "$HELPER_IMAGE" \ + -c '[ ! -f /etc/moshiro/update/apply.request ] || printf yes')" if [ "$requested" = yes ]; then do_apply; else do_check; fi else do_check diff --git a/scripts/package.sh b/scripts/package.sh index 8ab721b..d5e39ba 100644 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# 打包:scripts/package.sh → backend/artifacts/packages/monitor---.tar.gz(附 .sha256) +# 打包:scripts/package.sh → backend/artifacts/packages/moshiro---.tar.gz(附 .sha256) # 内容:节点二进制(agent 还带 fleet-enroll)、systemd 单元、OpenWrt procd 脚本、install.sh。 # 发布产物要先用 scripts/publish.sh 生成(agent 需要 agent 和 fleet-enroll 两个)。 set -euo pipefail @@ -7,14 +7,14 @@ role="${1:?usage: package.sh }" rid="${2:?usage: package.sh }" root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" version="$(sed -n 's#.*\(.*\).*#\1#p' "$root/Directory.Build.props" | head -1)" -name="monitor-$role-$version-$rid" +name="moshiro-$role-$version-$rid" stage="$root/backend/artifacts/packages/stage/$name" rm -rf "$stage" mkdir -p "$stage/systemd" -cp "$root/backend/artifacts/publish/$role/$rid/monitor-$role" "$stage/" +cp "$root/backend/artifacts/publish/$role/$rid/moshiro-$role" "$stage/" cp "$root/packaging/install.sh" "$stage/" -cp "$root/packaging/systemd/monitor-$role.service" "$stage/systemd/" +cp "$root/packaging/systemd/moshiro-$role.service" "$stage/systemd/" cp "$root/$role/README.md" "$stage/README.md" if [ "$role" = agent ]; then cp "$root/backend/artifacts/publish/fleet-enroll/$rid/fleet-enroll" "$stage/" diff --git a/scripts/publish.sh b/scripts/publish.sh index 963dc0c..f772815 100644 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -9,18 +9,18 @@ rid="${2:?usage: publish.sh }" root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" case "$project" in - agent) csproj="backend/agent/src/Monitor.Agent" ;; - probe) csproj="backend/probe/src/Monitor.Probe" ;; - backend) csproj="backend/src/Monitor.Backend" ;; + agent) csproj="backend/agent/src/MoShiro.Agent" ;; + probe) csproj="backend/probe/src/MoShiro.Probe" ;; + backend) csproj="backend/src/MoShiro.Backend" ;; fleet-enroll) csproj="backend/fleet/tools/fleet-enroll" ;; *) echo "unknown project: $project" >&2; exit 2 ;; esac # 构建信息(程序里显示的 tag、提交、构建时间):没在 git 仓库里就留空 -export MONITOR_TAG="${MONITOR_TAG:-$(git -C "$root" describe --tags --always --dirty 2>/dev/null || true)}" -export MONITOR_COMMIT="${MONITOR_COMMIT:-$(git -C "$root" rev-parse --short=10 HEAD 2>/dev/null || true)}" -export MONITOR_BUILT_AT="${MONITOR_BUILT_AT:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}" -build_env=(-e MONITOR_TAG -e MONITOR_COMMIT -e MONITOR_BUILT_AT) +export MOSHIRO_TAG="${MOSHIRO_TAG:-$(git -C "$root" describe --tags --always --dirty 2>/dev/null || true)}" +export MOSHIRO_COMMIT="${MOSHIRO_COMMIT:-$(git -C "$root" rev-parse --short=10 HEAD 2>/dev/null || true)}" +export MOSHIRO_BUILT_AT="${MOSHIRO_BUILT_AT:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}" +build_env=(-e MOSHIRO_TAG -e MOSHIRO_COMMIT -e MOSHIRO_BUILT_AT) out="backend/artifacts/publish/$project/$rid" publish_options=() @@ -32,11 +32,11 @@ args=(publish "$csproj" -c Release -r "$rid" -p:PublishAot=true -p:DebugType=non case "$rid" in linux-musl-x64) # SDK 镜像的版本可以比 global.json 新(rollForward = latestFeature) - docker run --rm "${build_env[@]}" -v "$root:/src" -v monitor-nuget:/root/.nuget -v "monitor-artifacts-$rid:/artifacts" -w /src \ + docker run --rm "${build_env[@]}" -v "$root:/src" -v moshiro-nuget:/root/.nuget -v "moshiro-artifacts-$rid:/artifacts" -w /src \ mcr.microsoft.com/dotnet/sdk:10.0-alpine-aot dotnet "${args[@]}" ;; linux-x64) - docker run --rm "${build_env[@]}" -v "$root:/src" -v monitor-nuget:/root/.nuget -v "monitor-artifacts-$rid:/artifacts" -w /src mcr.microsoft.com/dotnet/sdk:10.0-noble-aot dotnet "${args[@]}" + docker run --rm "${build_env[@]}" -v "$root:/src" -v moshiro-nuget:/root/.nuget -v "moshiro-artifacts-$rid:/artifacts" -w /src mcr.microsoft.com/dotnet/sdk:10.0-noble-aot dotnet "${args[@]}" ;; linux-musl-arm64|linux-arm64) echo "$rid needs an arm64 Alpine builder (native or qemu): run this script on an arm64 host or in CI" >&2 diff --git a/scripts/smoke-linux.sh b/scripts/smoke-linux.sh index 0c64f29..d026590 100644 --- a/scripts/smoke-linux.sh +++ b/scripts/smoke-linux.sh @@ -3,7 +3,7 @@ # # RID=linux-musl-x64 IMAGE=alpine:3.22 (默认) # RID=linux-x64 IMAGE=debian:bookworm-slim -# MODE=install 用打包产物里的 install.sh 安装(agent 注册、probe 身份、以 monitor 用户运行),而不是直接运行二进制 +# MODE=install 用打包产物里的 install.sh 安装(agent 注册、probe 身份、以 moshiro 用户运行),而不是直接运行二进制 # # 用法(在仓库根目录;Windows 下先 export MSYS_NO_PATHCONV=1;MODE=install 需要先运行 scripts/package.sh): # docker run --rm -e RID -e MODE -v "$PWD/backend/artifacts:/art:ro" -v "$PWD/scripts/smoke-linux.sh:/smoke.sh:ro" $IMAGE sh /smoke.sh [秒数] @@ -23,9 +23,9 @@ work=/tmp/smoke mkdir -p "$work/data" "$work/probe" base=http://127.0.0.1:18080 -export ASPNETCORE_URLS="$base" Monitor__DataDirectory="$work/data" Monitor__InitialAdminUser=admin \ - Monitor__InitialAdminPassword="correct horse battery" Monitor__SecureCookies=false -(cd "$pub/backend/$rid" && ./monitor-backend >"$work/backend.log" 2>&1 &) +export ASPNETCORE_URLS="$base" MoShiro__DataDirectory="$work/data" MoShiro__InitialAdminUser=admin \ + MoShiro__InitialAdminPassword="correct horse battery" MoShiro__SecureCookies=false +(cd "$pub/backend/$rid" && ./moshiro-backend >"$work/backend.log" 2>&1 &) for i in $(seq 1 60); do curl -fs "$base/healthz" >/dev/null 2>&1 && break; sleep 1; done curl -fs "$base/healthz" >/dev/null || { cat "$work/backend.log"; echo "backend did not start"; exit 1; } echo "backend up" @@ -38,27 +38,27 @@ auth="Authorization: Bearer $token" join=$(curl -fs -X POST "$base/api/admin/join-tokens" -H "$auth" -H 'Content-Type: application/json' -d '{"auto_approve":true,"max_uses":1,"expires_in_hours":1}' | jq -r .plaintext) if [ "$mode" = install ]; then - # 安装到 /usr/lib/monitor 和 /etc/monitor,以 monitor 用户运行(没有 systemd:自己启动) - mkdir -p /tmp/pkg && for role in agent probe; do tar -C /tmp/pkg -xzf /art/packages/monitor-$role-*-$rid.tar.gz; done - (cd /tmp/pkg/monitor-agent-* && ./install.sh agent --server "$base" --join "$join" --name smoke-agent --no-start) - ls -l /usr/lib/monitor /etc/monitor - run_as() { su -s /bin/sh monitor -c "exec $*"; } - run_as /usr/lib/monitor/monitor-agent --config /etc/monitor/agent.json >"$work/agent.log" 2>&1 & + # 安装到 /usr/lib/moshiro 和 /etc/moshiro,以 moshiro 用户运行(没有 systemd:自己启动) + mkdir -p /tmp/pkg && for role in agent probe; do tar -C /tmp/pkg -xzf /art/packages/moshiro-$role-*-$rid.tar.gz; done + (cd /tmp/pkg/moshiro-agent-* && ./install.sh agent --server "$base" --join "$join" --name smoke-agent --no-start) + ls -l /usr/lib/moshiro /etc/moshiro + run_as() { su -s /bin/sh moshiro -c "exec $*"; } + run_as /usr/lib/moshiro/moshiro-agent --config /etc/moshiro/agent.json >"$work/agent.log" 2>&1 & agent_pid=$! sleep 3 curl -fs -X POST "$base/api/admin/probe/identity" -H "$auth" -H 'Content-Type: application/json' -d '{}' >"$work/probe/probe.json" - (cd /tmp/pkg/monitor-probe-* && ./install.sh probe --probe-json "$work/probe/probe.json" --no-start) - run_as /usr/lib/monitor/monitor-probe --config /etc/monitor/probe.json >"$work/probe.log" 2>&1 & + (cd /tmp/pkg/moshiro-probe-* && ./install.sh probe --probe-json "$work/probe/probe.json" --no-start) + run_as /usr/lib/moshiro/moshiro-probe --config /etc/moshiro/probe.json >"$work/probe.log" 2>&1 & probe_pid=$! else mkdir -p "$work/agent-id" "$pub/fleet-enroll/$rid/fleet-enroll" --server "$base" --join "$join" --name smoke-agent --identity-dir "$work/agent-id" printf '{"fleet":{"server":"%s","identity_dir":"%s"},"listen":{"bind":"127.0.0.1"}}' "$base" "$work/agent-id" >"$work/agent.json" - "$pub/agent/$rid/monitor-agent" --config "$work/agent.json" >"$work/agent.log" 2>&1 & + "$pub/agent/$rid/moshiro-agent" --config "$work/agent.json" >"$work/agent.log" 2>&1 & agent_pid=$! sleep 3 curl -fs -X POST "$base/api/admin/probe/identity" -H "$auth" -H 'Content-Type: application/json' -d '{}' >"$work/probe/probe.json" - "$pub/probe/$rid/monitor-probe" --config "$work/probe/probe.json" >"$work/probe.log" 2>&1 & + "$pub/probe/$rid/moshiro-probe" --config "$work/probe/probe.json" >"$work/probe.log" 2>&1 & probe_pid=$! fi diff --git a/scripts/smoke-systemd.sh b/scripts/smoke-systemd.sh index 6954109..65c222a 100644 --- a/scripts/smoke-systemd.sh +++ b/scripts/smoke-systemd.sh @@ -6,7 +6,7 @@ apt-get update >/dev/null && apt-get install -y --no-install-recommends curl jq base=http://127.0.0.1:18080 mkdir -p /tmp/data cd /art/publish/backend/linux-x64 -ASPNETCORE_URLS=$base Monitor__DataDirectory=/tmp/data Monitor__InitialAdminUser=admin Monitor__InitialAdminPassword="correct horse battery" Monitor__SecureCookies=false nohup ./monitor-backend >/tmp/backend.log 2>&1 & +ASPNETCORE_URLS=$base MoShiro__DataDirectory=/tmp/data MoShiro__InitialAdminUser=admin MoShiro__InitialAdminPassword="correct horse battery" MoShiro__SecureCookies=false nohup ./moshiro-backend >/tmp/backend.log 2>&1 & for i in $(seq 1 60); do curl -fs $base/healthz >/dev/null 2>&1 && break; sleep 1; done login=$(curl -si -X POST $base/api/admin/auth/login -H 'Content-Type: application/json' -d '{"username":"admin","password":"correct horse battery"}') cookie=$(echo "$login" | grep -i '^set-cookie' | head -1 | sed 's/^[^:]*: //; s/;.*//' | tr -d '\r') @@ -14,18 +14,18 @@ csrf=$(echo "$login" | tail -1 | jq -r .csrf_token) token=$(curl -fs -X POST $base/api/admin/api-tokens -H "Cookie: $cookie" -H "X-CSRF-Token: $csrf" -H 'Content-Type: application/json' -d '{"name":"t","scope":"admin"}' | jq -r .plaintext) auth="Authorization: Bearer $token" join=$(curl -fs -X POST $base/api/admin/join-tokens -H "$auth" -H 'Content-Type: application/json' -d '{"auto_approve":true,"max_uses":1,"expires_in_hours":1}' | jq -r .plaintext) -mkdir -p /tmp/pkg; for r in agent probe; do tar -C /tmp/pkg -xzf /art/packages/monitor-$r-*-linux-x64.tar.gz; done -(cd /tmp/pkg/monitor-agent-* && ./install.sh agent --server $base --join "$join" --name sysd-agent) +mkdir -p /tmp/pkg; for r in agent probe; do tar -C /tmp/pkg -xzf /art/packages/moshiro-$r-*-linux-x64.tar.gz; done +(cd /tmp/pkg/moshiro-agent-* && ./install.sh agent --server $base --join "$join" --name sysd-agent) sleep 3 curl -fs -X POST $base/api/admin/probe/identity -H "$auth" -H 'Content-Type: application/json' -d '{}' >/tmp/probe.json -(cd /tmp/pkg/monitor-probe-* && ./install.sh probe --probe-json /tmp/probe.json) +(cd /tmp/pkg/moshiro-probe-* && ./install.sh probe --probe-json /tmp/probe.json) sleep 25 -systemctl is-active monitor-agent monitor-probe +systemctl is-active moshiro-agent moshiro-probe echo "agents: $(curl -fs $base/api/admin/agents -H "$auth" | jq -c '[.items[] | {name, status, probe_connected}]')" echo "chunks: $(curl -fs $base/api/admin/raw/chunks -H "$auth" | jq -c '[.items[].kind] | length')" -systemctl show monitor-agent -p MemoryCurrent -p NRestarts | tr '\n' ' '; systemctl show monitor-probe -p MemoryCurrent -p NRestarts | tr '\n' ' '; echo -ps -o user,rss,comm -C monitor-agent,monitor-probe -journalctl -u monitor-agent -u monitor-probe --no-pager | tail -8 -echo "--- sandbox check: agent cannot write /etc/monitor"; nsenter -t $(systemctl show monitor-agent -p MainPID --value) -m sh -c 'touch /etc/monitor/x 2>&1; ls /proc/self/status >/dev/null' 2>&1 | head -2 -grep -E "NoNewPrivs|CapEff|Seccomp:" /proc/$(systemctl show monitor-agent -p MainPID --value)/status -grep -E "NoNewPrivs|CapEff|Seccomp:" /proc/$(systemctl show monitor-probe -p MainPID --value)/status +systemctl show moshiro-agent -p MemoryCurrent -p NRestarts | tr '\n' ' '; systemctl show moshiro-probe -p MemoryCurrent -p NRestarts | tr '\n' ' '; echo +ps -o user,rss,comm -C moshiro-agent,moshiro-probe +journalctl -u moshiro-agent -u moshiro-probe --no-pager | tail -8 +echo "--- sandbox check: agent cannot write /etc/moshiro"; nsenter -t $(systemctl show moshiro-agent -p MainPID --value) -m sh -c 'touch /etc/moshiro/x 2>&1; ls /proc/self/status >/dev/null' 2>&1 | head -2 +grep -E "NoNewPrivs|CapEff|Seccomp:" /proc/$(systemctl show moshiro-agent -p MainPID --value)/status +grep -E "NoNewPrivs|CapEff|Seccomp:" /proc/$(systemctl show moshiro-probe -p MainPID --value)/status diff --git a/scripts/smoke-wsl.py b/scripts/smoke-wsl.py index 10c6d6b..029bb4f 100644 --- a/scripts/smoke-wsl.py +++ b/scripts/smoke-wsl.py @@ -1,8 +1,8 @@ """跨机器的真实链路验证:Windows 上的 Probe(NativeAOT exe)→ WSL2 里的 Agent 和 Backend(真实的虚拟网络、不同的单调时钟原点)。 前提:WSL 里有 Debian(root)、tc(netem 注入丢包/延迟/黑洞用);已经用 scripts/publish.sh 发布了 linux-x64 的 agent、backend、fleet-enroll, -并且 Windows 上发布了 probe(dotnet publish backend/probe/src/Monitor.Probe -c Release -r win-x64 -p:PublishAot=true -o backend/artifacts/aot-probe)。 -把 linux-x64 的产物复制到 WSL 的 /root/mon/,在 WSL 里用 setsid -f nohup 启动 monitor-backend(监听 0.0.0.0:29181),再运行本脚本。 +并且 Windows 上发布了 probe(dotnet publish backend/probe/src/MoShiro.Probe -c Release -r win-x64 -p:PublishAot=true -o backend/artifacts/aot-probe)。 +把 linux-x64 的产物复制到 WSL 的 /root/mon/,在 WSL 里用 setsid -f nohup 启动 moshiro-backend(监听 0.0.0.0:29181),再运行本脚本。 故障注入见 docs/deployment.md 第 3 节。 """ import json, os, subprocess, sys, time, urllib.request, urllib.error @@ -10,8 +10,8 @@ import json, os, subprocess, sys, time, urllib.request, urllib.error # 要连的是本机的虚拟网络(WSL),不能走环境变量里的 HTTP(S)_PROXY OPENER = urllib.request.build_opener(urllib.request.ProxyHandler({})) -ROOT = r"C:\Users\JustMe\Desktop\monitor-proj" -PROBE_EXE = os.path.join(ROOT, "backend", "artifacts", "aot-probe", "monitor-probe.exe") +ROOT = r"C:\Users\JustMe\Desktop\moshiro-proj" +PROBE_EXE = os.path.join(ROOT, "backend", "artifacts", "aot-probe", "moshiro-probe.exe") WORK = r"C:\Users\JustMe\AppData\Local\Temp\realnet" PORT = 29181 @@ -45,18 +45,18 @@ def req(method, path, body=None, headers=None, ctype="application/json"): def main(): os.makedirs(WORK, exist_ok=True) print("wsl ip", WSLIP) - resp, login = req("POST", "/api/admin/auth/login", {"username": "admin", "password": os.environ.get("MONITOR_ADMIN_PASSWORD", "correct horse battery")}) + resp, login = req("POST", "/api/admin/auth/login", {"username": "admin", "password": os.environ.get("MOSHIRO_ADMIN_PASSWORD", "correct horse battery")}) cookie = resp.headers["Set-Cookie"].split(";")[0] _, tok = req("POST", "/api/admin/api-tokens", {"name": "net", "scope": "admin"}, {"Cookie": cookie, "X-CSRF-Token": login["csrf_token"]}) auth = {"Authorization": "Bearer " + tok["plaintext"]} json.dump({"base": BASE, "token": tok["plaintext"], "wslip": WSLIP}, open(WORK + r"\state.json", "w")) _, join = req("POST", "/api/admin/join-tokens", {"auto_approve": True, "max_uses": 1, "expires_in_hours": 1}, auth) - wsl("pkill monitor-agent; cd /root/mon && rm -rf id agent.json") + wsl("pkill moshiro-agent; cd /root/mon && rm -rf id agent.json") print(wsl(f"cd /root/mon && ./fleet-enroll --server http://127.0.0.1:{PORT} --join {join['plaintext']} --name wsl-agent --identity-dir /root/mon/id")) cfg = {"fleet": {"server": f"http://127.0.0.1:{PORT}", "identity_dir": "/root/mon/id"}, "listen": {"bind": "0.0.0.0"}} wsl("cat > /root/mon/agent.json <<'EOF'\n" + json.dumps(cfg) + "\nEOF") - wsl("cd /root/mon && (setsid nohup ./monitor-agent --config /root/mon/agent.json > agent.log 2>&1 < /dev/null &)") + wsl("cd /root/mon && (setsid nohup ./moshiro-agent --config /root/mon/agent.json > agent.log 2>&1 < /dev/null &)") time.sleep(3) _, agents = req("GET", "/api/admin/agents", None, auth) agent = agents["items"][0] diff --git a/scripts/stability_wsl.py b/scripts/stability_wsl.py index cf91d09..69dac5b 100644 --- a/scripts/stability_wsl.py +++ b/scripts/stability_wsl.py @@ -5,7 +5,7 @@ Probe↔Agent 走真实的虚拟网络(eth0),Agent↔Backend 走 WSL 里的回环(故障用 tc 注入在 lo 上)。 前提:WSL 里有 Debian(root)和 tc;已发布 linux-x64 的 agent、backend、fleet-enroll(scripts/publish.sh), -以及 Windows 的 probe(dotnet publish backend/probe/src/Monitor.Probe -c Release -r win-x64 -p:PublishAot=true -o backend/artifacts/aot-probe)。 +以及 Windows 的 probe(dotnet publish backend/probe/src/MoShiro.Probe -c Release -r win-x64 -p:PublishAot=true -o backend/artifacts/aot-probe)。 用法:python scripts/stability_wsl.py [场景名 ...] (不带参数运行全部) 场景:init graceful crash probe_link backend_link silent soak @@ -23,11 +23,11 @@ import urllib.request OPENER = urllib.request.build_opener(urllib.request.ProxyHandler({})) ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) -PROBE_EXE = os.path.join(ROOT, "backend", "artifacts", "aot-probe", "monitor-probe.exe") +PROBE_EXE = os.path.join(ROOT, "backend", "artifacts", "aot-probe", "moshiro-probe.exe") PUB = "/mnt/" + ROOT[0].lower() + ROOT[2:].replace("\\", "/") + "/backend/artifacts/publish" WORK = os.path.join(os.environ.get("TEMP", "."), "stability") PORT = 29181 -ADMIN_PASSWORD = os.environ.get("MONITOR_ADMIN_PASSWORD", "correct horse battery") # 测试用后端的初始管理员密码 +ADMIN_PASSWORD = os.environ.get("MOSHIRO_ADMIN_PASSWORD", "correct horse battery") # 测试用后端的初始管理员密码 RESULTS = [] HIDDEN = subprocess.CREATE_NO_WINDOW # 所有子进程都不弹窗 @@ -109,14 +109,14 @@ def rss_mb(name): def start_backend(): - wsl(f"cd /root/mon && /root/mon/start.sh backend env ASPNETCORE_URLS=http://0.0.0.0:{PORT} Monitor__DataDirectory=/root/mon/data " - f"Monitor__InitialAdminUser=admin 'Monitor__InitialAdminPassword={ADMIN_PASSWORD}' Monitor__SecureCookies=false ./monitor-backend") + wsl(f"cd /root/mon && /root/mon/start.sh backend env ASPNETCORE_URLS=http://0.0.0.0:{PORT} MoShiro__DataDirectory=/root/mon/data " + f"MoShiro__InitialAdminUser=admin 'MoShiro__InitialAdminPassword={ADMIN_PASSWORD}' MoShiro__SecureCookies=false ./moshiro-backend") return wait_until(backend_up, 30) def start_agent(): - wsl("/root/mon/start.sh agent ./monitor-agent --config /root/mon/agent.json") - return wait_until(lambda: bool(pids("monitor-agent")), 10) + wsl("/root/mon/start.sh agent ./moshiro-agent --config /root/mon/agent.json") + return wait_until(lambda: bool(pids("moshiro-agent")), 10) def stop_proc(name, sig="TERM", timeout=30): @@ -124,7 +124,7 @@ def stop_proc(name, sig="TERM", timeout=30): start = now() wsl(f"pkill -{sig} -x {name} || true") gone = wait_until(lambda: not pids(name), timeout, 0.2) - code = wsl(f"cat /root/mon/{name.replace('monitor-', '')}.exit 2>/dev/null || true") + code = wsl(f"cat /root/mon/{name.replace('moshiro-', '')}.exit 2>/dev/null || true") return (now() - start if gone is not None else None), (int(code) if code.strip().lstrip('-').isdigit() else None) @@ -209,9 +209,9 @@ def setup(fresh=True): """Clean state, copy the artifacts, start backend/agent, create the probe identity. The probe is not started.""" global TOKEN, AGENT_ID PROBE.stop("kill") - wsl("pkill -9 -x monitor-agent; pkill -9 -x monitor-backend; tc qdisc del dev eth0 ingress 2>/dev/null; tc qdisc del dev eth0 root 2>/dev/null; tc qdisc del dev lo root 2>/dev/null; tc qdisc del dev lo ingress 2>/dev/null; true") + wsl("pkill -9 -x moshiro-agent; pkill -9 -x moshiro-backend; tc qdisc del dev eth0 ingress 2>/dev/null; tc qdisc del dev eth0 root 2>/dev/null; tc qdisc del dev lo root 2>/dev/null; tc qdisc del dev lo ingress 2>/dev/null; true") if fresh: - wsl(f"rm -rf /root/mon && mkdir -p /root/mon && cp {PUB}/backend/linux-x64/* {PUB}/agent/linux-x64/* {PUB}/fleet-enroll/linux-x64/* /root/mon/ && chmod +x /root/mon/monitor-* /root/mon/fleet-enroll") + wsl(f"rm -rf /root/mon && mkdir -p /root/mon && cp {PUB}/backend/linux-x64/* {PUB}/agent/linux-x64/* {PUB}/fleet-enroll/linux-x64/* /root/mon/ && chmod +x /root/mon/moshiro-* /root/mon/fleet-enroll") wsl("cat > /root/mon/start.sh <<'EOF'\n" + LAUNCHER + "EOF\nchmod +x /root/mon/start.sh") if os.path.isdir(WORK): subprocess.run(["cmd", "/c", "rmdir", "/s", "/q", WORK], capture_output=True, creationflags=HIDDEN) @@ -279,7 +279,7 @@ def healthy(): def ensure_healthy(timeout=60): if not backend_up(): start_backend() - if not pids("monitor-agent"): + if not pids("moshiro-agent"): start_agent() if not PROBE.alive(): PROBE.start() @@ -292,7 +292,7 @@ def scenario_init(): print("== init: cold starts in every order, bad configuration") # 1. everything down, then start in the opposite order: probe -> agent -> backend (each must retry until its peer is up) PROBE.stop("kill") - wsl("pkill -9 -x monitor-agent; pkill -9 -x monitor-backend; true") + wsl("pkill -9 -x moshiro-agent; pkill -9 -x moshiro-backend; true") time.sleep(1) PROBE.start() time.sleep(3) @@ -307,7 +307,7 @@ def scenario_init(): # 2. backend first, then agent, then probe (the normal order) after a full stop PROBE.stop("kill") - wsl("pkill -9 -x monitor-agent; pkill -9 -x monitor-backend; true") + wsl("pkill -9 -x moshiro-agent; pkill -9 -x moshiro-backend; true") start_backend() start_agent() PROBE.start() @@ -322,9 +322,9 @@ def scenario_init(): check("probe: malformed config exits 1 with a readable error", r.returncode == 1 and "startup failed" in r.stderr + r.stdout, (r.stderr + r.stdout).strip()[:120]) r = subprocess.run([PROBE_EXE, "--config", os.path.join(WORK, "missing.json")], capture_output=True, text=True, timeout=20, creationflags=HIDDEN) check("probe: missing config exits 1 with the file name", r.returncode == 1 and "missing.json" in r.stderr + r.stdout, (r.stderr + r.stdout).strip()[:120]) - out = wsl("cd /root/mon && echo '{ not json' > bad.json && ./monitor-agent --config bad.json 2>&1; echo exit=$?", check=False) + out = wsl("cd /root/mon && echo '{ not json' > bad.json && ./moshiro-agent --config bad.json 2>&1; echo exit=$?", check=False) check("agent: malformed config exits 1", "exit=1" in out and "startup failed" in out, out.strip()[-120:]) - out = wsl("cd /root/mon && printf '{\"fleet\":{\"server\":\"http://127.0.0.1:1\",\"identity_dir\":\"/nonexistent\"}}' > noid.json && ./monitor-agent --config noid.json 2>&1; echo exit=$?", check=False) + out = wsl("cd /root/mon && printf '{\"fleet\":{\"server\":\"http://127.0.0.1:1\",\"identity_dir\":\"/nonexistent\"}}' > noid.json && ./moshiro-agent --config noid.json 2>&1; echo exit=$?", check=False) check("agent: no identity says to run fleet-enroll first", "exit=1" in out and "fleet-enroll" in out, out.strip()[-140:]) out = wsl(f"cd /root/mon && ./fleet-enroll --server http://127.0.0.1:{PORT} --join bogus --name x --identity-dir /tmp/enroll-x 2>&1; echo exit=$?", check=False) check("fleet-enroll: a bad join token fails clearly (non-zero exit)", "exit=0" not in out, out.strip()[-140:]) @@ -345,7 +345,7 @@ def scenario_graceful(): check("probe restarts and reconnects", wait_until(healthy, 30) is not None) # agent - secs, code = stop_proc("monitor-agent", "TERM") + secs, code = stop_proc("moshiro-agent", "TERM") log = wsl("tail -5 /root/mon/agent.log") check("agent exits on SIGTERM within 5 s with code 0", secs is not None and secs < 5 and code == 0, f"{secs and round(secs, 2)}s code={code}") check("agent logs a clean stop (no crash trace)", "stopping" in log and "Unhandled" not in log, log.splitlines()[-1][:100] if log else "") @@ -355,7 +355,7 @@ def scenario_graceful(): check("agent restarts, reconnects to backend and probe", wait_until(healthy, 40) is not None) # backend - secs, code = stop_proc("monitor-backend", "TERM", 30) + secs, code = stop_proc("moshiro-backend", "TERM", 30) log = wsl("tail -5 /root/mon/backend.log") check("backend exits on SIGTERM within 15 s with code 0", secs is not None and secs < 15 and code == 0, f"{secs and round(secs, 2)}s code={code}") check("backend log has no unhandled exception", "Unhandled" not in log and "Exception" not in log, log.replace(chr(10), ' | ')[-160:]) @@ -373,7 +373,7 @@ def scenario_crash(): # backend crash: the agent keeps its outbox; after restart nothing acknowledged is lost t = now() - wsl("pkill -9 -x monitor-backend") + wsl("pkill -9 -x moshiro-backend") time.sleep(25) # agent outbox accumulates (2-3 chunk rounds) start_backend() back = wait_until(healthy, 60) @@ -384,7 +384,7 @@ def scenario_crash(): check("backend kill -9: chunks buffered by the agent are delivered after the restart (no gap)", not g, f"gaps in {n} buckets: {g}; chunks {before}->{after}") # agent crash - wsl("pkill -9 -x monitor-agent") + wsl("pkill -9 -x moshiro-agent") time.sleep(5) start_agent() check("agent kill -9: recovers", wait_until(healthy, 40) is not None) @@ -435,7 +435,7 @@ def scenario_probe_link(): print("== probe<->agent link: flapping, long blackhole (half-open), reconnect storms") ensure_healthy() time.sleep(20) - mem0 = (PROBE.working_set_mb(), rss_mb("monitor-agent")) + mem0 = (PROBE.working_set_mb(), rss_mb("moshiro-agent")) # 1. flapping: 3 s blackholes every 10 s, 8 times for _ in range(8): @@ -458,7 +458,7 @@ def scenario_probe_link(): # 3. reconnect storm: kill the agent 12 times in a row for _ in range(12): - wsl("pkill -9 -x monitor-agent; true") + wsl("pkill -9 -x moshiro-agent; true") time.sleep(0.5) start_agent() time.sleep(2) @@ -475,7 +475,7 @@ def scenario_probe_link(): time.sleep(2) check("8 probe restarts in a row: converges", wait_until(healthy, 60) is not None) time.sleep(40) - mem1 = (PROBE.working_set_mb(), rss_mb("monitor-agent")) + mem1 = (PROBE.working_set_mb(), rss_mb("moshiro-agent")) check("memory stays bounded after the storms", mem1[0] < mem0[0] + 15 and mem1[1] < mem0[1] + 15, f"probe {mem0[0]:.1f}->{mem1[0]:.1f} MB, agent {mem0[1]:.1f}->{mem1[1]:.1f} MB") ensure_healthy() @@ -501,7 +501,7 @@ def scenario_backend_link(): check("steady state: ~2 chunks / 10 s (udp + tcp), no duplicates", 4 <= c1 - c0 <= 8, f"{c1 - c0} chunks in 30 s") # the backend is stopped for a while (graceful): the agent keeps collecting, delivers after - stop_proc("monitor-backend", "TERM", 30) + stop_proc("moshiro-backend", "TERM", 30) time.sleep(40) start_backend() check("backend down 40 s then up: everything converges", wait_until(healthy, 90) is not None) @@ -525,16 +525,16 @@ def scenario_silent(): check("... and when the probe thaws it comes back", wait_until(healthy, 90) is not None) # a frozen agent: the probe must drop the session and keep retrying; the backend must mark the agent offline - wsl("pkill -STOP -x monitor-agent") + wsl("pkill -STOP -x moshiro-agent") seen_off = wait_until(lambda: not agent_online(), 150, 1) check("frozen agent: the backend marks it offline", seen_off is not None, f"{seen_off and round(seen_off)}s" if seen_off else "still online after 150 s") - wsl("pkill -CONT -x monitor-agent") + wsl("pkill -CONT -x moshiro-agent") check("... and when the agent thaws everything converges", wait_until(healthy, 90) is not None) # a frozen backend: the agent must notice (WebSocket ping timeout) and reconnect once the backend thaws - wsl("pkill -STOP -x monitor-backend") + wsl("pkill -STOP -x moshiro-backend") time.sleep(70) - wsl("pkill -CONT -x monitor-backend") + wsl("pkill -CONT -x moshiro-backend") check("frozen backend (70 s): converges after it thaws", wait_until(healthy, 90) is not None) time.sleep(30) g, n = gaps(3) @@ -546,7 +546,7 @@ def scenario_soak(): print("== soak: 8 minutes with random faults; memory, convergence and data continuity") ensure_healthy() time.sleep(20) - mem0 = (PROBE.working_set_mb(), rss_mb("monitor-agent"), rss_mb("monitor-backend")) + mem0 = (PROBE.working_set_mb(), rss_mb("moshiro-agent"), rss_mb("moshiro-backend")) import random rnd = random.Random(7) end = now() + 8 * 60 @@ -563,7 +563,7 @@ def scenario_soak(): time.sleep(rnd.uniform(5, 12)) clear_netem("eth0") elif fault == "agent_kill": - wsl("pkill -9 -x monitor-agent; true") + wsl("pkill -9 -x moshiro-agent; true") time.sleep(1) start_agent() elif fault == "probe_kill": @@ -574,7 +574,7 @@ def scenario_soak(): clear_netem("eth0") check(f"after {faults} random faults everything converges", ensure_healthy(90) is not None) time.sleep(45) - mem1 = (PROBE.working_set_mb(), rss_mb("monitor-agent"), rss_mb("monitor-backend")) + mem1 = (PROBE.working_set_mb(), rss_mb("moshiro-agent"), rss_mb("moshiro-backend")) check("memory bounded", mem1[0] < mem0[0] + 15 and mem1[1] < mem0[1] + 20 and mem1[2] < mem0[2] + 40, f"probe {mem0[0]:.0f}->{mem1[0]:.0f}, agent {mem0[1]:.0f}->{mem1[1]:.0f}, backend {mem0[2]:.0f}->{mem1[2]:.0f} MB") m, _ = metrics("30s") check("the final minute is measured correctly", (m.get("loss.up") or 0) < 1 and (m.get("loss.down") or 0) < 1, f"{m.get('loss.up')} {m.get('loss.down')}") @@ -601,7 +601,7 @@ def main(): except Exception as ex: check(f"{name} ran to completion", False, repr(ex)[:300]) PROBE.stop("kill") - wsl("pkill -9 -x monitor-agent; pkill -9 -x monitor-backend; tc qdisc del dev eth0 root 2>/dev/null; tc qdisc del dev eth0 ingress 2>/dev/null; tc qdisc del dev lo ingress 2>/dev/null; true") + wsl("pkill -9 -x moshiro-agent; pkill -9 -x moshiro-backend; tc qdisc del dev eth0 root 2>/dev/null; tc qdisc del dev eth0 ingress 2>/dev/null; tc qdisc del dev lo ingress 2>/dev/null; true") failed = [r for r in RESULTS if not r[1]] print(f"\n{len(RESULTS) - len(failed)}/{len(RESULTS)} checks passed") for name, _, detail in failed: diff --git a/scripts/test-container-updater.py b/scripts/test-container-updater.py index 1af2566..b9f3100 100644 --- a/scripts/test-container-updater.py +++ b/scripts/test-container-updater.py @@ -8,8 +8,8 @@ import shlex import subprocess import tempfile -SCRIPT = Path(__file__).resolve().parents[1] / "packaging/update/monitor-update.sh" -with tempfile.TemporaryDirectory(prefix="monitor-updater-test-") as directory: +SCRIPT = Path(__file__).resolve().parents[1] / "packaging/update/moshiro-update.sh" +with tempfile.TemporaryDirectory(prefix="moshiro-updater-test-") as directory: root = Path(directory) (root / "bin").mkdir() (root / "data/update").mkdir(parents=True) @@ -39,8 +39,8 @@ case "${0##*/}" in esac """) tool.chmod(0o755) - env = dict(os.environ, PATH=str(root / "bin") + os.pathsep + os.environ["PATH"], MONITOR_UPDATE_CONF_DIR=str(root / "conf"), TEST_LOG=str(log), TEST_MODE=str(mode)) - repo = "registry.example/monitor/monitor-agent" + env = dict(os.environ, PATH=str(root / "bin") + os.pathsep + os.environ["PATH"], MOSHIRO_UPDATE_CONF_DIR=str(root / "conf"), TEST_LOG=str(log), TEST_MODE=str(mode)) + repo = "registry.example/moshiro/moshiro-agent" digest = "sha256:" + "a" * 64 image_file = root / "agent.image" state = root / "state" @@ -48,7 +48,7 @@ esac auth.write_text('{"auths":{}}') def configure(engine="podman", scope="system", policy="manual", explicit=True): - values = dict(DATA_DIR=str(root / "data"), IMAGE_REPO=repo, UNIT="monitor-agent.service", PUBKEY=str(pub), ENV_FILE=str(image_file), STATE_DIR=str(state), POLICY=policy, AUTHFILE=str(auth)) + values = dict(DATA_DIR=str(root / "data"), IMAGE_REPO=repo, UNIT="moshiro-agent.service", PUBKEY=str(pub), ENV_FILE=str(image_file), STATE_DIR=str(state), POLICY=policy, AUTHFILE=str(auth)) if explicit: values.update(ENGINE=engine, SERVICE_SCOPE=scope) (root / "conf/agent.conf").write_text("".join(k + "=" + shlex.quote(v) + "\n" for k, v in values.items())) diff --git a/web/README.md b/web/README.md index 815f7c8..448b3c9 100644 --- a/web/README.md +++ b/web/README.md @@ -19,7 +19,7 @@ npm run gen:api # 后端接口变了之后,重新生成 shared/ npm run lint:css # 颜色只能写在 shared/theme/tokens.css,其他样式一律引用令牌 ``` -连别的后端(本机跑前端、连线上的):登录页左边选后端(这个页面自己所在的、保存过的,或者「添加后端」),右边都是用户名和密码;添加后端填地址、用户名、密码,登录成功才保存。跨域用不了 Cookie,所以登录时后端会返回会话令牌(`return_session`),前端存在浏览器里、之后每个请求带上,12 小时过期、退出登录即作废;用户看不到也不需要管它。后端需要放行这个页面的来源(`Monitor__CorsOrigins`)。展示端和管理端侧栏的插头图标是同一个切换器。 +连别的后端(本机跑前端、连线上的):登录页左边选后端(这个页面自己所在的、保存过的,或者「添加后端」),右边都是用户名和密码;添加后端填地址、用户名、密码,登录成功才保存。跨域用不了 Cookie,所以登录时后端会返回会话令牌(`return_session`),前端存在浏览器里、之后每个请求带上,12 小时过期、退出登录即作废;用户看不到也不需要管它。后端需要放行这个页面的来源(`MoShiro__CorsOrigins`)。展示端和管理端侧栏的插头图标是同一个切换器。 约定: - 展示端能拿到的主机数据只有汇总的数字(CPU、内存、磁盘占用,网卡累计流量与瞬时网速,运行时长),**没有 CPU 型号、主机名、网卡名,也没有任何 IP**——后端的公开接口不返回它们,Agent 也根本不采集。展示端不显示 Probe 的版本和来源地址(这些只在管理端)。 diff --git a/web/admin/index.html b/web/admin/index.html index 20cdccb..9f3ab12 100644 --- a/web/admin/index.html +++ b/web/admin/index.html @@ -3,7 +3,7 @@ - MyMonitor · 管理 + MoShiro · 管理
diff --git a/web/admin/package.json b/web/admin/package.json index 006f82d..a5f8ab4 100644 --- a/web/admin/package.json +++ b/web/admin/package.json @@ -1,5 +1,5 @@ { - "name": "monitor-admin", + "name": "moshiro-admin", "private": true, "version": "0.1.0", "type": "module", diff --git a/web/admin/src/App.tsx b/web/admin/src/App.tsx index c930c93..cb61d56 100644 --- a/web/admin/src/App.tsx +++ b/web/admin/src/App.tsx @@ -54,7 +54,7 @@ function Login() {