Skip to content

Conversation

@HowardvanRooijen
Copy link
Contributor

No description provided.

Added a `.gitattributes` file to standardize line endings and
file type handling across the repository. Enabled automatic
detection of text files with LF normalization by default.
Explicitly defined line ending rules for specific file types
(e.g., LF for `.sh`, `.gitignore`, CRLF for `.sln`, `.bat`).
Marked binary files (e.g., `.png`, `.dll`) to prevent modification.
Updated all projects to target .NET 10.0, including upgrading NuGet dependencies and Docker images. Refactored code to use modern C# features like expression-bodied members. Overhauled `.editorconfig` to enforce C# 12 coding standards. Replaced the old `.sln` file with a new `.slnx` format for better organization.

Enhanced `.gitignore` to include additional build artifacts and development environment-specific files. Updated GitHub Actions workflow to use .NET SDK 10.0 and improved Docker build steps for ARM-based images. Cleaned up and modernized code across multiple files for better readability and maintainability.
Refactored `ReceiverHostExtensions` to use a `switch` statement for window count handling, improving readability. Updated variable unpacking for clarity.

Enhanced `NmeaToAisMessageTypeProcessor` with a new `Subject` for parse errors, improving error observability. Fixed a bug where `VendorIdRev3` was used instead of `VendorIdRev4`. Added a `default` case for unknown Message Type 24 parts.

Updated `INmeaStreamReader` to use `ValueTask` for `ReadLineAsync` and removed the `DataAvailable` property. Simplified connection state checks.

Added `IdleTimeout` support to `NetworkStreamNmeaReceiver` for idle stream reconnection. Implemented `IAsyncDisposable` for proper resource cleanup. Improved retry logic with linear backoff.

Optimized `TcpClientNmeaStreamReader` with a larger buffer size and disabled Nagle's algorithm for better performance. Ensured consistent resource cleanup with `DisposeAsync`.

Simplified `ReceiverHost`'s `GetAsync` method with a ternary operator. Updated namespaces for consistency. Improved exception handling and resource management across the codebase.
Updated the `AisConfig` class to make the `Host` property required by using the `required` keyword and removed the `#nullable disable annotations` directive to enable nullable reference type checks.

Refined the `OnCompleted` method in `NmeaToAisMessageTypeProcessor` to properly complete the `messages` and `parseErrors` observables, replacing the previous `NotImplementedException` with a functional implementation.
Refactored NMEA data handling to use `ReadOnlyMemory<byte>` for improved memory efficiency and processing. Replaced `StreamReader` with `PipeReader` for better stream handling. Updated `PersistAsync` in `AzureAppendBlobStorageClient` for clarity and efficiency. Added graceful cancellation handling in `Program.cs` and ensured proper completion propagation in dataflow blocks. Marked critical configuration properties as `required` in `StorageConfig`. Introduced new extension methods for NMEA block tag handling. Improved error handling and resource cleanup across the codebase.
Improved the systemd service configuration to enhance robustness, maintainability, and alignment with best practices:

- Updated `Description` to "AIS.NET Receiver Service".
- Changed `After` to `network-online.target` and added `Wants=network-online.target`.
- Changed `Type` to `simple` and added `User=pi` and `WorkingDirectory=/home/pi/aisr`.
- Simplified `ExecStart` command and updated `Restart` policy to `always`.
- Added `SyslogIdentifier=aisr` and environment variables to suppress .NET telemetry and logo output.
- Adjusted formatting in the `[Install]` section for consistency.
Introduced OpenTelemetry for tracing and metrics in both the console and worker applications. Added `otel-collector` service in `docker-compose.yml` and its configuration in `otel-collector-config.yaml`. Updated `aisr.service` to support OpenTelemetry environment variables.

Refactored `Program.cs` to use `HostApplicationBuilder` for dependency injection and configuration. Added `ReceiverTelemetry` class for capturing metrics and enhanced `ReceiverHost` with OpenTelemetry `ActivitySource` for tracing.

Created a new worker service (`Ais.Net.Receiver.Host.Worker`) with OpenTelemetry integration and Docker support. Added `settings.json` updates for logging, retry, and storage configurations. Updated project files and dependencies to include OpenTelemetry and Microsoft.Extensions.Hosting.

Added `Directory.Build.props` and `Directory.Build.targets` for consistent build output paths. Performed general code cleanup, including namespace alignment and copyright updates.
- Removed unused `using` directives in `Program.cs` and `Worker.cs`.
- Reformatted `Subscribe` lambdas for better readability.
- Added `logger.IsEnabled` checks in `Worker.cs` to optimize logging.
- Refactored `OnError` in `NmeaToAisMessageTypeProcessor.cs` for conciseness.
- Clarified exception message in `NmeaToAisMessageTypeProcessor.cs`.
- Added `GC.SuppressFinalize` in `ReceiverTelemetry.cs` for better disposal.
Add metadata parsing and emission to ReceiverHost

Introduced the ability to parse and emit metadata (station ID and Unix timestamp) alongside AIS messages in the `ReceiverHost` class.

- Added `ParseNmeaBlockTags` method in `NmeaMessageExtensions.cs` to extract station ID and timestamp from NMEA block tags.
- Created a `Metadata` record in `Metadata.cs` to encapsulate metadata.
- Added a `metadata` subject and exposed it as an observable in `ReceiverHost.cs`.
- Updated `StartAsyncInternal` to process and emit metadata.
- Modified message processing logic to handle metadata observers.
- Ensured proper completion of the `metadata` subject.
- Added copyright header to `Metadata.cs`.

These changes enhance the extensibility and functionality of the AIS message processing pipeline.
Copilot AI review requested due to automatic review settings November 22, 2025 20:12
@github-actions
Copy link

github-actions bot commented Nov 22, 2025

Test Results

0 tests  ±0   0 ✅ ±0   0s ⏱️ ±0s
0 suites ±0   0 💤 ±0 
0 files   ±0   0 ❌ ±0 

Results for commit b2c51ba. ± Comparison against base commit e89346b.

♻️ This comment has been updated with latest results.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request upgrades the project from .NET 8 to .NET 10 and implements several significant performance and observability improvements for the AIS (Automatic Identification System) receiver application.

Key Changes:

  • Upgrade to .NET 10 with updated package dependencies
  • Replace string-based NMEA message processing with ReadOnlyMemory<byte> for better performance
  • Migrate from StreamReader to System.IO.Pipelines.PipeReader for efficient stream processing
  • Add OpenTelemetry instrumentation with metrics and distributed tracing support
  • Implement linear retry strategy and idle timeout handling for network connections

Reviewed changes

Copilot reviewed 38 out of 39 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Directory.Build.props/targets Centralized build configuration for artifact output paths
TcpClientNmeaStreamReader.cs Migrated to PipeReader with byte-based line reading and connection management improvements
ReceiverHost.cs Added ActivitySource tracing, metadata stream, and changed to Linear retry strategy
ReceiverTelemetry.cs New telemetry class using System.Diagnostics.Metrics for observability
NetworkStreamNmeaReceiver.cs Added idle timeout detection and improved connection lifecycle management
NmeaMessageExtensions.cs CRITICAL BUG: Invalid extension keyword syntax; added byte-based tag parsing
NmeaToAisMessageTypeProcessor.cs BUG: VendorIdRev4 incorrectly populated with VendorIdRev3 data; added error stream
FileStreamNmeaReceiver.cs Updated to return byte arrays instead of strings
AzureAppendBlobStorageClient.cs Improved blob client initialization logic to avoid redundant operations
Configuration classes Migrated from nullable disable to required keyword for better type safety
Project files Updated to target net10.0 with latest package versions
Docker/deployment configs Updated to use .NET 10 runtime/SDK and added OpenTelemetry collector setup
.editorconfig Modernized with comprehensive C# 12 coding standards

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Modified the `RunningCount` method in `ReceiverHostExtensions`
to include an initial value in the observable sequence.
Added the `StartWith(0L)` operator to ensure the sequence
starts with `0L` before processing any events. This change
provides an explicit initial count, improving usability for
consumers expecting a starting value.
Introduced a new benchmarking project `Ais.Net.Receiver.Benchmarks` to evaluate the performance of NMEA parsing methods.

- Added `Ais.Net.Receiver.Benchmarks.csproj` targeting `.NET 10.0` with references to `Ais.Net.Models` and `BenchmarkDotNet`.
- Implemented `NmeaParserBenchmarks` to benchmark parsing, tag-checking, and tag-prepending methods.
- Added `Program.cs` as the entry point for running benchmarks.
- Created `TestDataProvider` to supply NMEA sentences with and without tags for benchmarking.

This setup enables performance analysis and optimization of NMEA parsing functionality.
Introduced a new test project targeting .NET 10.0 with MSTest, including tools like Shouldly, NSubstitute, and coverlet for assertions, mocking, and code coverage. Enabled parallel test execution.

Added unit tests for:
- FileStreamNmeaReceiver: File reading and delay handling.
- NetworkStreamNmeaReceiver: Connection, reading, and retry logic.
- NmeaMessageExtensions: NMEA block tag validation and parsing.
- NmeaToAisMessageTypeProcessor: AIS message type decoding.
- ReceiverHostExtensions: Stream statistics and message combination.
- ReceiverHost: Message publishing and error handling.
- ReceiverTelemetry: Metrics recording for sentences and messages.
- TcpClientNmeaStreamReader: TCP connection and stream reading.

These tests ensure correctness, error handling, and performance metrics across the project.
Added "AIVDM" to the user dictionary in `Ais.Net.Receiver.sln.DotSettings` to recognize it as a valid word.
Included a reference to the new `Ais.Net.Receiver.Tests` project in the solution file `Ais.Net.Receiver.slnx`.
Updated `packages.lock.json` to include `Spectre.IO` as a transitive dependency and added it to `ais.net.receiver` project dependencies. Upgraded several testing-related NuGet packages in `Ais.Net.Receiver.Tests.csproj`, including `MSTest`, `Shouldly`, `NSubstitute`, and others. Added `Spectre.IO.Testing` for improved test support.

Refactored `FileStreamNmeaReceiverTests` to use `Spectre.IO`'s `FilePath` abstraction, updated test methods for better cancellation handling, and modernized the `Setup` method. Introduced a `TestContext` property for enhanced test configuration.

Refactored `FileStreamNmeaReceiver` to replace `string` paths with `FilePath` for better file path handling. Simplified constructors and improved `GetAsync` method with `[EnumeratorCancellation]` for cancellation token support.
Replaced Endjin.RecommendedPractices.Build with ZeroFailed for
managing the build process. Updated `build-config.ps1` and
`build.ps1` to use ZeroFailed tasks and extensions.

Key changes:
- Added ZeroFailed extensions and updated module imports.
- Introduced new build process control options.
- Switched to `Install-PSResource` for dependency management.
- Enhanced error handling with clearer failure summaries.
- Removed deprecated Endjin references and unused tasks.
- Updated documentation to reflect the migration.
- Changed default build configuration to `Debug`.
Added `builder.Configuration.AddEnvironmentVariables()` to enable
reading configuration values from environment variables alongside
existing JSON files. Updated OpenTelemetry configuration to set
service and meter names to `"Ais.Net.Receiver.Console"` and
`"Ais.Net.Receiver"` in respective instances. These changes improve
configurability and enhance observability with refined metrics
collection.
Updated the project to use MSBuild's test infrastructure by:
- Disabling the MSTest runner (`<EnableMSTestRunner>` set to `false`).
- Adding `<UseMSBuildTestInfrastructure>` property.
- Removing the `Microsoft.NET.Test.Sdk` package reference.
- Adding a `<Using>` directive for MSTest framework.
- Introducing a `DebugProps` target for build diagnostics.

The `<ProjectReference>` to `Ais.Net.Receiver.csproj` remains unchanged.
Removed custom intermediate and output paths from `Directory.Build.props` to rely on default MSBuild behavior. Also removed explicit exclusions for `obj\**` and `bin\**` files in `Directory.Build.targets`, simplifying the build process and reducing redundancy.
The `docker-compose.dcproj` project was commented out in the
`Ais.Net.Receiver.slnx` file to disable its inclusion in the
solution without permanently removing it.

The `Directory.Build.props` and `Directory.Build.targets` files
were completely removed, as they are no longer needed.
Updated the runtime base image to `10.0-noble-chiseled` and the build base image to `10.0-noble` for improved performance, security, and compatibility. Added `USER $APP_UID` to enhance container security by avoiding root user. Introduced `ARG BUILD_CONFIGURATION=Release` for configurable build settings.

Adjusted `COPY` directives to reflect changes in project structure, supporting both `Ais.Net.Receiver.Host.Console` and `Ais.Net.Receiver.Host.Worker` entry points while retaining shared dependencies.
Updated the file header comment to reflect the correct file name. Replaced `EnsureClientInitializedAsync` with `EnsureCurrentHourBlobInitializedAsync` in `PersistAsync` to focus on initializing blobs specific to the current hour. Renamed and updated the private method to construct `newBlobPath` based on the current timestamp, ensuring hour-specific blob handling.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 68 out of 69 changed files in this pull request and generated 18 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

Copilot AI commented Nov 29, 2025

@HowardvanRooijen I've opened a new pull request, #268, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link

Copilot AI commented Nov 29, 2025

@HowardvanRooijen I've opened a new pull request, #269, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link

Copilot AI commented Nov 29, 2025

@HowardvanRooijen I've opened a new pull request, #270, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link

Copilot AI commented Nov 29, 2025

@HowardvanRooijen I've opened a new pull request, #271, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link

Copilot AI commented Nov 29, 2025

@HowardvanRooijen I've opened a new pull request, #272, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 14 commits November 29, 2025 10:50
…lly block disposal (#272)

* Initial plan

* Refactor batchTimer to use CompositeDisposable instead of manual finally block disposal

Co-authored-by: HowardvanRooijen <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: HowardvanRooijen <[email protected]>
…iverTests (#271)

* Initial plan

* Add explanatory comment to empty catch block in NetworkStreamNmeaReceiverTests

Co-authored-by: HowardvanRooijen <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: HowardvanRooijen <[email protected]>
…st (#270)

* Initial plan

* Fix TcpListener disposal in ReadLineAsync_AfterDispose_ReturnsNull test

Co-authored-by: HowardvanRooijen <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: HowardvanRooijen <[email protected]>
* Initial plan

* Fix TcpListener disposal in TcpClientNmeaStreamReaderTests

Co-authored-by: HowardvanRooijen <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: HowardvanRooijen <[email protected]>
Co-authored-by: Howard van Rooijen <[email protected]>
* Initial plan

* Fix TcpListener disposal in TcpClientNmeaStreamReaderTests

Co-authored-by: HowardvanRooijen <[email protected]>

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: HowardvanRooijen <[email protected]>
Co-authored-by: Howard van Rooijen <[email protected]>
…faults

- Created Ais.Net.Receiver.ServiceDefaults project with necessary dependencies for OpenTelemetry and service discovery.
- Updated Ais.Net.Receiver.AppHost and Ais.Net.Receiver.Host.Console projects to reference the new ServiceDefaults project.
- Refactored Program.cs files in both console and worker projects to utilize the new AddServiceDefaults extension method.
- Removed OpenTelemetry configuration from Program.cs in console and worker projects, delegating it to the new extension methods.
- Updated solution file to include the new ServiceDefaults project.
Introduced a comprehensive telemetry and observability framework:
- Added `ApplicationMetrics` and `ApplicationInstrumentation` for centralized metrics and tracing.
- Integrated OpenTelemetry for distributed tracing and metrics collection.
- Added health checks for AIS connection and Azure Blob storage.
- Enhanced logging with source-generated methods for structured logging.
- Updated `ReceiverHost` and `Worker` to use new metrics and tracing.
- Improved error handling with OpenTelemetry semantic conventions.
- Added `ActivityExtensions` for enriching tracing activities with AIS-specific context.
- Refactored and removed `ReceiverTelemetry` in favor of new metrics classes.
- Updated dependencies to include OpenTelemetry and health check libraries.
- Added tests for `ApplicationMetrics` and removed obsolete telemetry tests.
Enhanced logging across health checks and receivers:
- Updated `appsettings.json` to refine log level configurations.
- Added `ILogger` support to `StorageHealthCheck`, `AisConnectionHealthCheck`, `NetworkStreamNmeaReceiver`, and `TcpClientNmeaStreamReader`.
- Introduced detailed logging for health check states (healthy, degraded, unhealthy) and connection events (connect, disconnect, retry, errors).
- Implemented source-generated logging methods in `Log.cs` for structured and consistent logging across components.
@github-actions
Copy link

Code Coverage Summary Report - Linux (No TFM)

Summary
Generated on: 11/29/2025 - 22:14:03
Parser: Cobertura
Assemblies: 1
Classes: 22
Files: 20
Line coverage: 70.5% (651 of 923)
Covered lines: 651
Uncovered lines: 272
Coverable lines: 923
Total lines: 2091
Branch coverage: 57.7% (186 of 322)
Covered branches: 186
Total branches: 322
Method coverage: Feature is only available for sponsors

Coverage

Ais.Net.Receiver - 70.5%
Name Line Branch
Ais.Net.Receiver 70.5% 57.7%
Ais.Net.Receiver.Configuration.AisConfig 75%
Ais.Net.Receiver.Configuration.AisConnectionConfig 75%
Ais.Net.Receiver.Configuration.AisReceiverConfig 50%
Ais.Net.Receiver.Configuration.AisRetryConfig 66.6%
Ais.Net.Receiver.Configuration.AisTelemetryConfig 75%
Ais.Net.Receiver.Health.AisConnectionHealthCheck 0% 0%
Ais.Net.Receiver.Health.AisConnectionMonitor 0% 0%
Ais.Net.Receiver.Health.ConnectionStatus 0%
Ais.Net.Receiver.Health.Log 0% 0%
Ais.Net.Receiver.Parser.NmeaMessageExtensions 94.4% 96.1%
Ais.Net.Receiver.Parser.NmeaToAisMessageTypeProcessor 98.8% 90%
Ais.Net.Receiver.Receiver.FileStreamNmeaReceiver 96.8% 83.3%
Ais.Net.Receiver.Receiver.Metadata 100%
Ais.Net.Receiver.Receiver.NetworkStreamNmeaReceiver 94% 76.9%
Ais.Net.Receiver.Receiver.ReceiverHost 93% 64.7%
Ais.Net.Receiver.Receiver.ReceiverHostExtensions 97.5% 92.8%
Ais.Net.Receiver.Receiver.ReceiverHostExtensions 97.5% 92.8%
Ais.Net.Receiver.Receiver.TcpClientNmeaStreamReader 100% 91.1%
Ais.Net.Receiver.Telemetry.ActivityExtensions 0% 0%
Ais.Net.Receiver.Telemetry.ApplicationInstrumentation 0% 0%
Ais.Net.Receiver.Telemetry.ApplicationMetrics 96.7%
Ais.Net.Receiver.Telemetry.Log 16% 20%

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants