From d300695b2a63b24f746da43d0c8f93579e210797 Mon Sep 17 00:00:00 2001 From: MithrilMan Date: Mon, 20 May 2024 16:58:37 +0200 Subject: [PATCH] Net8 (#43) * ported to net8 --- .editorconfig | 67 ++++++-- .github/workflows/main-build.yml | 2 +- Directory.Build.props | 8 +- .../DataTypes/NBitcoinTypes/Extensions.cs | 3 +- .../Benchmarks/DataTypes/Neo/Helper.cs | 6 +- .../Benchmarks/DataTypes/Neo/NEO_UInt256.cs | 3 +- .../Benchmarks/DataTypes/Neo/UInt160.cs | 3 +- .../MithrilShards.P2P.Benchmark.csproj | 15 +- src/ConnectionTest/ConnectionTest.csproj | 13 ++ .../BitcoinDevShard.cs | 6 +- .../MithrilShards.Chain.Bitcoin.Dev.csproj | 13 ++ ...BitcoinNetworkProtocolMessageSerializer.cs | 5 +- ...hards.Chain.Bitcoin.Network.Bedrock.csproj | 13 ++ .../BitcoinShard.cs | 29 +--- .../InvalidChainDefinitionException.cs | 3 - .../BlockHeaderRepositoryException.cs | 3 - .../Consensus/ChainState.cs | 57 ++++--- .../InMemoryBlockHeaderRepository.cs | 31 ++-- .../Consensus/InitialBlockDownloadTracker.cs | 6 +- .../Block/Validator/BlockValidator.cs | 2 +- .../Consensus/Validation/ValidationRuleSet.cs | 32 ++-- .../ForgeBuilderExtensions.cs | 2 +- .../MithrilShards.Chain.Bitcoin.csproj | 15 +- .../Network/BitcoinConnectionManager.cs | 5 - .../Protocol/Processors/BaseProcessor.cs | 55 +++---- .../Protocol/Processors/PingPongProcessor.cs | 10 +- .../Processors/SynchronizationProcessor.cs | 2 +- .../Crypto/HashGeneratorException.cs | 3 - .../DataAlgorithms/TopologicalSorter.cs | 20 +-- .../DataTypes/Uint256.Operators.cs | 4 +- .../EventBus/EventSubscriptionManager.cs | 4 +- .../EventBus/InMemoryEventBus.cs | 28 +--- .../EventBus/Subscription.cs | 4 +- .../Extensions/TaskExtensions.cs | 107 ------------- src/MithrilShards.Core/Forge/DataFolder.cs | 18 +-- src/MithrilShards.Core/Forge/DefaultForge.cs | 60 +++---- src/MithrilShards.Core/Forge/ForgeBuilder.cs | 15 +- .../Forge/ForgeBuilderException.cs | 3 - .../Forge/ForgeDataFolderLock.cs | 10 +- .../Forge/HostBuilderContextExtensions.cs | 2 +- .../ForgeBuilderExtensions.cs | 2 +- .../MithrilShards.Core.csproj | 31 ++-- .../Network/ConnectionManager.cs | 50 +++--- .../PeerAddressBook/DefaultPeerAddressBook.cs | 2 +- src/MithrilShards.Core/Network/PeerContext.cs | 52 +++--- .../MessageSerializationException.cs | 3 - .../NetworkMessageSerializerBase.cs | 5 +- .../Shards/IMithrilShard.cs | 6 +- .../Shards/MithrilShardSettingsBase.cs | 2 +- .../Validation/OptionsBuilderExtensions.cs | 34 ---- .../Validation/ValidationHostedService.cs | 53 ------ .../Shards/Validation/ValidatorOptions.cs | 10 -- .../Threading/BackgroundTaskQueue.cs | 5 +- .../Threading/PeriodicWork.cs | 23 ++- .../DevControllerShard.cs | 20 +-- .../MithrilShards.Dev.Controller.csproj | 15 +- .../ConsoleKeyDumper.cs | 24 ++- ...ards.Diagnostic.StatisticsCollector.csproj | 13 ++ .../StatisticFeedsCollector.cs | 13 +- .../StatisticsCollectorShard.cs | 32 ++-- .../MithrilShards.Example.Dev.csproj | 13 ++ ...ExampleNetworkProtocolMessageSerializer.cs | 5 +- ...thrilShards.Example.Network.Bedrock.csproj | 13 ++ .../MithrilShards.Example.Node.csproj | 13 ++ src/MithrilShards.Example/ExampleShard.cs | 28 +--- .../ForgeBuilderExtensions.cs | 2 +- .../MithrilShards.Example.csproj | 13 ++ .../Protocol/Processors/BaseProcessor.cs | 8 +- .../Protocol/Processors/PingPongProcessor.cs | 10 +- .../LevelSwitcherManager.cs | 7 +- .../MithrilShards.Logging.Serilog.csproj | 17 +- .../SerilogShard.cs | 6 +- ...ithrilShards.Logging.TableFormatter.csproj | 13 ++ .../TableAlreadyDefined.cs | 3 - .../TableBuilder.cs | 9 +- .../BedrockForgeConnectivity.cs | 5 +- .../BedrockNetworkShard.cs | 151 +++++++++--------- .../ForgeBuilderExtensions.cs | 5 +- .../MithrilForgeClientConnectionHandler.cs | 50 +++--- .../MithrilForgeServerConnectionHandler.cs | 22 +-- .../MithrilShards.Network.Bedrock.csproj | 17 +- .../BlazorServerShard.cs | 90 +++++------ .../MithrilShards.UI.BlazorServer.csproj | 19 ++- .../MithrilShards.WebApi.csproj | 15 +- src/MithrilShards.WebApi/WebApiShard.cs | 6 +- .../JsonFileDataAttribute.cs | 2 +- .../MithrilShards.Chain.BitcoinTests.csproj | 26 ++- 87 files changed, 757 insertions(+), 893 deletions(-) delete mode 100644 src/MithrilShards.Core/Extensions/TaskExtensions.cs delete mode 100644 src/MithrilShards.Core/Shards/Validation/OptionsBuilderExtensions.cs delete mode 100644 src/MithrilShards.Core/Shards/Validation/ValidationHostedService.cs delete mode 100644 src/MithrilShards.Core/Shards/Validation/ValidatorOptions.cs diff --git a/.editorconfig b/.editorconfig index 06d2bd27..3fe398cc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,6 +2,13 @@ [*] end_of_line = crlf indent_size = 3 +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 3 +dotnet_style_coalesce_expression = true:error +dotnet_style_null_propagation = true:warning +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_object_initializer = true:warning [*.xml] indent_style = space @@ -11,14 +18,14 @@ indent_style = space ########## Naming Styles ##### Naming Rules # name all constant fields using UPPERCASE -dotnet_naming_rule.constant_fields_should_be_upper_case.severity = error +dotnet_naming_rule.constant_fields_should_be_upper_case.severity = error dotnet_naming_rule.constant_fields_should_be_upper_case.symbols = constant_fields -dotnet_naming_rule.constant_fields_should_be_upper_case.style = upper_case_style +dotnet_naming_rule.constant_fields_should_be_upper_case.style = upper_case_style # name all private fields using camelCase and underscore prefix dotnet_naming_rule.private_members_with_underscore.symbols = private_fields -dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore -dotnet_naming_rule.private_members_with_underscore.severity = error +dotnet_naming_rule.private_members_with_underscore.style = prefix_underscore +dotnet_naming_rule.private_members_with_underscore.severity = error ##### End Naming Rules ##### End Symbol Specifications @@ -74,7 +81,7 @@ csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_open_brace = all csharp_new_line_between_query_expression_clauses = true csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async : error -csharp_prefer_braces = when_multiline : error +csharp_prefer_braces = when_multiline:error csharp_prefer_simple_default_expression = true : suggestion csharp_preserve_single_line_blocks = true csharp_preserve_single_line_statements = true @@ -90,20 +97,20 @@ csharp_space_between_parentheses = false csharp_style_deconstructed_variable_declaration = true : suggestion csharp_style_conditional_delegate_call = true : suggestion -csharp_style_expression_bodied_accessors = true : silent -csharp_style_expression_bodied_constructors = true : silent -csharp_style_expression_bodied_indexers = true : silent -csharp_style_expression_bodied_methods = true : silent -csharp_style_expression_bodied_operators = true : silent -csharp_style_expression_bodied_properties = true : silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_constructors = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_methods = true:silent +csharp_style_expression_bodied_operators = true:silent +csharp_style_expression_bodied_properties = true:silent csharp_style_inlined_variable_declaration = true : error csharp_style_pattern_local_over_anonymous_function = true : suggestion csharp_style_pattern_matching_over_as_with_null_check = true : error csharp_style_pattern_matching_over_is_with_cast_check = true : error csharp_style_throw_expression = true : silent -csharp_style_var_elsewhere = false : suggestion -csharp_style_var_for_built_in_types = false : suggestion -csharp_style_var_when_type_is_apparent = true : suggestion +csharp_style_var_elsewhere = false +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = true @@ -137,7 +144,7 @@ dotnet_diagnostic.CA1001.severity = suggestion dotnet_diagnostic.CA1028.severity = suggestion # CA1062: Validate arguments of public methods -dotnet_diagnostic.CA1062.severity = silent +dotnet_diagnostic.CA1062.severity = suggestion # CA1308: Normalize strings to uppercase dotnet_diagnostic.CA1308.severity = silent @@ -149,7 +156,7 @@ dotnet_diagnostic.VSTHRD200.severity = suggestion dotnet_diagnostic.CA1812.severity = none # CA1819: Properties should not return arrays -dotnet_diagnostic.CA1819.severity = suggestion +dotnet_diagnostic.CA1819.severity = silent # CA1040: Avoid empty interfaces dotnet_diagnostic.CA1040.severity = suggestion @@ -171,4 +178,30 @@ dotnet_diagnostic.CS1587.severity = silent # IDE0090: Use 'new(...)' csharp_style_implicit_object_creation_when_type_is_apparent = true: warning -csharp_style_namespace_declarations=file_scoped:warning +csharp_style_namespace_declarations= file_scoped:warning +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent + +# IDE0008: Use explicit type +dotnet_diagnostic.IDE0008.severity = silent + +# IDE0290: Use primary constructor +dotnet_diagnostic.IDE0290.severity = silent + +# CA1510: Use ArgumentNullException throw helper +dotnet_diagnostic.CA1510.severity = warning + +# CA2254: Template should be a static expression +dotnet_diagnostic.CA2254.severity = warning + +# IDE0057: Use range operator +dotnet_diagnostic.IDE0057.severity = silent + +# CA2012: Use ValueTasks correctly +dotnet_diagnostic.CA2012.severity = silent diff --git a/.github/workflows/main-build.yml b/.github/workflows/main-build.yml index 0ed1b1ad..fefe0f4f 100644 --- a/.github/workflows/main-build.yml +++ b/.github/workflows/main-build.yml @@ -104,7 +104,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: dotnet Restore run: dotnet restore -s "https://api.nuget.org/v3/index.json" -s "https://f.feedz.io/davidfowl/bedrockframework/nuget/index.json" diff --git a/Directory.Build.props b/Directory.Build.props index 5de0b51e..52eac962 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,9 @@ - 2020 Mithril Man. + 2024 Mithril Man. + 0.3.0 + false true @@ -21,8 +23,8 @@ true - net6.0 - 10.0 + net8.0 + 12.0 enable diff --git a/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/NBitcoinTypes/Extensions.cs b/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/NBitcoinTypes/Extensions.cs index 8a12fae6..93d389c9 100644 --- a/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/NBitcoinTypes/Extensions.cs +++ b/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/NBitcoinTypes/Extensions.cs @@ -6,8 +6,7 @@ public static class Extensions { internal static byte[] SafeSubarray(this byte[] array, int offset, int count) { - if (array == null) - throw new ArgumentNullException(nameof(array)); + ArgumentNullException.ThrowIfNull(array); if (offset < 0 || offset > array.Length) throw new ArgumentOutOfRangeException("offset"); if (count < 0 || offset + count > array.Length) diff --git a/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/Helper.cs b/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/Helper.cs index 31a92c32..97904c89 100644 --- a/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/Helper.cs +++ b/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/Helper.cs @@ -283,11 +283,11 @@ internal static BigInteger WeightedAverage(this IEnumerable source, Func WeightedFilter(this IList source, double start, double end, Func weightSelector, Func resultSelector) { - if (source == null) throw new ArgumentNullException(nameof(source)); + ArgumentNullException.ThrowIfNull(source); if (start < 0 || start > 1) throw new ArgumentOutOfRangeException(nameof(start)); if (end < start || start + end > 1) throw new ArgumentOutOfRangeException(nameof(end)); - if (weightSelector == null) throw new ArgumentNullException(nameof(weightSelector)); - if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + ArgumentNullException.ThrowIfNull(weightSelector); + ArgumentNullException.ThrowIfNull(resultSelector); if (source.Count == 0 || start == end) yield break; double amount = (double)source.Select(weightSelector).Sum(); BigInteger sum = 0; diff --git a/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/NEO_UInt256.cs b/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/NEO_UInt256.cs index cb4d11b3..cc3a058a 100644 --- a/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/NEO_UInt256.cs +++ b/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/NEO_UInt256.cs @@ -90,8 +90,7 @@ public override int GetHashCode() /// public static new NEO_UInt256 Parse(string s) { - if (s == null) - throw new ArgumentNullException(); + ArgumentNullException.ThrowIfNull(s); if (s.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) s = s.Substring(2); if (s.Length != LENGTH * 2) diff --git a/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/UInt160.cs b/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/UInt160.cs index 3c4fe56f..1371048c 100644 --- a/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/UInt160.cs +++ b/benchmarks/MithrilShards.P2P.Benchmark/Benchmarks/DataTypes/Neo/UInt160.cs @@ -82,8 +82,7 @@ public override int GetHashCode() /// public static new UInt160 Parse(string value) { - if (value == null) - throw new ArgumentNullException(nameof(value)); + ArgumentNullException.ThrowIfNull(value); if (value.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase)) value = value.Substring(2); if (value.Length != LENGTH * 2) diff --git a/benchmarks/MithrilShards.P2P.Benchmark/MithrilShards.P2P.Benchmark.csproj b/benchmarks/MithrilShards.P2P.Benchmark/MithrilShards.P2P.Benchmark.csproj index b295daf0..13afc3ea 100644 --- a/benchmarks/MithrilShards.P2P.Benchmark/MithrilShards.P2P.Benchmark.csproj +++ b/benchmarks/MithrilShards.P2P.Benchmark/MithrilShards.P2P.Benchmark.csproj @@ -14,7 +14,7 @@ - + @@ -23,4 +23,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/ConnectionTest/ConnectionTest.csproj b/src/ConnectionTest/ConnectionTest.csproj index b31a2c98..e11cbe3b 100644 --- a/src/ConnectionTest/ConnectionTest.csproj +++ b/src/ConnectionTest/ConnectionTest.csproj @@ -40,4 +40,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Chain.Bitcoin.Dev/BitcoinDevShard.cs b/src/MithrilShards.Chain.Bitcoin.Dev/BitcoinDevShard.cs index 35527c72..b8a629d1 100644 --- a/src/MithrilShards.Chain.Bitcoin.Dev/BitcoinDevShard.cs +++ b/src/MithrilShards.Chain.Bitcoin.Dev/BitcoinDevShard.cs @@ -9,7 +9,7 @@ namespace MithrilShards.Chain.Bitcoin.Dev; /// public class BitcoinDevShard : IMithrilShard { - public ValueTask InitializeAsync(CancellationToken cancellationToken) => default; - public ValueTask StartAsync(CancellationToken cancellationToken) => default; - public ValueTask StopAsync(CancellationToken cancellationToken) => default; + public Task InitializeAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/src/MithrilShards.Chain.Bitcoin.Dev/MithrilShards.Chain.Bitcoin.Dev.csproj b/src/MithrilShards.Chain.Bitcoin.Dev/MithrilShards.Chain.Bitcoin.Dev.csproj index c6beef65..b0b01965 100644 --- a/src/MithrilShards.Chain.Bitcoin.Dev/MithrilShards.Chain.Bitcoin.Dev.csproj +++ b/src/MithrilShards.Chain.Bitcoin.Dev/MithrilShards.Chain.Bitcoin.Dev.csproj @@ -8,4 +8,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Chain.Bitcoin.Network.Bedrock/BitcoinNetworkProtocolMessageSerializer.cs b/src/MithrilShards.Chain.Bitcoin.Network.Bedrock/BitcoinNetworkProtocolMessageSerializer.cs index d1a0f24f..d2973641 100644 --- a/src/MithrilShards.Chain.Bitcoin.Network.Bedrock/BitcoinNetworkProtocolMessageSerializer.cs +++ b/src/MithrilShards.Chain.Bitcoin.Network.Bedrock/BitcoinNetworkProtocolMessageSerializer.cs @@ -239,10 +239,7 @@ private bool TryReadChecksum(ref SequenceReader reader) public void WriteMessage(INetworkMessage message, IBufferWriter output) { - if (message is null) - { - throw new ArgumentNullException(nameof(message)); - } + ArgumentNullException.ThrowIfNull(message); string command = message.Command; using (_logger.BeginScope("Serializing and sending '{Command}'", command)) diff --git a/src/MithrilShards.Chain.Bitcoin.Network.Bedrock/MithrilShards.Chain.Bitcoin.Network.Bedrock.csproj b/src/MithrilShards.Chain.Bitcoin.Network.Bedrock/MithrilShards.Chain.Bitcoin.Network.Bedrock.csproj index 3b6c9908..06a2012e 100644 --- a/src/MithrilShards.Chain.Bitcoin.Network.Bedrock/MithrilShards.Chain.Bitcoin.Network.Bedrock.csproj +++ b/src/MithrilShards.Chain.Bitcoin.Network.Bedrock/MithrilShards.Chain.Bitcoin.Network.Bedrock.csproj @@ -6,4 +6,17 @@ + + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/src/MithrilShards.Chain.Bitcoin/BitcoinShard.cs b/src/MithrilShards.Chain.Bitcoin/BitcoinShard.cs index daaf5738..661efe30 100644 --- a/src/MithrilShards.Chain.Bitcoin/BitcoinShard.cs +++ b/src/MithrilShards.Chain.Bitcoin/BitcoinShard.cs @@ -1,35 +1,14 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using MithrilShards.Core.Shards; namespace MithrilShards.Chain.Bitcoin; public class BitcoinShard : IMithrilShard { - private readonly ILogger _logger; - private readonly BitcoinSettings _settings; + public Task InitializeAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public BitcoinShard(ILogger logger, IOptions settings) - { - _logger = logger; - _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings)); - } + public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public ValueTask InitializeAsync(CancellationToken cancellationToken) - { - return default; - } - - public ValueTask StartAsync(CancellationToken cancellationToken) - { - return default; - } - - public ValueTask StopAsync(CancellationToken cancellationToken) - { - return default; - } + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/src/MithrilShards.Chain.Bitcoin/ChainDefinitions/InvalidChainDefinitionException.cs b/src/MithrilShards.Chain.Bitcoin/ChainDefinitions/InvalidChainDefinitionException.cs index 9182e960..9bfe17c4 100644 --- a/src/MithrilShards.Chain.Bitcoin/ChainDefinitions/InvalidChainDefinitionException.cs +++ b/src/MithrilShards.Chain.Bitcoin/ChainDefinitions/InvalidChainDefinitionException.cs @@ -8,7 +8,4 @@ public class InvalidChainDefinitionException : Exception public InvalidChainDefinitionException() { } public InvalidChainDefinitionException(string message) : base(message) { } public InvalidChainDefinitionException(string message, Exception inner) : base(message, inner) { } - protected InvalidChainDefinitionException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } diff --git a/src/MithrilShards.Chain.Bitcoin/Consensus/BlockHeaderRepositoryException.cs b/src/MithrilShards.Chain.Bitcoin/Consensus/BlockHeaderRepositoryException.cs index cb19330a..9188eae1 100644 --- a/src/MithrilShards.Chain.Bitcoin/Consensus/BlockHeaderRepositoryException.cs +++ b/src/MithrilShards.Chain.Bitcoin/Consensus/BlockHeaderRepositoryException.cs @@ -8,7 +8,4 @@ public class BlockHeaderRepositoryException : Exception public BlockHeaderRepositoryException() { } public BlockHeaderRepositoryException(string message) : base(message) { } public BlockHeaderRepositoryException(string message, Exception inner) : base(message, inner) { } - protected BlockHeaderRepositoryException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } diff --git a/src/MithrilShards.Chain.Bitcoin/Consensus/ChainState.cs b/src/MithrilShards.Chain.Bitcoin/Consensus/ChainState.cs index 9aaffd23..044db783 100644 --- a/src/MithrilShards.Chain.Bitcoin/Consensus/ChainState.cs +++ b/src/MithrilShards.Chain.Bitcoin/Consensus/ChainState.cs @@ -1,4 +1,5 @@ -using System.Diagnostics.CodeAnalysis; +using System; +using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.Logging; using MithrilShards.Chain.Bitcoin.DataTypes; using MithrilShards.Chain.Bitcoin.Protocol.Types; @@ -30,8 +31,6 @@ public class ChainState : IChainState /// private protected readonly ICoinsView coinsView; - readonly IConsensusParameters _consensusParameters; - /// /// Gets or sets the block sequence identifier. /// @@ -79,15 +78,18 @@ public ChainState(ILogger logger, IBlockHeaderRepository blockHeaderRepository, IConsensusParameters consensusParameters) { + ArgumentNullException.ThrowIfNull(consensusParameters); + ArgumentNullException.ThrowIfNull(headersTree); + this.logger = logger; HeadersTree = headersTree; this.coinsView = coinsView; _blockHeaderRepository = blockHeaderRepository; - _consensusParameters = consensusParameters; + ChainTip = headersTree.Genesis; BestHeader = headersTree.Genesis; - _blockHeaderRepository.TryAddAsync(consensusParameters.GenesisHeader); + _ = _blockHeaderRepository.TryAddAsync(consensusParameters.GenesisHeader); } /// @@ -147,6 +149,8 @@ public BlockHeader GetTipHeader() public HeaderNode FindForkInGlobalIndex(BlockLocator locator) { + ArgumentNullException.ThrowIfNull(locator); + using (GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult()) { @@ -174,6 +178,8 @@ public HeaderNode FindForkInGlobalIndex(BlockLocator locator) public bool TryGetNext(HeaderNode headerNode, [MaybeNullWhen(false)] out HeaderNode nextHeaderNode) { + ArgumentNullException.ThrowIfNull(headerNode); + using (GlobalLocks.ReadOnMainAsync().GetAwaiter().GetResult()) { if (IsInBestChain(headerNode) && HeadersTree.TryGetNodeOnBestChain(headerNode.Height + 1, out nextHeaderNode)) @@ -188,6 +194,7 @@ public bool TryGetNext(HeaderNode headerNode, [MaybeNullWhen(false)] out HeaderN public bool TryGetBlockHeader(HeaderNode headerNode, [MaybeNullWhen(false)] out BlockHeader blockHeader) { + ArgumentNullException.ThrowIfNull(headerNode); return _blockHeaderRepository.TryGet(headerNode.Hash, out blockHeader); } @@ -201,31 +208,31 @@ public bool TryGetAtHeight(int height, [MaybeNullWhen(false)] out HeaderNode? he public HeaderNode AddToBlockIndex(BlockHeader header) { - using (GlobalLocks.WriteOnMainAsync().GetAwaiter().GetResult()) - { + ArgumentNullException.ThrowIfNull(header); - // Check for duplicate - if (TryGetKnownHeaderNode(header.Hash, out HeaderNode? headerNode)) - { - return headerNode; - } - - if (!TryGetKnownHeaderNode(header.PreviousBlockHash, out HeaderNode? previousHeader)) - { - ThrowHelper.ThrowNotSupportedException("Previous hash not found (shouldn't happen)."); - } + using var theLock = GlobalLocks.WriteOnMainAsync().GetAwaiter().GetResult(); - headerNode = new HeaderNode(header, previousHeader); + // Check for duplicate + if (TryGetKnownHeaderNode(header.Hash, out HeaderNode? headerNode)) + { + return headerNode; + } - if (BestHeader == null || BestHeader.ChainWork < headerNode.ChainWork) - { - BestHeader = headerNode; - } + if (!TryGetKnownHeaderNode(header.PreviousBlockHash, out HeaderNode? previousHeader)) + { + ThrowHelper.ThrowNotSupportedException("Previous hash not found (shouldn't happen)."); + } - HeadersTree.Add(headerNode); - _blockHeaderRepository.TryAddAsync(header); + headerNode = new HeaderNode(header, previousHeader); - return headerNode; + if (BestHeader == null || BestHeader.ChainWork < headerNode.ChainWork) + { + BestHeader = headerNode; } + + HeadersTree.Add(headerNode); + _ = _blockHeaderRepository.TryAddAsync(header); + + return headerNode; } } diff --git a/src/MithrilShards.Chain.Bitcoin/Consensus/InMemoryBlockHeaderRepository.cs b/src/MithrilShards.Chain.Bitcoin/Consensus/InMemoryBlockHeaderRepository.cs index e23de01b..6ce3574b 100644 --- a/src/MithrilShards.Chain.Bitcoin/Consensus/InMemoryBlockHeaderRepository.cs +++ b/src/MithrilShards.Chain.Bitcoin/Consensus/InMemoryBlockHeaderRepository.cs @@ -15,19 +15,14 @@ namespace MithrilShards.Chain.Bitcoin.Consensus; /// /// In-Memory implementation of , not suitable for production. /// -/// -public class InMemoryBlockHeaderRepository : IBlockHeaderRepository +/// +public class InMemoryBlockHeaderRepository( + ILogger logger, + IEventBus eventBus + ) : IBlockHeaderRepository, IDisposable { - private readonly Dictionary _headers = new(); + private readonly Dictionary _headers = []; private readonly ReaderWriterLockSlim _theLock = new(); - readonly ILogger _logger; - readonly IEventBus _eventBus; - - public InMemoryBlockHeaderRepository(ILogger logger, IEventBus eventBus) - { - _logger = logger; - _eventBus = eventBus; - } /// /// Tries to add a header to the repository. @@ -40,11 +35,11 @@ public InMemoryBlockHeaderRepository(ILogger logg /// Block Header hash cannot be null public async ValueTask TryAddAsync(BlockHeader header) { - if (header is null) throw new ArgumentNullException(nameof(header)); + ArgumentNullException.ThrowIfNull(header); - UInt256? hash = header.Hash; - if (hash == null) throw new NullReferenceException("Block Header hash cannot be null"); + logger.LogDebug("Adding block header {BlockHash} to repository", header.Hash); + UInt256? hash = header.Hash ?? throw new NullReferenceException("Block Header hash cannot be null"); bool success; using (new WriteLock(_theLock)) { @@ -61,7 +56,7 @@ public async ValueTask TryAddAsync(BlockHeader header) if (success) { - await _eventBus.PublishAsync(new BlockHeaderAddedToRepository(header)).ConfigureAwait(false); + await eventBus.PublishAsync(new BlockHeaderAddedToRepository(header)).ConfigureAwait(false); } return success; @@ -77,11 +72,15 @@ public async ValueTask TryAddAsync(BlockHeader header) /// public bool TryGet(UInt256 hash, [MaybeNullWhen(false)] out BlockHeader header) { - if (hash is null) throw new ArgumentNullException(nameof(hash)); + ArgumentNullException.ThrowIfNull(hash); using (new ReadLock(_theLock)) { return _headers.TryGetValue(hash, out header!); } } + + public void Dispose() { + _theLock.Dispose(); + } } diff --git a/src/MithrilShards.Chain.Bitcoin/Consensus/InitialBlockDownloadTracker.cs b/src/MithrilShards.Chain.Bitcoin/Consensus/InitialBlockDownloadTracker.cs index 4aea90d9..3cf0186b 100644 --- a/src/MithrilShards.Chain.Bitcoin/Consensus/InitialBlockDownloadTracker.cs +++ b/src/MithrilShards.Chain.Bitcoin/Consensus/InitialBlockDownloadTracker.cs @@ -11,23 +11,19 @@ namespace MithrilShards.Chain.Bitcoin.Consensus; public class InitialBlockDownloadTracker : IInitialBlockDownloadTracker { readonly ILogger _logger; - readonly IEventBus _eventBus; readonly IChainState _chainState; readonly IConsensusParameters _consensusParameters; readonly IDateTimeProvider _dateTimeProvider; private readonly Target? _minimumChainWork; private readonly long _maxTipAge; - readonly EventSubscriptionManager _subscriptionManager = new(); public InitialBlockDownloadTracker(ILogger logger, - IEventBus eventBus, IChainState chainState, IConsensusParameters consensusParameters, IOptions options, IDateTimeProvider dateTimeProvider) { _logger = logger; - _eventBus = eventBus; _chainState = chainState; _consensusParameters = consensusParameters; _dateTimeProvider = dateTimeProvider; @@ -38,7 +34,7 @@ public InitialBlockDownloadTracker(ILogger logger, _minimumChainWork = options.Value.MinimumChainWork ?? _consensusParameters.MinimumChainWork; if (_minimumChainWork < _consensusParameters.MinimumChainWork) { - _logger.LogWarning($"{nameof(_minimumChainWork)} set below default value of {_consensusParameters.MinimumChainWork}"); + _logger.LogWarning("_minimumChainWork set below default value of {DefaultMinimumChainWork}", _consensusParameters.MinimumChainWork); } _maxTipAge = options.Value.MaxTipAge; diff --git a/src/MithrilShards.Chain.Bitcoin/Consensus/Validation/Block/Validator/BlockValidator.cs b/src/MithrilShards.Chain.Bitcoin/Consensus/Validation/Block/Validator/BlockValidator.cs index 46728837..f26e52de 100644 --- a/src/MithrilShards.Chain.Bitcoin/Consensus/Validation/Block/Validator/BlockValidator.cs +++ b/src/MithrilShards.Chain.Bitcoin/Consensus/Validation/Block/Validator/BlockValidator.cs @@ -84,7 +84,7 @@ private async Task ValidationWorkAsync(CancellationToken cancellation) { await foreach (BlockToValidate request in _blocksToValidate.Reader.ReadAllAsync(cancellation)) { - using IDisposable logScope = _logger.BeginScope("Validating block {BlockHash}", request.Block.Header!.Hash); + using var _ = _logger.BeginScope("Validating block {BlockHash}", request.Block.Header!.Hash); BlockValidationState? state = null; diff --git a/src/MithrilShards.Chain.Bitcoin/Consensus/Validation/ValidationRuleSet.cs b/src/MithrilShards.Chain.Bitcoin/Consensus/Validation/ValidationRuleSet.cs index ff2ac2af..a556b5fb 100644 --- a/src/MithrilShards.Chain.Bitcoin/Consensus/Validation/ValidationRuleSet.cs +++ b/src/MithrilShards.Chain.Bitcoin/Consensus/Validation/ValidationRuleSet.cs @@ -7,44 +7,32 @@ namespace MithrilShards.Chain.Bitcoin.Consensus.Validation; -public class ValidationRuleSet : IValidationRuleSet where TValidationRule : class +public class ValidationRuleSet(ILogger> logger, IEnumerable rules) : IValidationRuleSet where TValidationRule : class { - protected class RuleDefinition + protected class RuleDefinition(TValidationRule rule, uint preferredExecutionOrder) { - public TValidationRule Rule { get; } + public TValidationRule Rule { get; } = rule; - public uint PreferredExecutionOrder { get; } + public uint PreferredExecutionOrder { get; } = preferredExecutionOrder; - private readonly HashSet _executeAfter = new(); + private readonly HashSet _executeAfter = []; public IEnumerable GetDependencies() => _executeAfter; - public RuleDefinition(TValidationRule rule, uint preferredExecutionOrder) - { - Rule = rule; - PreferredExecutionOrder = preferredExecutionOrder; - } - public void ExecuteAfter(TValidationRule rule) { _executeAfter.Add(rule); } } - protected readonly ILogger> logger; - protected List rules; + protected readonly ILogger> logger = logger; + protected List rules = rules.ToList(); public IEnumerable Rules => rules; - public ValidationRuleSet(ILogger> logger, IEnumerable rules) - { - this.logger = logger; - this.rules = rules.ToList(); - } - public void SetupRules() { - using IDisposable logScope = logger.BeginScope("Setting up validation rules for {ValidationRuleType}", typeof(TValidationRule)); + using var _ = logger.BeginScope("Setting up validation rules for {ValidationRuleType}", typeof(TValidationRule)); List definitions = VerifyValidationRules(); @@ -63,7 +51,7 @@ public void SetupRules() } (IEnumerable<(ValidationRuleSet.RuleDefinition item, int level)> sorted, IEnumerable.RuleDefinition> cycled) = resolver.Sort(); - if (cycled.Count() > 0) + if (cycled.Any()) { string circularDependency = string.Join(", ", cycled.Select(definition => definition.Rule.GetType().Name)); ThrowHelper.ThrowNotSupportedException($"Error configuring {typeof(TValidationRule).Name} rules, circular dependency detected: {circularDependency}"); @@ -95,7 +83,7 @@ static List GetRequiredRules(Type ruleType) Type validationRulesType = typeof(TValidationRule); - using IDisposable logScope = logger.BeginScope("Verifying validation rules for {ValidationRuleType}", validationRulesType.Name); + using var _ = logger.BeginScope("Verifying validation rules for {ValidationRuleType}", validationRulesType.Name); foreach (TValidationRule rule in rules) { RulePrecedenceAttribute? precedenceAttribute = rule.GetType().GetCustomAttribute(); diff --git a/src/MithrilShards.Chain.Bitcoin/ForgeBuilderExtensions.cs b/src/MithrilShards.Chain.Bitcoin/ForgeBuilderExtensions.cs index c4e5918d..89d1e109 100644 --- a/src/MithrilShards.Chain.Bitcoin/ForgeBuilderExtensions.cs +++ b/src/MithrilShards.Chain.Bitcoin/ForgeBuilderExtensions.cs @@ -38,7 +38,7 @@ public static IForgeBuilder UseBitcoinChain(this IForgeBuilder forgeBuilder, int minimumSupportedVersion, int currentVersion) { - if (forgeBuilder is null) throw new ArgumentNullException(nameof(forgeBuilder)); + ArgumentNullException.ThrowIfNull(forgeBuilder); Type? chainDefinitionType = networkName.ToLowerInvariant() switch { diff --git a/src/MithrilShards.Chain.Bitcoin/MithrilShards.Chain.Bitcoin.csproj b/src/MithrilShards.Chain.Bitcoin/MithrilShards.Chain.Bitcoin.csproj index 009f3216..bd31fbce 100644 --- a/src/MithrilShards.Chain.Bitcoin/MithrilShards.Chain.Bitcoin.csproj +++ b/src/MithrilShards.Chain.Bitcoin/MithrilShards.Chain.Bitcoin.csproj @@ -8,11 +8,24 @@ - + + + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/src/MithrilShards.Chain.Bitcoin/Network/BitcoinConnectionManager.cs b/src/MithrilShards.Chain.Bitcoin/Network/BitcoinConnectionManager.cs index b0c384ca..dd30f27c 100644 --- a/src/MithrilShards.Chain.Bitcoin/Network/BitcoinConnectionManager.cs +++ b/src/MithrilShards.Chain.Bitcoin/Network/BitcoinConnectionManager.cs @@ -3,7 +3,6 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -using MithrilShards.Core; using MithrilShards.Core.EventBus; using MithrilShards.Core.Network; using MithrilShards.Core.Network.Client; @@ -14,17 +13,13 @@ namespace MithrilShards.Chain.Bitcoin.Network; public class BitcoinConnectionManager : ConnectionManager { - private readonly TimeSpan _inactivityThreshold = TimeSpan.FromSeconds(2 * 60); - readonly IRandomNumberGenerator _randomNumberGenerator; readonly IPeriodicWork _periodicPeerHealthCheck; public BitcoinConnectionManager(ILogger logger, IEventBus eventBus, IStatisticFeedsCollector statisticFeedsCollector, IEnumerable connectors, - IRandomNumberGenerator randomNumberGenerator, IPeriodicWork periodicPeerHealthCheck) : base(logger, eventBus, statisticFeedsCollector, connectors) { - _randomNumberGenerator = randomNumberGenerator; _periodicPeerHealthCheck = periodicPeerHealthCheck; } diff --git a/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/BaseProcessor.cs b/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/BaseProcessor.cs index 7d7f70fc..d27226be 100644 --- a/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/BaseProcessor.cs +++ b/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/BaseProcessor.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.VisualStudio.Threading; using MithrilShards.Chain.Bitcoin.Network; using MithrilShards.Core.EventBus; using MithrilShards.Core.Extensions; @@ -13,15 +14,22 @@ namespace MithrilShards.Chain.Bitcoin.Protocol.Processors; -public abstract class BaseProcessor : INetworkMessageProcessor +/// Initializes a new instance of the class. +/// The logger. +/// The event bus. +/// The peer behavior manager. +/// If set to true register the instance to be handshake aware: when the peer is handshaked, OnPeerHandshaked method will be invoked. +/// if set to true receives messages only if handshaked. +public abstract class BaseProcessor( + ILogger logger, + IEventBus eventBus, + IPeerBehaviorManager peerBehaviorManager, + bool isHandshakeAware, + bool receiveMessagesOnlyIfHandshaked + ) : INetworkMessageProcessor { - const int INIT_PROTO_VERSION = KnownVersion.V209; - - protected readonly ILogger logger; - protected readonly IEventBus eventBus; - private readonly IPeerBehaviorManager _peerBehaviorManager; - private readonly bool _isHandshakeAware; - private readonly bool _receiveMessagesOnlyIfHandshaked; + protected readonly ILogger logger = logger; + protected readonly IEventBus eventBus = eventBus; private bool _isHandshaked = false; private INetworkMessageWriter _messageWriter = null!; //hack to not rising null warnings, these are initialized when calling AttachAsync @@ -35,22 +43,7 @@ public abstract class BaseProcessor : INetworkMessageProcessor public virtual bool Enabled { get; private set; } = true; /// - public virtual bool CanReceiveMessages => _isHandshaked || _receiveMessagesOnlyIfHandshaked == false; - - /// Initializes a new instance of the class. - /// The logger. - /// The event bus. - /// The peer behavior manager. - /// If set to true register the instance to be handshake aware: when the peer is handshaked, OnPeerHandshaked method will be invoked. - /// if set to true receives messages only if handshaked. - public BaseProcessor(ILogger logger, IEventBus eventBus, IPeerBehaviorManager peerBehaviorManager, bool isHandshakeAware, bool receiveMessagesOnlyIfHandshaked) - { - this.logger = logger; - this.eventBus = eventBus; - _peerBehaviorManager = peerBehaviorManager; - _isHandshakeAware = isHandshakeAware; - _receiveMessagesOnlyIfHandshaked = receiveMessagesOnlyIfHandshaked; - } + public virtual bool CanReceiveMessages => _isHandshaked || receiveMessagesOnlyIfHandshaked == false; public async ValueTask AttachAsync(IPeerContext peerContext) { @@ -70,7 +63,7 @@ protected virtual ValueTask OnPeerAttachedAsync() { _isHandshaked = true; - if (_isHandshakeAware) + if (isHandshakeAware) { await OnPeerHandshakedAsync().ConfigureAwait(false); } @@ -81,7 +74,7 @@ protected virtual ValueTask OnPeerAttachedAsync() } /// - /// Method invoked when the peer handshakes and is set to . + /// Method invoked when the peer handshakes and isHandshakeAware is set to . /// /// protected virtual ValueTask OnPeerHandshakedAsync() @@ -166,7 +159,7 @@ protected Task DisconnectIfAsync(Func> condition, TimeSpan timeo { try { - await Task.Delay(timeout).WithCancellationAsync(cancellation).ConfigureAwait(false); + await Task.Delay(timeout, cancellation).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -178,7 +171,7 @@ protected Task DisconnectIfAsync(Func> condition, TimeSpan timeo { PeerContext.Disconnect(reason); } - }); + }, cancellation); } /// @@ -200,7 +193,7 @@ protected Task ExecuteIfAsync(Func> condition, TimeSpan timeout, { try { - await Task.Delay(timeout).WithCancellationAsync(cancellation).ConfigureAwait(false); + await Task.Delay(timeout, cancellation).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -213,7 +206,7 @@ protected Task ExecuteIfAsync(Func> condition, TimeSpan timeout, logger.LogDebug("Condition met, trigger action."); await action().ConfigureAwait(false); } - }); + }, cancellation); } /// @@ -224,7 +217,7 @@ protected Task ExecuteIfAsync(Func> condition, TimeSpan timeout, /// if set to true [disconnect]. protected void Misbehave(uint penalty, string reason, bool disconnect = false) { - _peerBehaviorManager.Misbehave(PeerContext, penalty, reason); + peerBehaviorManager.Misbehave(PeerContext, penalty, reason); if (disconnect) { PeerContext.Disconnect(reason); diff --git a/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/PingPongProcessor.cs b/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/PingPongProcessor.cs index f12cc7df..15877436 100644 --- a/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/PingPongProcessor.cs +++ b/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/PingPongProcessor.cs @@ -65,7 +65,7 @@ private async Task PingAsync(CancellationToken cancellationToken) ping.Nonce = _randomNumberGenerator.GetUint64(); } - await SendMessageAsync(ping).ConfigureAwait(false); + await SendMessageAsync(ping, cancellationToken).ConfigureAwait(false); _status.PingSent(_dateTimeProvider.GetTimeMicros(), ping); logger.LogDebug("Sent ping request with nonce {PingNonce}", _status.PingRequestNonce); @@ -86,24 +86,24 @@ await DisconnectIfAsync(() => async ValueTask INetworkMessageHandler.ProcessMessageAsync(PingMessage message, CancellationToken cancellation) { logger.LogDebug("Received ping with nonce {PingNonce}.", message.Nonce); - await SendMessageAsync(new PongMessage { Nonce = message.Nonce }).ConfigureAwait(false); + await SendMessageAsync(new PongMessage { Nonce = message.Nonce }, cancellation).ConfigureAwait(false); return true; } - ValueTask INetworkMessageHandler.ProcessMessageAsync(PongMessage message, CancellationToken cancellation) + async ValueTask INetworkMessageHandler.ProcessMessageAsync(PongMessage message, CancellationToken cancellation) { if (_status.PingRequestNonce != 0 && message.Nonce == _status.PingRequestNonce) { (ulong Nonce, long RoundTrip) = _status.PongReceived(_dateTimeProvider.GetTimeMicros()); logger.LogDebug("Received pong with nonce {PingNonce} in {PingRoundTrip} usec.", Nonce, RoundTrip); - _pingCancellationTokenSource.Cancel(); + await _pingCancellationTokenSource.CancelAsync().ConfigureAwait(false); } else { logger.LogDebug("Received pong with wrong nonce: {PingNonce}", _status.PingRequestNonce); } - return new ValueTask(true); + return true; } } diff --git a/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/SynchronizationProcessor.cs b/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/SynchronizationProcessor.cs index f6c46bd2..4798de11 100644 --- a/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/SynchronizationProcessor.cs +++ b/src/MithrilShards.Chain.Bitcoin/Protocol/Processors/SynchronizationProcessor.cs @@ -77,7 +77,7 @@ public SynchronizationProcessor(ILogger logger, _minimumChainWork = _options.MinimumChainWork ?? _consensusParameters.MinimumChainWork; if (_minimumChainWork < _consensusParameters.MinimumChainWork) { - this.logger.LogWarning($"{nameof(_minimumChainWork)} set below default value of {_consensusParameters.MinimumChainWork}"); + this.logger.LogWarning("_minimumChainWork set below default value of {DefaultMinimumChainWork}", _consensusParameters.MinimumChainWork); } headerSyncLoop.Configure(stopOnException: false, this); diff --git a/src/MithrilShards.Core/Crypto/HashGeneratorException.cs b/src/MithrilShards.Core/Crypto/HashGeneratorException.cs index 6474cb54..7b03f5ba 100644 --- a/src/MithrilShards.Core/Crypto/HashGeneratorException.cs +++ b/src/MithrilShards.Core/Crypto/HashGeneratorException.cs @@ -8,7 +8,4 @@ public class HashGeneratorException : Exception public HashGeneratorException() { } public HashGeneratorException(string message) : base(message) { } public HashGeneratorException(string message, Exception inner) : base(message, inner) { } - protected HashGeneratorException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } diff --git a/src/MithrilShards.Core/DataAlgorithms/TopologicalSorter.cs b/src/MithrilShards.Core/DataAlgorithms/TopologicalSorter.cs index 4d3c85ac..f2e0085c 100644 --- a/src/MithrilShards.Core/DataAlgorithms/TopologicalSorter.cs +++ b/src/MithrilShards.Core/DataAlgorithms/TopologicalSorter.cs @@ -12,10 +12,10 @@ public class TopologicalSorter where TItem : notnull private class Relations { public int Dependencies = 0; - public HashSet Dependents = new(); + public HashSet Dependents = []; } - private readonly Dictionary _map = new(); + private readonly Dictionary _map = []; /// @@ -35,7 +35,7 @@ public void Add(TItem item, params TItem[] dependencies) /// The dependencies. public void Add(TItem item, IEnumerable dependencies) { - if (dependencies.Count() == 0 && !_map.ContainsKey(item)) + if (!dependencies.Any() && !_map.ContainsKey(item)) { _map.Add(item, new Relations()); return; @@ -46,21 +46,23 @@ public void Add(TItem item, IEnumerable dependencies) // do not add eventual dependency to itself if (dependency.Equals(item)) continue; - if (!_map.ContainsKey(dependency)) + if (!_map.TryGetValue(dependency, out TopologicalSorter.Relations? dependencyDependecies)) { - _map.Add(dependency, new Relations()); + dependencyDependecies = new Relations(); + _map.Add(dependency, dependencyDependecies); } - HashSet? dependents = _map[dependency].Dependents; + HashSet? dependents = dependencyDependecies.Dependents; - if (!_map.ContainsKey(item)) + if (!_map.TryGetValue(item, out TopologicalSorter.Relations? itemDependencies)) { - _map.Add(item, new Relations()); + itemDependencies = new Relations(); + _map.Add(item, itemDependencies); } if (dependents.Add(item)) { - _map[item].Dependencies++; + itemDependencies.Dependencies++; } } } diff --git a/src/MithrilShards.Core/DataTypes/Uint256.Operators.cs b/src/MithrilShards.Core/DataTypes/Uint256.Operators.cs index b2906751..ebd99df2 100644 --- a/src/MithrilShards.Core/DataTypes/Uint256.Operators.cs +++ b/src/MithrilShards.Core/DataTypes/Uint256.Operators.cs @@ -42,8 +42,8 @@ public bool Equals(UInt256? other) public static int Compare(UInt256? a, UInt256? b) { - if (a is null) throw new ArgumentNullException(nameof(a)); - if (b is null) throw new ArgumentNullException(nameof(b)); + ArgumentNullException.ThrowIfNull(a); + ArgumentNullException.ThrowIfNull(b); if (a.part4 < b.part4) return -1; diff --git a/src/MithrilShards.Core/EventBus/EventSubscriptionManager.cs b/src/MithrilShards.Core/EventBus/EventSubscriptionManager.cs index 68673849..74b5a6ea 100644 --- a/src/MithrilShards.Core/EventBus/EventSubscriptionManager.cs +++ b/src/MithrilShards.Core/EventBus/EventSubscriptionManager.cs @@ -12,7 +12,7 @@ namespace MithrilShards.Core.EventBus; public class EventSubscriptionManager : IDisposable { private readonly object _subscriptionsLock = new(); - private readonly List _subscriptionTokens = new(); + private readonly List _subscriptionTokens = []; /// /// Registers the provided subscriptions. @@ -21,7 +21,7 @@ public class EventSubscriptionManager : IDisposable /// The subscription action. public EventSubscriptionManager RegisterSubscriptions(params SubscriptionToken[] subscriptions) { - if (_disposedValue) throw new ObjectDisposedException(nameof(EventSubscriptionManager)); + ObjectDisposedException.ThrowIf(_disposedValue, this); lock (_subscriptionsLock) { diff --git a/src/MithrilShards.Core/EventBus/InMemoryEventBus.cs b/src/MithrilShards.Core/EventBus/InMemoryEventBus.cs index 06783ddc..f3208aeb 100644 --- a/src/MithrilShards.Core/EventBus/InMemoryEventBus.cs +++ b/src/MithrilShards.Core/EventBus/InMemoryEventBus.cs @@ -36,22 +36,19 @@ public InMemoryEventBus(ILogger logger, ISubscriptionErrorHand { _logger = logger; _subscriptionErrorHandler = subscriptionErrorHandler; - _subscriptions = new Dictionary>(); + _subscriptions = []; } public SubscriptionToken Subscribe(Func handler) where TEvent : EventBase { - if (handler == null) - { - throw new ArgumentNullException(nameof(handler)); - } + ArgumentNullException.ThrowIfNull(handler); lock (_subscriptionsLock) { if (!_subscriptions.TryGetValue(typeof(TEvent), out List? eventSubscriptions)) { - eventSubscriptions = new(); + eventSubscriptions = []; _subscriptions.Add(typeof(TEvent), eventSubscriptions); } @@ -74,21 +71,12 @@ public void Unsubscribe(SubscriptionToken subscriptionToken) lock (_subscriptionsLock) { - if (_subscriptions.ContainsKey(subscriptionToken.EventType)) - { - var subscriptionToRemove = _subscriptions[subscriptionToken.EventType].FirstOrDefault(sub => sub.SubscriptionToken.Token == subscriptionToken.Token); - if (subscriptionToRemove != null) - { - _subscriptions[subscriptionToken.EventType].Remove(subscriptionToRemove); - } - } - - if (_subscriptions.ContainsKey(subscriptionToken.EventType)) + if (_subscriptions.TryGetValue(subscriptionToken.EventType, out List? value)) { - var subscriptionToRemove = _subscriptions[subscriptionToken.EventType].FirstOrDefault(sub => sub.SubscriptionToken.Token == subscriptionToken.Token); + var subscriptionToRemove = value.FirstOrDefault(sub => sub.SubscriptionToken.Token == subscriptionToken.Token); if (subscriptionToRemove != null) { - _subscriptions[subscriptionToken.EventType].Remove(subscriptionToRemove); + value.Remove(subscriptionToRemove); } } } @@ -106,9 +94,9 @@ public async Task PublishAsync(TEvent @event, CancellationToken cancella List? allSubscriptions = null; lock (_subscriptionsLock) { - if (_subscriptions.ContainsKey(eventType)) + if (_subscriptions.TryGetValue(eventType, out List? value)) { - allSubscriptions = _subscriptions[eventType].ToList(); + allSubscriptions = [.. value]; } } diff --git a/src/MithrilShards.Core/EventBus/Subscription.cs b/src/MithrilShards.Core/EventBus/Subscription.cs index 30bcedf8..5afe5af4 100644 --- a/src/MithrilShards.Core/EventBus/Subscription.cs +++ b/src/MithrilShards.Core/EventBus/Subscription.cs @@ -24,9 +24,9 @@ public Subscription(Func action, Subsc public ValueTask ProcessEventAsync(EventBase eventItem, CancellationToken cancellationToken) { - if (eventItem is null) throw new ArgumentNullException(nameof(eventItem)); + ArgumentNullException.ThrowIfNull(eventItem); - if (!(eventItem is TEventBase)) + if (eventItem is not TEventBase) { throw new ArgumentException("Event Item is not the correct type."); } diff --git a/src/MithrilShards.Core/Extensions/TaskExtensions.cs b/src/MithrilShards.Core/Extensions/TaskExtensions.cs deleted file mode 100644 index b9308424..00000000 --- a/src/MithrilShards.Core/Extensions/TaskExtensions.cs +++ /dev/null @@ -1,107 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace MithrilShards.Core.Extensions; - -[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD003:Avoid awaiting foreign Tasks", Justification = "")] -public static class TaskExtensions -{ - /// - /// Wraps a task with one that will complete as cancelled based on a cancellation token, - /// allowing someone to await a task but be able to break out early by cancelling the token. - /// - /// The type of value returned by the task. - /// The task to wrap. - /// The token that can be canceled to break out of the await. - /// The wrapping task. - public static Task WithCancellationAsync(this Task task, CancellationToken cancellationToken) - { - if (task is null) throw new ArgumentNullException(nameof(task)); - - if (!cancellationToken.CanBeCanceled || task.IsCompleted) - { - return task; - } - - if (cancellationToken.IsCancellationRequested) - { - return Task.FromCanceled(cancellationToken); - } - - return WithCancellationSlow(task, cancellationToken); - } - - - /// - /// Wraps a task with one that will complete as cancelled based on a cancellation token, - /// allowing someone to await a task but be able to break out early by cancelling the token. - /// - /// The task to wrap. - /// The token that can be canceled to break out of the await. - /// The wrapping task. - public static Task WithCancellationAsync(this Task task, CancellationToken cancellationToken) - { - if (task is null) ThrowHelper.ThrowArgumentNullException(nameof(task)); - - if (!cancellationToken.CanBeCanceled || task.IsCompleted) - { - return task; - } - - if (cancellationToken.IsCancellationRequested) - { - return Task.FromCanceled(cancellationToken); - } - - return WithCancellationSlow(task, continueOnCapturedContext: false, cancellationToken: cancellationToken); - } - - /// - /// Wraps a task with one that will complete as cancelled based on a cancellation token, - /// allowing someone to await a task but be able to break out early by cancelling the token. - /// - /// The type of value returned by the task. - /// The task to wrap. - /// A value indicating whether *internal* continuations required to respond to cancellation should run on the current . - /// The token that can be canceled to break out of the await. - /// The wrapping task. - private static async Task WithCancellationSlow(Task task, CancellationToken cancellationToken, bool continueOnCapturedContext = false) - { - var tcs = new TaskCompletionSource(); - using (cancellationToken.Register(s => ((TaskCompletionSource)s!).TrySetResult(true), tcs)) - { - if (task != await Task.WhenAny(task, tcs.Task).ConfigureAwait(continueOnCapturedContext)) - { - cancellationToken.ThrowIfCancellationRequested(); - } - } - - // Rethrow any fault/cancellation exception, even if we awaited above. - // But if we skipped the above if branch, this will actually yield - // on an incompleted task. - return await task.ConfigureAwait(continueOnCapturedContext); - } - - /// - /// Wraps a task with one that will complete as cancelled based on a cancellation token, - /// allowing someone to await a task but be able to break out early by cancelling the token. - /// - /// The task to wrap. - /// A value indicating whether *internal* continuations required to respond to cancellation should run on the current . - /// The token that can be canceled to break out of the await. - /// The wrapping task. - private static async Task WithCancellationSlow(this Task task, CancellationToken cancellationToken, bool continueOnCapturedContext = false) - { - var tcs = new TaskCompletionSource(); - using (cancellationToken.Register(s => ((TaskCompletionSource)s!).TrySetResult(true), tcs)) - { - if (task != await Task.WhenAny(task, tcs.Task).ConfigureAwait(continueOnCapturedContext)) - { - cancellationToken.ThrowIfCancellationRequested(); - } - } - - await task.ConfigureAwait(continueOnCapturedContext); - } -} diff --git a/src/MithrilShards.Core/Forge/DataFolder.cs b/src/MithrilShards.Core/Forge/DataFolder.cs index 3fc205f0..816cfe0c 100644 --- a/src/MithrilShards.Core/Forge/DataFolder.cs +++ b/src/MithrilShards.Core/Forge/DataFolder.cs @@ -14,10 +14,7 @@ public string this[string featureKey] { get { - if (featureKey == null) - { - throw new ArgumentNullException(nameof(featureKey)); - } + ArgumentNullException.ThrowIfNull(featureKey); if (_paths.TryGetValue(featureKey.ToLowerInvariant(), out string? path)) { @@ -30,15 +27,8 @@ public string this[string featureKey] } set { - if (featureKey == null) - { - throw new ArgumentNullException(nameof(featureKey)); - } - - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } + ArgumentNullException.ThrowIfNull(featureKey); + ArgumentNullException.ThrowIfNull(value); _paths[featureKey.ToLowerInvariant()] = value; } @@ -47,7 +37,7 @@ public string this[string featureKey] public DataFolders(string rootPath) { RootPath = rootPath; - _paths = new Dictionary(); + _paths = []; this[ROOT_FEATURE] = rootPath; } } diff --git a/src/MithrilShards.Core/Forge/DefaultForge.cs b/src/MithrilShards.Core/Forge/DefaultForge.cs index f2dabd53..5f5a0637 100644 --- a/src/MithrilShards.Core/Forge/DefaultForge.cs +++ b/src/MithrilShards.Core/Forge/DefaultForge.cs @@ -9,78 +9,70 @@ namespace MithrilShards.Core.Forge; -public class DefaultForge : BackgroundService, IForge +public class DefaultForge(ILogger logger, + IForgeDataFolderLock forgeDataFolderLock, + IEnumerable mithrilShards, + DefaultConfigurationWriter? defaultConfigurationManager = null) : BackgroundService, IForge { - private readonly IForgeDataFolderLock _forgeDataFolderLock; - readonly IEnumerable _mithrilShards; - readonly DefaultConfigurationWriter? _defaultConfigurationManager; - private readonly ILogger _logger; - - public DefaultForge(ILogger logger, - IForgeDataFolderLock forgeDataFolderLock, - IEnumerable mithrilShards, - DefaultConfigurationWriter? defaultConfigurationManager = null) - { - _forgeDataFolderLock = forgeDataFolderLock; - _mithrilShards = mithrilShards; - _defaultConfigurationManager = defaultConfigurationManager; - _logger = logger; - } private async Task InitializeShardsAsync(CancellationToken stoppingToken) { //if no default configuration file is present, create one - _defaultConfigurationManager?.GenerateDefaultFile(); + defaultConfigurationManager?.GenerateDefaultFile(); - using (_logger.BeginScope("Initializing Shards")) + using (logger.BeginScope("Initializing Shards")) { - foreach (IMithrilShard shard in _mithrilShards) + foreach (IMithrilShard shard in mithrilShards) { - _logger.LogDebug("Initializing Shard {ShardType}", shard.GetType().Name); + logger.LogDebug("Initializing Shard {ShardType}", shard.GetType().Name); await shard.InitializeAsync(stoppingToken).ConfigureAwait(false); } } - foreach (IMithrilShard shard in _mithrilShards) + foreach (IMithrilShard shard in mithrilShards) { - _logger.LogDebug("Starting Shard {ShardType}", shard.GetType().Name); + logger.LogDebug("Starting Shard {ShardType}", shard.GetType().Name); _ = shard.StartAsync(stoppingToken); } } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - if (!_forgeDataFolderLock.TryLockDataFolder()) + if (!forgeDataFolderLock.TryLockDataFolder()) { - _logger.LogCritical("Node folder is being used by another instance of the application!"); + logger.LogCritical("Node folder is being used by another instance of the application!"); throw new Exception("Node folder is being used!"); } await InitializeShardsAsync(stoppingToken).ConfigureAwait(false); - _forgeDataFolderLock.UnlockDataFolder(); + forgeDataFolderLock.UnlockDataFolder(); } public override async Task StopAsync(CancellationToken cancellationToken) { - using IDisposable logScope = _logger.BeginScope("Shutting down the Forge."); + using var logScope = logger.BeginScope("Shutting down the Forge."); - _logger.LogDebug("Stopping Shards"); - foreach (IMithrilShard shard in _mithrilShards) + logger.LogDebug("Stopping Shards"); + + // use wait all to wait for all shards to stop + var tasks = mithrilShards.Select(shard => { - _logger.LogDebug("Stopping Shard {ShardType}", shard.GetType().Name); - _ = shard.StopAsync(cancellationToken); - } + logger.LogDebug("Stopping Shard {ShardType}", shard.GetType().Name); + return shard.StopAsync(cancellationToken); + }).ToArray(); + + await Task.WhenAll(tasks).ConfigureAwait(false); - _logger.LogDebug("Stopping Forge instance."); + logger.LogDebug("Stopping Forge instance."); await base.StopAsync(cancellationToken).ConfigureAwait(false); } public List<(string name, string version)> GetMeltedShardsNames() { - if (_mithrilShards.Count() == 0) return new List<(string name, string version)>(); + if (!mithrilShards.Any()) return []; - return _mithrilShards.Select(shard => ( + return mithrilShards.Select(shard => ( name: shard.GetType().Name, version: shard.GetType().Assembly.GetName().Version?.ToString(3) ?? "-" )).ToList(); diff --git a/src/MithrilShards.Core/Forge/ForgeBuilder.cs b/src/MithrilShards.Core/Forge/ForgeBuilder.cs index 4bed2af8..719d0a63 100644 --- a/src/MithrilShards.Core/Forge/ForgeBuilder.cs +++ b/src/MithrilShards.Core/Forge/ForgeBuilder.cs @@ -24,7 +24,7 @@ public class ForgeBuilder : IForgeBuilder private readonly ILogger _logger; private bool _isForgeSet = false; private bool _createDefaultConfigurationFileNeeded = false; - private readonly List> _preBuildActions = new(); + private readonly List> _preBuildActions = []; private readonly HostBuilder _hostBuilder; public string ConfigurationFileName { get; private set; } = null!; //set to something meaningful during initialization @@ -57,7 +57,7 @@ private void CreateDefaultConfigurationFile(FileLoadExceptionContext fileContext { _createDefaultConfigurationFileNeeded = true; - _logger.LogWarning($"Missing configuration file {ConfigurationFileName}, creating one with default values."); + _logger.LogWarning("Missing configuration file {ConfigurationFileName}. Creating a default one.", ConfigurationFileName); //default file created, no need to throw error fileContext.Ignore = true; @@ -82,7 +82,7 @@ public IForgeBuilder UseForge(string[] commandLineArgs, st services.AddSingleton(services => { return new DefaultConfigurationWriter( - services.GetService().CreateLogger(), + services.GetRequiredService().CreateLogger(), services.GetServices(), ConfigurationFileName ); @@ -91,11 +91,10 @@ public IForgeBuilder UseForge(string[] commandLineArgs, st services .AddOptions() - .AddHostedService() // used to validate IOptions at startup, when they use ValidateOnStart (shards are automatically configured to validate asap) .AddSingleton(services) // register forge service collection in order to create other sandboxed serviceProviders in other Hosts (e.g. for API purpose) .AddSingleton() .AddHostedService(serviceProvider => (TForgeImplementation)serviceProvider.GetRequiredService()) - .ConfigureForge(context); + .ConfigureForge(); }); _isForgeSet = true; @@ -132,7 +131,7 @@ public IForgeBuilder AddShard { - var optionsBuilder = services + OptionsBuilder optionsBuilder = services .AddOptions() .Bind(MithrilShardSettingsManager.GetSection(context.Configuration)) .ValidateOnStart(); @@ -215,13 +214,13 @@ private void EnsureForgeIsSet() } } - private IForgeBuilder Configure(string[] commandLineArgs, string configurationFile = CONFIGURATION_FILE) + private ForgeBuilder Configure(string[] commandLineArgs, string configurationFile = CONFIGURATION_FILE) { ConfigurationFileName = Path.GetFullPath(configurationFile ?? CONFIGURATION_FILE); string absoluteDirectoryPath = Path.GetDirectoryName(ConfigurationFileName)!; if (!Directory.Exists(absoluteDirectoryPath)) { - _logger.LogWarning($"Creating directory structure to store configuration file {ConfigurationFileName}."); + _logger.LogWarning("Creating directory structure to store configuration file {ConfigurationFileName}", ConfigurationFileName); Directory.CreateDirectory(absoluteDirectoryPath); } var configurationFileProvider = new PhysicalFileProvider(absoluteDirectoryPath); diff --git a/src/MithrilShards.Core/Forge/ForgeBuilderException.cs b/src/MithrilShards.Core/Forge/ForgeBuilderException.cs index 8a68189b..7539eb37 100644 --- a/src/MithrilShards.Core/Forge/ForgeBuilderException.cs +++ b/src/MithrilShards.Core/Forge/ForgeBuilderException.cs @@ -12,7 +12,4 @@ public class ForgeBuilderException : Exception public ForgeBuilderException() { } public ForgeBuilderException(string message) : base(message) { } public ForgeBuilderException(string message, Exception inner) : base(message, inner) { } - protected ForgeBuilderException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } diff --git a/src/MithrilShards.Core/Forge/ForgeDataFolderLock.cs b/src/MithrilShards.Core/Forge/ForgeDataFolderLock.cs index 18246cb7..ef30044b 100644 --- a/src/MithrilShards.Core/Forge/ForgeDataFolderLock.cs +++ b/src/MithrilShards.Core/Forge/ForgeDataFolderLock.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; namespace MithrilShards.Core.Forge; @@ -6,7 +7,7 @@ namespace MithrilShards.Core.Forge; /// Class that prevents another instance of the node to run in the same data folder /// and allows external applications to see if the node is running. /// -public class ForgeDataFolderLock : IForgeDataFolderLock +public class ForgeDataFolderLock : IForgeDataFolderLock, IDisposable { private const string LOCK_FILE_NAME = "lockfile"; private readonly string _lockFileName; @@ -40,4 +41,9 @@ public void UnlockDataFolder() } catch { } } + + public void Dispose() + { + _fileStream?.Dispose(); + } } diff --git a/src/MithrilShards.Core/Forge/HostBuilderContextExtensions.cs b/src/MithrilShards.Core/Forge/HostBuilderContextExtensions.cs index 9611a935..2fc7e222 100644 --- a/src/MithrilShards.Core/Forge/HostBuilderContextExtensions.cs +++ b/src/MithrilShards.Core/Forge/HostBuilderContextExtensions.cs @@ -22,9 +22,9 @@ public static class HostBuilderContextExtensions internal static TMithrilShardSettings SetShardSettings(this HostBuilderContext context, IServiceCollection services) where TMithrilShardSettings : class, IMithrilShardSettings { - TMithrilShardSettings? settings = null; var key = typeof(TMithrilShardSettings); + TMithrilShardSettings? settings; if (!context.Properties.TryGetValue(key, out object? value)) { var tempSP = services.BuildServiceProvider(); diff --git a/src/MithrilShards.Core/ForgeBuilderExtensions.cs b/src/MithrilShards.Core/ForgeBuilderExtensions.cs index c049e480..84d58717 100644 --- a/src/MithrilShards.Core/ForgeBuilderExtensions.cs +++ b/src/MithrilShards.Core/ForgeBuilderExtensions.cs @@ -16,7 +16,7 @@ namespace MithrilShards.Core; internal static class ForgeBuilderExtensions { - public static IServiceCollection ConfigureForge(this IServiceCollection services, HostBuilderContext context) + public static IServiceCollection ConfigureForge(this IServiceCollection services) { services // data folder diff --git a/src/MithrilShards.Core/MithrilShards.Core.csproj b/src/MithrilShards.Core/MithrilShards.Core.csproj index 9d278ff0..6c6b80da 100644 --- a/src/MithrilShards.Core/MithrilShards.Core.csproj +++ b/src/MithrilShards.Core/MithrilShards.Core.csproj @@ -11,15 +11,15 @@ - - - - - - - - - + + + + + + + + + @@ -27,4 +27,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Core/Network/ConnectionManager.cs b/src/MithrilShards.Core/Network/ConnectionManager.cs index 4d86a5b1..e4bf873c 100644 --- a/src/MithrilShards.Core/Network/ConnectionManager.cs +++ b/src/MithrilShards.Core/Network/ConnectionManager.cs @@ -15,14 +15,14 @@ namespace MithrilShards.Core.Network; -public class ConnectionManager : IConnectionManager, IStatisticFeedsProvider +public class ConnectionManager : IConnectionManager, IStatisticFeedsProvider, IDisposable { private const string FEED_CONNECTED_PEERS_SUMMARY = "ConnectedPeersSummary"; private const string FEED_CONNECTED_PEERS = "ConnectedPeers"; protected readonly ConcurrentDictionary inboundPeers = new(); protected readonly ConcurrentDictionary outboundPeers = new(); - protected readonly HashSet attemptingConnections = new(); + protected readonly HashSet attemptingConnections = []; private readonly ILogger _logger; private readonly IEventBus _eventBus; @@ -152,22 +152,22 @@ public void RegisterStatisticFeeds() _statisticFeedsCollector.RegisterStatisticFeeds(this, new StatisticFeedDefinition(FEED_CONNECTED_PEERS_SUMMARY, "Connected Peers summary", - new List{ - new FieldDefinition("Inbound","Number of inbound peers currently connected to one of the Forge listener",15), - new FieldDefinition("Outbound","Number of outbound peers our forge is currently connected to",15) - }, + [ + new FieldDefinition("Inbound","Number of inbound peers currently connected to one of the Forge listener",15), + new FieldDefinition("Outbound","Number of outbound peers our forge is currently connected to",15) + ], TimeSpan.FromSeconds(15) ), new StatisticFeedDefinition(FEED_CONNECTED_PEERS, "Connected Peers", - new List{ - new FieldDefinition("Endpoint", "Peer remote endpoint", 25), - new FieldDefinition("Type", "Type of connection (inbound, outbound, etc..)", 10), - new FieldDefinition("Version", "Negotiated protocol version", 8), - new FieldDefinition("User Agent", "Peer User Agent", 20), - new FieldDefinition("Received", "Bytes received from this peer", 10, null, byteFormatter), - new FieldDefinition("Sent", "Bytes sent to this peer", 10, null, byteFormatter), - new FieldDefinition( "Wasted","Bytes that we received but wasn't understood from our node", 10, null, byteFormatter), - }, + [ + new FieldDefinition("Endpoint", "Peer remote endpoint", 25), + new FieldDefinition("Type", "Type of connection (inbound, outbound, etc..)", 10), + new FieldDefinition("Version", "Negotiated protocol version", 8), + new FieldDefinition("User Agent", "Peer User Agent", 20), + new FieldDefinition("Received", "Bytes received from this peer", 10, null, byteFormatter), + new FieldDefinition("Sent", "Bytes sent to this peer", 10, null, byteFormatter), + new FieldDefinition( "Wasted","Bytes that we received but wasn't understood from our node", 10, null, byteFormatter), + ], TimeSpan.FromSeconds(15) ) ); @@ -177,12 +177,7 @@ public void RegisterStatisticFeeds() { return feedId switch { - FEED_CONNECTED_PEERS_SUMMARY => new List { - new object?[] { - inboundPeers.Count, - outboundPeers.Count - } - }, + FEED_CONNECTED_PEERS_SUMMARY => [[inboundPeers.Count, outboundPeers.Count]], FEED_CONNECTED_PEERS => inboundPeers.Values.Concat(outboundPeers.Values) .Select(peer => new object?[] { @@ -249,24 +244,22 @@ public bool CanConnectTo(IPEndPoint remoteEndPoint) return true; } - protected ValueTask OnPeerDisconnectionRequestedAsync(PeerDisconnectionRequired @event, CancellationToken cancellationToken) + protected async ValueTask OnPeerDisconnectionRequestedAsync(PeerDisconnectionRequired @event, CancellationToken cancellationToken) { IPEndPoint endPoint = @event.EndPoint.AsIPEndPoint().EnsureIPv6(); IPeerContext? peerContext = inboundPeers.Values - .Concat(outboundPeers.Values.ToList()) + .Concat([.. outboundPeers.Values]) .FirstOrDefault(peer => peer.RemoteEndPoint.Equals(endPoint)); if (peerContext != null) { _logger.LogDebug("Requesting peer {RemoteEndPoint} disconnection because: {DisconnectionReason}", endPoint, @event.Reason); - peerContext.ConnectionCancellationTokenSource.Cancel(); + await peerContext.ConnectionCancellationTokenSource.CancelAsync().ConfigureAwait(false); } else { _logger.LogDebug("Requesting peer {RemoteEndPoint} disconnection failed, endpoint not matching with any connected peer.", endPoint); } - - return ValueTask.CompletedTask; } private ValueTask OnPeerConnectionAttemptAsync(PeerConnectionAttempt @event, CancellationToken cancellationToken) @@ -299,4 +292,9 @@ private ValueTask OnPeerConnectionAttemptFailedAsync(PeerConnectionAttemptFailed return ValueTask.CompletedTask; } + + public void Dispose() + { + _eventSubscriptionManager.Dispose(); + } } diff --git a/src/MithrilShards.Core/Network/PeerAddressBook/DefaultPeerAddressBook.cs b/src/MithrilShards.Core/Network/PeerAddressBook/DefaultPeerAddressBook.cs index c4009f10..f39d2278 100644 --- a/src/MithrilShards.Core/Network/PeerAddressBook/DefaultPeerAddressBook.cs +++ b/src/MithrilShards.Core/Network/PeerAddressBook/DefaultPeerAddressBook.cs @@ -57,6 +57,6 @@ public bool IsBanned(IPeerContext peer) private void LogNotImplementedWarning([CallerMemberName] string methodName = null!) { - _logger.LogWarning($"{methodName} not implemented "); + _logger.LogWarning("{MethodName} is not implemented", methodName); } } diff --git a/src/MithrilShards.Core/Network/PeerContext.cs b/src/MithrilShards.Core/Network/PeerContext.cs index 59366af4..1d945afe 100644 --- a/src/MithrilShards.Core/Network/PeerContext.cs +++ b/src/MithrilShards.Core/Network/PeerContext.cs @@ -13,38 +13,45 @@ namespace MithrilShards.Core.Network; -public class PeerContext : IPeerContext +public class PeerContext( + ILogger logger, + IEventBus eventBus, + PeerConnectionDirection direction, + string peerId, + EndPoint localEndPoint, + EndPoint publicEndPoint, + EndPoint remoteEndPoint, + INetworkMessageWriter messageWriter + ) : IPeerContext { - private readonly List _messageProcessors = new(); - protected readonly ILogger logger; - protected readonly IEventBus eventBus; - protected readonly INetworkMessageWriter messageWriter; + private readonly List _messageProcessors = []; + protected readonly ILogger logger = logger; + protected readonly IEventBus eventBus = eventBus; + protected readonly INetworkMessageWriter messageWriter = messageWriter; /// /// Gets the direction of the peer connection. /// - public PeerConnectionDirection Direction { get; } + public PeerConnectionDirection Direction { get; } = direction; /// /// Gets the peer identifier. /// - public string PeerId { get; } - + public string PeerId { get; } = peerId; /// /// Gets the local peer end point. /// - public IPEndPoint LocalEndPoint { get; } - + public IPEndPoint LocalEndPoint { get; } = localEndPoint.AsIPEndPoint(); /// External IP address and port number used to access the node from external network. /// Used to announce to external peers the address they connect to in order to reach our Forge server. - public IPEndPoint PublicEndPoint { get; } + public IPEndPoint PublicEndPoint { get; } = publicEndPoint.AsIPEndPoint(); /// /// Gets the remote peer end point. /// - public IPEndPoint RemoteEndPoint { get; } + public IPEndPoint RemoteEndPoint { get; } = remoteEndPoint.AsIPEndPoint(); public string? UserAgent { get; set; } @@ -65,25 +72,6 @@ public class PeerContext : IPeerContext public bool IsConnected { get; protected set; } = false; - public PeerContext(ILogger logger, - IEventBus eventBus, - PeerConnectionDirection direction, - string peerId, - EndPoint localEndPoint, - EndPoint publicEndPoint, - EndPoint remoteEndPoint, - INetworkMessageWriter messageWriter) - { - this.logger = logger; - this.eventBus = eventBus; - Direction = direction; - PeerId = peerId; - this.messageWriter = messageWriter; - LocalEndPoint = localEndPoint.AsIPEndPoint(); - PublicEndPoint = publicEndPoint.AsIPEndPoint(); - RemoteEndPoint = remoteEndPoint.AsIPEndPoint(); - } - public INetworkMessageWriter GetMessageWriter() { return messageWriter; @@ -121,7 +109,7 @@ public async ValueTask DisposeAsync() } IsConnected = false; - ConnectionCancellationTokenSource.Cancel(); + await ConnectionCancellationTokenSource.CancelAsync().ConfigureAwait(false); await eventBus.PublishAsync(new PeerDisconnected(this, "Client disconnected", null)).ConfigureAwait(false); } diff --git a/src/MithrilShards.Core/Network/Protocol/Serialization/MessageSerializationException.cs b/src/MithrilShards.Core/Network/Protocol/Serialization/MessageSerializationException.cs index a119ef46..e0d48337 100644 --- a/src/MithrilShards.Core/Network/Protocol/Serialization/MessageSerializationException.cs +++ b/src/MithrilShards.Core/Network/Protocol/Serialization/MessageSerializationException.cs @@ -8,7 +8,4 @@ public class MessageSerializationException : Exception public MessageSerializationException() { } public MessageSerializationException(string message) : base(message) { } public MessageSerializationException(string message, Exception inner) : base(message, inner) { } - protected MessageSerializationException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } diff --git a/src/MithrilShards.Core/Network/Protocol/Serialization/NetworkMessageSerializerBase.cs b/src/MithrilShards.Core/Network/Protocol/Serialization/NetworkMessageSerializerBase.cs index 9bed7acb..c60b2958 100644 --- a/src/MithrilShards.Core/Network/Protocol/Serialization/NetworkMessageSerializerBase.cs +++ b/src/MithrilShards.Core/Network/Protocol/Serialization/NetworkMessageSerializerBase.cs @@ -30,10 +30,7 @@ public Type GetMessageType() public void Serialize(INetworkMessage message, int protocolVersion, IPeerContext peerContext, IBufferWriter output) { - if (message is null) - { - throw new ArgumentNullException(nameof(message)); - } + ArgumentNullException.ThrowIfNull(message); Serialize((TMessageType)message, protocolVersion, (TPeerContext)peerContext, output); } diff --git a/src/MithrilShards.Core/Shards/IMithrilShard.cs b/src/MithrilShards.Core/Shards/IMithrilShard.cs index d0df31df..d3a24a0a 100644 --- a/src/MithrilShards.Core/Shards/IMithrilShard.cs +++ b/src/MithrilShards.Core/Shards/IMithrilShard.cs @@ -5,9 +5,9 @@ namespace MithrilShards.Core.Shards; public interface IMithrilShard { - public ValueTask InitializeAsync(CancellationToken cancellationToken); + public Task InitializeAsync(CancellationToken cancellationToken); - public ValueTask StartAsync(CancellationToken cancellationToken); + public Task StartAsync(CancellationToken cancellationToken); - public ValueTask StopAsync(CancellationToken cancellationToken); + public Task StopAsync(CancellationToken cancellationToken); } diff --git a/src/MithrilShards.Core/Shards/MithrilShardSettingsBase.cs b/src/MithrilShards.Core/Shards/MithrilShardSettingsBase.cs index 4884d0b5..a050b405 100644 --- a/src/MithrilShards.Core/Shards/MithrilShardSettingsBase.cs +++ b/src/MithrilShards.Core/Shards/MithrilShardSettingsBase.cs @@ -36,5 +36,5 @@ public virtual string ConfigurationSection /// /// A collection that holds failed-validation information. /// - public virtual IEnumerable Validate(ValidationContext validationContext) => Enumerable.Empty(); + public virtual IEnumerable Validate(ValidationContext validationContext) => []; } diff --git a/src/MithrilShards.Core/Shards/Validation/OptionsBuilderExtensions.cs b/src/MithrilShards.Core/Shards/Validation/OptionsBuilderExtensions.cs deleted file mode 100644 index ee237656..00000000 --- a/src/MithrilShards.Core/Shards/Validation/OptionsBuilderExtensions.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; - -namespace MithrilShards.Core.Shards.Validation; - -public static class OptionsBuilderExtensions -{ - /// - /// Enforces options validation check on start rather than in runtime. - /// - /// The type of options. - /// The to configure options instance. - /// The so that additional calls can be chained. - public static OptionsBuilder ValidateOnStart(this OptionsBuilder optionsBuilder) - where TOptions : class - { - if (optionsBuilder == null) - { - throw new ArgumentNullException(nameof(optionsBuilder)); - } - - //optionsBuilder.Services.AddHostedService(); - optionsBuilder.Services.AddOptions() - .Configure>((vo, options) => - { - // This adds an action that resolves the options value to force evaluation - // We don't care about the result as duplicates are not important - vo.Validators[typeof(TOptions)] = () => options.Get(optionsBuilder.Name); - }); - - return optionsBuilder; - } -} diff --git a/src/MithrilShards.Core/Shards/Validation/ValidationHostedService.cs b/src/MithrilShards.Core/Shards/Validation/ValidationHostedService.cs deleted file mode 100644 index 01569310..00000000 --- a/src/MithrilShards.Core/Shards/Validation/ValidationHostedService.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Runtime.ExceptionServices; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; - -namespace MithrilShards.Core.Shards.Validation; - -internal class ValidationHostedService : IHostedService -{ - private readonly IDictionary _validators; - - public ValidationHostedService(IOptions validatorOptions) - { - _validators = validatorOptions?.Value?.Validators ?? throw new ArgumentNullException(nameof(validatorOptions)); - } - - public Task StartAsync(CancellationToken cancellationToken) - { - var exceptions = new List(); - - foreach (var validate in _validators.Values) - { - try - { - // Execute the validation method and catch the validation error - validate(); - } - catch (OptionsValidationException ex) - { - exceptions.Add(ex); - } - } - - if (exceptions.Count == 1) - { - // Rethrow if it's a single error - ExceptionDispatchInfo.Capture(exceptions[0]).Throw(); - } - - if (exceptions.Count > 1) - { - // Aggregate if we have many errors - throw new AggregateException(exceptions); - } - - return Task.CompletedTask; - } - - public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; -} diff --git a/src/MithrilShards.Core/Shards/Validation/ValidatorOptions.cs b/src/MithrilShards.Core/Shards/Validation/ValidatorOptions.cs deleted file mode 100644 index ec312f41..00000000 --- a/src/MithrilShards.Core/Shards/Validation/ValidatorOptions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace MithrilShards.Core.Shards.Validation; - -internal class ValidatorOptions -{ - // Maps each options type to a method that forces its evaluation, e.g. IOptionsMonitor.Get(name) - public IDictionary Validators { get; } = new Dictionary(); -} diff --git a/src/MithrilShards.Core/Threading/BackgroundTaskQueue.cs b/src/MithrilShards.Core/Threading/BackgroundTaskQueue.cs index ca4a8776..88af5780 100644 --- a/src/MithrilShards.Core/Threading/BackgroundTaskQueue.cs +++ b/src/MithrilShards.Core/Threading/BackgroundTaskQueue.cs @@ -12,10 +12,7 @@ public class BackgroundTaskQueue : IBackgroundTaskQueue public void QueueBackgroundWorkItem(Func workItem) { - if (workItem == null) - { - throw new ArgumentNullException(nameof(workItem)); - } + ArgumentNullException.ThrowIfNull(workItem); _workItems.Enqueue(workItem); _signal.Release(); diff --git a/src/MithrilShards.Core/Threading/PeriodicWork.cs b/src/MithrilShards.Core/Threading/PeriodicWork.cs index ac3f7629..81f921bb 100644 --- a/src/MithrilShards.Core/Threading/PeriodicWork.cs +++ b/src/MithrilShards.Core/Threading/PeriodicWork.cs @@ -38,8 +38,7 @@ public sealed class PeriodicWork : IDisposable, IPeriodicWork private volatile string _label = string.Empty; public string Label => _label; - private bool _stopOnException; - public bool StopOnException => _stopOnException; + public bool StopOnException { get; private set; } private IPeriodicWorkExceptionHandler? _exceptionHandler = null; @@ -55,7 +54,7 @@ public PeriodicWork(ILogger logger, IPeriodicWorkTracker periodicW public void Configure(bool stopOnException = false, IPeriodicWorkExceptionHandler? exceptionHandler = null) { - _stopOnException = stopOnException; + StopOnException = stopOnException; _exceptionHandler = exceptionHandler; } @@ -93,8 +92,8 @@ private async Task StartInternalAsync(string label, IPeriodicWork.WorkAsync work { try { - await work(token).WithCancellationAsync(token).ConfigureAwait(false); - await Task.Delay(interval()).WithCancellationAsync(token).ConfigureAwait(false); + await work(token).WaitAsync(token).ConfigureAwait(false); + await Task.Delay(interval(), token).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -106,7 +105,7 @@ private async Task StartInternalAsync(string label, IPeriodicWork.WorkAsync work _lastException = ex; Interlocked.Increment(ref _exceptionsCount); - var feedback = new IPeriodicWorkExceptionHandler.Feedback(!_stopOnException, false, null); + var feedback = new IPeriodicWorkExceptionHandler.Feedback(!StopOnException, false, null); _exceptionHandler?.OnPeriodicWorkException(this, ex, ref feedback); if (!feedback.ContinueExecution) @@ -139,23 +138,21 @@ private async Task StartInternalAsync(string label, IPeriodicWork.WorkAsync work _periodicWorkTracker.StopTracking(this); } - public Task StopAsync() + public async Task StopAsync() { if (!_isRunning) { _logger.LogDebug("PeriodicWork {PeriodicWorkId} is not running.", Id); - return Task.CompletedTask; + return; } - if (!_cancellationTokenSource?.IsCancellationRequested ?? true) + if (_cancellationTokenSource != null && !_cancellationTokenSource.IsCancellationRequested) { _logger.LogDebug("PeriodicWork {PeriodicWorkId} is stopping.", Id); - _cancellationTokenSource?.Cancel(); - _cancellationTokenSource?.Dispose(); + await _cancellationTokenSource.CancelAsync().ConfigureAwait(false); + _cancellationTokenSource.Dispose(); _cancellationTokenSource = null; } - - return Task.CompletedTask; } diff --git a/src/MithrilShards.Dev.Controller/DevControllerShard.cs b/src/MithrilShards.Dev.Controller/DevControllerShard.cs index dca0ce8a..9cd8a211 100644 --- a/src/MithrilShards.Dev.Controller/DevControllerShard.cs +++ b/src/MithrilShards.Dev.Controller/DevControllerShard.cs @@ -1,30 +1,16 @@ using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using MithrilShards.Core.Shards; namespace MithrilShards.Dev.Controller; internal class DevControllerShard : IMithrilShard { - readonly ILogger _logger; - readonly DevControllerSettings _settings; - - public DevControllerShard(ILogger logger, IOptions options) - { - _logger = logger; - _settings = options.Value; - } - - public ValueTask InitializeAsync(CancellationToken cancellationToken) - { - return default; - } + public Task InitializeAsync(CancellationToken cancellationToken) => Task.CompletedTask; /// - public ValueTask StartAsync(CancellationToken cancellationToken) => default; + public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; /// - public ValueTask StopAsync(CancellationToken cancellationToken) => default; + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/src/MithrilShards.Dev.Controller/MithrilShards.Dev.Controller.csproj b/src/MithrilShards.Dev.Controller/MithrilShards.Dev.Controller.csproj index 64f85716..6ae7c68f 100644 --- a/src/MithrilShards.Dev.Controller/MithrilShards.Dev.Controller.csproj +++ b/src/MithrilShards.Dev.Controller/MithrilShards.Dev.Controller.csproj @@ -4,7 +4,7 @@ - + @@ -16,4 +16,17 @@ + + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + \ No newline at end of file diff --git a/src/MithrilShards.Diagnostic.StatisticsCollector/ConsoleKeyDumper.cs b/src/MithrilShards.Diagnostic.StatisticsCollector/ConsoleKeyDumper.cs index ff55f04e..ba9dc82e 100644 --- a/src/MithrilShards.Diagnostic.StatisticsCollector/ConsoleKeyDumper.cs +++ b/src/MithrilShards.Diagnostic.StatisticsCollector/ConsoleKeyDumper.cs @@ -7,19 +7,13 @@ namespace MithrilShards.Diagnostic.StatisticsCollector; -public class ConsoleKeyDumper +public class ConsoleKeyDumper( + IHostApplicationLifetime hostApplicationLifetime, + IStatisticFeedsCollector statisticFeedsCollector) { - readonly IHostApplicationLifetime _hostApplicationLifetime; - readonly IStatisticFeedsCollector _statisticFeedsCollector; private bool _isRunning; - public ConsoleKeyDumper(IHostApplicationLifetime hostApplicationLifetime, IStatisticFeedsCollector statisticFeedsCollector) - { - _hostApplicationLifetime = hostApplicationLifetime; - _statisticFeedsCollector = statisticFeedsCollector; - } - - public async Task StartListening() + public async Task StartListeningAsync() { if (_isRunning) { @@ -28,17 +22,17 @@ public async Task StartListening() _isRunning = true; - while (!_hostApplicationLifetime.ApplicationStopping.IsCancellationRequested) + while (!hostApplicationLifetime.ApplicationStopping.IsCancellationRequested) { if (DumpKeyPressed()) { - IEnumerable feeds = _statisticFeedsCollector.GetRegisteredFeedsDefinitions(); + IEnumerable feeds = statisticFeedsCollector.GetRegisteredFeedsDefinitions(); Console.Clear(); foreach (var feed in feeds) { - var feedResult = _statisticFeedsCollector.GetFeedDump(feed.FeedId, true); + var feedResult = statisticFeedsCollector.GetFeedDump(feed.FeedId, true); if (feedResult is TabularStatisticFeedResult tabularResult) { Console.WriteLine(tabularResult.Content); @@ -46,11 +40,11 @@ public async Task StartListening() } } - await Task.Delay(500, _hostApplicationLifetime.ApplicationStopping).ConfigureAwait(false); + await Task.Delay(500, hostApplicationLifetime.ApplicationStopping).ConfigureAwait(false); } } - private bool DumpKeyPressed() + private static bool DumpKeyPressed() { bool found = false; while (Console.KeyAvailable) diff --git a/src/MithrilShards.Diagnostic.StatisticsCollector/MithrilShards.Diagnostic.StatisticsCollector.csproj b/src/MithrilShards.Diagnostic.StatisticsCollector/MithrilShards.Diagnostic.StatisticsCollector.csproj index 33290985..f8e483f9 100644 --- a/src/MithrilShards.Diagnostic.StatisticsCollector/MithrilShards.Diagnostic.StatisticsCollector.csproj +++ b/src/MithrilShards.Diagnostic.StatisticsCollector/MithrilShards.Diagnostic.StatisticsCollector.csproj @@ -9,4 +9,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Diagnostic.StatisticsCollector/StatisticFeedsCollector.cs b/src/MithrilShards.Diagnostic.StatisticsCollector/StatisticFeedsCollector.cs index 9c4b8621..9ab2e4ae 100644 --- a/src/MithrilShards.Diagnostic.StatisticsCollector/StatisticFeedsCollector.cs +++ b/src/MithrilShards.Diagnostic.StatisticsCollector/StatisticFeedsCollector.cs @@ -14,8 +14,8 @@ namespace MithrilShards.Diagnostic.StatisticsCollector; public class StatisticFeedsCollector : IStatisticFeedsCollector { - private readonly List _scheduledFeeds = new(); - private readonly List _registeredfeedDefinitions = new(); + private readonly List _scheduledFeeds = []; + private readonly List _registeredfeedDefinitions = []; private readonly ILogger _logger; private readonly object _statisticsFeedsLock = new(); private readonly StringBuilder _logStringBuilder; @@ -90,7 +90,7 @@ public async Task StartFetchingLoopAsync(CancellationToken cancellationToken) _logStringBuilder.Clear(); } - await Task.Delay(TimeSpan.FromSeconds(_settings.ContinuousConsoleDisplayRate)).WithCancellationAsync(cancellationToken).ConfigureAwait(false); + await Task.Delay(TimeSpan.FromSeconds(_settings.ContinuousConsoleDisplayRate), cancellationToken).ConfigureAwait(false); } } catch (OperationCanceledException) @@ -190,11 +190,8 @@ public object GetFeedsDump() /// public IStatisticFeedResult GetFeedDump(string feedId, bool humanReadable) { - ScheduledStatisticFeed? feed = _scheduledFeeds.Where(feed => feed.StatisticFeedDefinition.FeedId == feedId).FirstOrDefault(); - if (feed == null) - { - throw new ArgumentException("feedId not found"); - } + ScheduledStatisticFeed? feed = _scheduledFeeds.Where(feed => feed.StatisticFeedDefinition.FeedId == feedId).FirstOrDefault() + ?? throw new ArgumentException("feedId not found"); lock (_statisticsFeedsLock) { diff --git a/src/MithrilShards.Diagnostic.StatisticsCollector/StatisticsCollectorShard.cs b/src/MithrilShards.Diagnostic.StatisticsCollector/StatisticsCollectorShard.cs index d1750a0d..d39cfec0 100644 --- a/src/MithrilShards.Diagnostic.StatisticsCollector/StatisticsCollectorShard.cs +++ b/src/MithrilShards.Diagnostic.StatisticsCollector/StatisticsCollectorShard.cs @@ -5,34 +5,24 @@ namespace MithrilShards.Diagnostic.StatisticsCollector; -public class StatisticsCollectorShard : IMithrilShard +public class StatisticsCollectorShard( + ILogger logger, + ConsoleKeyDumper? consoleKeyDumper = null) + : IMithrilShard { - readonly ILogger _logger; - readonly ConsoleKeyDumper? _consoleKeyDumper; + public Task InitializeAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public StatisticsCollectorShard(ILogger logger, ConsoleKeyDumper? consoleKeyDumper = null) + public Task StartAsync(CancellationToken cancellationToken) { - _logger = logger; - _consoleKeyDumper = consoleKeyDumper; - } - - public ValueTask InitializeAsync(CancellationToken cancellationToken) - { - return default; - } + logger.LogDebug("Starting StatisticsCollectorShard"); - public ValueTask StartAsync(CancellationToken cancellationToken) - { - if (_consoleKeyDumper != null) + if (consoleKeyDumper != null) { - _ = _consoleKeyDumper.StartListening(); + _ = consoleKeyDumper.StartListeningAsync(); } - return default; + return Task.CompletedTask; } - public ValueTask StopAsync(CancellationToken cancellationToken) - { - return default; - } + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/src/MithrilShards.Example.Dev/MithrilShards.Example.Dev.csproj b/src/MithrilShards.Example.Dev/MithrilShards.Example.Dev.csproj index 0f6cc897..1a490c43 100644 --- a/src/MithrilShards.Example.Dev/MithrilShards.Example.Dev.csproj +++ b/src/MithrilShards.Example.Dev/MithrilShards.Example.Dev.csproj @@ -5,4 +5,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Example.Network.Bedrock/ExampleNetworkProtocolMessageSerializer.cs b/src/MithrilShards.Example.Network.Bedrock/ExampleNetworkProtocolMessageSerializer.cs index d9d16a91..63a65746 100644 --- a/src/MithrilShards.Example.Network.Bedrock/ExampleNetworkProtocolMessageSerializer.cs +++ b/src/MithrilShards.Example.Network.Bedrock/ExampleNetworkProtocolMessageSerializer.cs @@ -243,10 +243,7 @@ private bool TryReadChecksum(ref SequenceReader reader) public void WriteMessage(INetworkMessage message, IBufferWriter output) { - if (message is null) - { - throw new ArgumentNullException(nameof(message)); - } + ArgumentNullException.ThrowIfNull(message); string command = message.Command; using (_logger.BeginScope("Serializing and sending '{Command}'", command)) diff --git a/src/MithrilShards.Example.Network.Bedrock/MithrilShards.Example.Network.Bedrock.csproj b/src/MithrilShards.Example.Network.Bedrock/MithrilShards.Example.Network.Bedrock.csproj index 8c74a458..2977de2a 100644 --- a/src/MithrilShards.Example.Network.Bedrock/MithrilShards.Example.Network.Bedrock.csproj +++ b/src/MithrilShards.Example.Network.Bedrock/MithrilShards.Example.Network.Bedrock.csproj @@ -5,4 +5,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Example.Node/MithrilShards.Example.Node.csproj b/src/MithrilShards.Example.Node/MithrilShards.Example.Node.csproj index f7084421..92a57719 100644 --- a/src/MithrilShards.Example.Node/MithrilShards.Example.Node.csproj +++ b/src/MithrilShards.Example.Node/MithrilShards.Example.Node.csproj @@ -38,4 +38,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Example/ExampleShard.cs b/src/MithrilShards.Example/ExampleShard.cs index e520803b..f70ac4e8 100644 --- a/src/MithrilShards.Example/ExampleShard.cs +++ b/src/MithrilShards.Example/ExampleShard.cs @@ -1,35 +1,15 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using MithrilShards.Core.Shards; namespace MithrilShards.Example; public class ExampleShard : IMithrilShard { - private readonly ILogger _logger; - private readonly ExampleSettings _settings; - public ExampleShard(ILogger logger, IOptions settings) - { - _logger = logger; - _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings)); - } + public Task InitializeAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public ValueTask InitializeAsync(CancellationToken cancellationToken) - { - return default; - } + public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; - public ValueTask StartAsync(CancellationToken cancellationToken) - { - return default; - } - - public ValueTask StopAsync(CancellationToken cancellationToken) - { - return default; - } + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/src/MithrilShards.Example/ForgeBuilderExtensions.cs b/src/MithrilShards.Example/ForgeBuilderExtensions.cs index 7f81105b..fddd6b60 100644 --- a/src/MithrilShards.Example/ForgeBuilderExtensions.cs +++ b/src/MithrilShards.Example/ForgeBuilderExtensions.cs @@ -25,7 +25,7 @@ public static class ForgeBuilderExtensions /// public static IForgeBuilder UseExample(this IForgeBuilder forgeBuilder, int minimumSupportedVersion, int currentVersion) { - if (forgeBuilder is null) throw new ArgumentNullException(nameof(forgeBuilder)); + ArgumentNullException.ThrowIfNull(forgeBuilder); forgeBuilder.AddShard( (hostBuildContext, services) => diff --git a/src/MithrilShards.Example/MithrilShards.Example.csproj b/src/MithrilShards.Example/MithrilShards.Example.csproj index 8daf10f1..1fb00f5a 100644 --- a/src/MithrilShards.Example/MithrilShards.Example.csproj +++ b/src/MithrilShards.Example/MithrilShards.Example.csproj @@ -13,4 +13,17 @@ + + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/src/MithrilShards.Example/Protocol/Processors/BaseProcessor.cs b/src/MithrilShards.Example/Protocol/Processors/BaseProcessor.cs index 0a4e460e..d36b9669 100644 --- a/src/MithrilShards.Example/Protocol/Processors/BaseProcessor.cs +++ b/src/MithrilShards.Example/Protocol/Processors/BaseProcessor.cs @@ -162,7 +162,7 @@ protected Task DisconnectIfAsync(Func> condition, TimeSpan timeo { try { - await Task.Delay(timeout).WithCancellationAsync(cancellation).ConfigureAwait(false); + await Task.Delay(timeout, cancellation).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -174,7 +174,7 @@ protected Task DisconnectIfAsync(Func> condition, TimeSpan timeo { PeerContext.Disconnect(reason); } - }); + }, cancellation); } /// @@ -196,7 +196,7 @@ protected Task ExecuteIfAsync(Func> condition, TimeSpan timeout, { try { - await Task.Delay(timeout).WithCancellationAsync(cancellation).ConfigureAwait(false); + await Task.Delay(timeout, cancellation).ConfigureAwait(false); } catch (OperationCanceledException) { @@ -209,7 +209,7 @@ protected Task ExecuteIfAsync(Func> condition, TimeSpan timeout, logger.LogDebug("Condition met, trigger action."); await action().ConfigureAwait(false); } - }); + }, cancellation); } /// diff --git a/src/MithrilShards.Example/Protocol/Processors/PingPongProcessor.cs b/src/MithrilShards.Example/Protocol/Processors/PingPongProcessor.cs index 333daf3b..e2828381 100644 --- a/src/MithrilShards.Example/Protocol/Processors/PingPongProcessor.cs +++ b/src/MithrilShards.Example/Protocol/Processors/PingPongProcessor.cs @@ -68,7 +68,7 @@ private async Task PingAsync(CancellationToken cancellationToken) Nonce = _randomNumberGenerator.GetUint64() }; - await SendMessageAsync(ping).ConfigureAwait(false); + await SendMessageAsync(ping, cancellationToken).ConfigureAwait(false); _status.PingSent(_dateTimeProvider.GetTimeMicros(), ping); logger.LogDebug("Sent ping request with nonce {PingNonce}", _status.PingRequestNonce); @@ -92,24 +92,24 @@ await SendMessageAsync(new PongMessage Nonce = message.Nonce, Quote = _quoteService.GetRandomQuote() } - }).ConfigureAwait(false); + }, cancellation).ConfigureAwait(false); return true; } - ValueTask INetworkMessageHandler.ProcessMessageAsync(PongMessage message, CancellationToken cancellation) + async ValueTask INetworkMessageHandler.ProcessMessageAsync(PongMessage message, CancellationToken cancellation) { if (_status.PingRequestNonce != 0 && message.PongFancyResponse?.Nonce == _status.PingRequestNonce) { (ulong Nonce, long RoundTrip) = _status.PongReceived(_dateTimeProvider.GetTimeMicros()); logger.LogDebug("Received pong with nonce {PingNonce} in {PingRoundTrip} usec. {Quote}", Nonce, RoundTrip, message.PongFancyResponse.Quote); - _pingCancellationTokenSource.Cancel(); + await _pingCancellationTokenSource.CancelAsync().ConfigureAwait(false); } else { logger.LogDebug("Received pong with wrong nonce: {PingNonce}", _status.PingRequestNonce); } - return new ValueTask(true); + return true; } } diff --git a/src/MithrilShards.Logging.Serilog/LevelSwitcherManager.cs b/src/MithrilShards.Logging.Serilog/LevelSwitcherManager.cs index 826de4f4..fa1dc78e 100644 --- a/src/MithrilShards.Logging.Serilog/LevelSwitcherManager.cs +++ b/src/MithrilShards.Logging.Serilog/LevelSwitcherManager.cs @@ -20,7 +20,11 @@ internal Dictionary LoadLoggingLevelSwitches(IConfig //Set default log level if (configuration.GetSection("Serilog:MinimumLevel:Default").Exists()) { - _logLevels.Add("Default", new LoggingLevelSwitch((LogEventLevel)Enum.Parse(typeof(LogEventLevel), configuration.GetValue("Serilog:MinimumLevel:Default")))); + var defaultLogLevel = configuration.GetValue("Serilog:MinimumLevel:Default"); + _logLevels.Add("Default", new LoggingLevelSwitch(defaultLogLevel == null + ? LogEventLevel.Information + : (LogEventLevel)Enum.Parse(typeof(LogEventLevel), defaultLogLevel) + )); } //Set log level(s) overrides @@ -28,6 +32,7 @@ internal Dictionary LoadLoggingLevelSwitches(IConfig { foreach (IConfigurationSection levelOverride in configuration.GetSection("Serilog:MinimumLevel:Override").GetChildren()) { + if (levelOverride.Value == null) continue; _logLevels.Add(levelOverride.Key, new LoggingLevelSwitch((LogEventLevel)Enum.Parse(typeof(LogEventLevel), levelOverride.Value))); } } diff --git a/src/MithrilShards.Logging.Serilog/MithrilShards.Logging.Serilog.csproj b/src/MithrilShards.Logging.Serilog/MithrilShards.Logging.Serilog.csproj index ff8fbd8b..fe6bf341 100644 --- a/src/MithrilShards.Logging.Serilog/MithrilShards.Logging.Serilog.csproj +++ b/src/MithrilShards.Logging.Serilog/MithrilShards.Logging.Serilog.csproj @@ -5,8 +5,8 @@ - - + + @@ -24,4 +24,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Logging.Serilog/SerilogShard.cs b/src/MithrilShards.Logging.Serilog/SerilogShard.cs index 7a6042bf..0b69b554 100644 --- a/src/MithrilShards.Logging.Serilog/SerilogShard.cs +++ b/src/MithrilShards.Logging.Serilog/SerilogShard.cs @@ -6,7 +6,7 @@ namespace MithrilShards.Logging.Serilog; public class SerilogShard : IMithrilShard { - public ValueTask InitializeAsync(CancellationToken cancellationToken) => default; - public ValueTask StartAsync(CancellationToken cancellationToken) => default; - public ValueTask StopAsync(CancellationToken cancellationToken) => default; + public Task InitializeAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/src/MithrilShards.Logging.TableFormatter/MithrilShards.Logging.TableFormatter.csproj b/src/MithrilShards.Logging.TableFormatter/MithrilShards.Logging.TableFormatter.csproj index 27832ade..187db426 100644 --- a/src/MithrilShards.Logging.TableFormatter/MithrilShards.Logging.TableFormatter.csproj +++ b/src/MithrilShards.Logging.TableFormatter/MithrilShards.Logging.TableFormatter.csproj @@ -4,4 +4,17 @@ true + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.Logging.TableFormatter/TableAlreadyDefined.cs b/src/MithrilShards.Logging.TableFormatter/TableAlreadyDefined.cs index 83b423a3..41c7cb5a 100644 --- a/src/MithrilShards.Logging.TableFormatter/TableAlreadyDefined.cs +++ b/src/MithrilShards.Logging.TableFormatter/TableAlreadyDefined.cs @@ -9,7 +9,4 @@ public class TableAlreadyDefinedException : Exception public TableAlreadyDefinedException() : base(DEFAULT_ERROR_MESSAGE) { } public TableAlreadyDefinedException(string message) : base(message) { } public TableAlreadyDefinedException(string message, Exception inner) : base(message, inner) { } - protected TableAlreadyDefinedException( - System.Runtime.Serialization.SerializationInfo info, - System.Runtime.Serialization.StreamingContext context) : base(info, context) { } } diff --git a/src/MithrilShards.Logging.TableFormatter/TableBuilder.cs b/src/MithrilShards.Logging.TableFormatter/TableBuilder.cs index d8579ec1..1f124c02 100644 --- a/src/MithrilShards.Logging.TableFormatter/TableBuilder.cs +++ b/src/MithrilShards.Logging.TableFormatter/TableBuilder.cs @@ -19,7 +19,7 @@ public TableBuilder(StringBuilder builder) { _stringBuilder = builder ?? new StringBuilder(); - ColumnDefinitions = new List(); + ColumnDefinitions = []; } public TableBuilder AddColumns(params ColumnDefinition[] columns) @@ -68,10 +68,7 @@ public TableBuilder Prepare() } _prepared = true; - if (TableStyle == null) - { - TableStyle = new TableStyle(); - } + TableStyle ??= new TableStyle(); ComputeTableWidth(); return this; @@ -129,7 +126,7 @@ private void DrawTitle(string title) public TableBuilder DrawRow(string?[] values) { - if (values is null) throw new ArgumentNullException(nameof(values)); + ArgumentNullException.ThrowIfNull(values); if (values.Length > ColumnDefinitions.Count) { diff --git a/src/MithrilShards.Network.Bedrock/BedrockForgeConnectivity.cs b/src/MithrilShards.Network.Bedrock/BedrockForgeConnectivity.cs index dcbbb134..eea48d0d 100644 --- a/src/MithrilShards.Network.Bedrock/BedrockForgeConnectivity.cs +++ b/src/MithrilShards.Network.Bedrock/BedrockForgeConnectivity.cs @@ -18,18 +18,15 @@ public class BedrockForgeConnectivity : IForgeClientConnectivity private readonly ILogger _logger; private readonly IEventBus _eventBus; private readonly MithrilForgeClientConnectionHandler _clientConnectionHandler; - private readonly ForgeConnectivitySettings _settings; private readonly Client _client = null!; public BedrockForgeConnectivity(ILogger logger, IEventBus eventBus, - IOptions settings, MithrilForgeClientConnectionHandler clientConnectionHandler, ClientBuilder clientBuilder) { _logger = logger; _eventBus = eventBus; - _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings)); _clientConnectionHandler = clientConnectionHandler; _client = clientBuilder .UseSockets() @@ -39,7 +36,7 @@ public BedrockForgeConnectivity(ILogger logger, public async ValueTask AttemptConnectionAsync(OutgoingConnectionEndPoint remoteEndPoint, CancellationToken cancellation) { - using IDisposable logScope = _logger.BeginScope("Outbound connection to {RemoteEndPoint}", remoteEndPoint); + using var _ = _logger.BeginScope("Outbound connection to {RemoteEndPoint}", remoteEndPoint); await _eventBus.PublishAsync(new PeerConnectionAttempt(remoteEndPoint.EndPoint.AsIPEndPoint()), cancellation).ConfigureAwait(false); bool connectionEstablished = false; diff --git a/src/MithrilShards.Network.Bedrock/BedrockNetworkShard.cs b/src/MithrilShards.Network.Bedrock/BedrockNetworkShard.cs index 86ad8e8f..12b0553f 100644 --- a/src/MithrilShards.Network.Bedrock/BedrockNetworkShard.cs +++ b/src/MithrilShards.Network.Bedrock/BedrockNetworkShard.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using Bedrock.Framework; @@ -16,117 +17,111 @@ namespace MithrilShards.Network.Bedrock; -public class BedrockNetworkShard : IMithrilShard +public class BedrockNetworkShard( + ILogger logger, + IEnumerable serverPeerConnectionGuards, + IOptions settings, + IServiceProvider serviceProvider + ) : IMithrilShard { - readonly ILogger _logger; - readonly IEventBus _eventBus; - private readonly IEnumerable _serverPeerConnectionGuards; - private readonly IServiceProvider _serviceProvider; - private readonly ForgeConnectivitySettings _settings; - private readonly List _serverPeers; - - public BedrockNetworkShard(ILogger logger, - IEventBus eventBus, - IEnumerable serverPeerConnectionGuards, - IOptions settings, - IServiceProvider serviceProvider) - { - _logger = logger; - _eventBus = eventBus; - _serverPeerConnectionGuards = serverPeerConnectionGuards; - _serviceProvider = serviceProvider; - _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings)); - _serverPeers = new List(); - } + private readonly ForgeConnectivitySettings _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings)); + private readonly List _serverPeers = []; - public ValueTask InitializeAsync(CancellationToken cancellationToken) + public Task InitializeAsync(CancellationToken cancellationToken) { CreateServerInstances(); - return default; + return Task.CompletedTask; } - public ValueTask StartAsync(CancellationToken cancellationToken) + public Task StartAsync(CancellationToken cancellationToken) { foreach (Server serverPeer in _serverPeers) { _ = serverPeer.StartAsync(cancellationToken); } - return default; + return Task.CompletedTask; } - public ValueTask StopAsync(CancellationToken cancellationToken) + public async Task StopAsync(CancellationToken cancellationToken) { - foreach (Server serverPeer in _serverPeers) + var tasks = _serverPeers.Select(serverPeer => serverPeer.StopAsync(cancellationToken)).ToArray(); + + try { - _ = serverPeer.StopAsync(); + await Task.WhenAll(tasks).ConfigureAwait(false); + } + catch (Exception e) + { + logger.LogError(e, "Error while stopping server peers."); } - - return default; } private void CreateServerInstances() { - using (_logger.BeginScope("CreateServerInstances")) + using var _ = logger.BeginScope("CreateServerInstances"); + logger.LogInformation("Loading Forge Server listeners configuration."); + + if (serverPeerConnectionGuards.Any()) + { + logger.LogInformation( + "Using {PeerConnectionGuardsCount} peer connection guards: {PeerConnectionGuards}.", + serverPeerConnectionGuards.Count(), + serverPeerConnectionGuards.Select(guard => guard.GetType().Name) + ); + } + else { - _logger.LogInformation("Loading Forge Server listeners configuration."); - - if (_serverPeerConnectionGuards.Any()) - { - _logger.LogInformation( - "Using {PeerConnectionGuardsCount} peer connection guards: {PeerConnectionGuards}.", - _serverPeerConnectionGuards.Count(), - _serverPeerConnectionGuards.Select(guard => guard.GetType().Name) - ); - } - else - { - _logger.LogWarning("No peer connection guards detected."); - } - - if (_settings.Listeners?.Count > 0) - { - _logger.LogInformation("Found {ConfiguredListeners} listeners in configuration.", _serverPeers.Count); - - ServerBuilder builder = new ServerBuilder(_serviceProvider) - .UseSockets(sockets => + logger.LogWarning("No peer connection guards detected."); + } + + if (_settings.Listeners?.Count > 0) + { + logger.LogInformation("Found {ConfiguredListeners} listeners in configuration.", _serverPeers.Count); + + ServerBuilder builder = new ServerBuilder(serviceProvider) + .UseSockets(sockets => + { + //sockets.Options.NoDelay = true; + + foreach (ServerPeerBinding binding in _settings.Listeners) { - sockets.Options.NoDelay = true; + IPEndPoint localEndPoint = binding.GetIPEndPoint(); - foreach (ServerPeerBinding binding in _settings.Listeners) + if (!binding.HasPublicEndPoint()) { - IPEndPoint localEndPoint = binding.GetIPEndPoint(); + binding.PublicEndPoint = new IPEndPoint(IPAddress.Loopback, localEndPoint.Port).ToString(); + } - if (!binding.HasPublicEndPoint()) - { - binding.PublicEndPoint = new IPEndPoint(IPAddress.Loopback, localEndPoint.Port).ToString(); - } + binding.TryGetPublicIPEndPoint(out IPEndPoint? publicEndPoint); - binding.TryGetPublicIPEndPoint(out IPEndPoint? publicEndPoint); + logger.LogInformation("Added listener to local endpoint {ListenerLocalEndpoint}. (remote {ListenerPublicEndpoint})", localEndPoint, publicEndPoint); - _logger.LogInformation("Added listener to local endpoint {ListenerLocalEndpoint}. (remote {ListenerPublicEndpoint})", localEndPoint, publicEndPoint); + sockets.Listen( + localEndPoint.Address, + localEndPoint.Port, + builder => builder + .UseConnectionLogging() + .UseConnectionHandler() + ); + + //var tcpListener = new TcpListener(localEndPoint.Address, localEndPoint.Port); + //tcpListener.Start(); + //logger.LogInformation("Listening on {ListenerLocalEndpoint} for incoming connections.", tcpListener.LocalEndpoint); - sockets.Listen( - localEndPoint.Address, - localEndPoint.Port, - builder => builder - .UseConnectionLogging() - .UseConnectionHandler() - ); - } } - ); + } + ); - builder.ShutdownTimeout = TimeSpan.FromSeconds(_settings.ForceShutdownAfter); + builder.ShutdownTimeout = TimeSpan.FromSeconds(_settings.ForceShutdownAfter); - Server server = builder.Build(); + Server server = builder.Build(); - _serverPeers.Add(server); - } - else - { - _logger.LogWarning("No binding information found in configuration file, no Forge Servers available."); - } + _serverPeers.Add(server); + } + else + { + logger.LogWarning("No binding information found in configuration file, no Forge Servers available."); } } } diff --git a/src/MithrilShards.Network.Bedrock/ForgeBuilderExtensions.cs b/src/MithrilShards.Network.Bedrock/ForgeBuilderExtensions.cs index 3ac4610e..74f02ab9 100644 --- a/src/MithrilShards.Network.Bedrock/ForgeBuilderExtensions.cs +++ b/src/MithrilShards.Network.Bedrock/ForgeBuilderExtensions.cs @@ -18,10 +18,7 @@ public static class ForgeBuilderExtensions /// forgeBuilder public static IForgeBuilder UseBedrockNetwork(this IForgeBuilder forgeBuilder) where TNetworkProtocolMessageSerializer : class, INetworkProtocolMessageSerializer { - if (forgeBuilder is null) - { - throw new System.ArgumentNullException(nameof(forgeBuilder)); - } + System.ArgumentNullException.ThrowIfNull(forgeBuilder); forgeBuilder.AddShard( (hostBuildContext, services) => diff --git a/src/MithrilShards.Network.Bedrock/MithrilForgeClientConnectionHandler.cs b/src/MithrilShards.Network.Bedrock/MithrilForgeClientConnectionHandler.cs index 646e276a..9818c331 100644 --- a/src/MithrilShards.Network.Bedrock/MithrilForgeClientConnectionHandler.cs +++ b/src/MithrilShards.Network.Bedrock/MithrilForgeClientConnectionHandler.cs @@ -15,40 +15,28 @@ namespace MithrilShards.Network.Bedrock; -public class MithrilForgeClientConnectionHandler : ConnectionHandler +public class MithrilForgeClientConnectionHandler( + ILogger logger, + IServiceProvider serviceProvider, + IEventBus eventBus, + INetworkMessageProcessorFactory networkMessageProcessorFactory, + IPeerContextFactory peerContextFactory + ) : ConnectionHandler { - private readonly ILogger _logger; - private readonly IServiceProvider _serviceProvider; - private readonly IEventBus _eventBus; - private readonly INetworkMessageProcessorFactory _networkMessageProcessorFactory; - private readonly IPeerContextFactory _peerContextFactory; - - public MithrilForgeClientConnectionHandler(ILogger logger, - IServiceProvider serviceProvider, - IEventBus eventBus, - INetworkMessageProcessorFactory networkMessageProcessorFactory, - IPeerContextFactory peerContextFactory) - { - _logger = logger; - _serviceProvider = serviceProvider; - _eventBus = eventBus; - _networkMessageProcessorFactory = networkMessageProcessorFactory; - _peerContextFactory = peerContextFactory; - } public override async Task OnConnectedAsync(ConnectionContext connection) { - if (connection is null) throw new ArgumentNullException(nameof(connection)); + ArgumentNullException.ThrowIfNull(connection); OutgoingConnectionEndPoint outgoingConnectionEndPoint = connection.Features.Get() ?? throw new NullReferenceException($"Missing {nameof(OutgoingConnectionEndPoint)} feature."); - using var serviceProviderScope = _serviceProvider.CreateScope(); - using IDisposable logScope = _logger.BeginScope("Peer {PeerId} connected to outbound {PeerEndpoint}", connection.ConnectionId, connection.LocalEndPoint); + using var serviceProviderScope = serviceProvider.CreateScope(); + using var _ = logger.BeginScope("Peer {PeerId} connected to outbound {PeerEndpoint}", connection.ConnectionId, connection.LocalEndPoint); ProtocolReader reader = connection.CreateReader(); - INetworkProtocolMessageSerializer protocol = _serviceProvider.GetRequiredService(); + INetworkProtocolMessageSerializer protocol = serviceProvider.GetRequiredService(); - IPeerContext peerContext = _peerContextFactory.CreateOutgoingPeerContext(connection.ConnectionId, + IPeerContext peerContext = peerContextFactory.CreateOutgoingPeerContext(connection.ConnectionId, connection.LocalEndPoint!, outgoingConnectionEndPoint, new NetworkMessageWriter(protocol, connection.CreateWriter())); @@ -61,10 +49,10 @@ public override async Task OnConnectedAsync(ConnectionContext connection) protocol.SetPeerContext(peerContext); - await _eventBus.PublishAsync(new PeerConnected(peerContext)).ConfigureAwait(false); + await eventBus.PublishAsync(new PeerConnected(peerContext)).ConfigureAwait(false); - await _networkMessageProcessorFactory.StartProcessorsAsync(peerContext).ConfigureAwait(false); + await networkMessageProcessorFactory.StartProcessorsAsync(peerContext).ConfigureAwait(false); while (true) @@ -84,7 +72,7 @@ public override async Task OnConnectedAsync(ConnectionContext connection) } await ProcessMessageAsync(result.Message, peerContext, connection.ConnectionClosed) - .WithCancellationAsync(connection.ConnectionClosed) + .WaitAsync(connection.ConnectionClosed) .ConfigureAwait(false); } catch (OperationCanceledException) @@ -102,12 +90,12 @@ await ProcessMessageAsync(result.Message, peerContext, connection.ConnectionClos private async Task ProcessMessageAsync(INetworkMessage message, IPeerContext peerContext, CancellationToken cancellation) { - using IDisposable logScope = _logger.BeginScope("Processing message '{Command}'", message.Command); + using var _ = logger.BeginScope("Processing message '{Command}'", message.Command); - if (!(message is UnknownMessage)) + if (message is not UnknownMessage) { - await _networkMessageProcessorFactory.ProcessMessageAsync(message, peerContext, cancellation).ConfigureAwait(false); - await _eventBus.PublishAsync(new PeerMessageReceived(peerContext, message), cancellation).ConfigureAwait(false); + await networkMessageProcessorFactory.ProcessMessageAsync(message, peerContext, cancellation).ConfigureAwait(false); + await eventBus.PublishAsync(new PeerMessageReceived(peerContext, message), cancellation).ConfigureAwait(false); } } } diff --git a/src/MithrilShards.Network.Bedrock/MithrilForgeServerConnectionHandler.cs b/src/MithrilShards.Network.Bedrock/MithrilForgeServerConnectionHandler.cs index 8f3e0af3..e6c62977 100644 --- a/src/MithrilShards.Network.Bedrock/MithrilForgeServerConnectionHandler.cs +++ b/src/MithrilShards.Network.Bedrock/MithrilForgeServerConnectionHandler.cs @@ -43,12 +43,9 @@ public MithrilForgeServerConnectionHandler(ILogger(); @@ -69,7 +66,7 @@ public override async Task OnConnectedAsync(ConnectionContext connection) connection.Features.Set(peerContext); protocol.SetPeerContext(peerContext); - if (await EnsurePeerCanConnect(connection, peerContext).ConfigureAwait(false)) + if (await EnsurePeerCanConnectAsync(connection, peerContext).ConfigureAwait(false)) { await _eventBus.PublishAsync(new PeerConnected(peerContext)).ConfigureAwait(false); @@ -108,12 +105,9 @@ public override async Task OnConnectedAsync(ConnectionContext connection) /// Check if the client is allowed to connect based on certain criteria. /// /// When criteria is met returns true, to allow connection. - private async ValueTask EnsurePeerCanConnect(ConnectionContext connection, IPeerContext peerContext) + private async ValueTask EnsurePeerCanConnectAsync(ConnectionContext connection, IPeerContext peerContext) { - if (_serverPeerConnectionGuards == null) - { - return false; - } + if (_serverPeerConnectionGuards == null) return false; ServerPeerConnectionGuardResult? result = ( from guard in _serverPeerConnectionGuards @@ -139,12 +133,12 @@ select guardResult private async Task ProcessMessageAsync(INetworkMessage message, IPeerContext peerContext, CancellationToken cancellation) { - using IDisposable logScope = _logger.BeginScope("Processing message '{Command}'", message.Command); + using var _ = _logger.BeginScope("Processing message '{Command}'", message.Command); - if (!(message is UnknownMessage)) + if (message is not UnknownMessage) { await _networkMessageProcessorFactory.ProcessMessageAsync(message, peerContext, cancellation).ConfigureAwait(false); await _eventBus.PublishAsync(new PeerMessageReceived(peerContext, message), cancellation).ConfigureAwait(false); } } -} +} \ No newline at end of file diff --git a/src/MithrilShards.Network.Bedrock/MithrilShards.Network.Bedrock.csproj b/src/MithrilShards.Network.Bedrock/MithrilShards.Network.Bedrock.csproj index 420f81a1..7c81ce8a 100644 --- a/src/MithrilShards.Network.Bedrock/MithrilShards.Network.Bedrock.csproj +++ b/src/MithrilShards.Network.Bedrock/MithrilShards.Network.Bedrock.csproj @@ -1,15 +1,28 @@ - + true - + + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.UI.BlazorServer/BlazorServerShard.cs b/src/MithrilShards.UI.BlazorServer/BlazorServerShard.cs index 3288deff..bd860c1c 100644 --- a/src/MithrilShards.UI.BlazorServer/BlazorServerShard.cs +++ b/src/MithrilShards.UI.BlazorServer/BlazorServerShard.cs @@ -17,31 +17,23 @@ namespace MithrilShards.UI.BlazorServer; -internal class BlazorServerShard : IMithrilShard +internal class BlazorServerShard( + ILogger logger, + IOptions options, + IServiceCollection registeredServices, + IServiceProvider serviceProvider + ) : IMithrilShard { - readonly ILogger _logger; - readonly IServiceCollection _registeredServices; - readonly IServiceProvider _serviceProvider; - readonly IHostApplicationLifetime _hostApplicationLifetime; - readonly BlazorServerSettings _settings; + readonly BlazorServerSettings _settings = options.Value; private IWebHost? _webHost; - public BlazorServerShard(ILogger logger, IOptions options, IServiceCollection registeredServices, IServiceProvider serviceProvider, IHostApplicationLifetime hostApplicationLifetime) - { - _logger = logger; - _registeredServices = registeredServices; - _serviceProvider = serviceProvider; - _hostApplicationLifetime = hostApplicationLifetime; - _settings = options.Value; - } - - public ValueTask InitializeAsync(CancellationToken cancellationToken) + public Task InitializeAsync(CancellationToken cancellationToken) { if (!_settings.Enabled) { - _logger.LogWarning($"{nameof(BlazorServerSettings)} disabled, Dev API will not be available"); + logger.LogWarning($"{nameof(BlazorServerSettings)} disabled, Dev API will not be available"); - return default; + return Task.CompletedTask; } _webHost = new WebHostBuilder() @@ -75,7 +67,7 @@ public ValueTask InitializeAsync(CancellationToken cancellationToken) { // copies all the services registered in the forge, maintaining eventual singleton instances // also copies over singleton instances already defined - foreach (ServiceDescriptor service in _registeredServices) + foreach (ServiceDescriptor service in registeredServices) { if (service.ServiceType == typeof(IHostedService)) { @@ -92,7 +84,7 @@ public ValueTask InitializeAsync(CancellationToken cancellationToken) services.AddSingleton(service.ServiceType, sp => { //resolve singletons from the main provider - var instance = _serviceProvider.GetServices(service.ServiceType).First(s => service.ImplementationType == null || s?.GetType() == service.ImplementationType); + var instance = serviceProvider.GetServices(service.ServiceType).First(s => service.ImplementationType == null || s?.GetType() == service.ImplementationType); if (instance == null) ThrowHelper.ThrowNullReferenceException($"Service type {service.ServiceType.Name} not found."); return instance; @@ -112,50 +104,50 @@ public ValueTask InitializeAsync(CancellationToken cancellationToken) }); - services.AddBlazorise(options => { options.ChangeTextOnKeyPress = true; }) + services.AddBlazorise(options => { /*options.ChangeTextOnKeyPress = true;*/ }) .AddBootstrapProviders() .AddFontAwesomeIcons(); }).Build(); - return default; + return Task.CompletedTask; } - public ValueTask StartAsync(CancellationToken cancellationToken) + public Task StartAsync(CancellationToken cancellationToken) { - if (_webHost != null) + if (_webHost == null) { - _ = Task.Run(async () => - { - try - { - _logger.LogInformation("BlazorServer started, listening to endpoint {ListenerLocalEndpoint}.", _settings.EndPoint); - await _webHost.StartAsync(cancellationToken).ConfigureAwait(false); - } - catch (OperationCanceledException) - { - // Task canceled, legit, ignoring exception. - } - catch (Exception ex) - { - _logger.LogCritical(ex, "BlazorServer exception, {BlazorServerException}. The node will still run without BlazorServer functionality.", ex.Message); - // if we want to stop the application in case of exception, uncomment line below - // hostApplicationLifetime.StopApplication(); - } - }); + logger.LogWarning("BlazorServer not initialized, skipping start."); + return Task.CompletedTask; } + _ = Task.Run(async () => + { + try + { + logger.LogInformation("BlazorServer started, listening to endpoint {ListenerLocalEndpoint}.", _settings.EndPoint); + await _webHost.StartAsync(cancellationToken).ConfigureAwait(false); + } + catch (OperationCanceledException) + { + // Task canceled, legit, ignoring exception. + } + catch (Exception ex) + { + logger.LogCritical(ex, "BlazorServer exception, {BlazorServerException}. The node will still run without BlazorServer functionality.", ex.Message); + // if we want to stop the application in case of exception, uncomment line below + // hostApplicationLifetime.StopApplication(); + } + }, cancellationToken); + - return default; + return Task.CompletedTask; } - public ValueTask StopAsync(CancellationToken cancellationToken) + public async Task StopAsync(CancellationToken cancellationToken) { - if (_webHost != null) - { - _ = _webHost.StopAsync(cancellationToken); - } + if (_webHost == null) return; - return default; + await _webHost.StopAsync(cancellationToken).ConfigureAwait(false); } } diff --git a/src/MithrilShards.UI.BlazorServer/MithrilShards.UI.BlazorServer.csproj b/src/MithrilShards.UI.BlazorServer/MithrilShards.UI.BlazorServer.csproj index e132b795..41ca4e02 100644 --- a/src/MithrilShards.UI.BlazorServer/MithrilShards.UI.BlazorServer.csproj +++ b/src/MithrilShards.UI.BlazorServer/MithrilShards.UI.BlazorServer.csproj @@ -6,13 +6,26 @@ - - - + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/MithrilShards.WebApi/MithrilShards.WebApi.csproj b/src/MithrilShards.WebApi/MithrilShards.WebApi.csproj index fb3eea4a..1a4ef3f5 100644 --- a/src/MithrilShards.WebApi/MithrilShards.WebApi.csproj +++ b/src/MithrilShards.WebApi/MithrilShards.WebApi.csproj @@ -15,7 +15,7 @@ - + @@ -26,4 +26,17 @@ + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + \ No newline at end of file diff --git a/src/MithrilShards.WebApi/WebApiShard.cs b/src/MithrilShards.WebApi/WebApiShard.cs index 95e0b448..b40dbcc5 100644 --- a/src/MithrilShards.WebApi/WebApiShard.cs +++ b/src/MithrilShards.WebApi/WebApiShard.cs @@ -6,7 +6,7 @@ namespace MithrilShards.WebApi; public class WebApiShard : IMithrilShard { - public ValueTask InitializeAsync(CancellationToken cancellationToken) => default; - public ValueTask StartAsync(CancellationToken cancellationToken) => default; - public ValueTask StopAsync(CancellationToken cancellationToken) => default; + public Task InitializeAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; } diff --git a/tests/MithrilShards.Chain.BitcoinTests/JsonFileDataAttribute.cs b/tests/MithrilShards.Chain.BitcoinTests/JsonFileDataAttribute.cs index f84fa7f5..57489d57 100644 --- a/tests/MithrilShards.Chain.BitcoinTests/JsonFileDataAttribute.cs +++ b/tests/MithrilShards.Chain.BitcoinTests/JsonFileDataAttribute.cs @@ -48,7 +48,7 @@ public JsonFileDataAttribute(string filePath, string propertyName) /// public override IEnumerable GetData(MethodInfo testMethod) { - if (testMethod == null) { throw new ArgumentNullException(nameof(testMethod)); } + ArgumentNullException.ThrowIfNull(testMethod); // Get the absolute path to the JSON file string path = Path.IsPathRooted(_filePath) diff --git a/tests/MithrilShards.Chain.BitcoinTests/MithrilShards.Chain.BitcoinTests.csproj b/tests/MithrilShards.Chain.BitcoinTests/MithrilShards.Chain.BitcoinTests.csproj index d0eb2f92..1a7de31b 100644 --- a/tests/MithrilShards.Chain.BitcoinTests/MithrilShards.Chain.BitcoinTests.csproj +++ b/tests/MithrilShards.Chain.BitcoinTests/MithrilShards.Chain.BitcoinTests.csproj @@ -1,20 +1,19 @@ - net6.0 false disable - + - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -30,4 +29,21 @@ + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + +