mbproxy: cross-platform support — Linux/systemd alongside Windows
Make the service build, run, and install on Linux as a first-class target while keeping the Windows Service + Event Log behaviour intact. - Build: drop the hardcoded win-x64 RID — single-file publish now works for any RID. publish.ps1 gains -Rid; new publish.sh for Linux hosts. - Diagnostics: DiagnosticSinkSelector picks the Error+ sink per host — Windows Event Log under the SCM, local syslog under systemd (Serilog.Sinks.SyslogMessages), none for interactive runs. The EventLog truncation helper is extracted so it is testable cross-OS. - Host: Program.cs registers AddSystemd() alongside AddWindowsService(). - Config: a RID-conditioned appsettings template ships Windows or Unix paths; both templates are schema-validated by a test. - Install: systemd unit (Type=exec) plus install.sh / uninstall.sh. Also fixes two cross-platform bugs found while testing: install.ps1 and uninstall.ps1 used New-EventLog / Remove-EventLog (absent in PowerShell 7), and the E2E sim launcher hardcoded Windows venv paths. - Docs updated across README, CLAUDE.md, and docs/ for dual-platform. 413 tests pass on Windows; 374 (all non-simulator) on Linux. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -12,16 +12,19 @@
|
||||
<InformationalVersion>1.0.0</InformationalVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Single-file self-contained publish (Release only; Debug stays normal for fast iteration).
|
||||
The resulting Mbproxy.exe is ~100 MB because the self-contained publish bundles the full
|
||||
.NET 10 + ASP.NET Core runtime — fixed cost of self-contained deployment on .NET 10 with
|
||||
ASP.NET Core. Operators who need a smaller footprint can use a framework-dependent publish
|
||||
(dotnet publish -c Release -r win-x64 -p:SelfContained=false -p:PublishSingleFile=true)
|
||||
if the target machine has .NET 10 installed. -->
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
|
||||
<!-- Single-file publish settings — apply only to a Release publish with an explicit RID.
|
||||
Publishing with -r <rid> produces a single-file binary, self-contained by default
|
||||
(bundles the .NET 10 + ASP.NET Core runtime, ~100 MB) so no .NET install is needed on
|
||||
the target. Override with -p:SelfContained=false for a framework-dependent build
|
||||
(~1.6 MB) when the target already has the .NET 10 + ASP.NET Core runtime.
|
||||
|
||||
The RID is supplied per publish (win-x64, linux-x64, ...) and is deliberately NOT
|
||||
hardcoded here — see install/publish.ps1 / install/publish.sh. The
|
||||
'$(RuntimeIdentifier)' != '' guard means a plain `dotnet build -c Release` with no RID
|
||||
stays an ordinary framework build (SelfContained without a RID is an SDK error). -->
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release' and '$(RuntimeIdentifier)' != ''">
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -32,12 +35,19 @@
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Microsoft.Extensions.Hosting is already included transitively via
|
||||
Microsoft.AspNetCore.App — do not re-add it explicitly. -->
|
||||
Microsoft.AspNetCore.App — do not re-add it explicitly.
|
||||
The two init-system integration packages are both portable: each is
|
||||
safe to reference and call on any OS (the helper self-detects its host
|
||||
and no-ops otherwise), so no conditional reference is needed. -->
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="10.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Systemd" Version="10.0.8" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="10.0.0" />
|
||||
<PackageReference Include="Serilog.Settings.Configuration" Version="10.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.1.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||
<!-- Local-syslog sink for the Linux diagnostic bridge (Error+ events).
|
||||
Serilog.Sinks.SyslogMessages is the maintained IonxSolutions package. -->
|
||||
<PackageReference Include="Serilog.Sinks.SyslogMessages" Version="4.1.0" />
|
||||
<!-- Polly: backend-connect retry pipeline (PolicyFactory.BuildBackendConnect) and
|
||||
listener-recovery pipeline (PolicyFactory.BuildListenerRecovery). -->
|
||||
<PackageReference Include="Polly" Version="8.6.6" />
|
||||
@@ -48,17 +58,29 @@
|
||||
<InternalsVisibleTo Include="Mbproxy.Tests" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Link the platform-appropriate install template as the published appsettings.json so
|
||||
the binary ships with a fully-commented, usable example config (PLCs, BCD tags, all
|
||||
sections present) instead of an empty stub. The .NET configuration loader supports
|
||||
JSONC (comments) under the default Host.CreateApplicationBuilder path, so the comments
|
||||
in the template are valid at runtime.
|
||||
|
||||
The two templates differ only in OS-specific paths (log directory) and platform
|
||||
notes. A `dotnet publish -r linux-*` (or any non-win RID) ships the Linux template;
|
||||
win-* and a plain RID-less dev build ship the Windows one. -->
|
||||
<ItemGroup>
|
||||
<!-- Link the install template as the published appsettings.json so the binary ships
|
||||
with a fully-commented, usable example config (one PLC, one BCD tag, all sections
|
||||
present) instead of an empty stub. The .NET configuration loader supports JSONC
|
||||
(comments) under the default Host.CreateApplicationBuilder path, so the comments
|
||||
in the template are valid at runtime. -->
|
||||
<None Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(RuntimeIdentifier)' == '' or $(RuntimeIdentifier.StartsWith('win'))">
|
||||
<Content Include="..\..\install\mbproxy.config.template.json"
|
||||
Link="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(RuntimeIdentifier)' != '' and !$(RuntimeIdentifier.StartsWith('win'))">
|
||||
<Content Include="..\..\install\mbproxy.linux.config.template.json"
|
||||
Link="appsettings.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user