From f559b21fcfc565b79f6b15cd7538d7c2f7a25e98 Mon Sep 17 00:00:00 2001 From: Howard van Rooijen Date: Wed, 9 Oct 2024 07:39:02 +0100 Subject: [PATCH] Remove Ais.Net.Models and Upgrade to .NET 8.0 (#231) * Update scripted build. Migrate to GHA. * Remove Ais.Net.Models projects * Upgrade to .NET 8.0. * Tweak Readme * Change code style. * Don't run tests --- .github/config/pr-autoflow.json | 4 +- .github/dependabot.yml | 15 - .github/workflows/build.yml | 59 + .gitignore | 1 + README.md | 143 +- .../Ais.Net.Models.Specs.csproj | 48 - .../Features/AisMessageType18.feature | 1 - .../Features/AisMessageType18.feature.cs | 78 - .../Ais.Net.Models.Specs/packages.lock.json | 1471 ----------------- .../Ais.Net.Models/Ais.Net.Models.csproj | 31 - .../Net/Models/Abstractions/IAisIsAssigned.cs | 11 - .../Models/Abstractions/IAisIsDteNotReady.cs | 11 - .../Net/Models/Abstractions/IAisMessage.cs | 10 - .../Models/Abstractions/IAisMessageType.cs | 11 - .../Models/Abstractions/IAisMessageType18.cs | 25 - .../Models/Abstractions/IAisMessageType19.cs | 17 - .../Abstractions/IAisMessageType1to3.cs | 23 - .../Abstractions/IAisMessageType24Part0.cs | 11 - .../Abstractions/IAisMessageType24Part1.cs | 21 - .../Models/Abstractions/IAisMessageType5.cs | 27 - .../Abstractions/IAisMultipartMessage.cs | 11 - .../Abstractions/IAisPositionFixType.cs | 11 - .../Ais/Net/Models/Abstractions/ICallSign.cs | 11 - .../Ais/Net/Models/Abstractions/IRaimFlag.cs | 11 - .../Models/Abstractions/IRepeatIndicator.cs | 11 - .../Ais/Net/Models/Abstractions/IShipType.cs | 11 - .../Models/Abstractions/IVesselDimensions.cs | 17 - .../Models/Abstractions/IVesselIdentity.cs | 11 - .../Net/Models/Abstractions/IVesselName.cs | 11 - .../Models/Abstractions/IVesselNavigation.cs | 21 - .../Ais/Net/Models/Abstractions/Position.cs | 12 - .../Models/Abstractions/ShipTypeCategory.cs | 20 - .../Net/Models/Abstractions/ShipTypeGroup.cs | 59 - .../Ais/Net/Models/AisMessageBase.cs | 10 - .../Ais/Net/Models/AisMessageExtensions.cs | 246 --- .../Ais/Net/Models/AisMessageType18.cs | 34 - .../Ais/Net/Models/AisMessageType19.cs | 41 - .../Ais/Net/Models/AisMessageType1Through3.cs | 32 - .../Ais/Net/Models/AisMessageType24Part0.cs | 18 - .../Ais/Net/Models/AisMessageType24Part1.cs | 32 - .../Ais/Net/Models/AisMessageType5.cs | 39 - .../aisr.service | 4 + .../Ais.Net.Receiver.Host.Console.csproj | 19 +- .../Ais/Net/Receiver/Host/Console/Program.cs | 183 +- .../Host/Console/ReceiverHostExtensions.cs | 118 +- .../packages.lock.json | 579 ++++--- ...Ais.Net.Receiver.Storage.Azure.Blob.csproj | 6 +- .../Blob/AzureAppendBlobStorageClient.cs | 101 +- .../Azure/Blob/Configuration/StorageConfig.cs | 15 +- Solutions/Ais.Net.Receiver.sln | 99 +- .../Ais.Net.Receiver/Ais.Net.Receiver.csproj | 11 +- .../Net/Receiver/Configuration/AisConfig.cs | 23 +- .../Receiver/Configuration/LoggerVerbosity.cs | 3 - .../Receiver/Parser/NmeaMessageExtensions.cs | 37 +- .../Parser/NmeaToAisMessageTypeProcessor.cs | 466 +++--- .../Receiver/FileStreamNmeaReceiver.cs | 71 +- .../Net/Receiver/Receiver/INmeaReceiver.cs | 15 +- .../Receiver/NetworkStreamNmeaReceiver.cs | 145 +- .../Ais/Net/Receiver/Receiver/ReceiverHost.cs | 151 +- .../Net/Receiver/Storage/IStorageClient.cs | 15 +- azure-pipelines.release.yml | 15 - azure-pipelines.yml | 24 - build.ps1 | 88 +- 63 files changed, 1147 insertions(+), 3728 deletions(-) delete mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/build.yml delete mode 100644 Solutions/Ais.Net.Models.Specs/Ais.Net.Models.Specs.csproj delete mode 100644 Solutions/Ais.Net.Models.Specs/Features/AisMessageType18.feature delete mode 100644 Solutions/Ais.Net.Models.Specs/Features/AisMessageType18.feature.cs delete mode 100644 Solutions/Ais.Net.Models.Specs/packages.lock.json delete mode 100644 Solutions/Ais.Net.Models/Ais.Net.Models.csproj delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisIsAssigned.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisIsDteNotReady.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessage.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType18.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType19.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType1to3.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType24Part0.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType24Part1.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType5.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMultipartMessage.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisPositionFixType.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ICallSign.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IRaimFlag.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IRepeatIndicator.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IShipType.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselDimensions.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselIdentity.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselName.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselNavigation.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/Position.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ShipTypeCategory.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ShipTypeGroup.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageBase.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageExtensions.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType18.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType19.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType1Through3.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part0.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part1.cs delete mode 100644 Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType5.cs delete mode 100644 azure-pipelines.release.yml delete mode 100644 azure-pipelines.yml diff --git a/.github/config/pr-autoflow.json b/.github/config/pr-autoflow.json index 419c72e..4a5e46e 100644 --- a/.github/config/pr-autoflow.json +++ b/.github/config/pr-autoflow.json @@ -1,4 +1,4 @@ { "AUTO_MERGE_PACKAGE_WILDCARD_EXPRESSIONS": "[\"Endjin.*\",\"Corvus.*\"]", - "AUTO_RELEASE_PACKAGE_WILDCARD_EXPRESSIONS": "[\"Corvus.AzureFunctionsKeepAlive\",\"Corvus.Configuration\",\"Corvus.ContentHandling\",\"Corvus.Deployment\",\"Corvus.DotLiquidAsync\",\"Corvus.EventStore\",\"Corvus.Extensions\",\"Corvus.Extensions.CosmosDb\",\"Corvus.Extensions.Newtonsoft.Json\",\"Corvus.Extensions.System.Text.Json\",\"Corvus.Identity\",\"Corvus.Leasing\",\"Corvus.Monitoring\",\"Corvus.Retry\",\"Corvus.Tenancy\"]" -} + "AUTO_RELEASE_PACKAGE_WILDCARD_EXPRESSIONS": "[]" +} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 62b7b4b..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,15 +0,0 @@ -version: 2 -updates: -- package-ecosystem: nuget - directory: /Solutions - schedule: - interval: daily - open-pull-requests-limit: 10 - groups: - microsoft-identity: - patterns: - - Microsoft.Identity.* - microsoft-extensions: - patterns: - - Microsoft.Extensions.* - diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..c965a6e --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,59 @@ +name: build +on: + push: + branches: + - main + tags: + - '*' + pull_request: + branches: + - main + workflow_dispatch: + inputs: + forcePublish: + description: When true the Publish stage will always be run, otherwise it only runs for tagged versions. + required: false + default: false + type: boolean + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + checks: write # enable test result annotations + contents: write # enable creating releases + issues: read + packages: write # enable publishing packages + pull-requests: write # enable test result annotations + +jobs: + prepareConfig: + name: Prepare Configuration + runs-on: ubuntu-latest + outputs: + RESOLVED_ENV_VARS: ${{ steps.prepareEnvVarsAndSecrets.outputs.environmentVariablesYamlBase64 }} + RESOLVED_SECRETS: ${{ steps.prepareEnvVarsAndSecrets.outputs.secretsYamlBase64 }} + steps: + # Declare any environment variables and/or secrets that need to be available inside the build process + - uses: endjin/Endjin.RecommendedPractices.GitHubActions/actions/prepare-env-vars-and-secrets@main + id: prepareEnvVarsAndSecrets + with: + environmentVariablesYaml: | + BUILDVAR_ContainerRegistryFqdn: "endjin.azurecr.io" + BUILDVAR_ContainerImageVersionOverride: "" + BUILDVAR_Configuration: "Release" + secretsYaml: | + { + } + + build: + needs: prepareConfig + uses: endjin/Endjin.RecommendedPractices.GitHubActions/.github/workflows/scripted-build-single-job-pipeline.yml@main + with: + netSdkVersion: '8.0.x' + # workflow_dispatch inputs are always strings, the type property is just for the UI + forcePublish: ${{ github.event.inputs.forcePublish == 'true' }} + buildEnv: ${{ needs.prepareConfig.outputs.RESOLVED_ENV_VARS }} + secrets: + buildAzureCredentials: ${{ secrets.ENDJIN_PROD_ACR_PUBLISH_CREDENTIALS }} diff --git a/.gitignore b/.gitignore index d7ecf5d..247943c 100644 --- a/.gitignore +++ b/.gitignore @@ -343,3 +343,4 @@ _codeCoverage /Ais.Net.Receiver.sbom.json /Ais.Net.Receiver.sbom.html /Ais.Net.Receiver.sbom.cyclonedx.xml +/Solutions/Ais.Net.Receiver.sln.DotSettings diff --git a/README.md b/README.md index b82f9b1..69347c8 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,11 @@ # AIS.NET Projects -| Package | Status | -| ------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [Ais.Net](https://github.com/ais-dotnet/) | [![#](https://img.shields.io/nuget/v/Ais.Net.svg)](https://www.nuget.org/packages/Ais.Net/) | -| Ais.Net.Models | [![#](https://img.shields.io/nuget/v/Ais.Net.Models.svg)](https://www.nuget.org/packages/Ais.Net.Models/) | -| Ais.Net.Receiver | [![#](https://img.shields.io/nuget/v/Ais.Net.Receiver.svg)](https://www.nuget.org/packages/Ais.Net.Receiver/) | -| Ais.Net.Receiver.Storage.Azure.Blob | [![#](https://img.shields.io/nuget/v/Ais.Net.Receiver.Storage.Azure.Blob.svg)](https://www.nuget.org/packages/Ais.Net.Receiver.Storage.Azure.Blob/) | -| [IP Maturity Model Score](https://github.com/endjin/Endjin.Ip.Maturity.Matrix) | [![IMM](https://imm.endjin.com/api/imm/github/ais-dotnet/Ais.Net.Receiver/total?cache=false)](https://imm.endjin.com/api/imm/github/ais-dotnet/Ais.Net.Receiver/total?cache=false) | -| Build Status | [![Build Status](https://dev.azure.com/endjin-labs/Ais.Net.Receiver/_apis/build/status/CI?repoName=ais-dotnet%2FAis.Net.Receiver&branchName=master)](https://dev.azure.com/endjin-labs/Ais.Net.Receiver/_build/latest?definitionId=1&repoName=ais-dotnet%2FAis.Net.Receiver&branchName=master) | - +| Package | Status | +| ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Ais.Net](https://github.com/ais-dotnet/Ais.Net) | [![#](https://img.shields.io/nuget/v/Ais.Net.svg)](https://www.nuget.org/packages/Ais.Net/) | +| [Ais.Net.Models](https://github.com/ais-dotnet/Ais.Net.Models) | [![#](https://img.shields.io/nuget/v/Ais.Net.Models.svg)](https://www.nuget.org/packages/Ais.Net.Models/) | +| Ais.Net.Receiver | [![#](https://img.shields.io/nuget/v/Ais.Net.Receiver.svg)](https://www.nuget.org/packages/Ais.Net.Receiver/) | +| Ais.Net.Receiver.Storage.Azure.Blob | [![#](https://img.shields.io/nuget/v/Ais.Net.Receiver.Storage.Azure.Blob.svg)](https://www.nuget.org/packages/Ais.Net.Receiver.Storage.Azure.Blob/) | The AIS.NET project contains a series of layers, from a low-level high performance NMEA AIS sentence decoder, to a rich high-level C# 9.0 models of AIS message types, a receiver component that can listen to TCP streams of NMEA sentences and expose them as an `IObservable` of raw sentences or an decoded `IObservable`, and finally a Storage Client implementation to persisting the raw NMEA sentence stream to Azure Blob storage for future processing. @@ -16,9 +13,9 @@ The AIS.NET project contains a series of layers, from a low-level high performan # Ais.Net.Receiver -A simple .NET 5.0 AIS Receiver for capturing the Norwegian Coastal Administration's marine Automatic Identification System (AIS) [AIVDM/AIVDO](https://gpsd.gitlab.io/gpsd/AIVDM.html) NMEA message network data (available under [Norwegian license for public data (NLOD)](https://data.norge.no/nlod/en/2.0)) and persisting in Microsoft Azure Blob Storage. +A simple .NET AIS Receiver for capturing the Norwegian Coastal Administration's marine Automatic Identification System (AIS) [AIVDM/AIVDO](https://gpsd.gitlab.io/gpsd/AIVDM.html) NMEA message network data (available under [Norwegian license for public data (NLOD)](https://data.norge.no/nlod/en/2.0)) and persisting in Microsoft Azure Blob Storage. -The [Norwegian Costal Administration provide a TCP endpoint](https://ais.kystverket.no/) (`153.44.253.27:5631`) for broadcasting their raw AIS AIVDM/AIVDO sentences, captured by over 50 base stations, and covers the area 40-60 nautical miles from the Norwegian coastline. +The [Norwegian Coastal Administration provide a TCP endpoint](https://ais.kystverket.no/) (`153.44.253.27:5631`) for broadcasting their raw AIS AIVDM/AIVDO sentences, captured by over 50 base stations, and covers the area 40-60 nautical miles from the Norwegian coastline. This project contains a [NmeaReceiver](https://github.com/ais-dotnet/Ais.Net.Receiver/blob/master/Solutions/Ais.Net.Receiver/Receiver/NmeaReceiver.cs) which consumes the raw NetworkStream, a [NmeaToAisMessageTypeProcessor](https://github.com/ais-dotnet/Ais.Net.Receiver/blob/master/Solutions/Ais.Net.Receiver/Parser/NmeaToAisMessageTypeProcessor.cs), which can decode the raw sentences into `IAisMessage`, and [ReceiverHost](https://github.com/ais-dotnet/Ais.Net.Receiver/blob/master/Solutions/Ais.Net.Receiver/Receiver/ReceiverHost.cs) which manages the process and exposes an `IObservable` for raw sentences and an `IObservable` for decoded messages. `ReceiverHost` can be hosted in a console application or other runtime environments like [.NET Interactive](https://github.com/dotnet/interactive). @@ -26,7 +23,7 @@ The project also includes a [demo console](https://github.com/ais-dotnet/Ais.Net The purpose of this application is to provide sample data for [Ais.Net](https://github.com/ais-dotnet/Ais.Net) - the .NET Standard, high performance, zero allocation AIS decoder. The majority of raw AIS data is only available via commercial sources, and thus creating AIS datasets large enough to test / benchmark [Ais.Net](https://github.com/ais-dotnet/Ais.Net) is almost impossible. -The Norwegian Costal Administration TCP endpoint produces: +The Norwegian Coastal Administration TCP endpoint produces: - ~2.9 KB per second - ~10.3 MB per hour @@ -35,91 +32,6 @@ The Norwegian Costal Administration TCP endpoint produces: - ~7 GB per month - ~81.4 GB per year -## Ais.Net.Models - -Ais.Net.Receiver bridges the gap between the high performance, zero allocation world of [Ais.Net](https://github.com/ais-dotnet/Ais.Net) and the real world need for types to perform meaningful operations. Ais.Net.Models provides a series of [C# 9.0 records](https://devblogs.microsoft.com/dotnet/c-9-0-on-the-record/) -which define the the message types, a series of interfaces that define common behaviours, and extension methods to help with type conversions & calculations. - -The table below shows the messages, their properties and how they are mapped to interfaces. - -
Show AIS Message Types and .NET Interfaces - -| | Message Type 1 to 3 | Message Type 5 | Message Type 18 | Message Type 19 | Message Type 24 Part 0 | Message Type 24 Part 1 | -| ---------------------- | --------------------------- | -------------------- | ----------------------------------- | --------------------------- | ---------------------- | ---------------------- | -| IAisMessageType5 | | AisVersion | | | | | -| ICallSign | | CallSign | | | | CallSign | -| IAisMessageType18 | | | CanAcceptMessage22ChannelAssignment | | | | -| IAisMessageType18 | | | CanSwitchBands | | | | -| IVesselNavigation | CourseOverGround10thDegrees | | CourseOverGround10thDegrees | CourseOverGround10thDegrees | | | -| IAisMessageType5 | | Destination | | | | | -| IAisMessageType18 | | | CsUnit | | | | -| IVesselDimensions | | DimensionToBow | | DimensionToBow | | DimensionToBow | -| IVesselDimensions | | DimensionToPort | | DimensionToPort | | DimensionToPort | -| IVesselDimensions | | DimensionToStarboard | | DimensionToStarboard | | DimensionToStarboard | -| IVesselDimensions | | DimensionToStern | | DimensionToStern | | DimensionToStern | -| IAisMessageType5 | | Draught10thMetres | | | | | -| IAisMessageType5 | | EtaMonth | | | | | -| IAisMessageType5 | | EtaDay | | | | | -| IAisMessageType5 | | EtaHour | | | | | -| IAisMessageType5 | | EtaMinute | | | | | -| IAisMessageType18 | | | HasDisplay | | | | -| IIsAssigned | | | IsAssigned | IsAssigned | | | -| IAisMessageType18 | | | IsDscAttached | | | | -| IAisMessageType5 | | ImoNumber | | | | | -| IAisIsDteNotReady | | IsDteNotReady | | IsDteNotReady | | | -| IVesselNavigation | Latitude10000thMins | | Latitude10000thMins | Latitude10000thMins | | | -| IVesselNavigation | Longitude10000thMins | | Longitude10000thMins | Longitude10000thMins | | | -| IAisMessageType1to3 | ManoeuvreIndicator | | | | | | -| IAisMessageType24Part1 | | | | | | MothershipMmsi | -| IAisMessageType | MessageType | MessageType | MessageType | MessageType | MessageType | MessageType | -| IVesselIdentity | Mmsi | Mmsi | Mmsi | Mmsi | Mmsi | Mmsi | -| IAisMessageType1to3 | NavigationStatus | | | | | | -| IAisMultipartMessage | | | | | PartNumber | PartNumber | -| IVesselNavigation | PositionAccuracy | | PositionAccuracy | PositionAccuracy | | | -| IAisPositionFixType | | PositionFixType | | PositionFixType | | | -| IAisMessageType18 | | | RadioStatusType | | | | -| IAisMessageType1to3 | RadioSlotTimeout | | | | | | -| IAisMessageType1to3 | RadioSubMessage | | | | | | -| IAisMessageType1to3 | RadioSyncState | | | | | | -| IAisMessageType19 | | | | RegionalReserved139 | | | -| IAisMessageType19 | | | | RegionalReserved38 | | | -| IRaimFlag | RaimFlag | | RaimFlag | RaimFlag | | | -| IAisMessageType18 | | | RegionalReserved139 | | | | -| IAisMessageType18 | | | RegionalReserved38 | | | | -| IAisMessageType1to3 | RateOfTurn | | | | | | -| IRepeatIndicator | RepeatIndicator | RepeatIndicator | RepeatIndicator | RepeatIndicator | RepeatIndicator | RepeatIndicator | -| IAisMessageType24Part1 | | | | | | SerialNumber | -| IAisMessageType19 | | | | ShipName | | | -| IShipType | | ShipType | | ShipType | | ShipType | -| IAisMessageType1to3 | SpareBits145 | | | | | | -| IAisMessageType24Part0 | | | | | Spare160 | | -| IAisMessageType24Part1 | | | | | | Spare162 | -| IAisMessageType5 | | Spare423 | | | | | -| IAisMessageType19 | | | | Spare308 | | | -| IVesselNavigation | SpeedOverGroundTenths | | SpeedOverGroundTenths | SpeedOverGroundTenths | | | -| IVesselNavigation | TimeStampSecond | | TimeStampSecond | TimeStampSecond | | | -| IVesselNavigation | TrueHeadingDegrees | | TrueHeadingDegrees | TrueHeadingDegrees | | | -| IAisMessageType24Part1 | | | | | | UnitModelCode | -| IAisMessageType24Part1 | | | | | | VendorIdRev3 | -| IAisMessageType24Part1 | | | | | | VendorIdRev4 | -| IVesselName | | VesselName | | | | | -
- - -The C# record types then implement the relevant interfaces, which enables simpler higher level programming constructs, such as Rx queries over an `IAisMessage` stream: - -```csharp -IObservable> byVessel = receiverHost.Messages.GroupBy(m => m.Mmsi); - -IObservable<(uint mmsi, IVesselNavigation navigation, IVesselName name)>? vesselNavigationWithNameStream = - from perVesselMessages in byVessel - let vesselNavigationUpdates = perVesselMessages.OfType() - let vesselNames = perVesselMessages.OfType() - let vesselLocationsWithNames = vesselNavigationUpdates.CombineLatest(vesselNames, (navigation, name) => (navigation, name)) - from vesselLocationAndName in vesselLocationsWithNames - select (mmsi: perVesselMessages.Key, vesselLocationAndName.navigation, vesselLocationAndName.name); -``` - ## Azure Blob Storage Taxonomy The AIS data is stored using the following taxonomy @@ -186,9 +98,9 @@ From the command line: `dotnet Ais.Net.Receiver.Host.Console.exe` # Raspberry Pi -As the AIS.NET stack is written in .NET 6.0 and .NET Standard you can publish the Ais.Net.Recevier.Host.Console application with a target runtime of Portable. This will allow you to run the recevier on a Raspberry Pi if you want to capture your own AIS data. +As the AIS.NET stack is written in .NET 6.0 and .NET Standard you can publish the Ais.Net.Receiver.Host.Console application with a target runtime of Portable. This will allow you to run the receiver on a Raspberry Pi if you want to capture your own AIS data. -For reliability you can run `Ais.Net.Recevier.Host.Console.dll` as daemon. +For reliability you can run `Ais.Net.Receiver.Host.Console.dll` as daemon. ## Installation @@ -230,7 +142,7 @@ use the command `pwsh` to enter the PowerShell session. 7. run `sudo systemctl enable aisr.service` 8. run `sudo reboot` -You can use `journalctl -u "aisr"` to view the console output of `Ais.Net.Recevier.Host.Console.dll` +You can use `journalctl -u "aisr"` to view the console output of `Ais.Net.Receiver.Host.Console.dll` You can use `sudo systemctl restart aisr` to restart the service. @@ -296,19 +208,38 @@ The Data ingested by the AIS.Net.Receiver is licensed under the [Norwegian licen ## Project Sponsor -This project is sponsored by [endjin](https://endjin.com), a UK based Microsoft Gold Partner for Cloud Platform, Data Platform, Data Analytics, DevOps, Power BI Partner, and .NET Foundation Corporate Sponsor. +This project is sponsored by [endjin](https://endjin.com), a UK based Technology Consultancy which specializes in Data & Analytics, AI & Cloud Native App Dev, and is a [.NET Foundation Corporate Sponsor](https://dotnetfoundation.org/membership/corporate-sponsorship). -For more information about our products and services, or for commercial support of this project, please [contact us](https://endjin.com/contact-us). +> We help small teams achieve big things. + +We produce two free weekly newsletters: + + - [Azure Weekly](https://azureweekly.info) for all things about the Microsoft Azure Platform + - [Power BI Weekly](https://powerbiweekly.info) for all things Power BI, Microsoft Fabric, and Azure Synapse Analytics -We produce two free weekly newsletters; [Azure Weekly](https://azureweekly.info) for all things about the Microsoft Azure Platform, and [Power BI Weekly](https://powerbiweekly.info). +Keep up with everything that's going on at endjin via our [blog](https://endjin.com/blog), follow us on [Twitter](https://twitter.com/endjin), [YouTube](https://www.youtube.com/c/endjin) or [LinkedIn](https://www.linkedin.com/company/endjin). -Keep up with everything that's going on at endjin via our [blog](https://blogs.endjin.com/), follow us on [Twitter](https://twitter.com/endjin), or [LinkedIn](https://www.linkedin.com/company/1671851/). +We have become the maintainers of a number of popular .NET Open Source Projects: -Our other Open Source projects can be found on [GitHub](https://github.com/endjin) +- [Reactive Extensions for .NET](https://github.com/dotnet/reactive) +- [Reaqtor](https://github.com/reaqtive) +- [Argotic Syndication Framework](https://github.com/argotic-syndication-framework/) + +And we have over 50 Open Source projects of our own, spread across the following GitHub Orgs: + +- [endjin](https://github.com/endjin/) +- [Corvus](https://github.com/corvus-dotnet) +- [Menes](https://github.com/menes-dotnet) +- [Marain](https://github.com/marain-dotnet) +- [AIS.NET](https://github.com/ais-dotnet) + +And the DevOps tooling we have created for managing all these projects is available on the [PowerShell Gallery](https://www.powershellgallery.com/profiles/endjin). + +For more information about our products and services, or for commercial support of this project, please [contact us](https://endjin.com/contact-us). ## Code of conduct -This project has adopted a code of conduct adapted from the [Contributor Covenant](http://contributor-covenant.org/) to clarify expected behavior in our community. This code of conduct has been [adopted by many other projects](http://contributor-covenant.org/adopters/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [hello@endjin.com](mailto:hello@endjin.com) with any additional questions or comments. +This project has adopted a code of conduct adapted from the [Contributor Covenant](http://contributor-covenant.org/) to clarify expected behaviour in our community. This code of conduct has been [adopted by many other projects](http://contributor-covenant.org/adopters/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [hello@endjin.com](mailto:hello@endjin.com) with any additional questions or comments. ## IP Maturity Model (IMM) diff --git a/Solutions/Ais.Net.Models.Specs/Ais.Net.Models.Specs.csproj b/Solutions/Ais.Net.Models.Specs/Ais.Net.Models.Specs.csproj deleted file mode 100644 index adcb236..0000000 --- a/Solutions/Ais.Net.Models.Specs/Ais.Net.Models.Specs.csproj +++ /dev/null @@ -1,48 +0,0 @@ - - - - - net6.0 - latest - false - Corvus.Configuration.Specs - - RCS1029;SA0001;SA1204;SA1600;SA1602;CS1591 - enable - - - - true - true - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - - diff --git a/Solutions/Ais.Net.Models.Specs/Features/AisMessageType18.feature b/Solutions/Ais.Net.Models.Specs/Features/AisMessageType18.feature deleted file mode 100644 index 60cf792..0000000 --- a/Solutions/Ais.Net.Models.Specs/Features/AisMessageType18.feature +++ /dev/null @@ -1 +0,0 @@ -Feature: AisMessageType18 diff --git a/Solutions/Ais.Net.Models.Specs/Features/AisMessageType18.feature.cs b/Solutions/Ais.Net.Models.Specs/Features/AisMessageType18.feature.cs deleted file mode 100644 index 97f7296..0000000 --- a/Solutions/Ais.Net.Models.Specs/Features/AisMessageType18.feature.cs +++ /dev/null @@ -1,78 +0,0 @@ -// ------------------------------------------------------------------------------ -// -// This code was generated by SpecFlow (https://www.specflow.org/). -// SpecFlow Version:3.9.0.0 -// SpecFlow Generator Version:3.9.0.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -// ------------------------------------------------------------------------------ -#region Designer generated code -#pragma warning disable -namespace Corvus.Configuration.Specs.Features -{ - using TechTalk.SpecFlow; - using System; - using System.Linq; - - - [System.CodeDom.Compiler.GeneratedCodeAttribute("TechTalk.SpecFlow", "3.9.0.0")] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [NUnit.Framework.TestFixtureAttribute()] - [NUnit.Framework.DescriptionAttribute("AisMessageType18")] - public partial class AisMessageType18Feature - { - - private TechTalk.SpecFlow.ITestRunner testRunner; - - private static string[] featureTags = ((string[])(null)); - -#line 1 "AisMessageType18.feature" -#line hidden - - [NUnit.Framework.OneTimeSetUpAttribute()] - public virtual void FeatureSetup() - { - testRunner = TechTalk.SpecFlow.TestRunnerManager.GetTestRunner(); - TechTalk.SpecFlow.FeatureInfo featureInfo = new TechTalk.SpecFlow.FeatureInfo(new System.Globalization.CultureInfo("en-US"), "Features", "AisMessageType18", null, ProgrammingLanguage.CSharp, featureTags); - testRunner.OnFeatureStart(featureInfo); - } - - [NUnit.Framework.OneTimeTearDownAttribute()] - public virtual void FeatureTearDown() - { - testRunner.OnFeatureEnd(); - testRunner = null; - } - - [NUnit.Framework.SetUpAttribute()] - public void TestInitialize() - { - } - - [NUnit.Framework.TearDownAttribute()] - public void TestTearDown() - { - testRunner.OnScenarioEnd(); - } - - public void ScenarioInitialize(TechTalk.SpecFlow.ScenarioInfo scenarioInfo) - { - testRunner.OnScenarioInitialize(scenarioInfo); - testRunner.ScenarioContext.ScenarioContainer.RegisterInstanceAs(NUnit.Framework.TestContext.CurrentContext); - } - - public void ScenarioStart() - { - testRunner.OnScenarioStart(); - } - - public void ScenarioCleanup() - { - testRunner.CollectScenarioErrors(); - } - } -} -#pragma warning restore -#endregion diff --git a/Solutions/Ais.Net.Models.Specs/packages.lock.json b/Solutions/Ais.Net.Models.Specs/packages.lock.json deleted file mode 100644 index 76b2e9d..0000000 --- a/Solutions/Ais.Net.Models.Specs/packages.lock.json +++ /dev/null @@ -1,1471 +0,0 @@ -{ - "version": 1, - "dependencies": { - "net6.0": { - "Corvus.Testing.SpecFlow.NUnit": { - "type": "Direct", - "requested": "[1.5.1, )", - "resolved": "1.5.1", - "contentHash": "y0ztTHAvKYa9QTqmcQqVgNMMSeggmBy+je7v0cs0XIw8XMmdwxt3am66JT9hN354LD6l9l/Cey/pjWkAH1Kkxg==", - "dependencies": { - "Corvus.Testing.SpecFlow": "1.5.1", - "Microsoft.NET.Test.Sdk": "16.11.0", - "Moq": "4.17.2", - "SpecFlow.NUnit.Runners": "3.9.74", - "coverlet.msbuild": "3.1.2" - } - }, - "Endjin.RecommendedPractices.GitHub": { - "type": "Direct", - "requested": "[2.1.2, )", - "resolved": "2.1.2", - "contentHash": "mBUCmeSdWWrIQKuuYd9zflcwupRDmpF39dsbb07e6azlNIQqaE1J5TQa17c3SFVRXn9IZrClsmKoMporRTAWwQ==", - "dependencies": { - "Endjin.RecommendedPractices": "2.1.2", - "Microsoft.SourceLink.GitHub": "1.1.1" - } - }, - "Roslynator.Analyzers": { - "type": "Direct", - "requested": "[4.1.1, )", - "resolved": "4.1.1", - "contentHash": "3cPVlrB1PytlO1ztZZBOExDKQWpMZgI15ZDa0BqLu0l6xv+xIRfEpqjNRcpvUy3aLxWTkPgSKZbbaO+VoFEJ1g==" - }, - "StyleCop.Analyzers": { - "type": "Direct", - "requested": "[1.2.0-beta.435, )", - "resolved": "1.2.0-beta.435", - "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", - "dependencies": { - "StyleCop.Analyzers.Unstable": "1.2.0.435" - } - }, - "Ais.Net": { - "type": "Transitive", - "resolved": "0.4.2", - "contentHash": "+wtx8g0YwxEaDbilf4MiED9S4Yxr9J7RHAAMEN48+yB0it10KYdhmtB6dxt7qdCOvdoDnBOumggcGYefWMz+WA==", - "dependencies": { - "System.IO.Pipelines": "4.7.4" - } - }, - "BoDi": { - "type": "Transitive", - "resolved": "1.5.0", - "contentHash": "CzIPzdIAFSd2zuLxI+0K9s48Qv3HQDbWiApn9h96j284rHs2bSPrn/PMca3mi4q3xLSEqOp+GUJ6+mXDD9prKg==" - }, - "Castle.Core": { - "type": "Transitive", - "resolved": "4.4.1", - "contentHash": "zanbjWC0Y05gbx4eGXkzVycOQqVOFVeCjVsDSyuao9P4mtN1w3WxxTo193NGC7j3o2u3AJRswaoC6hEbnGACnQ==", - "dependencies": { - "NETStandard.Library": "1.6.1", - "System.Collections.Specialized": "4.3.0", - "System.ComponentModel": "4.3.0", - "System.ComponentModel.TypeConverter": "4.3.0", - "System.Diagnostics.TraceSource": "4.3.0", - "System.Dynamic.Runtime": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Xml.XmlDocument": "4.3.0" - } - }, - "Corvus.Testing.SpecFlow": { - "type": "Transitive", - "resolved": "1.5.1", - "contentHash": "V2T6PjkWwzMrkwew29GmaIceDepKEaev+CyBDJLfCOZth4lHiiyhEb0mlIv/GKJTwLLzvTUlUr8yxetIeRCE6Q==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "3.1.24", - "Microsoft.Extensions.DependencyInjection": "3.1.24", - "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.24", - "NUnit": "3.13.3", - "SpecFlow": "3.9.74", - "System.Management": "4.7.0" - } - }, - "coverlet.msbuild": { - "type": "Transitive", - "resolved": "3.1.2", - "contentHash": "QhM0fnDtmIMImY7oxyQ/kh1VYtRxPyRVeLwRUGuUvI6Xp83pSYG9gerK8WgJj4TzUl7ISziADUGtIWKhtlbkbQ==" - }, - "Endjin.RecommendedPractices": { - "type": "Transitive", - "resolved": "2.1.2", - "contentHash": "Nbj0WS3zVDD2wjfU2/nbkWIWS9Ljg8VN+SSpaCuf5lHBOIEb0Ra201lGcyJHtRHybAciz+hQA9lHj7TnG52qqw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1" - } - }, - "Gherkin": { - "type": "Transitive", - "resolved": "19.0.3", - "contentHash": "kq9feqMojMj9aABrHb/ABEPaH2Y4dSclseSahAru6qxCeqVQNLLTgw/6vZMauzI1yBUL2fz03ub5yEd5btLfvg==" - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" - }, - "Microsoft.CodeCoverage": { - "type": "Transitive", - "resolved": "16.11.0", - "contentHash": "wf6lpAeCqP0KFfbDVtfL50lr7jY1gq0+0oSphyksfLOEygMDXqnaxHK5LPFtMEhYSEtgXdNyXNnEddOqQQUdlQ==" - }, - "Microsoft.CSharp": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "17h8b5mXa87XYKrrVqdgZ38JefSUqLChUQpXgSnpzsM0nDOhE40FTeNWOJ/YmySGV6tG6T8+hjz6vxbknHJr6A==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Reflection.Primitives": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Threading": "4.0.11" - } - }, - "Microsoft.DotNet.InternalAbstractions": { - "type": "Transitive", - "resolved": "1.0.0", - "contentHash": "AAguUq7YyKk3yDWPoWA8DrLZvURxB/LrDdTn1h5lmPeznkFUpfC3p459w5mQYQE0qpquf/CkSQZ0etiV5vRHFA==", - "dependencies": { - "System.AppContext": "4.1.0", - "System.Collections": "4.0.11", - "System.IO": "4.1.0", - "System.IO.FileSystem": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.InteropServices.RuntimeInformation": "4.0.0" - } - }, - "Microsoft.DotNet.PlatformAbstractions": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "rF92Gp5L2asYrFNf0cKNBxzzGLh1krHuj6TRDk9wdjN2qdvJLaNYOn1s9oYkMlptYX436KiEFqxhLB+I5veXvQ==", - "dependencies": { - "System.AppContext": "4.1.0", - "System.Collections": "4.0.11", - "System.IO": "4.1.0", - "System.IO.FileSystem": "4.0.1", - "System.Reflection.TypeExtensions": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.InteropServices": "4.1.0", - "System.Runtime.InteropServices.RuntimeInformation": "4.0.0" - } - }, - "Microsoft.Extensions.Configuration.Abstractions": { - "type": "Transitive", - "resolved": "3.1.24", - "contentHash": "3YeuWZKoBxLe3KjYMY9Hk0cUs9VpqqUOekfUkNP3Px2DlOLi5S+qJx2sUkOjKsbDztbb+35v5TUylSysvdNJvg==", - "dependencies": { - "Microsoft.Extensions.Primitives": "3.1.24" - } - }, - "Microsoft.Extensions.DependencyInjection": { - "type": "Transitive", - "resolved": "3.1.24", - "contentHash": "edKD2klSQqQood/i/S8Wcwj7GdpJrx6YNx6aEwrrD9HPb9E9b6K1jhAEqd5Pjy3YrIgB+lG4a59GB8ZkVDRN6A==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "3.1.24" - } - }, - "Microsoft.Extensions.DependencyInjection.Abstractions": { - "type": "Transitive", - "resolved": "3.1.24", - "contentHash": "vUVCGgYpwKK3C20t0swdxWKTmom3TByacyyj/sEMPWjfufcGxNM2W+qxgBOTMucFQpvbyPwBIFKAik7gYYFqxw==" - }, - "Microsoft.Extensions.DependencyModel": { - "type": "Transitive", - "resolved": "1.0.3", - "contentHash": "Z3o19EnheuegmvgpCzwoSlnCWxYA6qIUhvKJ7ifKHHvU7U+oYR/gliLiL3LVYOOeGMEEzkpJ5W67sOcXizGtlw==", - "dependencies": { - "Microsoft.DotNet.PlatformAbstractions": "1.0.3", - "Newtonsoft.Json": "9.0.1", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Linq": "4.1.0" - } - }, - "Microsoft.Extensions.Primitives": { - "type": "Transitive", - "resolved": "3.1.24", - "contentHash": "MCg9BTY32DBAYCIltI5pkE7LbK/2KTpeK3ZknbTQuQOEV+guLVOHv5yNDW7NhiX2n3FTGTL9uhAf7effqYkAbg==" - }, - "Microsoft.NET.Test.Sdk": { - "type": "Transitive", - "resolved": "16.11.0", - "contentHash": "f4mbG1SUSkNWF5p7B3Y8ZxMsvKhxCmpZhdl+w6tMtLSUGE7Izi1syU6TkmKOvB2BV66pdbENConFAISOix4ohQ==", - "dependencies": { - "Microsoft.CodeCoverage": "16.11.0", - "Microsoft.TestPlatform.TestHost": "16.11.0" - } - }, - "Microsoft.NETCore.Platforms": { - "type": "Transitive", - "resolved": "3.1.0", - "contentHash": "z7aeg8oHln2CuNulfhiLYxCVMPEwBl3rzicjvIX+4sUuCwvXw5oXQEtbiU2c0z4qYL5L3Kmx0mMA/+t/SbY67w==" - }, - "Microsoft.NETCore.Targets": { - "type": "Transitive", - "resolved": "1.1.0", - "contentHash": "aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==" - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" - }, - "Microsoft.SourceLink.GitHub": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "Microsoft.TestPlatform.ObjectModel": { - "type": "Transitive", - "resolved": "16.11.0", - "contentHash": "EiknJx9N9Z30gs7R+HHhki7fA8EiiM3pwD1vkw3bFsBC8kdVq/O7mHf1hrg5aJp+ASO6BoOzQueD2ysfTOy/Bg==", - "dependencies": { - "NuGet.Frameworks": "5.0.0", - "System.Reflection.Metadata": "1.6.0" - } - }, - "Microsoft.TestPlatform.TestHost": { - "type": "Transitive", - "resolved": "16.11.0", - "contentHash": "/Q+R0EcCJE8JaYCk+bGReicw/xrB0HhecrYrUcLbn95BnAlaTJrZhoLkUhvtKTAVtqX/AIKWXYtutiU/Q6QUgg==", - "dependencies": { - "Microsoft.TestPlatform.ObjectModel": "16.11.0", - "Newtonsoft.Json": "9.0.1" - } - }, - "Microsoft.Win32.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "9ZQKCWxH7Ijp9BfahvL2Zyf1cJIk8XYLF6Yjzr2yi0b2cOut/HQ31qf1ThHAgCc3WiZMdnWcfJCgN82/0UunxA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "Microsoft.Win32.Registry": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "KSrRMb5vNi0CWSGG1++id2ZOs/1QhRqROt+qgbEAdQuGjGrFcl4AOl4/exGPUYz2wUnU42nvJqon1T3U0kPXLA==", - "dependencies": { - "System.Security.AccessControl": "4.7.0", - "System.Security.Principal.Windows": "4.7.0" - } - }, - "Moq": { - "type": "Transitive", - "resolved": "4.17.2", - "contentHash": "HytUPJ3/uks2UgJ9hIcyXm3YxpFAR4OJzbQwTHltbKGun3lFLhEHs97hiiPj1dY8jV/kasXeihTzDxct6Zf3iQ==", - "dependencies": { - "Castle.Core": "4.4.1", - "System.Threading.Tasks.Extensions": "4.5.4" - } - }, - "NETStandard.Library": { - "type": "Transitive", - "resolved": "2.0.0", - "contentHash": "7jnbRU+L08FXKMxqUflxEXtVymWvNOrS8yHgu9s6EM8Anr6T/wIX4nZ08j/u3Asz+tCufp3YVwFSEvFTPYmBPA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0" - } - }, - "Newtonsoft.Json": { - "type": "Transitive", - "resolved": "9.0.1", - "contentHash": "U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==", - "dependencies": { - "Microsoft.CSharp": "4.0.1", - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Dynamic.Runtime": "4.0.11", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Linq": "4.1.0", - "System.Linq.Expressions": "4.1.0", - "System.ObjectModel": "4.0.12", - "System.Reflection": "4.1.0", - "System.Reflection.Extensions": "4.0.1", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Runtime.Serialization.Primitives": "4.1.1", - "System.Text.Encoding": "4.0.11", - "System.Text.Encoding.Extensions": "4.0.11", - "System.Text.RegularExpressions": "4.1.0", - "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11", - "System.Xml.XDocument": "4.0.11" - } - }, - "NuGet.Frameworks": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "c5JVjuVAm4f7E9Vj+v09Z9s2ZsqFDjBpcsyS3M9xRo0bEdm/LVZSzLxxNvfvAwRiiE8nwe1h2G4OwiwlzFKXlA==" - }, - "NUnit": { - "type": "Transitive", - "resolved": "3.13.3", - "contentHash": "KNPDpls6EfHwC3+nnA67fh5wpxeLb3VLFAfLxrug6JMYDLHH6InaQIWR7Sc3y75d/9IKzMksH/gi08W7XWbmnQ==", - "dependencies": { - "NETStandard.Library": "2.0.0" - } - }, - "NUnit.Console": { - "type": "Transitive", - "resolved": "3.12.0", - "contentHash": "9KXFnViEIKQjz4vqiYFpLV9sntfHxixQomLCJzDMXC6WDo9DP2GhDQiBND6we6MRStMSNzoAWgourbLKwo7utQ==", - "dependencies": { - "NUnit.ConsoleRunner": "3.12.0", - "NUnit.Extension.NUnitProjectLoader": "3.6.0", - "NUnit.Extension.NUnitV2Driver": "3.8.0", - "NUnit.Extension.NUnitV2ResultWriter": "3.6.0", - "NUnit.Extension.TeamCityEventListener": "1.0.7", - "NUnit.Extension.VSProjectLoader": "3.8.0" - } - }, - "NUnit.ConsoleRunner": { - "type": "Transitive", - "resolved": "3.12.0", - "contentHash": "ZUtI8leU9ozCjLy4ZZ2X6ClU0hxfQtb95VOdmMA4SxIUvf62rIPxoHXS+jghvo5QxgRihGGcEp8xT3vCfgDdsA==" - }, - "NUnit.Extension.NUnitProjectLoader": { - "type": "Transitive", - "resolved": "3.6.0", - "contentHash": "ev2+dCJShMNIATkYNm/vHEuieBfbismr9DcUfBvafJZf5vNyugXPuMXO/MaOFcJaoW9j6/zjMmXKG7R5umWzXA==" - }, - "NUnit.Extension.NUnitV2Driver": { - "type": "Transitive", - "resolved": "3.8.0", - "contentHash": "l6MgFJPTnrlDaMXWfbUZ82h1uvtj0C1ExPpqm6HrYOBa5Z4MBwmFLqj85rnv9JMhu/Ju7jQB/FIaMbfoXInI2A==" - }, - "NUnit.Extension.NUnitV2ResultWriter": { - "type": "Transitive", - "resolved": "3.6.0", - "contentHash": "P/Nc+wgFRe3dT59/VjhiIT0SWfLMbb/Vc9AtBU3L71VOCs8zQnuNjCOEFLQL/Mq6XSaZeB2Sug9tUgTfCnQk9w==" - }, - "NUnit.Extension.TeamCityEventListener": { - "type": "Transitive", - "resolved": "1.0.7", - "contentHash": "bw+ZwHsUmxqb9leo91qLEF7ggtdpawY2V6wNqHI6+ATa2SHxHxoxiV5UV07ZWDRpf/qlQJELNlZu7wIB3+w2qQ==" - }, - "NUnit.Extension.VSProjectLoader": { - "type": "Transitive", - "resolved": "3.8.0", - "contentHash": "CIScV9a7+wUu6Ylb+WO0q/WGWQVoB05TUj3XZHa1CO+2BInDdfIVkqtlrSguhy6D/AGIMaLVrCZpQkQ2m0bbzQ==" - }, - "NUnit3TestAdapter": { - "type": "Transitive", - "resolved": "3.17.0", - "contentHash": "I9MNvK+GM2yXrHPitwZkAZKU9sYI2OO/8wKC+VuBD7V3z+ySQ1pSopX/urr0ooedI8/TIcajYPRO4vGRr7AM8A==", - "dependencies": { - "Microsoft.DotNet.InternalAbstractions": "1.0.0", - "System.ComponentModel.EventBasedAsync": "4.3.0", - "System.ComponentModel.TypeConverter": "4.3.0", - "System.Diagnostics.Process": "4.3.0", - "System.Reflection": "4.3.0", - "System.Runtime.InteropServices.RuntimeInformation": "4.3.0", - "System.Threading.Thread": "4.3.0", - "System.Xml.XPath.XmlDocument": "4.3.0", - "System.Xml.XmlDocument": "4.3.0" - } - }, - "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "7VSGO0URRKoMEAq0Sc9cRz8mb6zbyx/BZDEWhgPdzzpmFhkam3fJ1DAGWFXBI4nGlma+uPKpfuMQP5LXRnOH5g==" - }, - "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "0oAaTAm6e2oVH+/Zttt0cuhGaePQYKII1dY8iaqP7CvOpVKgLybKRFvQjXR2LtxXOXTVPNv14j0ot8uV+HrUmw==" - }, - "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "G24ibsCNi5Kbz0oXWynBoRgtGvsw5ZSVEWjv13/KiCAM8C6wz9zzcCniMeQFIkJ2tasjo2kXlvlBZhplL51kGg==" - }, - "runtime.native.System": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "c/qWt2LieNZIj1jGnVNsE2Kl23Ya2aSTBuXMD6V7k9KWr6l16Tqdwq+hJScEpWER9753NWC8h96PaVNY5Ld7Jw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "runtime.native.System.Net.Http": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ZVuZJqnnegJhd2k/PtAbbIcZ3aZeITq3sj06oKfMBSfphW3HDmk/t4ObvbOk/JA/swGR0LNqMksAh/f7gpTROg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "runtime.native.System.Security.Cryptography.Apple": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "DloMk88juo0OuOWr56QG7MNchmafTLYWvABy36izkrLI5VledI0rq28KGs1i9wbpeT9NPQrx/wTf8U2vazqQ3Q==", - "dependencies": { - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": "4.3.0" - } - }, - "runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "QR1OwtwehHxSeQvZKXe+iSd+d3XZNkEcuWMFYa2i0aG1l+lR739HPicKMlTbJst3spmeekDVBUS7SeS26s4U/g==", - "dependencies": { - "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.fedora.23-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.fedora.24-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2", - "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" - } - }, - "runtime.opensuse.13.2-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "I+GNKGg2xCHueRd1m9PzeEW7WLbNNLznmTuEi8/vZX71HudUbx1UTwlGkiwMri7JLl8hGaIAWnA/GONhu+LOyQ==" - }, - "runtime.opensuse.42.1-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "1Z3TAq1ytS1IBRtPXJvEUZdVsfWfeNEhBkbiOCGEl9wwAfsjP2lz3ZFDx5tq8p60/EqbS0HItG5piHuB71RjoA==" - }, - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.Apple": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "kVXCuMTrTlxq4XOOMAysuNwsXWpYeboGddNGpIgNSZmv1b6r/s/DPk0fYMB7Q5Qo4bY68o48jt4T4y5BVecbCQ==" - }, - "runtime.osx.10.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "6mU/cVmmHtQiDXhnzUImxIcDL48GbTk+TsptXyJA+MIOG9LRjPoAQC/qBFB7X+UNyK86bmvGwC8t+M66wsYC8w==" - }, - "runtime.rhel.7-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "vjwG0GGcTW/PPg6KVud8F9GLWYuAV1rrw1BKAqY0oh4jcUqg15oYF1+qkGR2x2ZHM4DQnWKQ7cJgYbfncz/lYg==" - }, - "runtime.ubuntu.14.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "7KMFpTkHC/zoExs+PwP8jDCWcrK9H6L7soowT80CUx3e+nxP/AFnq0AQAW5W76z2WYbLAYCRyPfwYFG6zkvQRw==" - }, - "runtime.ubuntu.16.04-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "xrlmRCnKZJLHxyyLIqkZjNXqgxnKdZxfItrPkjI+6pkRo5lHX8YvSZlWrSI5AVwLMi4HbNWP7064hcAWeZKp5w==" - }, - "runtime.ubuntu.16.10-x64.runtime.native.System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.2", - "contentHash": "leXiwfiIkW7Gmn7cgnNcdtNAU70SjmKW3jxGj1iKHOvdn0zRWsgv/l2OJUO5zdGdiv2VRFnAsxxhDgMzofPdWg==" - }, - "SpecFlow": { - "type": "Transitive", - "resolved": "3.9.74", - "contentHash": "n6kcg9ZeQWxqJFoT23SsFT89U1QQNwvcN9pAX5alB6ZPr6K0p5D5nGIJ1PZsSaFaRFutiwQ+DicmxBCPAZVYIA==", - "dependencies": { - "BoDi": "1.5.0", - "Gherkin": "19.0.3", - "Microsoft.Extensions.DependencyModel": "1.0.3", - "SpecFlow.Internal.Json": "1.0.8", - "System.Configuration.ConfigurationManager": "4.5.0", - "System.Net.Http": "4.3.4", - "System.Runtime.Loader": "4.3.0" - } - }, - "SpecFlow.Internal.Json": { - "type": "Transitive", - "resolved": "1.0.8", - "contentHash": "lVCC/Rie7N5rFoc7YxPS0nneLfsWSTIMMlkndwxhaD8MxBp3Bsv1HeiVjVwXCjWaQeoqZcvIy52fF5Xit00ZLw==" - }, - "SpecFlow.NUnit": { - "type": "Transitive", - "resolved": "3.9.74", - "contentHash": "nMPLztTT5IZDMnvNCUxklqaM+agn4kjuNy/qAcYQQOxau2G1MF73UxhL9OXjJQaEuPuyT8gJvXudOYCFZWztxA==", - "dependencies": { - "NUnit": "3.13.1", - "SpecFlow": "[3.9.74]", - "SpecFlow.Tools.MsBuild.Generation": "[3.9.74]" - } - }, - "SpecFlow.NUnit.Runners": { - "type": "Transitive", - "resolved": "3.9.74", - "contentHash": "m595x3GM7CYco+KsXo96irQ2jcjC6+1+41bKdmnTdl3RAvnC4jUZ9f5B5FhGuaVK4+j4GwWi8MZtGMrT//zHLA==", - "dependencies": { - "NUnit.Console": "3.12.0", - "NUnit3TestAdapter": "3.17.0", - "SpecFlow.NUnit": "[3.9.74]" - } - }, - "SpecFlow.Tools.MsBuild.Generation": { - "type": "Transitive", - "resolved": "3.9.74", - "contentHash": "I/9OvmKOohJqIUNJ0xGYJCWfL6WKDaes8OoOAD/2yhGX+tzC5ofs9yqkP9Cu/xfnIx+11IR3pZs7YhBhGAcgWQ==", - "dependencies": { - "SpecFlow": "[3.9.74]" - } - }, - "StyleCop.Analyzers.Unstable": { - "type": "Transitive", - "resolved": "1.2.0.435", - "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" - }, - "System.AppContext": { - "type": "Transitive", - "resolved": "4.1.0", - "contentHash": "3QjO4jNV7PdKkmQAVp9atA+usVnKRwI3Kx1nMwJ93T0LcQfx7pKAYk0nKz5wn1oP5iqlhZuy6RXOFdhr7rDwow==", - "dependencies": { - "System.Runtime": "4.1.0" - } - }, - "System.CodeDom": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "Hs9pw/kmvH3lXaZ1LFKj3pLQsiGfj2xo3sxSzwiLlRL6UcMZUTeCfoJ9Udalvn3yq5dLlPEZzYegrTQ1/LhPOQ==" - }, - "System.Collections": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Collections.Concurrent": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ztl69Xp0Y/UXCL+3v3tEU+lIy+bvjKNUmopn1wep/a291pVPK7dxBd6T7WnlQqRog+d1a/hSsgRsmFnIBKTPLQ==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Globalization": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Collections.NonGeneric": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "prtjIEMhGUnQq6RnPEYLpFt8AtLbp9yq2zxOSrY7KJJZrw25Fi97IzBqY7iqssbM61Ek5b8f3MG/sG1N2sN5KA==", - "dependencies": { - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Collections.Specialized": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "Epx8PoVZR0iuOnJJDzp7pWvdfMMOAvpUo95pC4ScH2mJuXkKA2Y4aR3cG9qt2klHgSons1WFh4kcGW7cSXvrxg==", - "dependencies": { - "System.Collections.NonGeneric": "4.3.0", - "System.Globalization": "4.3.0", - "System.Globalization.Extensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.ComponentModel": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VyGn1jGRZVfxnh8EdvDCi71v3bMXrsu8aYJOwoV7SNDLVhiEqwP86pPMyRGsDsxhXAm2b3o9OIqeETfN5qfezw==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.ComponentModel.EventBasedAsync": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "fCFl8f0XdwA/BuoNrVBB5D0Y48/hv2J+w4xSDdXQitXZsR6UCSOrDVE7TCUraY802ENwcHUnUCv4En8CupDU1g==", - "dependencies": { - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.ComponentModel.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "j8GUkCpM8V4d4vhLIIoBLGey2Z5bCkMVNjEZseyAlm4n5arcsJOeI3zkUP+zvZgzsbLTYh4lYeP/ZD/gdIAPrw==", - "dependencies": { - "System.ComponentModel": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.ComponentModel.TypeConverter": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "16pQ6P+EdhcXzPiEK4kbA953Fu0MNG2ovxTZU81/qsCd1zPRsKc3uif5NgvllCY598k6bI0KUyKW8fanlfaDQg==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Collections.NonGeneric": "4.3.0", - "System.Collections.Specialized": "4.3.0", - "System.ComponentModel": "4.3.0", - "System.ComponentModel.Primitives": "4.3.0", - "System.Globalization": "4.3.0", - "System.Linq": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Extensions": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Configuration.ConfigurationManager": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "UIFvaFfuKhLr9u5tWMxmVoDPkFeD+Qv8gUuap4aZgVGYSYMdERck4OhLN/2gulAc0nYTEigWXSJNNWshrmxnng==", - "dependencies": { - "System.Security.Cryptography.ProtectedData": "4.5.0", - "System.Security.Permissions": "4.5.0" - } - }, - "System.Diagnostics.Debug": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Diagnostics.DiagnosticSource": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "tD6kosZnTAGdrEa0tZSuFyunMbt/5KYDnHdndJYGqZoNy00XVXyACd5d6KnE1YgYv3ne2CjtAfNXo/fwEhnKUA==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Diagnostics.Process": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "J0wOX07+QASQblsfxmIMFc9Iq7KTXYL3zs2G/Xc704Ylv3NpuVdo6gij6V3PGiptTxqsK0K7CdXenRvKUnkA2g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.Win32.Primitives": "4.3.0", - "Microsoft.Win32.Registry": "4.3.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Text.Encoding.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "System.Threading.Thread": "4.3.0", - "System.Threading.ThreadPool": "4.3.0", - "runtime.native.System": "4.3.0" - } - }, - "System.Diagnostics.Tools": { - "type": "Transitive", - "resolved": "4.0.1", - "contentHash": "xBfJ8pnd4C17dWaC9FM6aShzbJcRNMChUMD42I6772KGGrqaFdumwhn9OdM68erj1ueNo3xdQ1EwiFjK5k8p0g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", - "Microsoft.NETCore.Targets": "1.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Diagnostics.TraceSource": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VnYp1NxGx8Ww731y2LJ1vpfb/DKVNKEZ8Jsh5SgQTZREL/YpWRArgh9pI8CDLmgHspZmLL697CaLvH85qQpRiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "runtime.native.System": "4.3.0" - } - }, - "System.Diagnostics.Tracing": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "rswfv0f/Cqkh78rA5S8eN8Neocz234+emGCtTF3lxPY96F+mmmUen6tbn0glN6PMvlKQb9bPAY5e9u7fgPTkKw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Dynamic.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "SNVi1E/vfWUAs/WYKhE9+qlS6KqK0YVhnlT0HQtr8pMIA8YX3lwy3uPMownDwdYISBdmAF/2holEIldVp85Wag==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Linq": "4.3.0", - "System.Linq.Expressions": "4.3.0", - "System.ObjectModel": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Globalization": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Globalization.Calendars": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "GUlBtdOWT4LTV3I+9/PJW+56AnnChTaOqqTLFtdmype/L500M2LIyXgmtd9X2P2VOkmJd5c67H5SaC2QcL1bFA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Globalization": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Globalization.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "FhKmdR6MPG+pxow6wGtNAWdZh7noIOpdD5TwQ3CprzgIE1bBBoim0vbR1+AWsWjQmU7zXHgQo4TWSP6lCeiWcQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.InteropServices": "4.3.0" - } - }, - "System.IO": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.IO.FileSystem": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "3wEMARTnuio+ulnvi+hkRNROYwa1kylvYahhcLk4HSoVdl+xxTFVeVlYOfLwrDPImGls0mDqbMhrza8qnWPTdA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.IO.FileSystem.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "6QOb2XFLch7bEc4lIcJH49nJN2HV+OC3fHDgsLVsBVBk3Y4hFAnOBGzJ2lUu7CyDDFo9IBWkSsnbkT6IBwwiMw==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.IO.Pipelines": { - "type": "Transitive", - "resolved": "4.7.4", - "contentHash": "TQqNjDcTVu6eTDB2S0vjSUhn0udEugL93D9zgsOsSiJO1kv1UWDM2o0+79H95I5X+S0VPEzm4ihj6KPwhNEb7g==" - }, - "System.Linq": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0" - } - }, - "System.Linq.Expressions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Linq": "4.3.0", - "System.ObjectModel": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Emit.Lightweight": "4.3.0", - "System.Reflection.Extensions": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Reflection.TypeExtensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Management": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "IY+uuGhgzWiCg21i8IvQeY/Z7m1tX8VuPF+ludfn7iTCaccTtJo5HkjZbBEL8kbBubKhAKKtNXr7uMtmAc28Pw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.1.0", - "Microsoft.Win32.Registry": "4.7.0", - "System.CodeDom": "4.7.0" - } - }, - "System.Net.Http": { - "type": "Transitive", - "resolved": "4.3.4", - "contentHash": "aOa2d51SEbmM+H+Csw7yJOuNZoHkrP2XnAurye5HWYgGVVU54YZDvsLUYRv6h18X3sPnjNCANmN7ZhIPiqMcjA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.1", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Diagnostics.DiagnosticSource": "4.3.0", - "System.Diagnostics.Tracing": "4.3.0", - "System.Globalization": "4.3.0", - "System.Globalization.Extensions": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.Net.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.OpenSsl": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Security.Cryptography.X509Certificates": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "runtime.native.System": "4.3.0", - "runtime.native.System.Net.Http": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.2" - } - }, - "System.Net.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "qOu+hDwFwoZPbzPvwut2qATe3ygjeQBDQj91xlsaqGFQUI5i4ZnZb8yyQuLGpDGivEPIt8EJkd1BVzVoP31FXA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, - "System.ObjectModel": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Reflection": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.IO": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Emit": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", - "dependencies": { - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Emit.ILGeneration": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Emit.Lightweight": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Reflection.Emit.ILGeneration": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.Metadata": { - "type": "Transitive", - "resolved": "1.6.0", - "contentHash": "COC1aiAJjCoA5GBF+QKL2uLqEBew4JsCkQmoHKbN3TlOZKa2fKLz5CpiRQKDz0RsAOEGsVKqOD5bomsXq/4STQ==" - }, - "System.Reflection.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Reflection.TypeExtensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Resources.ResourceManager": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Globalization": "4.3.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0" - } - }, - "System.Runtime.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.Handles": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.InteropServices": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Reflection": "4.3.0", - "System.Reflection.Primitives": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, - "System.Runtime.InteropServices.RuntimeInformation": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "cbz4YJMqRDR7oLeMRbdYv7mYzc++17lNhScCX0goO2XpGWdvAt60CGN+FHdePUEHCe/Jy9jUlvNAiNdM+7jsOw==", - "dependencies": { - "System.Reflection": "4.3.0", - "System.Reflection.Extensions": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Threading": "4.3.0", - "runtime.native.System": "4.3.0" - } - }, - "System.Runtime.Loader": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "DHMaRn8D8YCK2GG2pw+UzNxn/OHVfaWx7OTLBD/hPegHZZgcZh3H6seWegrC4BYwsfuGrywIuT+MQs+rPqRLTQ==", - "dependencies": { - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Runtime": "4.3.0" - } - }, - "System.Runtime.Numerics": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "yMH+MfdzHjy17l2KESnPiF2dwq7T+xLnSJar7slyimAkUh/gTrS9/UQOtv7xarskJ2/XDSNvfLGOBQPjL7PaHQ==", - "dependencies": { - "System.Globalization": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0" - } - }, - "System.Runtime.Serialization.Primitives": { - "type": "Transitive", - "resolved": "4.1.1", - "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", - "dependencies": { - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0" - } - }, - "System.Security.AccessControl": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "JECvTt5aFF3WT3gHpfofL2MNNP6v84sxtXxpqhLBCcDRzqsPBmHhQ6shv4DwwN2tRlzsUxtb3G9M3763rbXKDg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "3.1.0", - "System.Security.Principal.Windows": "4.7.0" - } - }, - "System.Security.Cryptography.Algorithms": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "W1kd2Y8mYSCgc3ULTAZ0hOP2dSdG5YauTb1089T0/kRcN2MpSAW1izOFROrJgxSlMn3ArsgHXagigyi+ibhevg==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.Apple": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.Cng": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "03idZOqFlsKRL4W+LuCpJ6dBYDUWReug6lZjBa3uJWnk5sPCUXckocevTaUA8iT/MFSrY/2HXkOt753xQ/cf8g==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0" - } - }, - "System.Security.Cryptography.Csp": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "X4s/FCkEUnRGnwR3aSfVIkldBmtURMhmexALNTwpjklzxWU7yjMk7GHLKOZTNkgnWnE0q7+BCf9N2LVRWxewaA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.IO": "4.3.0", - "System.Reflection": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0" - } - }, - "System.Security.Cryptography.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "1DEWjZZly9ae9C79vFwqaO5kaOlI5q+3/55ohmq/7dpDyDfc8lYe7YVxJUZ5MF/NtbkRjwFRo14yM4OEo9EmDw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Collections.Concurrent": "4.3.0", - "System.Linq": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.OpenSsl": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "h4CEgOgv5PKVF/HwaHzJRiVboL2THYCou97zpmhjghx5frc7fIvlkY1jL+lnIQyChrJDMNEXS6r7byGif8Cy4w==", - "dependencies": { - "System.Collections": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Cryptography.Primitives": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "7bDIyVFNL/xKeFHjhobUAQqSpJq9YTOpbEs6mR233Et01STBMXNAc/V+BM6dwYGc95gVh/Zf+iVXWzj3mE8DWg==", - "dependencies": { - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Threading": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Security.Cryptography.ProtectedData": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "wLBKzFnDCxP12VL9ANydSYhk59fC4cvOr9ypYQLPnAj48NQIhqnjdD2yhP8yEKyBJEjERWS9DisKL7rX5eU25Q==" - }, - "System.Security.Cryptography.X509Certificates": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "t2Tmu6Y2NtJ2um0RtcuhP7ZdNNxXEgUm2JeoA/0NvlMjAhKCnM1NX07TDl3244mVp3QU6LPEhT3HTtH1uF7IYw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.Globalization.Calendars": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.Handles": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Runtime.Numerics": "4.3.0", - "System.Security.Cryptography.Algorithms": "4.3.0", - "System.Security.Cryptography.Cng": "4.3.0", - "System.Security.Cryptography.Csp": "4.3.0", - "System.Security.Cryptography.Encoding": "4.3.0", - "System.Security.Cryptography.OpenSsl": "4.3.0", - "System.Security.Cryptography.Primitives": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "runtime.native.System": "4.3.0", - "runtime.native.System.Net.Http": "4.3.0", - "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" - } - }, - "System.Security.Permissions": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "9gdyuARhUR7H+p5CjyUB/zPk7/Xut3wUSP8NJQB6iZr8L3XUXTMdoLeVAg9N4rqF8oIpE7MpdqHdDHQ7XgJe0g==", - "dependencies": { - "System.Security.AccessControl": "4.5.0" - } - }, - "System.Security.Principal.Windows": { - "type": "Transitive", - "resolved": "4.7.0", - "contentHash": "ojD0PX0XhneCsUbAZVKdb7h/70vyYMDYs85lwEI+LngEONe/17A0cFaRFqZU+sOEidcVswYWikYOQ9PPfjlbtQ==" - }, - "System.Text.Encoding": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Text.Encoding.Extensions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "YVMK0Bt/A43RmwizJoZ22ei2nmrhobgeiYwFzC4YAN+nue8RF6djXDMog0UCn+brerQoYVyaS+ghy9P/MUVcmw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0", - "System.Text.Encoding": "4.3.0" - } - }, - "System.Text.RegularExpressions": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "RpT2DA+L660cBt1FssIE9CAGpLFdFPuheB7pLpKpn6ZXNby7jDERe8Ua/Ne2xGiwLVG2JOqziiaVCGDon5sKFA==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.Threading": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", - "dependencies": { - "System.Runtime": "4.3.0", - "System.Threading.Tasks": "4.3.0" - } - }, - "System.Threading.Tasks": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", - "dependencies": { - "Microsoft.NETCore.Platforms": "1.1.0", - "Microsoft.NETCore.Targets": "1.1.0", - "System.Runtime": "4.3.0" - } - }, - "System.Threading.Tasks.Extensions": { - "type": "Transitive", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" - }, - "System.Threading.Thread": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "OHmbT+Zz065NKII/ZHcH9XO1dEuLGI1L2k7uYss+9C1jLxTC9kTZZuzUOyXHayRk+dft9CiDf3I/QZ0t8JKyBQ==", - "dependencies": { - "System.Runtime": "4.3.0" - } - }, - "System.Threading.ThreadPool": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "k/+g4b7vjdd4aix83sTgC9VG6oXYKAktSfNIJUNGxPEj7ryEOfzHHhfnmsZvjxawwcD9HyWXKCXmPjX8U4zeSw==", - "dependencies": { - "System.Runtime": "4.3.0", - "System.Runtime.Handles": "4.3.0" - } - }, - "System.Xml.ReaderWriter": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "GrprA+Z0RUXaR4N7/eW71j1rgMnEnEVlgii49GZyAjTH7uliMnrOU3HNFBr6fEDBCJCIdlVNq9hHbaDR621XBA==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.IO.FileSystem": "4.3.0", - "System.IO.FileSystem.Primitives": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Runtime.InteropServices": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Text.Encoding.Extensions": "4.3.0", - "System.Text.RegularExpressions": "4.3.0", - "System.Threading.Tasks": "4.3.0", - "System.Threading.Tasks.Extensions": "4.3.0" - } - }, - "System.Xml.XDocument": { - "type": "Transitive", - "resolved": "4.0.11", - "contentHash": "Mk2mKmPi0nWaoiYeotq1dgeNK1fqWh61+EK+w4Wu8SWuTYLzpUnschb59bJtGywaPq7SmTuPf44wrXRwbIrukg==", - "dependencies": { - "System.Collections": "4.0.11", - "System.Diagnostics.Debug": "4.0.11", - "System.Diagnostics.Tools": "4.0.1", - "System.Globalization": "4.0.11", - "System.IO": "4.1.0", - "System.Reflection": "4.1.0", - "System.Resources.ResourceManager": "4.0.1", - "System.Runtime": "4.1.0", - "System.Runtime.Extensions": "4.1.0", - "System.Text.Encoding": "4.0.11", - "System.Threading": "4.0.11", - "System.Xml.ReaderWriter": "4.0.11" - } - }, - "System.Xml.XmlDocument": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "lJ8AxvkX7GQxpC6GFCeBj8ThYVyQczx2+f/cWHJU8tjS7YfI6Cv6bon70jVEgs2CiFbmmM8b9j1oZVx0dSI2Ww==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Text.Encoding": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0" - } - }, - "System.Xml.XPath": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "v1JQ5SETnQusqmS3RwStF7vwQ3L02imIzl++sewmt23VGygix04pEH+FCj1yWb+z4GDzKiljr1W7Wfvrx0YwgA==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Diagnostics.Debug": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0" - } - }, - "System.Xml.XPath.XmlDocument": { - "type": "Transitive", - "resolved": "4.3.0", - "contentHash": "A/uxsWi/Ifzkmd4ArTLISMbfFs6XpRPsXZonrIqyTY70xi8t+mDtvSM5Os0RqyRDobjMBwIDHDL4NOIbkDwf7A==", - "dependencies": { - "System.Collections": "4.3.0", - "System.Globalization": "4.3.0", - "System.IO": "4.3.0", - "System.Resources.ResourceManager": "4.3.0", - "System.Runtime": "4.3.0", - "System.Runtime.Extensions": "4.3.0", - "System.Threading": "4.3.0", - "System.Xml.ReaderWriter": "4.3.0", - "System.Xml.XPath": "4.3.0", - "System.Xml.XmlDocument": "4.3.0" - } - }, - "ais.net.models": { - "type": "Project", - "dependencies": { - "Ais.Net": "[0.4.2, )" - } - } - } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais.Net.Models.csproj b/Solutions/Ais.Net.Models/Ais.Net.Models.csproj deleted file mode 100644 index 9fa6033..0000000 --- a/Solutions/Ais.Net.Models/Ais.Net.Models.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - net6.0 - latest - enable - True - - - - Apache-2.0 - .NET types and interfaces that describe AIS message types 1,2,3,5,18,19,24 Part 0, and 24 Part 1. These can be used on top of the high performance, zero allocation AIS.Net message decoder, which can process millions of AIVDM/AIVDO sentences per second on a single core. Sponsored by endjin. - ais;aisvdm;aivdo;nmea;marine;gis;iot;aiforearth;endjin - - - - - RCS1029;SA1313;SA1009;SA1600;SA1591;CS1591; - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisIsAssigned.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisIsAssigned.cs deleted file mode 100644 index 24d53be..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisIsAssigned.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisIsAssigned - { - bool IsAssigned { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisIsDteNotReady.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisIsDteNotReady.cs deleted file mode 100644 index 29bba87..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisIsDteNotReady.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisIsDteNotReady - { - bool IsDteNotReady { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessage.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessage.cs deleted file mode 100644 index 1be37c8..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessage.cs +++ /dev/null @@ -1,10 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMessage : IVesselIdentity, IAisMessageType - { - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType.cs deleted file mode 100644 index a7af2a9..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMessageType - { - int MessageType { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType18.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType18.cs deleted file mode 100644 index 850d750..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType18.cs +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMessageType18 - { - bool CanAcceptMessage22ChannelAssignment { get; } - - bool CanSwitchBands { get; } - - ClassBUnit CsUnit { get; } - - bool HasDisplay { get; } - - bool IsDscAttached { get; } - - ClassBRadioStatusType RadioStatusType { get; } - - int RegionalReserved139 { get; } - - int RegionalReserved38 { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType19.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType19.cs deleted file mode 100644 index 060994f..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType19.cs +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMessageType19 - { - int RegionalReserved139 { get; } - - int RegionalReserved38 { get; } - - string ShipName { get; } - - uint Spare308 { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType1to3.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType1to3.cs deleted file mode 100644 index 7652941..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType1to3.cs +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMessageType1to3 - { - ManoeuvreIndicator ManoeuvreIndicator { get; } - - NavigationStatus NavigationStatus { get; } - - uint RadioSlotTimeout { get; } - - uint RadioSubMessage { get; } - - RadioSyncState RadioSyncState { get; } - - int RateOfTurn { get; } - - uint SpareBits145 { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType24Part0.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType24Part0.cs deleted file mode 100644 index c6f0b19..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType24Part0.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMessageType24Part0 - { - uint Spare160 { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType24Part1.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType24Part1.cs deleted file mode 100644 index 245c601..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType24Part1.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMessageType24Part1 - { - uint MothershipMmsi { get; } - - uint SerialNumber { get; } - - uint Spare162 { get; } - - uint UnitModelCode { get; } - - string VendorIdRev3 { get; } - - string VendorIdRev4 { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType5.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType5.cs deleted file mode 100644 index c2cb755..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMessageType5.cs +++ /dev/null @@ -1,27 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMessageType5 - { - uint AisVersion { get; } - - string Destination { get; } - - uint Draught10thMetres { get; } - - uint EtaMonth { get; } - - uint EtaDay { get; } - - uint EtaHour { get; } - - uint EtaMinute { get; } - - uint ImoNumber { get; } - - uint Spare423 { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMultipartMessage.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMultipartMessage.cs deleted file mode 100644 index b9532e0..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisMultipartMessage.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisMultipartMessage - { - uint PartNumber { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisPositionFixType.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisPositionFixType.cs deleted file mode 100644 index 47215d8..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IAisPositionFixType.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IAisPositionFixType - { - EpfdFixType PositionFixType { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ICallSign.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ICallSign.cs deleted file mode 100644 index b71e756..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ICallSign.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface ICallSign - { - string CallSign { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IRaimFlag.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IRaimFlag.cs deleted file mode 100644 index 8c5527d..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IRaimFlag.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IRaimFlag - { - bool RaimFlag { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IRepeatIndicator.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IRepeatIndicator.cs deleted file mode 100644 index fba462a..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IRepeatIndicator.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IRepeatIndicator - { - uint RepeatIndicator { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IShipType.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IShipType.cs deleted file mode 100644 index 68ecf1e..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IShipType.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IShipType - { - ShipType ShipType { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselDimensions.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselDimensions.cs deleted file mode 100644 index b72d43f..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselDimensions.cs +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IVesselDimensions - { - uint DimensionToBow { get; } - - uint DimensionToPort { get; } - - uint DimensionToStarboard { get; } - - uint DimensionToStern { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselIdentity.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselIdentity.cs deleted file mode 100644 index f6e88b8..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselIdentity.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IVesselIdentity - { - uint Mmsi { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselName.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselName.cs deleted file mode 100644 index c81b9e9..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselName.cs +++ /dev/null @@ -1,11 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IVesselName - { - string VesselName { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselNavigation.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselNavigation.cs deleted file mode 100644 index 5578986..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/IVesselNavigation.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public interface IVesselNavigation - { - float? CourseOverGroundDegrees { get; } - - Position? Position { get; } - - bool PositionAccuracy { get; } - - float? SpeedOverGround { get; } - - uint TimeStampSecond { get; } - - uint TrueHeadingDegrees { get; } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/Position.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/Position.cs deleted file mode 100644 index 443423f..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/Position.cs +++ /dev/null @@ -1,12 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public record Position(double Latitude, double Longitude) - { - public static Position From10000thMins(int latitude, int longitude) => - new (latitude.From10000thMinsToDegrees(), longitude.From10000thMinsToDegrees()); - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ShipTypeCategory.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ShipTypeCategory.cs deleted file mode 100644 index bd49872..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ShipTypeCategory.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public enum ShipTypeCategory - { - NotAvailable = 0, - Reserved = 1, - WingInGround = 2, - SpecialCategory3 = 3, - HighSpeedCraft = 4, - SpecialCategory5 = 5, - Passenger = 6, - Cargo = 7, - Tanker = 8, - Other = 9 - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ShipTypeGroup.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ShipTypeGroup.cs deleted file mode 100644 index 8c48d8e..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/Abstractions/ShipTypeGroup.cs +++ /dev/null @@ -1,59 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models.Abstractions -{ - public enum ShipTypeGroup - { - NotAvailable, - Reserved, - WingInGroundAll, - WingInGroundHazardous, - WingInGroundReserved, - - Fishing, - Towing, - TowingLengthOver200OmrBreadthOver25m, - DredgingOrUnderwaterOps, - DivingOps, - MilitaryOps, - Sailing, - PleasureCraft, - - HighSpeedCraftAll, - HighSpeedCraftHazardous, - HighSpeedCraftReserved, - HighSpeedCraftNoAdditionalInformation, - - PilotVessel, - SearchAndRescueVessel, - Tug, - PortTender, - AntiPollutionEquipment, - LawEnforcement, - SpareLocalVessel, - MedicalTransport, - NoncombatantShip, - - PassengerAll, - PassengerHazardous, - PassengerReserved, - PassengerNoAdditionalInformation, - - CargoAll, - CargoHazardous, - CargoReserved, - CargoNoAdditionalInformation, - - TankerAll, - TankerHazardous, - TankerReserved, - TankerNoAdditionalInformation, - - OtherAll, - OtherHazardous, - OtherReserved, - OtherNoAdditionalInformation, - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageBase.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageBase.cs deleted file mode 100644 index f3dadf5..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageBase.cs +++ /dev/null @@ -1,10 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models -{ - using Ais.Net.Models.Abstractions; - - public record AisMessageBase(int MessageType, uint Mmsi) : IAisMessage; -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageExtensions.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageExtensions.cs deleted file mode 100644 index d85a1a2..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageExtensions.cs +++ /dev/null @@ -1,246 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models -{ - using System; - using System.Text; - using Ais.Net.Models.Abstractions; - - public static class AisMessageExtensions - { - public static double From10000thMinsToDegrees(this int value) - { - return value / 600000.0; - } - - public static float? FromTenths(this uint value) - { - return value == 1023 ? null : (value / 10.0f); - } - - public static float? FromTenthsToDegrees(this uint value) - { - return value == 3600 ? null : (value / 10.0f); - } - - public static string CleanVesselName(this string value) - { - return value.Trim('@').Trim().Replace(" ", " "); - } - - public static string GetString(this Span value) - { - return Encoding.ASCII.GetString(value); - } - - public static string TextFieldToString(this NmeaAisTextFieldParser field) - { - Span ascii = stackalloc byte[(int)field.CharacterCount]; - field.WriteAsAscii(ascii); - - return Encoding.ASCII.GetString(ascii); - } - - public static ShipTypeCategory ToShipTypeCategory(this ShipType shipType) - { - return shipType.ToShipTypeGroup().ToShipTypeCategory(); - } - - public static ShipTypeCategory ToShipTypeCategory(this ShipTypeGroup shipTypeGroup) - { - return shipTypeGroup switch - { - ShipTypeGroup.NotAvailable => ShipTypeCategory.NotAvailable, - ShipTypeGroup.Reserved => ShipTypeCategory.Reserved, - ShipTypeGroup.WingInGroundAll => ShipTypeCategory.WingInGround, - ShipTypeGroup.WingInGroundHazardous => ShipTypeCategory.WingInGround, - ShipTypeGroup.WingInGroundReserved => ShipTypeCategory.WingInGround, - ShipTypeGroup.Fishing => ShipTypeCategory.SpecialCategory3, - ShipTypeGroup.Towing => ShipTypeCategory.SpecialCategory3, - ShipTypeGroup.TowingLengthOver200OmrBreadthOver25m => ShipTypeCategory.SpecialCategory3, - ShipTypeGroup.DredgingOrUnderwaterOps => ShipTypeCategory.SpecialCategory3, - ShipTypeGroup.DivingOps => ShipTypeCategory.SpecialCategory3, - ShipTypeGroup.MilitaryOps => ShipTypeCategory.SpecialCategory3, - ShipTypeGroup.Sailing => ShipTypeCategory.SpecialCategory3, - ShipTypeGroup.PleasureCraft => ShipTypeCategory.SpecialCategory3, - ShipTypeGroup.HighSpeedCraftAll => ShipTypeCategory.HighSpeedCraft, - ShipTypeGroup.HighSpeedCraftHazardous => ShipTypeCategory.HighSpeedCraft, - ShipTypeGroup.HighSpeedCraftReserved => ShipTypeCategory.HighSpeedCraft, - ShipTypeGroup.HighSpeedCraftNoAdditionalInformation => ShipTypeCategory.HighSpeedCraft, - ShipTypeGroup.PilotVessel => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.SearchAndRescueVessel => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.Tug => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.PortTender => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.AntiPollutionEquipment => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.LawEnforcement => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.SpareLocalVessel => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.MedicalTransport => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.NoncombatantShip => ShipTypeCategory.SpecialCategory5, - ShipTypeGroup.PassengerAll => ShipTypeCategory.Passenger, - ShipTypeGroup.PassengerHazardous => ShipTypeCategory.Passenger, - ShipTypeGroup.PassengerReserved => ShipTypeCategory.Passenger, - ShipTypeGroup.PassengerNoAdditionalInformation => ShipTypeCategory.Passenger, - ShipTypeGroup.CargoAll => ShipTypeCategory.Cargo, - ShipTypeGroup.CargoHazardous => ShipTypeCategory.Cargo, - ShipTypeGroup.CargoReserved => ShipTypeCategory.Cargo, - ShipTypeGroup.CargoNoAdditionalInformation => ShipTypeCategory.Cargo, - ShipTypeGroup.TankerAll => ShipTypeCategory.Tanker, - ShipTypeGroup.TankerHazardous => ShipTypeCategory.Tanker, - ShipTypeGroup.TankerReserved => ShipTypeCategory.Tanker, - ShipTypeGroup.TankerNoAdditionalInformation => ShipTypeCategory.Tanker, - ShipTypeGroup.OtherAll => ShipTypeCategory.Other, - ShipTypeGroup.OtherHazardous => ShipTypeCategory.Other, - ShipTypeGroup.OtherReserved => ShipTypeCategory.Other, - ShipTypeGroup.OtherNoAdditionalInformation => ShipTypeCategory.Other, - _ => ShipTypeCategory.NotAvailable, - }; - } - - public static string ToShipTypeDescription(this int shipType) - { - switch (shipType) - { - case 0: goto default; - case >= 1 and <= 19: return "Reserved for future use"; - case 20: return "Wing in ground(WIG), all ships of this type"; - case 21: return "Wing in ground(WIG), Hazardous category A"; - case 22: return "Wing in ground(WIG), Hazardous category B"; - case 23: return "Wing in ground(WIG), Hazardous category C"; - case 24: return "Wing in ground(WIG), Hazardous category D"; - case 25: return "Wing in ground(WIG), Reserved for future use"; - case 26: return "Wing in ground(WIG), Reserved for future use"; - case 27: return "Wing in ground(WIG), Reserved for future use"; - case 28: return "Wing in ground(WIG), Reserved for future use"; - case 29: return "Wing in ground(WIG), Reserved for future use"; - case 30: return "Fishing"; - case 31: return "Towing"; - case 32: return "Towing: length exceeds 200m or breadth exceeds 25m"; - case 33: return "Dredging or underwater ops"; - case 34: return "Diving ops"; - case 35: return "Military ops"; - case 36: return "Sailing"; - case 37: return "Pleasure Craft"; - case 38: return "Reserved"; - case 39: return "Reserved"; - case 40: return "High speed craft(HSC), all ships of this type"; - case 41: return "High speed craft(HSC), Hazardous category A"; - case 42: return "High speed craft(HSC), Hazardous category B"; - case 43: return "High speed craft(HSC), Hazardous category C"; - case 44: return "High speed craft(HSC), Hazardous category D"; - case 45: return "High speed craft(HSC), Reserved for future use"; - case 46: return "High speed craft(HSC), Reserved for future use"; - case 47: return "High speed craft(HSC), Reserved for future use"; - case 48: return "High speed craft(HSC), Reserved for future use"; - case 49: return "High speed craft(HSC), No additional information"; - case 50: return "Pilot Vessel"; - case 51: return "Search and Rescue vessel"; - case 52: return "Tug"; - case 53: return "Port Tender"; - case 54: return "Anti - pollution equipment"; - case 55: return "Law Enforcement"; - case 56: return "Spare - Local Vessel"; - case 57: return "Spare - Local Vessel"; - case 58: return "Medical Transport"; - case 59: return "Noncombatant ship according to RR Resolution No. 18"; - case 60: return "Passenger, all ships of this type"; - case 61: return "Passenger, Hazardous category A"; - case 62: return "Passenger, Hazardous category B"; - case 63: return "Passenger, Hazardous category C"; - case 64: return "Passenger, Hazardous category D"; - case 65: return "Passenger, Reserved for future use"; - case 66: return "Passenger, Reserved for future use"; - case 67: return "Passenger, Reserved for future use"; - case 68: return "Passenger, Reserved for future use"; - case 69: return "Passenger, No additional information"; - case 70: return "Cargo, all ships of this type"; - case 71: return "Cargo, Hazardous category A"; - case 72: return "Cargo, Hazardous category B"; - case 73: return "Cargo, Hazardous category C"; - case 74: return "Cargo, Hazardous category D"; - case 75: return "Cargo, Reserved for future use"; - case 76: return "Cargo, Reserved for future use"; - case 77: return "Cargo, Reserved for future use"; - case 78: return "Cargo, Reserved for future use"; - case 79: return "Cargo, No additional information"; - case 80: return "Tanker, all ships of this type"; - case 81: return "Tanker, Hazardous category A"; - case 82: return "Tanker, Hazardous category B"; - case 83: return "Tanker, Hazardous category C"; - case 84: return "Tanker, Hazardous category D"; - case 85: return "Tanker, Reserved for future use"; - case 86: return "Tanker, Reserved for future use"; - case 87: return "Tanker, Reserved for future use"; - case 88: return "Tanker, Reserved for future use"; - case 89: return "Tanker, No additional information"; - case 90: return "Other Type, all ships of this type"; - case 91: return "Other Type, Hazardous category A"; - case 92: return "Other Type, Hazardous category B"; - case 93: return "Other Type, Hazardous category C"; - case 94: return "Other Type, Hazardous category D"; - case 95: return "Other Type, Reserved for future use"; - case 96: return "Other Type, Reserved for future use"; - case 97: return "Other Type, Reserved for future use"; - case 98: return "Other Type, Reserved for future use"; - case 99: return "Other Type, no additional information"; - default: return "Not available"; - } - } - - public static ShipTypeGroup ToShipTypeGroup(this ShipType shipType) - { - return ToShipTypeGroup((int)shipType); - } - - public static ShipTypeGroup ToShipTypeGroup(this int shipType) - { - switch (shipType) - { - case 0: goto default; - case >= 1 and <= 19: return ShipTypeGroup.Reserved; - case 20: return ShipTypeGroup.WingInGroundAll; - case >= 21 and <= 24: return ShipTypeGroup.WingInGroundHazardous; - case >= 25 and <= 29: return ShipTypeGroup.WingInGroundReserved; - case 30: return ShipTypeGroup.Fishing; - case 31: return ShipTypeGroup.Towing; - case 32: return ShipTypeGroup.TowingLengthOver200OmrBreadthOver25m; - case 33: return ShipTypeGroup.DredgingOrUnderwaterOps; - case 34: return ShipTypeGroup.DivingOps; - case 35: return ShipTypeGroup.MilitaryOps; - case 36: return ShipTypeGroup.Sailing; - case 37: return ShipTypeGroup.PleasureCraft; - case >= 38 and <= 39: return ShipTypeGroup.Reserved; - case 40: return ShipTypeGroup.HighSpeedCraftAll; - case >= 41 and <= 44: return ShipTypeGroup.HighSpeedCraftHazardous; - case >= 45 and <= 49: return ShipTypeGroup.HighSpeedCraftReserved; - case 50: return ShipTypeGroup.PilotVessel; - case 51: return ShipTypeGroup.SearchAndRescueVessel; - case 52: return ShipTypeGroup.Tug; - case 53: return ShipTypeGroup.PortTender; - case 54: return ShipTypeGroup.AntiPollutionEquipment; - case 55: return ShipTypeGroup.LawEnforcement; - case >= 56 and <= 57: return ShipTypeGroup.SpareLocalVessel; - case 58: return ShipTypeGroup.MedicalTransport; - case 59: return ShipTypeGroup.NoncombatantShip; - case 60: return ShipTypeGroup.PassengerAll; - case >= 61 and <= 64: return ShipTypeGroup.PassengerHazardous; - case >= 65 and <= 68: return ShipTypeGroup.PassengerReserved; - case 69: return ShipTypeGroup.PassengerNoAdditionalInformation; - case 70: return ShipTypeGroup.CargoAll; - case >= 71 and <= 74: return ShipTypeGroup.CargoHazardous; - case >= 75 and <= 78: return ShipTypeGroup.CargoReserved; - case 79: return ShipTypeGroup.CargoNoAdditionalInformation; - case 80: return ShipTypeGroup.TankerAll; - case >= 81 and <= 84: return ShipTypeGroup.TankerHazardous; - case >= 85 and <= 88: return ShipTypeGroup.TankerReserved; - case 89: return ShipTypeGroup.TankerNoAdditionalInformation; - case 90: return ShipTypeGroup.OtherAll; - case >= 91 and <= 94: return ShipTypeGroup.OtherHazardous; - case >= 95 and <= 98: return ShipTypeGroup.OtherReserved; - case 99: return ShipTypeGroup.OtherNoAdditionalInformation; - default: return ShipTypeGroup.NotAvailable; - } - } - } -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType18.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType18.cs deleted file mode 100644 index d5ec527..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType18.cs +++ /dev/null @@ -1,34 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models -{ - using Ais.Net.Models.Abstractions; - - public record AisMessageType18( - bool CanAcceptMessage22ChannelAssignment, - bool CanSwitchBands, - float? CourseOverGroundDegrees, - ClassBUnit CsUnit, - bool HasDisplay, - bool IsAssigned, - bool IsDscAttached, - uint Mmsi, - Position? Position, - bool PositionAccuracy, - ClassBRadioStatusType RadioStatusType, - bool RaimFlag, - int RegionalReserved139, - int RegionalReserved38, - uint RepeatIndicator, - float? SpeedOverGround, - uint TimeStampSecond, - uint TrueHeadingDegrees) : - AisMessageBase(MessageType: 18, Mmsi), - IAisMessageType18, - IAisIsAssigned, - IRaimFlag, - IRepeatIndicator, - IVesselNavigation; -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType19.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType19.cs deleted file mode 100644 index 45f2796..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType19.cs +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models -{ - using Ais.Net.Models.Abstractions; - - public record AisMessageType19( - float? CourseOverGroundDegrees, - uint DimensionToBow, - uint DimensionToPort, - uint DimensionToStarboard, - uint DimensionToStern, - bool IsAssigned, - bool IsDteNotReady, - uint Mmsi, - Position? Position, - bool PositionAccuracy, - EpfdFixType PositionFixType, - bool RaimFlag, - int RegionalReserved139, - int RegionalReserved38, - uint RepeatIndicator, - string ShipName, - ShipType ShipType, - uint Spare308, - float? SpeedOverGround, - uint TimeStampSecond, - uint TrueHeadingDegrees) : - AisMessageBase(MessageType: 19, Mmsi), - IAisMessageType19, - IAisIsAssigned, - IAisIsDteNotReady, - IAisPositionFixType, - IRaimFlag, - IRepeatIndicator, - IShipType, - IVesselDimensions, - IVesselNavigation; -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType1Through3.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType1Through3.cs deleted file mode 100644 index 718431c..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType1Through3.cs +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models -{ - using Ais.Net.Models.Abstractions; - - public record AisMessageType1Through3( - float? CourseOverGroundDegrees, - ManoeuvreIndicator ManoeuvreIndicator, - int MessageType, - uint Mmsi, - NavigationStatus NavigationStatus, - Position? Position, - bool PositionAccuracy, - uint RadioSlotTimeout, - uint RadioSubMessage, - RadioSyncState RadioSyncState, - int RateOfTurn, - bool RaimFlag, - uint RepeatIndicator, - uint SpareBits145, - float? SpeedOverGround, - uint TimeStampSecond, - uint TrueHeadingDegrees) : - AisMessageBase(MessageType, Mmsi), - IAisMessageType1to3, - IRaimFlag, - IRepeatIndicator, - IVesselNavigation; -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part0.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part0.cs deleted file mode 100644 index d57748b..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part0.cs +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models -{ - using Ais.Net.Models.Abstractions; - - public record AisMessageType24Part0( - uint Mmsi, - uint PartNumber, - uint RepeatIndicator, - uint Spare160) : - AisMessageBase(MessageType: 24, Mmsi), - IAisMultipartMessage, - IRepeatIndicator, - IAisMessageType24Part0; -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part1.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part1.cs deleted file mode 100644 index 86bc85d..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType24Part1.cs +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models -{ - using Ais.Net.Models.Abstractions; - - public record AisMessageType24Part1( - string CallSign, - uint DimensionToBow, - uint DimensionToPort, - uint DimensionToStarboard, - uint DimensionToStern, - uint Mmsi, - uint MothershipMmsi, - uint PartNumber, - uint RepeatIndicator, - uint SerialNumber, - uint Spare162, - ShipType ShipType, - uint UnitModelCode, - string VendorIdRev3, - string VendorIdRev4) : - AisMessageBase(MessageType: 24, Mmsi), - IAisMessageType24Part1, - IAisMultipartMessage, - ICallSign, - IRepeatIndicator, - IShipType, - IVesselDimensions; -} \ No newline at end of file diff --git a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType5.cs b/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType5.cs deleted file mode 100644 index a9c2d19..0000000 --- a/Solutions/Ais.Net.Models/Ais/Net/Models/AisMessageType5.cs +++ /dev/null @@ -1,39 +0,0 @@ -// -// Copyright (c) Endjin Limited. All rights reserved. -// - -namespace Ais.Net.Models -{ - using Ais.Net.Models.Abstractions; - - public record AisMessageType5( - uint AisVersion, - string CallSign, - string Destination, - uint DimensionToBow, - uint DimensionToPort, - uint DimensionToStarboard, - uint DimensionToStern, - uint Draught10thMetres, - uint EtaDay, - uint EtaHour, - uint EtaMinute, - uint EtaMonth, - bool IsDteNotReady, - uint ImoNumber, - uint Mmsi, - EpfdFixType PositionFixType, - uint RepeatIndicator, - ShipType ShipType, - uint Spare423, - string VesselName) : - AisMessageBase(MessageType: 5, Mmsi), - IAisMessageType5, - IAisIsDteNotReady, - IAisPositionFixType, - ICallSign, - IRepeatIndicator, - IShipType, - IVesselDimensions, - IVesselName; -} diff --git a/Solutions/Ais.Net.Receiver.Host.Console.RaspberryPi/aisr.service b/Solutions/Ais.Net.Receiver.Host.Console.RaspberryPi/aisr.service index 174d487..a68ece7 100644 --- a/Solutions/Ais.Net.Receiver.Host.Console.RaspberryPi/aisr.service +++ b/Solutions/Ais.Net.Receiver.Host.Console.RaspberryPi/aisr.service @@ -1,10 +1,14 @@ [Unit] Description=aisr After=multi-user.target + StartLimitIntervalSec=500 + StartLimitBurst=5 [Service] Type=idle ExecStart=/home/pi/.dotnet/dotnet /home/pi/aisr/Ais.Net.Receiver.Host.Console.dll + Restart=on-failure + RestartSec=5s [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver.Host.Console/Ais.Net.Receiver.Host.Console.csproj b/Solutions/Ais.Net.Receiver.Host.Console/Ais.Net.Receiver.Host.Console.csproj index 9fe636e..720b2f3 100644 --- a/Solutions/Ais.Net.Receiver.Host.Console/Ais.Net.Receiver.Host.Console.csproj +++ b/Solutions/Ais.Net.Receiver.Host.Console/Ais.Net.Receiver.Host.Console.csproj @@ -4,7 +4,7 @@ Exe - net6.0 + net8.0 latest enable false @@ -15,19 +15,22 @@ true + + RCS1029;SA1200;SA1313;SA1009;SA1600;SA1591;CS1591; + + - - - - - - - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Solutions/Ais.Net.Receiver.Host.Console/Ais/Net/Receiver/Host/Console/Program.cs b/Solutions/Ais.Net.Receiver.Host.Console/Ais/Net/Receiver/Host/Console/Program.cs index e47841b..0aa7c37 100644 --- a/Solutions/Ais.Net.Receiver.Host.Console/Ais/Net/Receiver/Host/Console/Program.cs +++ b/Solutions/Ais.Net.Receiver.Host.Console/Ais/Net/Receiver/Host/Console/Program.cs @@ -2,112 +2,119 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Host.Console +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using System.Threading.Tasks.Dataflow; + +using Ais.Net.Models; +using Ais.Net.Models.Abstractions; +using Ais.Net.Receiver.Configuration; +using Ais.Net.Receiver.Receiver; +using Ais.Net.Receiver.Storage; +using Ais.Net.Receiver.Storage.Azure.Blob; +using Ais.Net.Receiver.Storage.Azure.Blob.Configuration; + +using Microsoft.Extensions.Configuration; + +namespace Ais.Net.Receiver.Host.Console; + +/// +/// Host application for the . +/// +public static class Program { - using System; - using System.Collections.Generic; - using System.Threading; - using System.Threading.Tasks; - using System.Threading.Tasks.Dataflow; - - using Ais.Net.Models; - using Ais.Net.Models.Abstractions; - using Ais.Net.Receiver.Configuration; - using Ais.Net.Receiver.Receiver; - using Ais.Net.Receiver.Storage; - using Ais.Net.Receiver.Storage.Azure.Blob; - using Ais.Net.Receiver.Storage.Azure.Blob.Configuration; - - using Microsoft.Extensions.Configuration; - /// - /// Host application for the . + /// Entry point for the application. /// - public static class Program + /// Task representing the operation. + public static async Task Main() { - /// - /// Entry point for the application. - /// - /// Task representing the operation. - public static async Task Main() + IConfiguration config = new ConfigurationBuilder() + .AddJsonFile("settings.json", true, true) + .AddJsonFile("settings.local.json", true, true) + .Build(); + + AisConfig? aisConfig = config.GetSection("Ais").Get(); + StorageConfig? storageConfig = config.GetSection("Storage").Get(); + + if (aisConfig is null || storageConfig is null) { - IConfiguration config = new ConfigurationBuilder() - .AddJsonFile("settings.json", true, true) - .AddJsonFile("settings.local.json", true, true) - .Build(); + throw new InvalidOperationException("Configuration is invalid."); + } - AisConfig aisConfig = config.GetSection("Ais").Get(); - StorageConfig storageConfig = config.GetSection("Storage").Get(); + INmeaReceiver receiver = new NetworkStreamNmeaReceiver( + aisConfig.Host, + aisConfig.Port, + aisConfig.RetryPeriodicity, + retryAttemptLimit: aisConfig.RetryAttempts); - INmeaReceiver receiver = new NetworkStreamNmeaReceiver( - aisConfig.Host, - aisConfig.Port, - aisConfig.RetryPeriodicity, - aisConfig.RetryAttempts); + // If you wanted to run from a captured stream uncomment this line: - // If you wanted to run from a captured stream uncomment this line: - /*INmeaReceiver receiver = new FileStreamNmeaReceiver(@"PATH-TO-RECORDING.nm4");*/ + /* + INmeaReceiver receiver = new FileStreamNmeaReceiver(@"PATH-TO-RECORDING.nm4"); + */ - var receiverHost = new ReceiverHost(receiver); + ReceiverHost receiverHost = new(receiver); - if (aisConfig.LoggerVerbosity == LoggerVerbosity.Minimal) - { - receiverHost.GetStreamStatistics(aisConfig.StatisticsPeriodicity) - .Subscribe(statistics => Console.WriteLine($"{DateTime.UtcNow.ToUniversalTime()}: Sentences: {statistics.Sentence} | Messages: {statistics.Message} | Errors: {statistics.Error}")); - } + if (aisConfig.LoggerVerbosity == LoggerVerbosity.Minimal) + { + receiverHost.GetStreamStatistics(aisConfig.StatisticsPeriodicity) + .Subscribe(statistics => System.Console.WriteLine($"{DateTime.UtcNow.ToUniversalTime()}: Sentences: {statistics.Sentence} | Messages: {statistics.Message} | Errors: {statistics.Error}")); + } - if (aisConfig.LoggerVerbosity == LoggerVerbosity.Normal) - { - receiverHost.Messages.VesselNavigationWithNameStream().Subscribe(navigationWithName => - { - (uint mmsi, IVesselNavigation navigation, IVesselName name) = navigationWithName; - string positionText = navigation.Position is null ? "unknown position" : $"{navigation.Position.Latitude},{navigation.Position.Longitude}"; - - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"[{mmsi}: '{name.VesselName.CleanVesselName()}'] - [{positionText}] - [{navigation.CourseOverGroundDegrees ?? 0}]"); - Console.ResetColor(); - }); - } - - if (aisConfig.LoggerVerbosity == LoggerVerbosity.Detailed) + if (aisConfig.LoggerVerbosity == LoggerVerbosity.Normal) + { + receiverHost.Messages.VesselNavigationWithNameStream().Subscribe(navigationWithName => { - // Write out the messages as they are received over the wire. - receiverHost.Sentences.Subscribe(Console.WriteLine); - } + (uint mmsi, IVesselNavigation navigation, IVesselName name) = navigationWithName; + string positionText = navigation.Position is null ? "unknown position" : $"{navigation.Position.Latitude},{navigation.Position.Longitude}"; - if (aisConfig.LoggerVerbosity == LoggerVerbosity.Diagnostic) - { - receiverHost.Messages.Subscribe(Console.WriteLine); - - // Write out errors in the console - receiverHost.Errors.Subscribe(error => - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine($"Error received: {error.Exception.Message}"); - Console.WriteLine($"Bad line: {error.Line}"); - Console.ResetColor(); - }); - } - - if (storageConfig.EnableCapture) - { - IStorageClient storageClient = new AzureAppendBlobStorageClient(storageConfig); - var batchBlock = new BatchBlock(storageConfig.WriteBatchSize); - var actionBlock = new ActionBlock>(storageClient.PersistAsync); - batchBlock.LinkTo(actionBlock); + System.Console.ForegroundColor = ConsoleColor.Green; + System.Console.WriteLine($"[{mmsi}: '{name.VesselName.CleanVesselName()}'] - [{positionText}] - [{navigation.CourseOverGroundDegrees ?? 0}]"); + System.Console.ResetColor(); + }); + } - // Persist the messages as they are received over the wire. - receiverHost.Sentences.Subscribe(batchBlock.AsObserver()); - } + if (aisConfig.LoggerVerbosity == LoggerVerbosity.Detailed) + { + // Write out the messages as they are received over the wire. + receiverHost.Sentences.Subscribe(System.Console.WriteLine); + } - var cts = new CancellationTokenSource(); + if (aisConfig.LoggerVerbosity == LoggerVerbosity.Diagnostic) + { + receiverHost.Messages.Subscribe(System.Console.WriteLine); - Task task = receiverHost.StartAsync(cts.Token); + // Write out errors in the console + receiverHost.Errors.Subscribe(error => + { + System.Console.ForegroundColor = ConsoleColor.Red; + System.Console.WriteLine($"Error received: {error.Exception.Message}"); + System.Console.WriteLine($"Bad line: {error.Line}"); + System.Console.ResetColor(); + }); + } - // If you wanted to cancel the long running process: - /* cts.Cancel(); */ + if (storageConfig.EnableCapture) + { + IStorageClient storageClient = new AzureAppendBlobStorageClient(storageConfig); + BatchBlock batchBlock = new(storageConfig.WriteBatchSize); + ActionBlock> actionBlock = new(storageClient.PersistAsync); + batchBlock.LinkTo(actionBlock); - await task; + // Persist the messages as they are received over the wire. + receiverHost.Sentences.Subscribe(batchBlock.AsObserver()); } + + CancellationTokenSource cts = new(); + + Task task = receiverHost.StartAsync(cts.Token); + + // If you wanted to cancel the long-running process: + /* cts.Cancel(); */ + + await task; } } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver.Host.Console/Ais/Net/Receiver/Host/Console/ReceiverHostExtensions.cs b/Solutions/Ais.Net.Receiver.Host.Console/Ais/Net/Receiver/Host/Console/ReceiverHostExtensions.cs index be37039..88fc43f 100644 --- a/Solutions/Ais.Net.Receiver.Host.Console/Ais/Net/Receiver/Host/Console/ReceiverHostExtensions.cs +++ b/Solutions/Ais.Net.Receiver.Host.Console/Ais/Net/Receiver/Host/Console/ReceiverHostExtensions.cs @@ -2,73 +2,71 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Host.Console -{ - using System; - using System.Linq; - using System.Reactive.Linq; - using Ais.Net.Models.Abstractions; - using Ais.Net.Receiver.Receiver; +using System; +using System.Reactive.Linq; +using Ais.Net.Models.Abstractions; +using Ais.Net.Receiver.Receiver; + +namespace Ais.Net.Receiver.Host.Console; +/// +/// Extensions for the and its data streams. +/// +public static class ReceiverHostExtensions +{ /// - /// Extensions for the and its data streams. + /// Calculates statistics about the number of , and + /// generated during the specified . /// - public static class ReceiverHostExtensions + /// The to extend. + /// The duration statistics should be collected for, before returning. + /// An observable sequence of tuple containing statistics. + public static IObservable<(long Message, long Sentence, long Error)> GetStreamStatistics(this ReceiverHost receiverHost, TimeSpan period) { - /// - /// Calculates statistics about the number of , and - /// generated during the specified . - /// - /// The to extend. - /// The duration statistics should be collected for, before returning. - /// An observable sequence of tuple containing statistics. - public static IObservable<(long Message, long Sentence, long Error)> GetStreamStatistics(this ReceiverHost receiverHost, TimeSpan period) - { - IObservable<(long Messages, long Sentences, long Errors)> runningCounts = - receiverHost.Messages.RunningCount().CombineLatest( - receiverHost.Sentences.RunningCount(), - receiverHost.Errors.RunningCount(), - (messages, sentences, errors) => (messages, sentences, errors)); + IObservable<(long Messages, long Sentences, long Errors)> runningCounts = + receiverHost.Messages.RunningCount().CombineLatest( + receiverHost.Sentences.RunningCount(), + receiverHost.Errors.RunningCount(), + (messages, sentences, errors) => (messages, sentences, errors)); - return runningCounts.Buffer(period) - .Select(window => (window[0], window[^1])) - .Select<((long, long, long), (long, long, long)), (long, long, long)>( - (((long Messages, long Sentences, long Errors) First, - (long Messages, long Sentences, long Errors) Last) pair) - => (pair.Last.Messages - pair.First.Messages, - pair.Last.Sentences - pair.First.Sentences, - pair.Last.Errors - pair.First.Errors)); - } + return runningCounts.Buffer(period) + .Select(window => (window[0], window[^1])) + .Select<((long, long, long), (long, long, long)), (long, long, long)>( + (((long Messages, long Sentences, long Errors) First, + (long Messages, long Sentences, long Errors) Last) pair) + => (pair.Last.Messages - pair.First.Messages, + pair.Last.Sentences - pair.First.Sentences, + pair.Last.Errors - pair.First.Errors)); + } - /// - /// Groups and combines the AIS Messages so that vessel name and navigation information can be displayed. - /// - /// An observable stream of AIS Messages. - /// An observable sequence of tuple containing vessel information. - public static IObservable<(uint Mmsi, IVesselNavigation Navigation, IVesselName Name)> VesselNavigationWithNameStream(this IObservable messages) - { - // Decode the sentences into messages, and group by the vessel by Id - IObservable> byVessel = messages.GroupBy(m => m.Mmsi); + /// + /// Groups and combines the AIS Messages so that vessel name and navigation information can be displayed. + /// + /// An observable stream of AIS Messages. + /// An observable sequence of tuple containing vessel information. + public static IObservable<(uint Mmsi, IVesselNavigation Navigation, IVesselName Name)> VesselNavigationWithNameStream(this IObservable messages) + { + // Decode the sentences into messages, and group by the vessel by Id + IObservable> byVessel = messages.GroupBy(m => m.Mmsi); - // Combine the various message types required to create a stream containing name and navigation - return - from perVesselMessages in byVessel - let vesselNavigationUpdates = perVesselMessages.OfType() - let vesselNames = perVesselMessages.OfType() - let vesselLocationsWithNames = vesselNavigationUpdates.CombineLatest(vesselNames, (navigation, name) => (navigation, name)) - from vesselLocationAndName in vesselLocationsWithNames - select (Mmsi: perVesselMessages.Key, vesselLocationAndName.navigation, vesselLocationAndName.name); - } + // Combine the various message types required to create a stream containing name and navigation + return + from perVesselMessages in byVessel + let vesselNavigationUpdates = perVesselMessages.OfType() + let vesselNames = perVesselMessages.OfType() + let vesselLocationsWithNames = vesselNavigationUpdates.CombineLatest(vesselNames, (navigation, name) => (navigation, name)) + from vesselLocationAndName in vesselLocationsWithNames + select (Mmsi: perVesselMessages.Key, vesselLocationAndName.navigation, vesselLocationAndName.name); + } - /// - /// Provides a running count of events provided by an observable stream. - /// - /// Type of events to count. - /// Observable stream of events to count. - /// An observable sequence representing the count of events. - private static IObservable RunningCount(this IObservable eventsForCount) - { - return eventsForCount.Scan(0L, (total, _) => total + 1); - } + /// + /// Provides a running count of events provided by an observable stream. + /// + /// Type of events to count. + /// Observable stream of events to count. + /// An observable sequence representing the count of events. + private static IObservable RunningCount(this IObservable eventsForCount) + { + return eventsForCount.Scan(0L, (total, _) => total + 1); } } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver.Host.Console/packages.lock.json b/Solutions/Ais.Net.Receiver.Host.Console/packages.lock.json index 6b11016..10b03ff 100644 --- a/Solutions/Ais.Net.Receiver.Host.Console/packages.lock.json +++ b/Solutions/Ais.Net.Receiver.Host.Console/packages.lock.json @@ -1,295 +1,286 @@ -{ - "version": 1, - "dependencies": { - "net6.0": { - "Endjin.RecommendedPractices.GitHub": { - "type": "Direct", - "requested": "[2.1.2, )", - "resolved": "2.1.2", - "contentHash": "mBUCmeSdWWrIQKuuYd9zflcwupRDmpF39dsbb07e6azlNIQqaE1J5TQa17c3SFVRXn9IZrClsmKoMporRTAWwQ==", - "dependencies": { - "Endjin.RecommendedPractices": "2.1.2", - "Microsoft.SourceLink.GitHub": "1.1.1" - } - }, - "Microsoft.Extensions.Configuration": { - "type": "Direct", - "requested": "[6.0.*, )", - "resolved": "6.0.1", - "contentHash": "BUyFU9t+HzlSE7ri4B+AQN2BgTgHv/uM82s5ZkgU1BApyzWzIl48nDsG5wR1t0pniNuuyTBzG3qCW8152/NtSw==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "Direct", - "requested": "[6.0.*, )", - "resolved": "6.0.0", - "contentHash": "b3ErKzND8LIC7o08QAVlKfaEIYEvLJbtmVbFZVBRXeu9YkKfSSzLZfR1SUfQPBIy9mKLhEtJgGYImkcMNaKE0A==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.FileExtensions": { - "type": "Direct", - "requested": "[6.0.*, )", - "resolved": "6.0.0", - "contentHash": "V4Dth2cYMZpw3HhGw9XUDIijpI6gN+22LDt0AhufIgOppCUfpWX4483OmN+dFXRJkJLc8Tv0Q8QK+1ingT2+KQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileProviders.Physical": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.Configuration.Json": { - "type": "Direct", - "requested": "[6.0.*, )", - "resolved": "6.0.0", - "contentHash": "GJGery6QytCzS/BxJ96klgG9in3uH26KcUBbiVG/coNDXCRq6LGVVlUT4vXq34KPuM+R2av+LeYdX9h4IZOCUg==", - "dependencies": { - "Microsoft.Extensions.Configuration": "6.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "6.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "6.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "System.Text.Json": "6.0.0" - } - }, - "Roslynator.Analyzers": { - "type": "Direct", - "requested": "[4.1.1, )", - "resolved": "4.1.1", - "contentHash": "3cPVlrB1PytlO1ztZZBOExDKQWpMZgI15ZDa0BqLu0l6xv+xIRfEpqjNRcpvUy3aLxWTkPgSKZbbaO+VoFEJ1g==" - }, - "StyleCop.Analyzers": { - "type": "Direct", - "requested": "[1.2.0-beta.435, )", - "resolved": "1.2.0-beta.435", - "contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==", - "dependencies": { - "StyleCop.Analyzers.Unstable": "1.2.0.435" - } - }, - "System.Threading.Tasks.Dataflow": { - "type": "Direct", - "requested": "[6.0.*, )", - "resolved": "6.0.0", - "contentHash": "+tyDCU3/B1lDdOOAJywHQoFwyXIUghIaP2BxG79uvhfTnO+D9qIgjVlL/JV2NTliYbMHpd6eKDmHp2VHpij7MA==" - }, - "Ais.Net": { - "type": "Transitive", - "resolved": "0.4.2", - "contentHash": "+wtx8g0YwxEaDbilf4MiED9S4Yxr9J7RHAAMEN48+yB0it10KYdhmtB6dxt7qdCOvdoDnBOumggcGYefWMz+WA==", - "dependencies": { - "System.IO.Pipelines": "4.7.4" - } - }, - "Azure.Core": { - "type": "Transitive", - "resolved": "1.25.0", - "contentHash": "X8Dd4sAggS84KScWIjEbFAdt2U1KDolQopTPoHVubG2y3CM54f9l6asVrP5Uy384NWXjsspPYaJgz5xHc+KvTA==", - "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "1.1.1", - "System.Diagnostics.DiagnosticSource": "4.6.0", - "System.Memory.Data": "1.0.2", - "System.Numerics.Vectors": "4.5.0", - "System.Text.Encodings.Web": "4.7.2", - "System.Text.Json": "4.7.2", - "System.Threading.Tasks.Extensions": "4.5.4" - } - }, - "Azure.Storage.Blobs": { - "type": "Transitive", - "resolved": "12.14.1", - "contentHash": "DvRBWUDMB2LjdRbsBNtz/LiVIYk56hqzSooxx4uq4rCdLj2M+7Vvoa1r+W35Dz6ZXL6p+SNcgEae3oZ+CkPfow==", - "dependencies": { - "Azure.Storage.Common": "12.13.0", - "System.Text.Json": "4.7.2" - } - }, - "Azure.Storage.Common": { - "type": "Transitive", - "resolved": "12.13.0", - "contentHash": "jDv8xJWeZY2Er9zA6QO25BiGolxg87rItt9CwAp7L/V9EPJeaz8oJydaNL9Wj0+3ncceoMgdiyEv66OF8YUwWQ==", - "dependencies": { - "Azure.Core": "1.25.0", - "System.IO.Hashing": "6.0.0" - } - }, - "Corvus.Retry": { - "type": "Transitive", - "resolved": "1.0.2", - "contentHash": "Jzmv1VpjJnIaz+b0uadkl3yoNh+qnmzHvOcHUXc5oAo1fVqclzxLJAqhOPnm5BVURA5nlqgB3mtmI1YQQhwh9A==" - }, - "Endjin.RecommendedPractices": { - "type": "Transitive", - "resolved": "2.1.2", - "contentHash": "Nbj0WS3zVDD2wjfU2/nbkWIWS9Ljg8VN+SSpaCuf5lHBOIEb0Ra201lGcyJHtRHybAciz+hQA9lHj7TnG52qqw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1" - } - }, - "Microsoft.Bcl.AsyncInterfaces": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" - }, - "Microsoft.Build.Tasks.Git": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" - }, - "Microsoft.Extensions.Configuration.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "qWzV9o+ZRWq+pGm+1dF+R7qTgTYoXvbyowRoBxQJGfqTpqDun2eteerjRQhq5PQ/14S+lqto3Ft4gYaRyl4rdQ==", - "dependencies": { - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.FileProviders.Abstractions": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "0pd4/fho0gC12rQswaGQxbU34jOS1TPS8lZPpkFCH68ppQjHNHYle9iRuHeev1LhrJ94YPvzcRd8UmIuFk23Qw==", - "dependencies": { - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.FileProviders.Physical": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "QvkL7l0nM8udt3gfyu0Vw8bbCXblxaKOl7c2oBfgGy4LCURRaL9XWZX1FWJrQc43oMokVneVxH38iz+bY1sbhg==", - "dependencies": { - "Microsoft.Extensions.FileProviders.Abstractions": "6.0.0", - "Microsoft.Extensions.FileSystemGlobbing": "6.0.0", - "Microsoft.Extensions.Primitives": "6.0.0" - } - }, - "Microsoft.Extensions.FileSystemGlobbing": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "ip8jnL1aPiaPeKINCqaTEbvBFDmVx9dXQEBZ2HOBRXPD1eabGNqP/bKlsIcp7U2lGxiXd5xIhoFcmY8nM4Hdiw==" - }, - "Microsoft.Extensions.Primitives": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "Microsoft.SourceLink.Common": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" - }, - "Microsoft.SourceLink.GitHub": { - "type": "Transitive", - "resolved": "1.1.1", - "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", - "dependencies": { - "Microsoft.Build.Tasks.Git": "1.1.1", - "Microsoft.SourceLink.Common": "1.1.1" - } - }, - "StyleCop.Analyzers.Unstable": { - "type": "Transitive", - "resolved": "1.2.0.435", - "contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg==" - }, - "System.Diagnostics.DiagnosticSource": { - "type": "Transitive", - "resolved": "4.6.0", - "contentHash": "mbBgoR0rRfl2uimsZ2avZY8g7Xnh1Mza0rJZLPcxqiMWlkGukjmRkuMJ/er+AhQuiRIh80CR/Hpeztr80seV5g==" - }, - "System.IO.Hashing": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Rfm2jYCaUeGysFEZjDe7j1R4x6Z6BzumS/vUT5a1AA/AWJuGX71PoGB0RmpyX3VmrGqVnAwtfMn39OHR8Y/5+g==" - }, - "System.IO.Pipelines": { - "type": "Transitive", - "resolved": "4.7.4", - "contentHash": "TQqNjDcTVu6eTDB2S0vjSUhn0udEugL93D9zgsOsSiJO1kv1UWDM2o0+79H95I5X+S0VPEzm4ihj6KPwhNEb7g==" - }, - "System.Linq.Async": { - "type": "Transitive", - "resolved": "6.0.1", - "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", - "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "6.0.0" - } - }, - "System.Memory.Data": { - "type": "Transitive", - "resolved": "1.0.2", - "contentHash": "JGkzeqgBsiZwKJZ1IxPNsDFZDhUvuEdX8L8BDC8N3KOj+6zMcNU28CNN59TpZE/VJYy9cP+5M+sbxtWJx3/xtw==", - "dependencies": { - "System.Text.Encodings.Web": "4.7.2", - "System.Text.Json": "4.6.0" - } - }, - "System.Numerics.Vectors": { - "type": "Transitive", - "resolved": "4.5.0", - "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" - }, - "System.Reactive": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ==" - }, - "System.Runtime.CompilerServices.Unsafe": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" - }, - "System.Text.Encodings.Web": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0" - } - }, - "System.Text.Json": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "zaJsHfESQvJ11vbXnNlkrR46IaMULk/gHxYsJphzSF+07kTjPHv+Oc14w6QEOfo3Q4hqLJgStUaYB9DBl0TmWg==", - "dependencies": { - "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "6.0.0" - } - }, - "System.Threading.Tasks.Extensions": { - "type": "Transitive", - "resolved": "4.5.4", - "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" - }, - "ais.net.models": { - "type": "Project", - "dependencies": { - "Ais.Net": "[0.4.2, )" - } - }, - "ais.net.receiver": { - "type": "Project", - "dependencies": { - "Ais.Net.Models": "[1.0.0, )", - "Corvus.Retry": "[1.0.2, )", - "System.Linq.Async": "[6.0.*, )", - "System.Reactive": "[5.0.*, )" - } - }, - "ais.net.receiver.storage.azure.blob": { - "type": "Project", - "dependencies": { - "Ais.Net.Receiver": "[1.0.0, )", - "Azure.Storage.Blobs": "[12.14.1, )" - } - } - } - } +{ + "version": 1, + "dependencies": { + "net8.0": { + "Endjin.RecommendedPractices.GitHub": { + "type": "Direct", + "requested": "[2.1.13, )", + "resolved": "2.1.13", + "contentHash": "ZefZtlE4NE4ajKMzUtdeb9+SSWv95gutAykQmTEuj2Ln13/1etgxha9QFhrALHr+ewvUH7M3X1qh9HBmWMLRFg==", + "dependencies": { + "Endjin.RecommendedPractices": "2.1.13", + "Microsoft.SourceLink.GitHub": "1.1.1" + } + }, + "Microsoft.Extensions.Configuration": { + "type": "Direct", + "requested": "[8.0.0, )", + "resolved": "8.0.0", + "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Direct", + "requested": "[8.0.2, )", + "resolved": "8.0.2", + "contentHash": "7IQhGK+wjyGrNsPBjJcZwWAr+Wf6D4+TwOptUt77bWtgNkiV8tDEbhFS+dDamtQFZ2X7kWG9m71iZQRj2x3zgQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.FileExtensions": { + "type": "Direct", + "requested": "[8.0.1, )", + "resolved": "8.0.1", + "contentHash": "EJzSNO9oaAXnTdtdNO6npPRsIIeZCBSNmdQ091VDO7fBiOtJAAeEq6dtrVXIi3ZyjC5XRSAtVvF8SzcneRHqKQ==", + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.Configuration.Json": { + "type": "Direct", + "requested": "[8.0.1, )", + "resolved": "8.0.1", + "contentHash": "L89DLNuimOghjV3tLx0ArFDwVEJD6+uGB3BMCMX01kaLzXkaXHb2021xOMl2QOxUxbdePKUZsUY7n2UUkycjRg==", + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.1", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0" + } + }, + "System.Threading.Tasks.Dataflow": { + "type": "Direct", + "requested": "[8.0.1, )", + "resolved": "8.0.1", + "contentHash": "4pjq2vIPNZkKA9asAXzf5IRBb7K+b0+UQZZbpv6g029sAPZgnKdg/NNOC/DbJL8SWqYcFMVjb/T/YEmb0PHUYg==" + }, + "Ais.Net": { + "type": "Transitive", + "resolved": "0.4.2", + "contentHash": "+wtx8g0YwxEaDbilf4MiED9S4Yxr9J7RHAAMEN48+yB0it10KYdhmtB6dxt7qdCOvdoDnBOumggcGYefWMz+WA==", + "dependencies": { + "System.IO.Pipelines": "4.7.4" + } + }, + "Ais.Net.Models": { + "type": "Transitive", + "resolved": "0.2.1", + "contentHash": "JKW8/2Vf7D3sfCBnl7Z7hCtH4gOgfOGZNbPLitpEjNKq1EH+jikmPsXthyX9w9nQ6w6mbphsZ0wJV3oXgCkgxA==", + "dependencies": { + "Ais.Net": "0.4.2" + } + }, + "Azure.Core": { + "type": "Transitive", + "resolved": "1.43.0", + "contentHash": "XE6GHvFAv0djbzNSC3jJPDytcDRmg2CUYlh4V4HjIjX9xLP90OYDPz1KyF02qJJJTF9wLuG4C0XIQm22MGkCww==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0", + "System.ClientModel": "1.0.0", + "System.Diagnostics.DiagnosticSource": "6.0.1", + "System.Memory.Data": "1.0.2", + "System.Numerics.Vectors": "4.5.0", + "System.Text.Encodings.Web": "6.0.0", + "System.Text.Json": "6.0.9", + "System.Threading.Tasks.Extensions": "4.5.4" + } + }, + "Azure.Storage.Blobs": { + "type": "Transitive", + "resolved": "12.22.1", + "contentHash": "x0TZRhkLQwVf+BYjFJybRu0G8OdIXm0mYZJUgUX2I27DHxHmW6+qR4q3VsbOKYT1r/CFwDKBt7wDVohr14k4bQ==", + "dependencies": { + "Azure.Storage.Common": "12.21.0", + "System.Text.Json": "6.0.9" + } + }, + "Azure.Storage.Common": { + "type": "Transitive", + "resolved": "12.21.0", + "contentHash": "4DosxjTeu1BpRJr8iPuUQ0QMGgLHreErKy1DdqsqABkwA5FzzRr/fUD+IfxTpCyi7uhLhcgz5FmDdts+uyrvpQ==", + "dependencies": { + "Azure.Core": "1.43.0", + "System.IO.Hashing": "6.0.0" + } + }, + "Corvus.Retry": { + "type": "Transitive", + "resolved": "1.0.7", + "contentHash": "CMAb5YGTXzUeNS+9aumQCGUH6MzymbvlsljHAamxNwffmEly8S50UoqdMi6lHlQlkl2bc+xrvIbGnhJnnF6Puw==" + }, + "Endjin.RecommendedPractices": { + "type": "Transitive", + "resolved": "2.1.13", + "contentHash": "ZXMVKFaBJYaAfRKS/Uv8kUANDsEj2L9H5L4XVXyZULI0UANqZ/ROVTpOqulkukf3UFc/jnnVG2EfByynTiztDg==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1" + } + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.FileProviders.Abstractions": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.FileProviders.Physical": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + } + }, + "Microsoft.Extensions.FileSystemGlobbing": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==" + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" + }, + "Microsoft.SourceLink.GitHub": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "System.ClientModel": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "I3CVkvxeqFYjIVEP59DnjbeoGNfo/+SZrCLpRz2v/g0gpCHaEMPtWSY0s9k/7jR1rAsLNg2z2u1JRB76tPjnIw==", + "dependencies": { + "System.Memory.Data": "1.0.2", + "System.Text.Json": "4.7.2" + } + }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "KiLYDu2k2J82Q9BJpWiuQqCkFjRBWVq4jDzKKWawVi9KWzyD0XG3cmfX0vqTQlL14Wi9EufJrbL0+KCLTbqWiQ==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.IO.Hashing": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "Rfm2jYCaUeGysFEZjDe7j1R4x6Z6BzumS/vUT5a1AA/AWJuGX71PoGB0RmpyX3VmrGqVnAwtfMn39OHR8Y/5+g==" + }, + "System.IO.Pipelines": { + "type": "Transitive", + "resolved": "4.7.4", + "contentHash": "TQqNjDcTVu6eTDB2S0vjSUhn0udEugL93D9zgsOsSiJO1kv1UWDM2o0+79H95I5X+S0VPEzm4ihj6KPwhNEb7g==" + }, + "System.Linq.Async": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "0YhHcaroWpQ9UCot3Pizah7ryAzQhNvobLMSxeDIGmnXfkQn8u5owvpOH0K6EVB+z9L7u6Cc4W17Br/+jyttEQ==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "System.Memory.Data": { + "type": "Transitive", + "resolved": "1.0.2", + "contentHash": "JGkzeqgBsiZwKJZ1IxPNsDFZDhUvuEdX8L8BDC8N3KOj+6zMcNU28CNN59TpZE/VJYy9cP+5M+sbxtWJx3/xtw==", + "dependencies": { + "System.Text.Encodings.Web": "4.7.2", + "System.Text.Json": "4.6.0" + } + }, + "System.Numerics.Vectors": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" + }, + "System.Reactive": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "rHaWtKDwCi9qJ3ObKo8LHPMuuwv33YbmQi7TcUK1C264V3MFnOr5Im7QgCTdLniztP3GJyeiSg5x8NqYJFqRmg==" + }, + "System.Runtime.CompilerServices.Unsafe": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "6.0.9", + "contentHash": "2j16oUgtIzl7Xtk7demG0i/v5aU/ZvULcAnJvPb63U3ZhXJ494UYcxuEj5Fs49i3XDrk5kU/8I+6l9zRCw3cJw==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "6.0.0" + } + }, + "System.Threading.Tasks.Extensions": { + "type": "Transitive", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==" + }, + "ais.net.receiver": { + "type": "Project", + "dependencies": { + "Ais.Net.Models": "[0.2.1, )", + "Corvus.Retry": "[1.0.7, )", + "System.Linq.Async": "[6.0.*, )", + "System.Reactive": "[6.0.1, )" + } + }, + "ais.net.receiver.storage.azure.blob": { + "type": "Project", + "dependencies": { + "Ais.Net.Receiver": "[1.0.0, )", + "Azure.Storage.Blobs": "[12.22.1, )" + } + } + } + } } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais.Net.Receiver.Storage.Azure.Blob.csproj b/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais.Net.Receiver.Storage.Azure.Blob.csproj index 4d1e82b..7a57f2b 100644 --- a/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais.Net.Receiver.Storage.Azure.Blob.csproj +++ b/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais.Net.Receiver.Storage.Azure.Blob.csproj @@ -3,7 +3,7 @@ - net6.0 + net8.0 latest enable True @@ -21,8 +21,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais/Net/Receiver/Storage/Azure/Blob/AzureAppendBlobStorageClient.cs b/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais/Net/Receiver/Storage/Azure/Blob/AzureAppendBlobStorageClient.cs index c51653f..b991ccc 100644 --- a/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais/Net/Receiver/Storage/Azure/Blob/AzureAppendBlobStorageClient.cs +++ b/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais/Net/Receiver/Storage/Azure/Blob/AzureAppendBlobStorageClient.cs @@ -2,69 +2,68 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Storage.Azure.Blob +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Ais.Net.Receiver.Storage.Azure.Blob.Configuration; + +using global::Azure.Storage.Blobs; +using global::Azure.Storage.Blobs.Specialized; + +namespace Ais.Net.Receiver.Storage.Azure.Blob; + +public class AzureAppendBlobStorageClient : IStorageClient { - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Text; - using System.Threading.Tasks; + private readonly StorageConfig configuration; + private AppendBlobClient? appendBlobClient; + private BlobContainerClient? blobContainerClient; - using Ais.Net.Receiver.Storage.Azure.Blob.Configuration; + public AzureAppendBlobStorageClient(StorageConfig configuration) + { + this.configuration = configuration; + } - using global::Azure.Storage.Blobs; - using global::Azure.Storage.Blobs.Specialized; + public async Task PersistAsync(IEnumerable messages) + { + await this.InitialiseContainerAsync().ConfigureAwait(false); + await using MemoryStream stream = new (Encoding.UTF8.GetBytes(messages.Aggregate(new StringBuilder(), (sb, a) => sb.AppendLine(string.Join(",", a)), sb => sb.ToString()))); + await this.appendBlobClient!.AppendBlockAsync(stream).ConfigureAwait(false); + } - public class AzureAppendBlobStorageClient : IStorageClient + private async Task InitialiseContainerAsync() { - private readonly StorageConfig configuration; - private AppendBlobClient? appendBlobClient; - private BlobContainerClient? blobContainerClient; + DateTimeOffset timestamp = DateTimeOffset.UtcNow; - public AzureAppendBlobStorageClient(StorageConfig configuration) + try { - this.configuration = configuration; - } + this.blobContainerClient = new BlobContainerClient( + this.configuration.ConnectionString, + this.configuration.ContainerName); - public async Task PersistAsync(IEnumerable messages) + this.appendBlobClient = new AppendBlobClient( + this.configuration.ConnectionString, + this.configuration.ContainerName, + $"raw/{timestamp:yyyy}/{timestamp:MM}/{timestamp:dd}/{timestamp:yyyyMMddTHH}.nm4"); + } + catch (Exception e) { - await this.InitialiseContainerAsync().ConfigureAwait(false); - await using MemoryStream stream = new (Encoding.UTF8.GetBytes(messages.Aggregate(new StringBuilder(), (sb, a) => sb.AppendLine(string.Join(",", a)), sb => sb.ToString()))); - await this.appendBlobClient!.AppendBlockAsync(stream).ConfigureAwait(false); + Console.WriteLine(e); + throw; } - private async Task InitialiseContainerAsync() + try { - DateTimeOffset timestamp = DateTimeOffset.UtcNow; - - try - { - this.blobContainerClient = new BlobContainerClient( - this.configuration.ConnectionString, - this.configuration.ContainerName); - - this.appendBlobClient = new AppendBlobClient( - this.configuration.ConnectionString, - this.configuration.ContainerName, - $"raw/{timestamp:yyyy}/{timestamp:MM}/{timestamp:dd}/{timestamp:yyyyMMddTHH}.nm4"); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - - try - { - await this.blobContainerClient.CreateIfNotExistsAsync().ConfigureAwait(false); - await this.appendBlobClient.CreateIfNotExistsAsync().ConfigureAwait(false); - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } + await this.blobContainerClient.CreateIfNotExistsAsync().ConfigureAwait(false); + await this.appendBlobClient.CreateIfNotExistsAsync().ConfigureAwait(false); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; } } } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais/Net/Receiver/Storage/Azure/Blob/Configuration/StorageConfig.cs b/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais/Net/Receiver/Storage/Azure/Blob/Configuration/StorageConfig.cs index 94ab5ab..4b4dc82 100644 --- a/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais/Net/Receiver/Storage/Azure/Blob/Configuration/StorageConfig.cs +++ b/Solutions/Ais.Net.Receiver.Storage.Azure.Blob/Ais/Net/Receiver/Storage/Azure/Blob/Configuration/StorageConfig.cs @@ -6,16 +6,15 @@ // of config files are outside the compiler's control. #nullable disable annotations -namespace Ais.Net.Receiver.Storage.Azure.Blob.Configuration +namespace Ais.Net.Receiver.Storage.Azure.Blob.Configuration; + +public class StorageConfig { - public class StorageConfig - { - public string ConnectionString { get; set; } + public string ConnectionString { get; set; } - public string ContainerName { get; set; } + public string ContainerName { get; set; } - public bool EnableCapture { get; set; } + public bool EnableCapture { get; set; } - public int WriteBatchSize { get; set; } - } + public int WriteBatchSize { get; set; } } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver.sln b/Solutions/Ais.Net.Receiver.sln index f43a6dc..71b0b3b 100644 --- a/Solutions/Ais.Net.Receiver.sln +++ b/Solutions/Ais.Net.Receiver.sln @@ -1,56 +1,43 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.0.32126.317 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ais.Net.Receiver", "Ais.Net.Receiver\Ais.Net.Receiver.csproj", "{39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6C0840FD-F495-41BA-9D68-2B691313D2DC}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - ..\azure-pipelines.yml = ..\azure-pipelines.yml - ..\GitVersion.yml = ..\GitVersion.yml - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ais.Net.Models", "Ais.Net.Models\Ais.Net.Models.csproj", "{5B090F5E-28EA-4394-83DB-8C2764970FDC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ais.Net.Receiver.Storage.Azure.Blob", "Ais.Net.Receiver.Storage.Azure.Blob\Ais.Net.Receiver.Storage.Azure.Blob.csproj", "{C6485EBE-8939-4918-AA28-703E024E1B4C}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ais.Net.Receiver.Host.Console", "Ais.Net.Receiver.Host.Console\Ais.Net.Receiver.Host.Console.csproj", "{F7297F19-858C-4663-BA47-D001876F9868}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ais.Net.Models.Specs", "Ais.Net.Models.Specs\Ais.Net.Models.Specs.csproj", "{AA6F29A1-3F00-4796-A7C7-9EDFD6C677F8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}.Release|Any CPU.Build.0 = Release|Any CPU - {5B090F5E-28EA-4394-83DB-8C2764970FDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5B090F5E-28EA-4394-83DB-8C2764970FDC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5B090F5E-28EA-4394-83DB-8C2764970FDC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5B090F5E-28EA-4394-83DB-8C2764970FDC}.Release|Any CPU.Build.0 = Release|Any CPU - {C6485EBE-8939-4918-AA28-703E024E1B4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C6485EBE-8939-4918-AA28-703E024E1B4C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C6485EBE-8939-4918-AA28-703E024E1B4C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C6485EBE-8939-4918-AA28-703E024E1B4C}.Release|Any CPU.Build.0 = Release|Any CPU - {F7297F19-858C-4663-BA47-D001876F9868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7297F19-858C-4663-BA47-D001876F9868}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7297F19-858C-4663-BA47-D001876F9868}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7297F19-858C-4663-BA47-D001876F9868}.Release|Any CPU.Build.0 = Release|Any CPU - {AA6F29A1-3F00-4796-A7C7-9EDFD6C677F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AA6F29A1-3F00-4796-A7C7-9EDFD6C677F8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AA6F29A1-3F00-4796-A7C7-9EDFD6C677F8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AA6F29A1-3F00-4796-A7C7-9EDFD6C677F8}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {B807F890-1DEB-4C00-A4FC-67EC55DE21F5} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32126.317 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ais.Net.Receiver", "Ais.Net.Receiver\Ais.Net.Receiver.csproj", "{39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6C0840FD-F495-41BA-9D68-2B691313D2DC}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + ..\GitVersion.yml = ..\GitVersion.yml + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ais.Net.Receiver.Storage.Azure.Blob", "Ais.Net.Receiver.Storage.Azure.Blob\Ais.Net.Receiver.Storage.Azure.Blob.csproj", "{C6485EBE-8939-4918-AA28-703E024E1B4C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ais.Net.Receiver.Host.Console", "Ais.Net.Receiver.Host.Console\Ais.Net.Receiver.Host.Console.csproj", "{F7297F19-858C-4663-BA47-D001876F9868}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {39A469DF-E331-4A68-ACA3-5E7ECBE2B1FB}.Release|Any CPU.Build.0 = Release|Any CPU + {C6485EBE-8939-4918-AA28-703E024E1B4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6485EBE-8939-4918-AA28-703E024E1B4C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6485EBE-8939-4918-AA28-703E024E1B4C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6485EBE-8939-4918-AA28-703E024E1B4C}.Release|Any CPU.Build.0 = Release|Any CPU + {F7297F19-858C-4663-BA47-D001876F9868}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7297F19-858C-4663-BA47-D001876F9868}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7297F19-858C-4663-BA47-D001876F9868}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7297F19-858C-4663-BA47-D001876F9868}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B807F890-1DEB-4C00-A4FC-67EC55DE21F5} + EndGlobalSection +EndGlobal diff --git a/Solutions/Ais.Net.Receiver/Ais.Net.Receiver.csproj b/Solutions/Ais.Net.Receiver/Ais.Net.Receiver.csproj index e6b8bef..95ea555 100644 --- a/Solutions/Ais.Net.Receiver/Ais.Net.Receiver.csproj +++ b/Solutions/Ais.Net.Receiver/Ais.Net.Receiver.csproj @@ -3,7 +3,7 @@ - net6.0 + net8.0 latest enable True @@ -21,17 +21,14 @@ + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - + diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Configuration/AisConfig.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Configuration/AisConfig.cs index a7e53a7..e780862 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Configuration/AisConfig.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Configuration/AisConfig.cs @@ -6,22 +6,21 @@ // of config files are outside the compiler's control. #nullable disable annotations -namespace Ais.Net.Receiver.Configuration -{ - using System; +using System; + +namespace Ais.Net.Receiver.Configuration; - public class AisConfig - { - public string Host { get; set; } +public class AisConfig +{ + public string Host { get; set; } - public LoggerVerbosity LoggerVerbosity { get; set; } + public LoggerVerbosity LoggerVerbosity { get; set; } - public TimeSpan StatisticsPeriodicity { get; set; } + public TimeSpan StatisticsPeriodicity { get; set; } - public int Port { get; set; } + public int Port { get; set; } - public int RetryAttempts { get; set; } + public int RetryAttempts { get; set; } - public TimeSpan RetryPeriodicity { get; set; } - } + public TimeSpan RetryPeriodicity { get; set; } } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Configuration/LoggerVerbosity.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Configuration/LoggerVerbosity.cs index ecd6f3d..daa3929 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Configuration/LoggerVerbosity.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Configuration/LoggerVerbosity.cs @@ -2,9 +2,6 @@ // Copyright (c) Endjin Limited. All rights reserved. // -// Configuration binding types are typically better off as null-oblivious, because the contents -// of config files are outside the compiler's control. -#nullable disable annotations namespace Ais.Net.Receiver.Configuration; /// diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaMessageExtensions.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaMessageExtensions.cs index 69fc85c..ded3559 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaMessageExtensions.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaMessageExtensions.cs @@ -2,28 +2,27 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Parser -{ - using System; - using System.Linq; +using System; +using System.Linq; - public static class NmeaMessageExtensions - { - public static bool IsMissingNmeaBlockTags(this string message) - { - return message.AsSpan()[0] == '!'; - } +namespace Ais.Net.Receiver.Parser; - public static string PrependNmeaBlockTags(this string message) - { - string timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); +public static class NmeaMessageExtensions +{ + public static bool IsMissingNmeaBlockTags(this string message) + { + return message.AsSpan()[0] == '!'; + } - // Some messages are missing NMEA Block Tags - see https://gpsd.gitlab.io/gpsd/AIVDM.html#_nmea_tag_blocks - // s: = source stations - in our case AIS.Net.Receiver = 1000001 - // c: = UNIX time in seconds or milliseconds + checksum - return $"\\s:1000001,c:{timestamp}*{NmeaChecksum("c:" + timestamp)}\\{message}"; - } + public static string PrependNmeaBlockTags(this string message) + { + string timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); - private static string NmeaChecksum(string s) => s.Aggregate(0, (t, c) => t ^ c).ToString("X2"); + // Some messages are missing NMEA Block Tags - see https://gpsd.gitlab.io/gpsd/AIVDM.html#_nmea_tag_blocks + // s: = source stations - in our case AIS.Net.Receiver = 1000001 + // c: = UNIX time in seconds or milliseconds + checksum + return $@"\s:1000001,c:{timestamp}*{NmeaChecksum("c:" + timestamp)}\{message}"; } + + private static string NmeaChecksum(string s) => s.Aggregate(0, (t, c) => t ^ c).ToString("X2"); } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaToAisMessageTypeProcessor.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaToAisMessageTypeProcessor.cs index 8799176..c0bc7f2 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaToAisMessageTypeProcessor.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Parser/NmeaToAisMessageTypeProcessor.cs @@ -2,262 +2,262 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Parser +using System; +using System.Reactive.Subjects; + +using Ais.Net.Models; +using Ais.Net.Models.Abstractions; + +namespace Ais.Net.Receiver.Parser; + +/// +/// Receives AIS messages parsed from an NMEA sentence and converts it into an +/// stream of based types. +/// +public class NmeaToAisMessageTypeProcessor : INmeaAisMessageStreamProcessor { - using System; - using System.Reactive.Subjects; + private readonly Subject messages = new(); - using Ais.Net.Models; - using Ais.Net.Models.Abstractions; + public IObservable Messages => this.messages; - /// - /// Receives AIS messages parsed from an NMEA sentence and converts it into an - /// stream of based types. - /// - public class NmeaToAisMessageTypeProcessor : INmeaAisMessageStreamProcessor + public void OnNext(in NmeaLineParser parsedLine, in ReadOnlySpan asciiPayload, uint padding) { - private readonly Subject messages = new(); - - public IObservable Messages => this.messages; + int messageType = NmeaPayloadParser.PeekMessageType(asciiPayload, padding); - public void OnNext(in NmeaLineParser parsedLine, in ReadOnlySpan asciiPayload, uint padding) + try { - int messageType = NmeaPayloadParser.PeekMessageType(asciiPayload, padding); - - try + switch (messageType) { - switch (messageType) + case >= 1 and <= 3: { - case >= 1 and <= 3: - { - this.ParseMessageTypes1Through3(asciiPayload, padding, messageType); - return; - } - - case 5: - { - this.ParseMessageType5(asciiPayload, padding); - return; - } - - case 18: - { - this.ParseMessageType18(asciiPayload, padding); - return; - } - - case 19: - { - this.ParseMessageType19(asciiPayload, padding); - return; - } - - case 24: - { - this.ParseMessageType24(asciiPayload, padding); - return; - } + this.ParseMessageTypes1Through3(asciiPayload, padding, messageType); + return; + } + + case 5: + { + this.ParseMessageType5(asciiPayload, padding); + return; + } + + case 18: + { + this.ParseMessageType18(asciiPayload, padding); + return; + } + + case 19: + { + this.ParseMessageType19(asciiPayload, padding); + return; + } + + case 24: + { + this.ParseMessageType24(asciiPayload, padding); + return; } - } - catch (Exception e) - { - Console.WriteLine($"[{messageType}] {e.Message}"); } } - - public void OnError(in ReadOnlySpan line, Exception error, int lineNumber) + catch (Exception e) { - throw new NotImplementedException(); + Console.WriteLine($"[{messageType}] {e.Message}"); } + } - public void OnCompleted() - { - throw new NotImplementedException(); - } + public void OnError(in ReadOnlySpan line, Exception error, int lineNumber) + { + throw new NotImplementedException(); + } - public void Progress( - bool done, - int totalNmeaLines, - int totalAisMessages, - int totalTicks, - int nmeaLinesSinceLastUpdate, - int aisMessagesSinceLastUpdate, - int ticksSinceLastUpdate) - { - throw new NotImplementedException(); - } + public void OnCompleted() + { + throw new NotImplementedException(); + } - private void ParseMessageTypes1Through3(ReadOnlySpan asciiPayload, uint padding, int messageType) - { - var parser = new NmeaAisPositionReportClassAParser(asciiPayload, padding); - - var message = new AisMessageType1Through3( - CourseOverGroundDegrees: parser.CourseOverGround10thDegrees.FromTenthsToDegrees(), - ManoeuvreIndicator: parser.ManoeuvreIndicator, - MessageType: messageType, - Mmsi: parser.Mmsi, - NavigationStatus: parser.NavigationStatus, - Position: Position.From10000thMins(parser.Latitude10000thMins, parser.Longitude10000thMins), - PositionAccuracy: parser.PositionAccuracy, - RadioSlotTimeout: parser.RadioSlotTimeout, - RadioSubMessage: parser.RadioSubMessage, - RadioSyncState: parser.RadioSyncState, - RaimFlag: parser.RaimFlag, - RateOfTurn: parser.RateOfTurn, - RepeatIndicator: parser.RepeatIndicator, - SpareBits145: parser.SpareBits145, - SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(), - TimeStampSecond: parser.TimeStampSecond, - TrueHeadingDegrees: parser.TrueHeadingDegrees); - - this.messages.OnNext(message); - } + public void Progress( + bool done, + int totalNmeaLines, + int totalAisMessages, + int totalTicks, + int nmeaLinesSinceLastUpdate, + int aisMessagesSinceLastUpdate, + int ticksSinceLastUpdate) + { + throw new NotImplementedException(); + } - private void ParseMessageType5(ReadOnlySpan asciiPayload, uint padding) - { - var parser = new NmeaAisStaticAndVoyageRelatedDataParser(asciiPayload, padding); - - var message = new AisMessageType5( - AisVersion: parser.AisVersion, - EtaMonth: parser.EtaMonth, - EtaDay: parser.EtaDay, - EtaHour: parser.EtaHour, - EtaMinute: parser.EtaMinute, - Mmsi: parser.Mmsi, - IsDteNotReady: parser.IsDteNotReady, - ImoNumber: parser.ImoNumber, - CallSign: parser.CallSign.TextFieldToString(), - Destination: parser.Destination.TextFieldToString(), - VesselName: parser.VesselName.TextFieldToString(), - ShipType: parser.ShipType, - RepeatIndicator: parser.RepeatIndicator, - DimensionToBow: parser.DimensionToBow, - DimensionToPort: parser.DimensionToPort, - DimensionToStarboard: parser.DimensionToStarboard, - DimensionToStern: parser.DimensionToStern, - Draught10thMetres: parser.Draught10thMetres, - Spare423: parser.Spare423, - PositionFixType: parser.PositionFixType); - - this.messages.OnNext(message); - } + private void ParseMessageTypes1Through3(ReadOnlySpan asciiPayload, uint padding, int messageType) + { + NmeaAisPositionReportClassAParser parser = new(asciiPayload, padding); + + AisMessageType1Through3 message = new( + CourseOverGroundDegrees: parser.CourseOverGround10thDegrees.FromTenthsToDegrees(), + ManoeuvreIndicator: parser.ManoeuvreIndicator, + MessageType: messageType, + Mmsi: parser.Mmsi, + NavigationStatus: parser.NavigationStatus, + Position: Position.From10000thMins(parser.Latitude10000thMins, parser.Longitude10000thMins), + PositionAccuracy: parser.PositionAccuracy, + RadioSlotTimeout: parser.RadioSlotTimeout, + RadioSubMessage: parser.RadioSubMessage, + RadioSyncState: parser.RadioSyncState, + RaimFlag: parser.RaimFlag, + RateOfTurn: parser.RateOfTurn, + RepeatIndicator: parser.RepeatIndicator, + SpareBits145: parser.SpareBits145, + SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(), + TimeStampSecond: parser.TimeStampSecond, + TrueHeadingDegrees: parser.TrueHeadingDegrees); + + this.messages.OnNext(message); + } - private void ParseMessageType18(ReadOnlySpan asciiPayload, uint padding) - { - var parser = new NmeaAisPositionReportClassBParser(asciiPayload, padding); - - var message = new AisMessageType18( - Mmsi: parser.Mmsi, - Position: Position.From10000thMins(parser.Latitude10000thMins, parser.Longitude10000thMins), - CanAcceptMessage22ChannelAssignment: parser.CanAcceptMessage22ChannelAssignment, - CanSwitchBands: parser.CanSwitchBands, - CsUnit: parser.CsUnit, - HasDisplay: parser.HasDisplay, - IsDscAttached: parser.IsDscAttached, - RadioStatusType: parser.RadioStatusType, - RegionalReserved139: parser.RegionalReserved139, - RegionalReserved38: parser.RegionalReserved38, - CourseOverGroundDegrees: parser.CourseOverGround10thDegrees.FromTenthsToDegrees(), - PositionAccuracy: parser.PositionAccuracy, - SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(), - TimeStampSecond: parser.TimeStampSecond, - TrueHeadingDegrees: parser.TrueHeadingDegrees, - IsAssigned: parser.IsAssigned, - RaimFlag: parser.RaimFlag, - RepeatIndicator: parser.RepeatIndicator); - - this.messages.OnNext(message); - } + private void ParseMessageType5(ReadOnlySpan asciiPayload, uint padding) + { + NmeaAisStaticAndVoyageRelatedDataParser parser = new(asciiPayload, padding); + + AisMessageType5 message = new( + AisVersion: parser.AisVersion, + EtaMonth: parser.EtaMonth, + EtaDay: parser.EtaDay, + EtaHour: parser.EtaHour, + EtaMinute: parser.EtaMinute, + Mmsi: parser.Mmsi, + IsDteNotReady: parser.IsDteNotReady, + ImoNumber: parser.ImoNumber, + CallSign: parser.CallSign.TextFieldToString(), + Destination: parser.Destination.TextFieldToString(), + VesselName: parser.VesselName.TextFieldToString(), + ShipType: parser.ShipType, + RepeatIndicator: parser.RepeatIndicator, + DimensionToBow: parser.DimensionToBow, + DimensionToPort: parser.DimensionToPort, + DimensionToStarboard: parser.DimensionToStarboard, + DimensionToStern: parser.DimensionToStern, + Draught10thMetres: parser.Draught10thMetres, + Spare423: parser.Spare423, + PositionFixType: parser.PositionFixType); + + this.messages.OnNext(message); + } - private void ParseMessageType19(ReadOnlySpan asciiPayload, uint padding) - { - var parser = new NmeaAisPositionReportExtendedClassBParser(asciiPayload, padding); - - Span shipNameAscii = stackalloc byte[(int)parser.ShipName.CharacterCount]; - parser.ShipName.WriteAsAscii(shipNameAscii); - - var message = new AisMessageType19( - Mmsi: parser.Mmsi, - ShipName: shipNameAscii.GetString(), - CourseOverGroundDegrees: parser.CourseOverGround10thDegrees.FromTenthsToDegrees(), - DimensionToBow: parser.DimensionToBow, - DimensionToPort: parser.DimensionToPort, - DimensionToStarboard: parser.DimensionToStarboard, - DimensionToStern: parser.DimensionToStern, - IsAssigned: parser.IsAssigned, - IsDteNotReady: parser.IsDteNotReady, - PositionAccuracy: parser.PositionAccuracy, - PositionFixType: parser.PositionFixType, - RaimFlag: parser.RaimFlag, - RegionalReserved139: parser.RegionalReserved139, - RegionalReserved38: parser.RegionalReserved38, - RepeatIndicator: parser.RepeatIndicator, - ShipType: parser.ShipType, - Spare308: parser.Spare308, - SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(), - TimeStampSecond: parser.TimeStampSecond, - TrueHeadingDegrees: parser.TrueHeadingDegrees, - Position: Position.From10000thMins(parser.Latitude10000thMins, parser.Longitude10000thMins)); - - this.messages.OnNext(message); - } + private void ParseMessageType18(ReadOnlySpan asciiPayload, uint padding) + { + NmeaAisPositionReportClassBParser parser = new(asciiPayload, padding); + + AisMessageType18 message = new( + Mmsi: parser.Mmsi, + Position: Position.From10000thMins(parser.Latitude10000thMins, parser.Longitude10000thMins), + CanAcceptMessage22ChannelAssignment: parser.CanAcceptMessage22ChannelAssignment, + CanSwitchBands: parser.CanSwitchBands, + CsUnit: parser.CsUnit, + HasDisplay: parser.HasDisplay, + IsDscAttached: parser.IsDscAttached, + RadioStatusType: parser.RadioStatusType, + RegionalReserved139: parser.RegionalReserved139, + RegionalReserved38: parser.RegionalReserved38, + CourseOverGroundDegrees: parser.CourseOverGround10thDegrees.FromTenthsToDegrees(), + PositionAccuracy: parser.PositionAccuracy, + SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(), + TimeStampSecond: parser.TimeStampSecond, + TrueHeadingDegrees: parser.TrueHeadingDegrees, + IsAssigned: parser.IsAssigned, + RaimFlag: parser.RaimFlag, + RepeatIndicator: parser.RepeatIndicator); + + this.messages.OnNext(message); + } + + private void ParseMessageType19(ReadOnlySpan asciiPayload, uint padding) + { + NmeaAisPositionReportExtendedClassBParser parser = new(asciiPayload, padding); + + Span shipNameAscii = stackalloc byte[(int)parser.ShipName.CharacterCount]; + parser.ShipName.WriteAsAscii(shipNameAscii); + + AisMessageType19 message = new( + Mmsi: parser.Mmsi, + ShipName: shipNameAscii.GetString(), + CourseOverGroundDegrees: parser.CourseOverGround10thDegrees.FromTenthsToDegrees(), + DimensionToBow: parser.DimensionToBow, + DimensionToPort: parser.DimensionToPort, + DimensionToStarboard: parser.DimensionToStarboard, + DimensionToStern: parser.DimensionToStern, + IsAssigned: parser.IsAssigned, + IsDteNotReady: parser.IsDteNotReady, + PositionAccuracy: parser.PositionAccuracy, + PositionFixType: parser.PositionFixType, + RaimFlag: parser.RaimFlag, + RegionalReserved139: parser.RegionalReserved139, + RegionalReserved38: parser.RegionalReserved38, + RepeatIndicator: parser.RepeatIndicator, + ShipType: parser.ShipType, + Spare308: parser.Spare308, + SpeedOverGround: parser.SpeedOverGroundTenths.FromTenths(), + TimeStampSecond: parser.TimeStampSecond, + TrueHeadingDegrees: parser.TrueHeadingDegrees, + Position: Position.From10000thMins(parser.Latitude10000thMins, parser.Longitude10000thMins)); + + this.messages.OnNext(message); + } + + private void ParseMessageType24(ReadOnlySpan asciiPayload, uint padding) + { + uint part = NmeaAisStaticDataReportParser.GetPartNumber(asciiPayload, padding); - private void ParseMessageType24(ReadOnlySpan asciiPayload, uint padding) + switch (part) { - uint part = NmeaAisStaticDataReportParser.GetPartNumber(asciiPayload, padding); + case 0: + { + NmeaAisStaticDataReportParserPartA parser = new(asciiPayload, padding); + + Span vesselNameAscii = stackalloc byte[(int)parser.VesselName.CharacterCount]; + parser.VesselName.WriteAsAscii(vesselNameAscii); + + AisMessageType24Part0 message = new( + Mmsi: parser.Mmsi, + PartNumber: parser.PartNumber, + RepeatIndicator: parser.RepeatIndicator, + Spare160: parser.Spare160); + + this.messages.OnNext(message); + + break; + } - switch (part) + case 1: { - case 0: - { - var parser = new NmeaAisStaticDataReportParserPartA(asciiPayload, padding); - - Span vesselNameAscii = stackalloc byte[(int)parser.VesselName.CharacterCount]; - parser.VesselName.WriteAsAscii(vesselNameAscii); - - var message = new AisMessageType24Part0( - Mmsi: parser.Mmsi, - PartNumber: parser.PartNumber, - RepeatIndicator: parser.RepeatIndicator, - Spare160: parser.Spare160); - - this.messages.OnNext(message); - break; - } - - case 1: - { - var parser = new NmeaAisStaticDataReportParserPartB(asciiPayload, padding); - - Span callSignAscii = stackalloc byte[(int)parser.CallSign.CharacterCount]; - parser.CallSign.WriteAsAscii(callSignAscii); - - Span vendorIdRev3Ascii = stackalloc byte[(int)parser.VendorIdRev3.CharacterCount]; - parser.VendorIdRev3.WriteAsAscii(vendorIdRev3Ascii); - - Span vendorIdRev4Ascii = stackalloc byte[(int)parser.VendorIdRev4.CharacterCount]; - parser.VendorIdRev3.WriteAsAscii(vendorIdRev4Ascii); - - var message = new AisMessageType24Part1( - Mmsi: parser.Mmsi, - CallSign: callSignAscii.GetString(), - DimensionToBow: parser.DimensionToBow, - DimensionToPort: parser.DimensionToPort, - DimensionToStarboard: parser.DimensionToStarboard, - DimensionToStern: parser.DimensionToStern, - MothershipMmsi: parser.MothershipMmsi, - PartNumber: parser.PartNumber, - RepeatIndicator: parser.RepeatIndicator, - SerialNumber: parser.SerialNumber, - ShipType: parser.ShipType, - Spare162: parser.Spare162, - UnitModelCode: parser.UnitModelCode, - VendorIdRev3: vendorIdRev3Ascii.GetString(), - VendorIdRev4: vendorIdRev4Ascii.GetString()); - - this.messages.OnNext(message); - break; - } + NmeaAisStaticDataReportParserPartB parser = new(asciiPayload, padding); + + Span callSignAscii = stackalloc byte[(int)parser.CallSign.CharacterCount]; + parser.CallSign.WriteAsAscii(callSignAscii); + + Span vendorIdRev3Ascii = stackalloc byte[(int)parser.VendorIdRev3.CharacterCount]; + parser.VendorIdRev3.WriteAsAscii(vendorIdRev3Ascii); + + Span vendorIdRev4Ascii = stackalloc byte[(int)parser.VendorIdRev4.CharacterCount]; + parser.VendorIdRev3.WriteAsAscii(vendorIdRev4Ascii); + + AisMessageType24Part1 message = new( + Mmsi: parser.Mmsi, + CallSign: callSignAscii.GetString(), + DimensionToBow: parser.DimensionToBow, + DimensionToPort: parser.DimensionToPort, + DimensionToStarboard: parser.DimensionToStarboard, + DimensionToStern: parser.DimensionToStern, + MothershipMmsi: parser.MothershipMmsi, + PartNumber: parser.PartNumber, + RepeatIndicator: parser.RepeatIndicator, + SerialNumber: parser.SerialNumber, + ShipType: parser.ShipType, + Spare162: parser.Spare162, + UnitModelCode: parser.UnitModelCode, + VendorIdRev3: vendorIdRev3Ascii.GetString(), + VendorIdRev4: vendorIdRev4Ascii.GetString()); + + this.messages.OnNext(message); + break; } } } diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/FileStreamNmeaReceiver.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/FileStreamNmeaReceiver.cs index 29963ac..7ede61e 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/FileStreamNmeaReceiver.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/FileStreamNmeaReceiver.cs @@ -2,51 +2,50 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Receiver +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Ais.Net.Receiver.Receiver; + +public class FileStreamNmeaReceiver : INmeaReceiver { - using System; - using System.Collections.Generic; - using System.IO; - using System.Runtime.CompilerServices; - using System.Threading; - using System.Threading.Tasks; - - public class FileStreamNmeaReceiver : INmeaReceiver - { - private readonly string path; - private readonly TimeSpan delay = TimeSpan.Zero; + private readonly string path; + private readonly TimeSpan delay = TimeSpan.Zero; - public FileStreamNmeaReceiver(string path) - { - this.path = path; - } + public FileStreamNmeaReceiver(string path) + { + this.path = path; + } - public FileStreamNmeaReceiver(string path, TimeSpan delay) - { - this.path = path; - this.delay = delay; - } + public FileStreamNmeaReceiver(string path, TimeSpan delay) + { + this.path = path; + this.delay = delay; + } - public async IAsyncEnumerable GetAsync([EnumeratorCancellation] CancellationToken cancellationToken = default) - { - using var sr = new StreamReader(this.path); + public async IAsyncEnumerable GetAsync([EnumeratorCancellation] CancellationToken cancellationToken = default) + { + using StreamReader sr = new(this.path); - while (sr.Peek() >= 0) + while (sr.Peek() >= 0) + { + if (cancellationToken.IsCancellationRequested) { - if (cancellationToken.IsCancellationRequested) - { - break; - } + break; + } - if (this.delay > TimeSpan.Zero) - { - await Task.Delay(this.delay, cancellationToken).ConfigureAwait(false); - } + if (this.delay > TimeSpan.Zero) + { + await Task.Delay(this.delay, cancellationToken).ConfigureAwait(false); + } - string? line = await sr.ReadLineAsync().ConfigureAwait(false); + string? line = await sr.ReadLineAsync(cancellationToken).ConfigureAwait(false); - if (line is not null) { yield return line; } - } + if (line is not null) { yield return line; } } } } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/INmeaReceiver.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/INmeaReceiver.cs index a056b5b..49d9a86 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/INmeaReceiver.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/INmeaReceiver.cs @@ -2,13 +2,12 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Receiver -{ - using System.Collections.Generic; - using System.Threading; +using System.Collections.Generic; +using System.Threading; + +namespace Ais.Net.Receiver.Receiver; - public interface INmeaReceiver - { - IAsyncEnumerable GetAsync(CancellationToken cancellationToken = default); - } +public interface INmeaReceiver +{ + IAsyncEnumerable GetAsync(CancellationToken cancellationToken = default); } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/NetworkStreamNmeaReceiver.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/NetworkStreamNmeaReceiver.cs index 603f7b7..b7aaf7d 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/NetworkStreamNmeaReceiver.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/NetworkStreamNmeaReceiver.cs @@ -2,95 +2,94 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Receiver +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Sockets; +using System.Reactive.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Ais.Net.Receiver.Receiver; + +public class NetworkStreamNmeaReceiver : INmeaReceiver { - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Net.Sockets; - using System.Reactive.Linq; - using System.Threading; - using System.Threading.Tasks; - - public class NetworkStreamNmeaReceiver : INmeaReceiver + public NetworkStreamNmeaReceiver(string host, int port, TimeSpan? retryPeriodicity, int retryAttemptLimit = 100) { - public NetworkStreamNmeaReceiver(string host, int port, TimeSpan? retryPeriodicity, int retryAttemptLimit = 100) - { - this.Host = host; - this.Port = port; - this.RetryPeriodicity = (retryPeriodicity ?? TimeSpan.FromSeconds(1)); - this.RetryAttemptLimit = retryAttemptLimit; - } + this.Host = host; + this.Port = port; + this.RetryPeriodicity = (retryPeriodicity ?? TimeSpan.FromSeconds(1)); + this.RetryAttemptLimit = retryAttemptLimit; + } - public string Host { get; } + public string Host { get; } - public int Port { get; } + public int Port { get; } - public int RetryAttemptLimit { get; } + public int RetryAttemptLimit { get; } - public TimeSpan RetryPeriodicity { get; } + public TimeSpan RetryPeriodicity { get; } - //public IAsyncEnumerable GetAsync([EnumeratorCancellation] CancellationToken cancellationToken = default) - public IAsyncEnumerable GetAsync(CancellationToken cancellationToken = default) - { - // We're letting Rx handle the retries for us. Since the rest of the code is currently written - // to assume we return an IAsyncEnumerable (which we used to) we convert to that, but it's now - // really all Rx. And since I think it's Rx above us too, we can probably remove IAsyncEnumerable - // from the picture completely. This is all reactive stuff, so I don't think it really belongs. - return this.GetObservable(cancellationToken).ToAsyncEnumerable(); - } - - public IObservable GetObservable(CancellationToken cancellationToken = default) + //public IAsyncEnumerable GetAsync([EnumeratorCancellation] CancellationToken cancellationToken = default) + public IAsyncEnumerable GetAsync(CancellationToken cancellationToken = default) + { + // We're letting Rx handle the retries for us. Since the rest of the code is currently written + // to assume we return an IAsyncEnumerable (which we used to) we convert to that, but it's now + // really all Rx. And since I think it's Rx above us too, we can probably remove IAsyncEnumerable + // from the picture completely. This is all reactive stuff, so I don't think it really belongs. + return this.GetObservable(cancellationToken).ToAsyncEnumerable(); + } + + public IObservable GetObservable(CancellationToken cancellationToken = default) + { + IObservable withoutRetry = Observable.Create(async (obs, innerCancel) => { - IObservable withoutRetry = Observable.Create(async (obs, innerCancel) => - { - using CancellationTokenSource? cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancel); - CancellationToken mergedToken = cts.Token; + using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancel); + CancellationToken mergedToken = cts.Token; - while (!mergedToken.IsCancellationRequested) - { - // Seems like we need a new one each time we try to connect, because if we reuse - // the previous TcpClient after a failure, it tells us it's disposed even if we - // didn't dispose it directly. (Perhaps disposing the NetworkStream has that effect?) - using TcpClient tcpClient = new(); - await tcpClient.ConnectAsync(this.Host, this.Port, mergedToken); - await using NetworkStream stream = tcpClient.GetStream(); - using StreamReader reader = new(stream); + while (!mergedToken.IsCancellationRequested) + { + // Seems like we need a new one each time we try to connect, because if we reuse + // the previous TcpClient after a failure, it tells us it's disposed even if we + // didn't dispose it directly. (Perhaps disposing the NetworkStream has that effect?) + using TcpClient tcpClient = new(); + await tcpClient.ConnectAsync(this.Host, this.Port, mergedToken); + await using NetworkStream stream = tcpClient.GetStream(); + using StreamReader reader = new(stream); - int retryAttempt = 0; + int retryAttempt = 0; - while (tcpClient.Connected) + while (tcpClient.Connected) + { + while (stream.DataAvailable && !mergedToken.IsCancellationRequested) { - while (stream.DataAvailable && !mergedToken.IsCancellationRequested) - { - string? line = await reader.ReadLineAsync().ConfigureAwait(false); - if (line is not null) { obs.OnNext(line); } - retryAttempt = 0; - } - - if (mergedToken.IsCancellationRequested || retryAttempt == this.RetryAttemptLimit) - { - break; - } - - await Task.Delay(this.RetryPeriodicity, mergedToken).ConfigureAwait(false); + string? line = await reader.ReadLineAsync(mergedToken).ConfigureAwait(false); + if (line is not null) { obs.OnNext(line); } + retryAttempt = 0; + } - retryAttempt++; + if (mergedToken.IsCancellationRequested || retryAttempt == this.RetryAttemptLimit) + { + break; } - // Sometimes if the network connection drops, the TcpClient will just calmly set its - // Connected property to false and it won't throw an exception. So we need a non-exception - // retry loop. If we hit this point we just go round the outer try loop one more time. - // (It's quite likely if we hit this point that the very next thing to happen will - // be that the attempt to reconnect fails with an exception, but at that point the - // Rx-based retry will save us. + await Task.Delay(this.RetryPeriodicity, mergedToken).ConfigureAwait(false); + + retryAttempt++; } - }); - // Let Rx handle the retries for us in the event of a failure that produces - // an exception. - return withoutRetry.Retry(); - } + // Sometimes if the network connection drops, the TcpClient will just calmly set its + // Connected property to false, and it won't throw an exception. So we need a non-exception + // retry loop. If we hit this point we just go round the outer try loop one more time. + // (It's quite likely if we hit this point that the very next thing to happen will + // be that the attempt to reconnect fails with an exception, but at that point the + // Rx-based retry will save us. + } + }); + + // Let Rx handle the retries for us in the event of a failure that produces + // an exception. + return withoutRetry.Retry(); } } \ No newline at end of file diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/ReceiverHost.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/ReceiverHost.cs index aff0585..994768c 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/ReceiverHost.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Receiver/ReceiverHost.cs @@ -2,105 +2,104 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Receiver +using System; +using System.Collections.Generic; +using System.Reactive.Subjects; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +using Ais.Net.Models.Abstractions; +using Ais.Net.Receiver.Parser; + +using Corvus.Retry; +using Corvus.Retry.Policies; +using Corvus.Retry.Strategies; + +namespace Ais.Net.Receiver.Receiver; + +public class ReceiverHost { - using System; - using System.Collections.Generic; - using System.Reactive.Subjects; - using System.Runtime.CompilerServices; - using System.Text; - using System.Threading; - using System.Threading.Tasks; - - using Ais.Net.Models.Abstractions; - using Ais.Net.Receiver.Parser; - - using Corvus.Retry; - using Corvus.Retry.Policies; - using Corvus.Retry.Strategies; - - public class ReceiverHost - { - private readonly INmeaReceiver receiver; - private readonly Subject sentences = new(); - private readonly Subject messages = new(); - private readonly Subject<(Exception Exception, string Line)> errors = new(); + private readonly INmeaReceiver receiver; + private readonly Subject sentences = new(); + private readonly Subject messages = new(); + private readonly Subject<(Exception Exception, string Line)> errors = new(); - public ReceiverHost(INmeaReceiver receiver) - { - this.receiver = receiver; - } + public ReceiverHost(INmeaReceiver receiver) + { + this.receiver = receiver; + } - public IObservable Sentences => this.sentences; + public IObservable Sentences => this.sentences; - public IObservable Messages => this.messages; + public IObservable Messages => this.messages; - public IObservable<(Exception Exception, string Line)> Errors => this.errors; + public IObservable<(Exception Exception, string Line)> Errors => this.errors; - public Task StartAsync(CancellationToken cancellationToken = default) - { - return Retriable.RetryAsync(() => - this.StartAsyncInternal(cancellationToken), - cancellationToken, - new Backoff(maxTries: 100, deltaBackoff: TimeSpan.FromSeconds(5)), - new AnyExceptionPolicy(), - false); - } + public Task StartAsync(CancellationToken cancellationToken = default) + { + return Retriable.RetryAsync(() => + this.StartAsyncInternal(cancellationToken), + cancellationToken, + new Backoff(maxTries: 100, deltaBackoff: TimeSpan.FromSeconds(5)), + new AnyExceptionPolicy(), + continueOnCapturedContext: false); + } - private async Task StartAsyncInternal(CancellationToken cancellationToken = default) - { - var processor = new NmeaToAisMessageTypeProcessor(); - var adapter = new NmeaLineToAisStreamAdapter(processor); + private async Task StartAsyncInternal(CancellationToken cancellationToken = default) + { + NmeaToAisMessageTypeProcessor processor = new(); + NmeaLineToAisStreamAdapter adapter = new(processor); - processor.Messages.Subscribe(this.messages); + processor.Messages.Subscribe(this.messages); - await foreach (string? message in this.GetAsync(cancellationToken).WithCancellation(cancellationToken)) + await foreach (string? message in this.GetAsync(cancellationToken).WithCancellation(cancellationToken)) + { + static void ProcessLineNonAsync(string line, INmeaLineStreamProcessor lineStreamProcessor, Subject<(Exception Exception, string Line)> errorSubject) { - static void ProcessLineNonAsync(string line, INmeaLineStreamProcessor lineStreamProcessor, Subject<(Exception Exception, string Line)> errorSubject) - { - byte[]? lineAsAscii = Encoding.ASCII.GetBytes(line); + byte[] lineAsAscii = Encoding.ASCII.GetBytes(line); - try - { - lineStreamProcessor.OnNext(new NmeaLineParser(lineAsAscii), 0); - } - catch (ArgumentException ex) + try + { + lineStreamProcessor.OnNext(new NmeaLineParser(lineAsAscii), lineNumber: 0); + } + catch (ArgumentException ex) + { + if (errorSubject.HasObservers) { - if (errorSubject.HasObservers) - { - errorSubject.OnNext((ex, line)); - } + errorSubject.OnNext((Exception: ex, line)); } - catch (NotImplementedException ex) + } + catch (NotImplementedException ex) + { + if (errorSubject.HasObservers) { - if (errorSubject.HasObservers) - { - errorSubject.OnNext((ex, line)); - } + errorSubject.OnNext((Exception: ex, line)); } } + } - this.sentences.OnNext(message); + this.sentences.OnNext(message); - if (this.messages.HasObservers) - { - ProcessLineNonAsync(message, adapter, this.errors); - } + if (this.messages.HasObservers) + { + ProcessLineNonAsync(message, adapter, this.errors); } } + } - private async IAsyncEnumerable GetAsync([EnumeratorCancellation]CancellationToken cancellationToken = default) + private async IAsyncEnumerable GetAsync([EnumeratorCancellation]CancellationToken cancellationToken = default) + { + await foreach (string message in this.receiver.GetAsync(cancellationToken)) { - await foreach (string? message in this.receiver.GetAsync(cancellationToken).WithCancellation(cancellationToken)) + if (message.IsMissingNmeaBlockTags()) { - if (message.IsMissingNmeaBlockTags()) - { - yield return message.PrependNmeaBlockTags(); - } - else - { - yield return message; - } + yield return message.PrependNmeaBlockTags(); + } + else + { + yield return message; } } } diff --git a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Storage/IStorageClient.cs b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Storage/IStorageClient.cs index 7f3a2f1..3eb5032 100644 --- a/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Storage/IStorageClient.cs +++ b/Solutions/Ais.Net.Receiver/Ais/Net/Receiver/Storage/IStorageClient.cs @@ -2,13 +2,12 @@ // Copyright (c) Endjin Limited. All rights reserved. // -namespace Ais.Net.Receiver.Storage -{ - using System.Collections.Generic; - using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Ais.Net.Receiver.Storage; - public interface IStorageClient - { - Task PersistAsync(IEnumerable messages); - } +public interface IStorageClient +{ + Task PersistAsync(IEnumerable messages); } \ No newline at end of file diff --git a/azure-pipelines.release.yml b/azure-pipelines.release.yml deleted file mode 100644 index 4ea43da..0000000 --- a/azure-pipelines.release.yml +++ /dev/null @@ -1,15 +0,0 @@ -trigger: none -pr: none - -resources: - repositories: - - repository: recommended_practices - type: github - name: endjin/Endjin.RecommendedPractices.AzureDevopsPipelines.GitHub - endpoint: ais-dotnet-github - -jobs: -- template: templates/tag.for.release.yml@recommended_practices - parameters: - vmImage: 'windows-latest' - service_connection_github: $(Endjin_Service_Connection_GitHub) \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index 4189757..0000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,24 +0,0 @@ -trigger: - branches: - include: - - master - - feature/* - tags: - include: - - '*' - -resources: - repositories: - - repository: recommended_practices - type: github - name: endjin/Endjin.RecommendedPractices.AzureDevopsPipelines.GitHub - endpoint: ais-dotnet-github - -jobs: -- template: templates/build.and.release.scripted.yml@recommended_practices - parameters: - vmImage: 'ubuntu-latest' - service_connection_nuget_org: $(Endjin_Service_Connection_NuGet_Org) - service_connection_github: $(Endjin_Service_Connection_GitHub) - solution_to_build: $(Endjin_Solution_To_Build) - netSdkVersion: '6.x' \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 076b553..bdf8b9e 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,4 @@ +#Requires -Version 7 <# .SYNOPSIS Runs a .NET flavoured build process. @@ -10,22 +11,14 @@ the build process. .PARAMETER Tasks Optionally override the default task executed as the entry-point of the build. -.PARAMETER Configuration - The build configuration, defaults to 'Release'. -.PARAMETER BuildRepositoryUri - Optional URI that supports pulling MSBuild logic from a web endpoint (e.g. a GitHub blob). +.PARAMETER ContainerRegistryType + The type of container registry to use when publishing any images (supported values: acr,docker,ghcr) +.PARAMETER ContainerRegistryFqdn + The fully-qualified domain name for the target container registry .PARAMETER SourcesDir The path where the source code to be built is located, defaults to the current working directory. -.PARAMETER CoverageDir - The output path for the test coverage data, if run. -.PARAMETER TestReportTypes - The test report format that should be generated by the test report generator, if run. -.PARAMETER PackagesDir - The output path for any packages produced as part of the build. .PARAMETER LogLevel The logging verbosity. -.PARAMETER Clean - When true, the .NET solution will be cleaned and all output/intermediate folders deleted. .PARAMETER BuildModulePath The path to import the Endjin.RecommendedPractices.Build module from. This is useful when testing pre-release versions of the Endjin.RecommendedPractices.Build that are not yet @@ -43,35 +36,27 @@ param ( [string[]] $Tasks = @("."), [Parameter()] - [string] $Configuration = "Debug", + [ValidateSet("", "docker", "acr", "ghcr")] + [string] $ContainerRegistryType = "acr", [Parameter()] - [string] $BuildRepositoryUri = "", + [string] $ContainerRegistryFqdn = "", [Parameter()] [string] $SourcesDir = $PWD, - [Parameter()] - [string] $CoverageDir = "_codeCoverage", - - [Parameter()] - [string] $TestReportTypes = "Cobertura", - - [Parameter()] - [string] $PackagesDir = "_packages", - [Parameter()] [ValidateSet("minimal","normal","detailed")] [string] $LogLevel = "minimal", [Parameter()] - [switch] $Clean, + [string] $Configuration = "Debug", [Parameter()] [string] $BuildModulePath, [Parameter()] - [version] $BuildModuleVersion = "1.5.10", + [string] $BuildModuleVersion = "1.5.10-beta0003", [Parameter()] [version] $InvokeBuildModuleVersion = "5.10.3" @@ -83,19 +68,26 @@ $InformationPreference = 'Continue' $here = Split-Path -Parent $PSCommandPath #region InvokeBuild setup -if (!(Get-Module -ListAvailable InvokeBuild)) { - Install-Module InvokeBuild -RequiredVersion $InvokeBuildModuleVersion -Scope CurrentUser -Force -Repository PSGallery -} -Import-Module InvokeBuild # This handles calling the build engine when this file is run like a normal PowerShell script # (i.e. avoids the need to have another script to setup the InvokeBuild environment and issue the 'Invoke-Build' command ) if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { + Install-PSResource InvokeBuild -Version $InvokeBuildModuleVersion -Scope CurrentUser -TrustRepository | Out-Null try { Invoke-Build $Tasks $MyInvocation.MyCommand.Path @PSBoundParameters } catch { - $_.ScriptStackTrace - throw + if ($env:GITHUB_ACTIONS) { + Write-Host ("::error file={0},line={1},col={2}::{3}" -f ` + $_.InvocationInfo.ScriptName, + $_.InvocationInfo.ScriptLineNumber, + $_.InvocationInfo.OffsetInLine, + $_.Exception.Message + ) + } + Write-Host -f Yellow "`n`n***`n*** Build Failure Summary - check previous logs for more details`n***" + Write-Host -f Yellow $_.Exception.Message + Write-Host -f Yellow $_.ScriptStackTrace + exit 1 } return } @@ -103,59 +95,40 @@ if ($MyInvocation.ScriptName -notlike '*Invoke-Build.ps1') { #region Import shared tasks and initialise build framework if (!($BuildModulePath)) { - if (!(Get-Module -ListAvailable Endjin.RecommendedPractices.Build | ? { $_.Version -eq $BuildModuleVersion })) { - Write-Information "Installing 'Endjin.RecommendedPractices.Build' module..." - Install-Module Endjin.RecommendedPractices.Build -RequiredVersion $BuildModuleVersion -Scope CurrentUser -Force -Repository PSGallery - } + Install-PSResource Endjin.RecommendedPractices.Build -Version $BuildModuleVersion -Scope CurrentUser -TrustRepository | Out-Null $BuildModulePath = "Endjin.RecommendedPractices.Build" } else { Write-Information "BuildModulePath: $BuildModulePath" } -Import-Module $BuildModulePath -RequiredVersion $BuildModuleVersion -Force +Import-Module $BuildModulePath -RequiredVersion ($BuildModuleVersion -split '-')[0] -Force +Write-Host "Using Build module version: $((Get-Module Endjin.RecommendedPractices.Build | Select-Object -ExpandProperty Version).ToString())" # Load the build process & tasks . Endjin.RecommendedPractices.Build.tasks #endregion - # # Build process control options # $SkipInit = $false $SkipVersion = $false $SkipBuild = $false -$CleanBuild = $Clean -$SkipTest = $false +$CleanBuild = $false +$SkipTest = $true $SkipTestReport = $false $SkipAnalysis = $false $SkipPackage = $false $SkipPublish = $false - # # Build process configuration # -$SolutionToBuild = (Resolve-Path (Join-Path $here ".\Solutions\Ais.Net.Receiver.sln")).Path -$ProjectsToPublish = @( - # "Solutions/MySolution/MyWebSite/MyWebSite.csproj" -) -$NuSpecFilesToPackage = @( - # "Solutions/MySolution/MyProject/MyProject.nuspec" -) - -# -# Specify files to exclude from code coverage -# This option is for excluding generated code -# - Use file path or directory path with globbing (e.g dir1/*.cs) -# - Use single or multiple paths (separated by comma) (e.g. **/dir1/class1.cs,**/dir2/*.cs,**/dir3/**/*.cs) -# -$ExcludeFilesFromCodeCoverage = "" +$SolutionToBuild = (Resolve-Path (Join-Path $here "./Solutions/Ais.Net.Receiver.sln")).Path # Synopsis: Build, Test and Package task . FullBuild - # build extensibility tasks task RunFirst {} task PreInit {} @@ -174,5 +147,4 @@ task PrePackage {} task PostPackage {} task PrePublish {} task PostPublish {} -task RunLast {} - +task RunLast {} \ No newline at end of file