diff --git a/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Benchmarks/FirstAndLastBenchmark.cs b/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Benchmarks/FirstAndLastBenchmark.cs new file mode 100644 index 0000000..9809b4e --- /dev/null +++ b/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Benchmarks/FirstAndLastBenchmark.cs @@ -0,0 +1,145 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Engines; +using Talkie.Models; +using Talkie.Sequences; + +namespace Talkie.Benchmarks.Benchmarks; + +[MemoryDiagnoser] +[SimpleJob(RunStrategy.Throughput)] +public class FirstAndLastBenchmark +{ + private const int Capacity = 10; + + private FrozenSequence? _frozenSequence; + + private IEnumerable? _referenceFrozenSequence; + + private RemovableSequence? _removableSequence; + + private Sequence? _sequence; + + private LinkedList? _linkedList; + + private List? _list; + + [GlobalSetup] + public void Setup() + { + SetupFrozenSequence(); + SetupRemovableSequence(); + SetupSequence(); + SetupLinkedList(); + SetupList(); + } + + public void SetupFrozenSequence() + { + var sequence = new List(); + + for (var i = 0; i < Capacity; i++) + { + sequence.Add(Reference.Shared); + } + + _frozenSequence = sequence.ToFrozenSequence(); + _referenceFrozenSequence = _frozenSequence; + } + + public void SetupRemovableSequence() + { + var removableSequence = new RemovableSequence(); + + for (var i = 0; i < Capacity; i++) + { + _ = removableSequence.Add(Reference.Shared); + } + + _removableSequence = removableSequence; + } + + public void SetupSequence() + { + var sequence = new Sequence(); + + for (var i = 0; i < Capacity; i++) + { + sequence.Add(Reference.Shared); + } + + _sequence = sequence; + } + + public void SetupLinkedList() + { + var linkedList = new LinkedList(); + + for (var i = 0; i < Capacity; i++) + { + _ = linkedList.AddLast(Reference.Shared); + } + + _linkedList = linkedList; + } + + public void SetupList() + { + var list = new List(); + + for (var i = 0; i < Capacity; i++) + { + list.Add(Reference.Shared); + } + + _list = list; + } + + [Benchmark] + public void RunFrozenSequenceFirstAndLast() + { + _ = _frozenSequence!.First(); + _ = _frozenSequence!.Last(); + } + + [Benchmark] + public void RunReferenceFrozenSequenceFirstAndLast() + { + _ = _referenceFrozenSequence!.First(); + _ = _referenceFrozenSequence!.Last(); + } + + [Benchmark] + public void RunReferenceSequencingFrozenSequenceFirstAndLast() + { + _ = _referenceFrozenSequence!.Sequencing().First(); + _ = _referenceFrozenSequence!.Sequencing().Last(); + } + + [Benchmark] + public void RunRemovableSequenceFirstAndLast() + { + _ = _removableSequence!.First(); + _ = _removableSequence!.Last(); + } + + [Benchmark] + public void RunSequenceFirstAndLast() + { + _ = _sequence!.First(); + _ = _sequence!.Last(); + } + + [Benchmark] + public void RunLinkedListFirstAndLast() + { + _ = _linkedList!.First(); + _ = _linkedList!.Last(); + } + + [Benchmark] + public void RunListFirstAndLast() + { + _ = _list!.First(); + _ = _list!.Last(); + } +} diff --git a/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Benchmarks/ForeachBenchmark.cs b/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Benchmarks/ForeachBenchmark.cs index 6fe1930..d5641b1 100644 --- a/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Benchmarks/ForeachBenchmark.cs +++ b/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Benchmarks/ForeachBenchmark.cs @@ -5,11 +5,14 @@ namespace Talkie.Benchmarks.Benchmarks; +[MemoryDiagnoser] [SimpleJob(RunStrategy.Throughput)] public class ForeachBenchmark { private FrozenSequence? _frozenSequence; + private IEnumerable? _referenceFrozenSequence; + private RemovableSequence? _removableSequence; private Sequence? _sequence; @@ -18,6 +21,8 @@ public class ForeachBenchmark private List? _list; + private IEnumerable? _referenceList; + [Params(0, 1, 10, 100, 1000, 10000)] public int Capacity { get; set; } @@ -41,6 +46,7 @@ public void SetupFrozenSequence() } _frozenSequence = sequence.ToFrozenSequence(); + _referenceFrozenSequence = _frozenSequence; } public void SetupRemovableSequence() @@ -89,6 +95,7 @@ public void SetupList() } _list = list; + _referenceList = _list; } [Benchmark] @@ -100,6 +107,15 @@ public void RunFrozenSequenceForeach() } } + [Benchmark] + public void RunReferenceFrozenSequenceForeach() + { + foreach (var value in _referenceFrozenSequence!) + { + _ = value; + } + } + [Benchmark] public void RunRemovableSequenceForeach() { @@ -135,4 +151,13 @@ public void RunListForeach() _ = value; } } + + [Benchmark] + public void RunReferenceListForeach() + { + foreach (var value in _referenceList!) + { + _ = value; + } + } } diff --git a/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Falko.Talkie.Benchmarks.Sequences.csproj b/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Falko.Talkie.Benchmarks.Sequences.csproj index 7e1e7ec..af4ccc9 100644 --- a/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Falko.Talkie.Benchmarks.Sequences.csproj +++ b/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Falko.Talkie.Benchmarks.Sequences.csproj @@ -4,5 +4,6 @@ + diff --git a/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Program.cs b/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Program.cs index a782057..48d3e48 100644 --- a/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Program.cs +++ b/Benchmarks/Falko.Talkie.Benchmarks.Sequences/Program.cs @@ -2,5 +2,6 @@ using Talkie.Benchmarks.Benchmarks; BenchmarkRunner.Run(); +BenchmarkRunner.Run(); BenchmarkRunner.Run(); BenchmarkRunner.Run(); diff --git a/Directory.Packages.props b/Directory.Packages.props index c8ca075..08c2666 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,14 +1,14 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + \ No newline at end of file diff --git a/Examples.Build.props b/Examples.Build.props index 930ec28..01046ec 100644 --- a/Examples.Build.props +++ b/Examples.Build.props @@ -3,7 +3,7 @@ exe - true + false speed full true diff --git a/Examples/Falko.Talkie.Examples.Microsoft.Hosting/Falko.Talkie.Examples.Microsoft.Hosting.csproj b/Examples/Falko.Talkie.Examples.Microsoft.Hosting/Falko.Talkie.Examples.Microsoft.Hosting.csproj index 48360d5..cb120e8 100644 --- a/Examples/Falko.Talkie.Examples.Microsoft.Hosting/Falko.Talkie.Examples.Microsoft.Hosting.csproj +++ b/Examples/Falko.Talkie.Examples.Microsoft.Hosting/Falko.Talkie.Examples.Microsoft.Hosting.csproj @@ -2,7 +2,7 @@ - SimpleTelegramBot + Bot diff --git a/Examples/Falko.Talkie.Examples.Microsoft.Hosting/HelloSubscriber.cs b/Examples/Falko.Talkie.Examples.Microsoft.Hosting/HelloSubscriber.cs index 5db8cfc..bcacec6 100644 --- a/Examples/Falko.Talkie.Examples.Microsoft.Hosting/HelloSubscriber.cs +++ b/Examples/Falko.Talkie.Examples.Microsoft.Hosting/HelloSubscriber.cs @@ -4,7 +4,6 @@ using Talkie.Flows; using Talkie.Handlers; using Talkie.Models.Messages; -using Talkie.Models.Messages.Attachments; using Talkie.Pipelines.Handling; using Talkie.Pipelines.Intercepting; using Talkie.Signals; diff --git a/Examples/Falko.Talkie.Examples.Microsoft.Hosting/Program.cs b/Examples/Falko.Talkie.Examples.Microsoft.Hosting/Program.cs index c77938f..dc1040b 100644 --- a/Examples/Falko.Talkie.Examples.Microsoft.Hosting/Program.cs +++ b/Examples/Falko.Talkie.Examples.Microsoft.Hosting/Program.cs @@ -14,7 +14,8 @@ .WriteTo.Console()) .UseTalkie(configuration => configuration .SetSignalsLogging()) - .AddIntegrations() - .AddBehaviors() - .AddBehaviors() + .ConfigureServices(services => services + .AddIntegrations() + .AddBehaviors() + .AddBehaviors()) .RunConsoleAsync(); diff --git a/Examples/Falko.Talkie.Examples.Microsoft.Hosting/StartSubscriber.cs b/Examples/Falko.Talkie.Examples.Microsoft.Hosting/StartSubscriber.cs index fa50e4b..62231f4 100644 --- a/Examples/Falko.Talkie.Examples.Microsoft.Hosting/StartSubscriber.cs +++ b/Examples/Falko.Talkie.Examples.Microsoft.Hosting/StartSubscriber.cs @@ -31,7 +31,7 @@ public void Subscribe(ISignalFlow flow, IRegisterOnlyDisposableScope disposables .PublishMessageAsync(message => message .SetReply(context.GetMessage()) .SetContent(content => content - .AddText(nameof(Talkie), [BoldTextStyle.FromTextRange, BoldTextStyle.FromTextRange]) + .AddText(nameof(Talkie), BoldTextStyle.FromTextRange) .AddText(" is a library for building chatbots in .NET.", ItalicTextStyle.FromTextRange, BoldTextStyle.FromTextRange)), cancellation) .AsValueTask()) diff --git a/Falko.Talkie.slnx b/Falko.Talkie.slnx index c36ee08..ebf1147 100644 --- a/Falko.Talkie.slnx +++ b/Falko.Talkie.slnx @@ -1,41 +1,37 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Sources/Falko.Talkie.Bridges.Telegram/Clients/ITelegramClient.cs b/Sources/Falko.Talkie.Bridges.Telegram/Clients/ITelegramClient.cs index 0efa3d2..1f15cdb 100644 --- a/Sources/Falko.Talkie.Bridges.Telegram/Clients/ITelegramClient.cs +++ b/Sources/Falko.Talkie.Bridges.Telegram/Clients/ITelegramClient.cs @@ -2,18 +2,23 @@ namespace Talkie.Bridges.Telegram.Clients; public interface ITelegramClient : IDisposable { - internal Task SendAsync(string methodName, TRequest request, - CancellationToken cancellationToken = default); + internal Task SendAsync + ( + string methodName, + TRequest request, + CancellationToken cancellationToken = default + ); - internal Task SendAsync(string methodName, - CancellationToken cancellationToken = default); + internal Task SendAsync(string methodName, CancellationToken cancellationToken = default); - internal Task SendAsync(string methodName, TRequest request, - CancellationToken cancellationToken = default); + internal Task SendAsync + ( + string methodName, + TRequest request, + CancellationToken cancellationToken = default + ); - internal Task SendAsync(string methodName, - CancellationToken cancellationToken = default); + internal Task SendAsync(string methodName, CancellationToken cancellationToken = default); - Task DownloadAsync(string file, - CancellationToken cancellationToken = default); + Task DownloadAsync(string file, CancellationToken cancellationToken = default); } diff --git a/Sources/Falko.Talkie.Bridges.Telegram/Clients/TelegramClient.cs b/Sources/Falko.Talkie.Bridges.Telegram/Clients/TelegramClient.cs index 21a0459..b1dd629 100644 --- a/Sources/Falko.Talkie.Bridges.Telegram/Clients/TelegramClient.cs +++ b/Sources/Falko.Talkie.Bridges.Telegram/Clients/TelegramClient.cs @@ -32,8 +32,12 @@ public TelegramClient(TelegramConfiguration configuration) _client = BuildHttpClient(configuration); } - async Task ITelegramClient.SendAsync(string methodName, TRequest request, - CancellationToken cancellationToken) + async Task ITelegramClient.SendAsync + ( + string methodName, + TRequest request, + CancellationToken cancellationToken + ) { ArgumentNullException.ThrowIfNull(request); ArgumentException.ThrowIfNullOrWhiteSpace(methodName); @@ -46,8 +50,7 @@ async Task ITelegramClient.SendAsync(string methodNa description: "Result is null"); } - async Task ITelegramClient.SendAsync(string methodName, - CancellationToken cancellationToken) + async Task ITelegramClient.SendAsync(string methodName, CancellationToken cancellationToken) { ArgumentException.ThrowIfNullOrWhiteSpace(methodName); @@ -61,8 +64,7 @@ async Task ITelegramClient.SendAsync(string methodName, return result; } - Task ITelegramClient.SendAsync(string methodName, TRequest request, - CancellationToken cancellationToken) + Task ITelegramClient.SendAsync(string methodName, TRequest request, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(request); ArgumentException.ThrowIfNullOrWhiteSpace(methodName); @@ -73,8 +75,7 @@ Task ITelegramClient.SendAsync(string methodName, TRequest request, return SendRepeatableRequestAsync(methodName, request, scopedCancellationTokenSource.Token); } - Task ITelegramClient.SendAsync(string methodName, - CancellationToken cancellationToken) + Task ITelegramClient.SendAsync(string methodName, CancellationToken cancellationToken) { using var scopedCancellationTokenSource = CancellationTokenSource .CreateLinkedTokenSource(_globalCancellationTokenSource.Token, cancellationToken); @@ -104,8 +105,7 @@ public async Task DownloadAsync(string file, CancellationToken cancellat } } - private async Task DownloadCoreAsync(string file, - CancellationToken cancellationToken) + private async Task DownloadCoreAsync(string file, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -157,8 +157,12 @@ private async Task DownloadCoreAsync(string file, } } - private async Task SendRepeatableRequestAsync(string method, TRequest? request, - CancellationToken cancellationToken) + private async Task SendRepeatableRequestAsync + ( + string method, + TRequest? request, + CancellationToken cancellationToken + ) { while (true) { @@ -178,8 +182,12 @@ private async Task DownloadCoreAsync(string file, } } - private async Task SendRequestAsync(string method, TRequest? request, - CancellationToken cancellationToken) + private async Task SendRequestAsync + ( + string method, + TRequest? request, + CancellationToken cancellationToken + ) { cancellationToken.ThrowIfCancellationRequested(); @@ -207,8 +215,12 @@ private async Task DownloadCoreAsync(string file, } } - private async Task ParseHttpResponseAsync(string method, HttpResponseMessage httpResponse, - CancellationToken cancellationToken) + private async Task ParseHttpResponseAsync + ( + string method, + HttpResponseMessage httpResponse, + CancellationToken cancellationToken + ) { if (typeof(TResult) == typeof(object)) { @@ -235,8 +247,12 @@ private async Task DownloadCoreAsync(string file, return response.Result; } - private async Task BuildHttpRequestAsync(string method, TRequest? request, - CancellationToken cancellationToken) + private async Task BuildHttpRequestAsync + ( + string method, + TRequest? request, + CancellationToken cancellationToken + ) { var httpRequest = new HttpRequestMessage(HttpMethod.Post, method); @@ -261,8 +277,12 @@ private static void AddJsonContent(HttpRequestMessage httpRequest, string reques httpRequest.Content = new StringContent(requestJson, Encoding.UTF8, ApplicationJson); } - private static async Task AddGzipJsonContentAsync(HttpRequestMessage httpRequest, string requestJson, - CancellationToken cancellationToken) + private static async Task AddGzipJsonContentAsync + ( + HttpRequestMessage httpRequest, + string requestJson, + CancellationToken cancellationToken + ) { await using var memoryStream = new MemoryStream(); await using var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress); @@ -279,8 +299,7 @@ private static async Task AddGzipJsonContentAsync(HttpRequestMessage httpRequest httpRequest.Content.Headers.ContentEncoding.Add(Gzip); } - private async Task WaitRetryDelayAsync(TelegramException exception, - CancellationToken cancellationToken) + private async Task WaitRetryDelayAsync(TelegramException exception, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/Sources/Falko.Talkie.Bridges.Telegram/Clients/TelegramClientExtensions.cs b/Sources/Falko.Talkie.Bridges.Telegram/Clients/TelegramClientExtensions.cs index b9e10ef..be5fb66 100644 --- a/Sources/Falko.Talkie.Bridges.Telegram/Clients/TelegramClientExtensions.cs +++ b/Sources/Falko.Talkie.Bridges.Telegram/Clients/TelegramClientExtensions.cs @@ -5,8 +5,12 @@ namespace Talkie.Bridges.Telegram.Clients; public static partial class TelegramClientExtensions { - public static Task> GetUpdatesAsync(this ITelegramClient client, TelegramGetUpdatesRequest getUpdates, - CancellationToken cancellationToken = default) + public static Task> GetUpdatesAsync + ( + this ITelegramClient client, + TelegramGetUpdatesRequest getUpdates, + CancellationToken cancellationToken = default + ) { return client.SendAsync, TelegramGetUpdatesRequest> ( @@ -16,8 +20,11 @@ public static Task> GetUpdatesAsync(this ITelegram ); } - public static Task GetMeAsync(this ITelegramClient client, - CancellationToken cancellationToken = default) + public static Task GetMeAsync + ( + this ITelegramClient client, + CancellationToken cancellationToken = default + ) { return client.SendAsync ( diff --git a/Sources/Falko.Talkie.Bridges.Telegram/Configurations/TelegramConfiguration.cs b/Sources/Falko.Talkie.Bridges.Telegram/Configurations/TelegramConfiguration.cs index 133c507..3e28163 100644 --- a/Sources/Falko.Talkie.Bridges.Telegram/Configurations/TelegramConfiguration.cs +++ b/Sources/Falko.Talkie.Bridges.Telegram/Configurations/TelegramConfiguration.cs @@ -23,4 +23,9 @@ public void ThrowIfInvalid() ArgumentNullException.ThrowIfNull(ServerConfiguration); ArgumentNullException.ThrowIfNull(ClientConfiguration); } + + public static implicit operator TelegramConfiguration(TelegramServerConfiguration serverConfiguration) + { + return new TelegramConfiguration(serverConfiguration); + } } diff --git a/Sources/Falko.Talkie.Bridges.Telegram/Serialization/ModelsJsonSerializerContext.cs b/Sources/Falko.Talkie.Bridges.Telegram/Serialization/ModelsJsonSerializerContext.cs index d9dccff..65f1410 100644 --- a/Sources/Falko.Talkie.Bridges.Telegram/Serialization/ModelsJsonSerializerContext.cs +++ b/Sources/Falko.Talkie.Bridges.Telegram/Serialization/ModelsJsonSerializerContext.cs @@ -5,7 +5,8 @@ namespace Talkie.Bridges.Telegram.Serialization; -[JsonSourceGenerationOptions(WriteIndented = false, +[JsonSourceGenerationOptions( + WriteIndented = false, GenerationMode = JsonSourceGenerationMode.Metadata, UseStringEnumConverter = true, IgnoreReadOnlyFields = false, @@ -14,8 +15,9 @@ namespace Talkie.Bridges.Telegram.Serialization; DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower, DictionaryKeyPolicy = JsonKnownNamingPolicy.SnakeCaseLower, - Converters = [typeof(DateTimeUnixConverter), typeof(TextOrNumberValueDictionaryConverter)])] -[JsonSerializable(typeof(TelegramResponse))] + Converters = [typeof(DateTimeUnixConverter), typeof(TextOrNumberValueDictionaryConverter)] +)] +[JsonSerializable(typeof(TelegramResponse>))] [JsonSerializable(typeof(TelegramResponse))] [JsonSerializable(typeof(TelegramResponse))] [JsonSerializable(typeof(TelegramResponse))] diff --git a/Sources/Falko.Talkie.Core/Common/StringExtensions.cs b/Sources/Falko.Talkie.Core/Common/StringExtensions.cs index 3951ec6..d342d11 100644 --- a/Sources/Falko.Talkie.Core/Common/StringExtensions.cs +++ b/Sources/Falko.Talkie.Core/Common/StringExtensions.cs @@ -1,8 +1,12 @@ +using System.Runtime.CompilerServices; + namespace Talkie.Common; public static partial class StringExtensions { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullOrEmpty(this string? value) => string.IsNullOrEmpty(value); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullOrWhiteSpace(this string? value) => string.IsNullOrWhiteSpace(value); } diff --git a/Sources/Falko.Talkie.Core/Concurrent/ParallelEnumerableExtensions.cs b/Sources/Falko.Talkie.Core/Concurrent/ParallelEnumerableExtensions.cs index 7ec94d8..2223292 100644 --- a/Sources/Falko.Talkie.Core/Concurrent/ParallelEnumerableExtensions.cs +++ b/Sources/Falko.Talkie.Core/Concurrent/ParallelEnumerableExtensions.cs @@ -15,21 +15,31 @@ public static SequenceParallelismCoordinator.Static Parallelize(this IRead return new SequenceParallelismCoordinator.Static(sequence); } - public static SequenceParallelismCoordinator.Dynamic Parallelize(this IReadOnlySequence sequence, ParallelismMeter meter) + public static SequenceParallelismCoordinator.Dynamic Parallelize + ( + this IReadOnlySequence sequence, + ParallelismMeter meter + ) { return new SequenceParallelismCoordinator.Dynamic(sequence, meter); } - public static Task ForEachAsync(this SequenceParallelismCoordinator.Static parallel, + public static Task ForEachAsync + ( + this SequenceParallelismCoordinator.Static parallel, Func @do, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { return Parallel.ForEachAsync(parallel.Sequence, cancellationToken, @do); } - public static async Task ForEachAsync(this SequenceParallelismCoordinator.Dynamic parallel, + public static async Task ForEachAsync + ( + this SequenceParallelismCoordinator.Dynamic parallel, Func @do, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { var startTicks = Environment.TickCount64; @@ -58,8 +68,12 @@ public static async Task ForEachAsync(this SequenceParallelismCoordinator. parallel.Meter.Measure(endTicks - startTicks, parallel.Sequence.Count); } - public static void ForEach(this SequenceParallelismCoordinator.Static parallel, Action @do, - CancellationToken cancellationToken = default) + public static void ForEach + ( + this SequenceParallelismCoordinator.Static parallel, + Action @do, + CancellationToken cancellationToken = default + ) { var options = new ParallelOptions { @@ -69,8 +83,12 @@ public static void ForEach(this SequenceParallelismCoordinator.Static para Parallel.ForEach(parallel.Sequence.ToPartitioner(), options, item => @do(item, cancellationToken)); } - public static void ForEach(this SequenceParallelismCoordinator.Dynamic parallel, Action @do, - CancellationToken cancellationToken = default) + public static void ForEach + ( + this SequenceParallelismCoordinator.Dynamic parallel, + Action @do, + CancellationToken cancellationToken = default + ) { var startTicks = Environment.TickCount64; diff --git a/Sources/Falko.Talkie.Core/Concurrent/TaskExtensions.cs b/Sources/Falko.Talkie.Core/Concurrent/TaskExtensions.cs index 3409d16..b3a87d5 100644 --- a/Sources/Falko.Talkie.Core/Concurrent/TaskExtensions.cs +++ b/Sources/Falko.Talkie.Core/Concurrent/TaskExtensions.cs @@ -1,6 +1,9 @@ +using System.Runtime.CompilerServices; + namespace Talkie.Concurrent; public static partial class TaskExtensions { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ValueTask AsValueTask(this Task task) => new(task); } diff --git a/Sources/Falko.Talkie.Core/Disposables/DisposableExtensions.cs b/Sources/Falko.Talkie.Core/Disposables/DisposableExtensions.cs index b8fe4eb..5674ee7 100644 --- a/Sources/Falko.Talkie.Core/Disposables/DisposableExtensions.cs +++ b/Sources/Falko.Talkie.Core/Disposables/DisposableExtensions.cs @@ -2,46 +2,64 @@ namespace Talkie.Disposables; public static partial class DisposableExtensions { - public static T DisposeWith(this T disposable, - IRegisterOnlyDisposableScope enumerableDisposables) where T : IDisposable + public static T DisposeWith + ( + this T disposable, + IRegisterOnlyDisposableScope enumerableDisposables + ) where T : IDisposable { enumerableDisposables.Register(disposable); return disposable; } - public static T DisposeAsyncWith(this T asyncDisposable, - IRegisterOnlyDisposableScope enumerableDisposables) where T : IAsyncDisposable + public static T DisposeAsyncWith + ( + this T asyncDisposable, + IRegisterOnlyDisposableScope enumerableDisposables + ) where T : IAsyncDisposable { enumerableDisposables.Register(asyncDisposable); return asyncDisposable; } - public static async ValueTask DisposeWith(this ValueTask asyncDisposableValueTask, - IRegisterOnlyDisposableScope enumerableDisposables) where T : IDisposable + public static async ValueTask DisposeWith + ( + this ValueTask asyncDisposableValueTask, + IRegisterOnlyDisposableScope enumerableDisposables + ) where T : IDisposable { var asyncDisposable = await asyncDisposableValueTask; enumerableDisposables.Register(asyncDisposable); return asyncDisposable; } - public static async Task DisposeWith(this Task asyncDisposableValueTask, - IRegisterOnlyDisposableScope enumerableDisposables) where T : IDisposable + public static async Task DisposeWith + ( + this Task asyncDisposableValueTask, + IRegisterOnlyDisposableScope enumerableDisposables + ) where T : IDisposable { var asyncDisposable = await asyncDisposableValueTask; enumerableDisposables.Register(asyncDisposable); return asyncDisposable; } - public static async ValueTask DisposeAsyncWith(this ValueTask asyncDisposableValueTask, - IRegisterOnlyDisposableScope enumerableDisposables) where T : IAsyncDisposable + public static async ValueTask DisposeAsyncWith + ( + this ValueTask asyncDisposableValueTask, + IRegisterOnlyDisposableScope enumerableDisposables + ) where T : IAsyncDisposable { var asyncDisposable = await asyncDisposableValueTask; enumerableDisposables.Register(asyncDisposable); return asyncDisposable; } - public static async Task DisposeAsyncWith(this Task asyncDisposableValueTask, - IRegisterOnlyDisposableScope enumerableDisposables) where T : IAsyncDisposable + public static async Task DisposeAsyncWith + ( + this Task asyncDisposableValueTask, + IRegisterOnlyDisposableScope enumerableDisposables + ) where T : IAsyncDisposable { var asyncDisposable = await asyncDisposableValueTask; enumerableDisposables.Register(asyncDisposable); diff --git a/Sources/Falko.Talkie.Core/Sequences/FrozenSequence.cs b/Sources/Falko.Talkie.Core/Sequences/FrozenSequence.cs index acfd2cc..164109b 100644 --- a/Sources/Falko.Talkie.Core/Sequences/FrozenSequence.cs +++ b/Sources/Falko.Talkie.Core/Sequences/FrozenSequence.cs @@ -13,7 +13,6 @@ public partial class FrozenSequence : IReadOnlySequence public FrozenSequence(IEnumerable values) { - var list = new List(); _items = values.ToArray(); _itemsCount = _items.Length; } diff --git a/Sources/Falko.Talkie.Core/Sequences/Sequence.Linq.cs b/Sources/Falko.Talkie.Core/Sequences/Sequence.Linq.cs index f8c9d6c..f8c8f47 100644 --- a/Sources/Falko.Talkie.Core/Sequences/Sequence.Linq.cs +++ b/Sources/Falko.Talkie.Core/Sequences/Sequence.Linq.cs @@ -21,6 +21,20 @@ public T First() : _first.Value; } + public T? SingleOrDefault() + { + return _first is not null && _first == _last + ? _first.Value + : default; + } + + public T Single() + { + return _first is not null && _first == _last + ? _first.Value + : throw new InvalidOperationException(); + } + public T Last() { return _last is null diff --git a/Sources/Falko.Talkie.Core/Sequences/SequenceAdapter.cs b/Sources/Falko.Talkie.Core/Sequences/SequenceAdapter.cs new file mode 100644 index 0000000..d1f9561 --- /dev/null +++ b/Sources/Falko.Talkie.Core/Sequences/SequenceAdapter.cs @@ -0,0 +1,9 @@ +using System.Runtime.CompilerServices; + +namespace Talkie.Sequences; + +[method: MethodImpl(MethodImplOptions.AggressiveInlining)] +public readonly ref struct SequenceAdapter(IEnumerable sequence) +{ + public readonly IEnumerable Sequence = sequence; +} diff --git a/Sources/Falko.Talkie.Core/Sequences/SequenceExtensions.Sequenize.cs b/Sources/Falko.Talkie.Core/Sequences/SequenceExtensions.Sequenize.cs new file mode 100644 index 0000000..29d44e0 --- /dev/null +++ b/Sources/Falko.Talkie.Core/Sequences/SequenceExtensions.Sequenize.cs @@ -0,0 +1,108 @@ +namespace Talkie.Sequences; + +public static partial class SequenceExtensions +{ + public static SequenceAdapter Sequencing(this IEnumerable sequence) + { + return new SequenceAdapter(sequence); + } + + public static bool Any(this SequenceAdapter sequence) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.Any(), + { Sequence: Sequence addableSequence } => addableSequence.Any(), + { Sequence: RemovableSequence removableSequence } => removableSequence.Any(), + _ => sequence.Sequence.Any() + }; + } + + public static T? FirstOrDefault(this SequenceAdapter sequence) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.FirstOrDefault(), + { Sequence: Sequence addableSequence } => addableSequence.FirstOrDefault(), + { Sequence: RemovableSequence removableSequence } => removableSequence.FirstOrDefault(), + _ => sequence.Sequence.FirstOrDefault() + }; + } + + public static T First(this SequenceAdapter sequence) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.First(), + { Sequence: Sequence addableSequence } => addableSequence.First(), + { Sequence: RemovableSequence removableSequence } => removableSequence.First(), + _ => sequence.Sequence.First() + }; + } + + public static T? SingleOrDefault(this SequenceAdapter sequence) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.SingleOrDefault(), + { Sequence: Sequence addableSequence } => addableSequence.SingleOrDefault(), + { Sequence: RemovableSequence removableSequence } => removableSequence.SingleOrDefault(), + _ => sequence.Sequence.SingleOrDefault() + }; + } + + public static T Single(this SequenceAdapter sequence) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.Single(), + { Sequence: Sequence addableSequence } => addableSequence.Single(), + { Sequence: RemovableSequence removableSequence } => removableSequence.Single(), + _ => sequence.Sequence.Single() + }; + } + + public static T? LastOrDefault(this SequenceAdapter sequence) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.LastOrDefault(), + { Sequence: Sequence addableSequence } => addableSequence.LastOrDefault(), + { Sequence: RemovableSequence removableSequence } => removableSequence.LastOrDefault(), + _ => sequence.Sequence.LastOrDefault() + }; + } + + public static T Last(this SequenceAdapter sequence) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.Last(), + { Sequence: Sequence addableSequence } => addableSequence.Last(), + { Sequence: RemovableSequence removableSequence } => removableSequence.Last(), + _ => sequence.Sequence.Last() + }; + } + + public static bool Contains(this SequenceAdapter sequence, T value, IEqualityComparer comparer) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.Contains(value, comparer), + { Sequence: Sequence addableSequence } => addableSequence.Contains(value, comparer), + { Sequence: RemovableSequence removableSequence } => removableSequence.Contains(value, comparer), + _ => sequence.Sequence.Contains(value, comparer) + }; + } + + public static bool Contains(this SequenceAdapter sequence, T value) + { + return sequence switch + { + { Sequence: FrozenSequence frozenSequence } => frozenSequence.Contains(value), + { Sequence: Sequence addableSequence } => addableSequence.Contains(value), + { Sequence: RemovableSequence removableSequence } => removableSequence.Contains(value), + _ => sequence.Sequence.Contains(value) + }; + } +} diff --git a/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.AddBehaviors.cs b/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.AddBehaviors.cs index d6f2f7f..b4853ad 100644 --- a/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.AddBehaviors.cs +++ b/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.AddBehaviors.cs @@ -1,21 +1,15 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Talkie.Subscribers; namespace Talkie.Hosting; public static partial class HostingExtensions { - public static IHostBuilder AddBehaviors<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(this IHostBuilder builder) - where T : class, IBehaviorsSubscriber - { - return builder.ConfigureServices(services => services - .AddBehaviors()); - } - - public static IServiceCollection AddBehaviors<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(this IServiceCollection services) - where T : class, IBehaviorsSubscriber + public static IServiceCollection AddBehaviors<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T> + ( + this IServiceCollection services + ) where T : class, IBehaviorsSubscriber { return services.AddSingleton(); } diff --git a/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.AddIntegrations.cs b/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.AddIntegrations.cs index 11ebac3..3f99208 100644 --- a/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.AddIntegrations.cs +++ b/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.AddIntegrations.cs @@ -1,21 +1,15 @@ using System.Diagnostics.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; using Talkie.Subscribers; namespace Talkie.Hosting; public static partial class HostingExtensions { - public static IHostBuilder AddIntegrations<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(this IHostBuilder builder) - where T : class, IIntegrationsSubscriber - { - return builder.ConfigureServices(services => services - .AddIntegrations()); - } - - public static IServiceCollection AddIntegrations<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(this IServiceCollection services) - where T : class, IIntegrationsSubscriber + public static IServiceCollection AddIntegrations<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T> + ( + this IServiceCollection services + ) where T : class, IIntegrationsSubscriber { return services.AddSingleton(); } diff --git a/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.UseTalkie.cs b/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.UseTalkie.cs index 5f9c484..ad9a798 100644 --- a/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.UseTalkie.cs +++ b/Sources/Falko.Talkie.Microsoft.Hosting/Hosting/HostingExtensions.UseTalkie.cs @@ -7,8 +7,11 @@ namespace Talkie.Hosting; public static partial class HostingExtensions { - public static IHostBuilder UseTalkie(this IHostBuilder builder, - TalkieHostingConfiguration configuration) + public static IHostBuilder UseTalkie + ( + this IHostBuilder builder, + TalkieHostingConfiguration configuration + ) { return builder .ConfigureServices(services => services @@ -24,31 +27,40 @@ public static IHostBuilder UseTalkie(this IHostBuilder builder) return builder.UseTalkie(new TalkieHostingConfiguration()); } - public static IHostBuilder UseTalkie(this IHostBuilder builder, - TalkieHostingConfigurationBuilder configurationBuilder) + public static IHostBuilder UseTalkie + ( + this IHostBuilder builder, + TalkieHostingConfigurationBuilder configurationBuilder + ) { return builder.UseTalkie(configurationBuilder.Build()); } - public static IHostBuilder UseTalkie(this IHostBuilder builder, - Func configure) + public static IHostBuilder UseTalkie + ( + this IHostBuilder builder, + Func configure + ) { return builder.UseTalkie(configure(new TalkieHostingConfigurationBuilder())); } - private static IServiceCollection TryAddShutdown(this IServiceCollection services, - TalkieHostingConfiguration configuration) + private static IServiceCollection TryAddShutdown + ( + this IServiceCollection services, + TalkieHostingConfiguration configuration + ) { - if (configuration.ShutdownOnUnobservedExceptions) - { - return services.AddBehaviors(); - } - - return services.AddBehaviors(); + return configuration.ShutdownOnUnobservedExceptions + ? services.AddBehaviors() + : services.AddBehaviors(); } - private static IServiceCollection TryAddSignalsLogging(this IServiceCollection services, - TalkieHostingConfiguration configuration) + private static IServiceCollection TryAddSignalsLogging + ( + this IServiceCollection services, + TalkieHostingConfiguration configuration + ) { return configuration.LogSignals ? services.AddBehaviors() diff --git a/Sources/Falko.Talkie.Microsoft.Hosting/Subscribers/UnobservedExceptionsLoggingSubscriber.cs b/Sources/Falko.Talkie.Microsoft.Hosting/Subscribers/UnobservedExceptionsLoggingSubscriber.cs index 47f789c..3b7eab6 100644 --- a/Sources/Falko.Talkie.Microsoft.Hosting/Subscribers/UnobservedExceptionsLoggingSubscriber.cs +++ b/Sources/Falko.Talkie.Microsoft.Hosting/Subscribers/UnobservedExceptionsLoggingSubscriber.cs @@ -6,7 +6,10 @@ namespace Talkie.Subscribers; -internal sealed class UnobservedExceptionsLoggingSubscriber(ILogger logger) : IBehaviorsSubscriber +internal sealed class UnobservedExceptionsLoggingSubscriber +( + ILogger logger +) : IBehaviorsSubscriber { private static readonly string UnobservedExceptionLogMessage = "Unobserved exception occurred in the signal flow"; diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramMessageBuildContext.cs b/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramMessageBuildContext.cs new file mode 100644 index 0000000..e84a828 --- /dev/null +++ b/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramMessageBuildContext.cs @@ -0,0 +1,42 @@ +using Talkie.Bridges.Telegram.Models; +using Talkie.Models.Profiles; +using Talkie.Platforms; + +namespace Talkie.Connections; + +internal readonly ref struct TelegramMessageBuildContext +{ + public readonly long Identifier; + + public readonly TelegramPlatform Platform; + + public readonly TelegramMessage? Reply; + + public readonly IProfile EnvironmentProfile; + + public readonly IProfile PublisherProfile; + + public readonly DateTime PublishedDate; + + public readonly DateTime ReceivedDate; + + public TelegramMessageBuildContext + ( + long identifier, + TelegramPlatform platform, + IProfile environmentProfile, + IProfile publisherProfile, + DateTime? publishedDate, + TelegramMessage? reply = null) + { + var receivedDate = DateTime.UtcNow; + + Identifier = identifier; + Platform = platform; + EnvironmentProfile = environmentProfile; + PublisherProfile = publisherProfile; + Reply = reply; + PublishedDate = publishedDate ?? receivedDate; + ReceivedDate = receivedDate; + } +} diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramSignalConnection.cs b/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramSignalConnection.cs index e08fb4e..3385513 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramSignalConnection.cs +++ b/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramSignalConnection.cs @@ -1,135 +1,103 @@ using System.Net; using Talkie.Bridges.Telegram.Clients; using Talkie.Bridges.Telegram.Configurations; -using Talkie.Bridges.Telegram.Models; using Talkie.Bridges.Telegram.Requests; -using Talkie.Concurrent; using Talkie.Converters; using Talkie.Flows; -using Talkie.Models.Messages.Incoming; using Talkie.Models.Profiles; using Talkie.Platforms; -using Talkie.Sequences; namespace Talkie.Connections; -public sealed class TelegramSignalConnection(ISignalFlow flow, - TelegramServerConfiguration serverConfiguration, - TelegramClientConfiguration clientConfiguration) : SignalConnection(flow), IWithPlatformSignalConnection +public sealed class TelegramSignalConnection : ModernSignalConnection, IWithPlatformSignalConnection { - public TelegramPlatform? Platform { get; private set; } + private readonly ISignalFlow _flow; - IPlatform? IWithPlatformSignalConnection.Platform => Platform; + private readonly TelegramConfiguration _configuration; - protected override async Task WhenInitializingAsync(CancellationToken cancellationToken) + private readonly CancellationTokenSource _executingCts = new(); + + private TelegramPlatform _platform = null!; + private Task _executingTask = null!; + + internal TelegramSignalConnection(ISignalFlow flow, TelegramConfiguration configuration) { - ArgumentNullException.ThrowIfNull(serverConfiguration); - ArgumentNullException.ThrowIfNull(clientConfiguration); + ArgumentNullException.ThrowIfNull(flow); + configuration.ThrowIfInvalid(); - var client = new TelegramClient(new TelegramConfiguration(serverConfiguration, clientConfiguration)); + _flow = flow; + _configuration = configuration; + } - TelegramBotProfile self; + public IPlatform? Platform => IsInitialized ? _platform : null; - try - { - self = GetSelf(await client.GetMeAsync(cancellationToken)); - } - catch (TelegramException exception) - { - if (exception.StatusCode is null or not HttpStatusCode.Unauthorized) throw; + protected override async ValueTask InitializeCoreAsync(CancellationToken cancellationToken) + { + var client = new TelegramClient(_configuration); - throw new UnauthorizedAccessException("Invalid token"); - } + var self = await GetSelfAsync(client, cancellationToken); - Platform = new TelegramPlatform(flow, client, self); + _platform = new TelegramPlatform(_flow, client, self); + + _executingTask = Task + .Factory + .StartNew + ( + function: () => ExecuteAsync(_executingCts.Token), + cancellationToken: _executingCts.Token, + creationOptions: TaskCreationOptions.LongRunning, + scheduler: TaskScheduler.Default + ); } - protected override async Task WhenExecutingAsync(CancellationToken cancellationToken) + private async Task ExecuteAsync(CancellationToken cancellationToken) { - int offset = 0; + var publisher = new TelegramUpdatePublisher(_flow, _platform, this); + var offset = 0; while (cancellationToken.IsCancellationRequested is false) { try { - var updates = await Platform!.BotApiClient.GetUpdatesAsync(new TelegramGetUpdatesRequest(offset), cancellationToken); + var updates = await _platform + .BotApiClient + .GetUpdatesAsync(new TelegramGetUpdatesRequest(offset), cancellationToken); + + publisher.Handle(updates, cancellationToken); if (updates.Count is 0) continue; offset = updates[^1].UpdateId + 1; - - _ = updates - .ToFrozenSequence() - .Parallelize() - .ForEachAsync((update, scopedCancellationToken) => - ProcessUpdate(Platform!, update, scopedCancellationToken), cancellationToken) - .ContinueWith(task => - HandleProcessUpdateFaults(cancellationToken, task), TaskContinuationOptions.ExecuteSynchronously); } catch (Exception exception) { - _ = Flow.PublishUnobservedConnectionExceptionAsync(this, exception, cancellationToken); + _ = _flow.PublishUnobservedConnectionExceptionAsync(this, exception, cancellationToken); } } } - protected override Task WhenDisposingAsync() + protected override async ValueTask DisposeCoreAsync() { - Platform?.Dispose(); + await _executingCts.CancelAsync(); + _executingCts.Dispose(); - return Task.CompletedTask; + await _executingTask; + _executingTask.Dispose(); + + _platform.Dispose(); } - private async ValueTask ProcessUpdate(TelegramPlatform platform, TelegramUpdate update, CancellationToken cancellationToken) + private static async Task GetSelfAsync(TelegramClient client, CancellationToken cancellationToken) { - if (update.Message is { } message) + try { - var incomingMessage = IncomingMessageConverter.Convert(platform, message); - - if (incomingMessage is null) return; - - try - { - await Flow.PublishAsync(incomingMessage.ToMessageReceivedSignal(), cancellationToken); - } - catch (Exception exception) - { - _ = Flow.PublishUnobservedPublishingExceptionAsync(exception, cancellationToken); - } + return (await client.GetMeAsync(cancellationToken)).ToBotProfile(); } - - if (update.EditedMessage is { } editedMessage) + catch (TelegramException exception) { - var incomingMessage = IncomingMessageConverter.Convert(platform, editedMessage); - - if (incomingMessage is null) return; + if (exception.StatusCode is null or not HttpStatusCode.Unauthorized) throw; - try - { - await Flow.PublishAsync(incomingMessage.ToMessageEditedSignal(), cancellationToken); - } - catch (Exception exception) - { - _ = Flow.PublishUnobservedPublishingExceptionAsync(exception, cancellationToken); - } + throw new UnauthorizedAccessException("Invalid telegram bot token", exception); } } - - private static TelegramBotProfile GetSelf(TelegramUser self) - { - return new TelegramBotProfile - { - Identifier = self.Id, - FirstName = self.FirstName, - LastName = self.LastName, - NickName = self.Username - }; - } - - private void HandleProcessUpdateFaults(CancellationToken cancellationToken, Task task) - { - if (task.IsFaulted is false || task.Exception is null) return; - - _ = Flow.PublishUnobservedConnectionExceptionAsync(this, task.Exception, cancellationToken); - } } diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramUpdatePublisher.cs b/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramUpdatePublisher.cs new file mode 100644 index 0000000..47c99eb --- /dev/null +++ b/Sources/Falko.Talkie.Platforms.Telegram/Connections/TelegramUpdatePublisher.cs @@ -0,0 +1,105 @@ +using Talkie.Bridges.Telegram.Models; +using Talkie.Converters; +using Talkie.Flows; +using Talkie.Models.Messages.Incoming; +using Talkie.Platforms; +using Talkie.Sequences; + +namespace Talkie.Connections; + +public sealed class TelegramUpdatePublisher(ISignalFlow flow, TelegramPlatform platform, ISignalConnection connection) +{ + private Sequence _messagesGroup = []; + + private bool _isMessagesGroupAboutPublishedUpdates; + + public void Handle(IReadOnlyList updates, CancellationToken cancellationToken) + { + if (updates.Count is 0) + { + if (_messagesGroup.Count is 0) return; + + ProcessMessageGroup(cancellationToken); + } + + foreach (var update in updates) + { + if (cancellationToken.IsCancellationRequested) break; + + if (update.Message is { } publishedMessage) + { + OnMessageUpdate(publishedMessage, true, cancellationToken); + } + else if (update.EditedMessage is { } exchangedMessage) + { + OnMessageUpdate(exchangedMessage, false, cancellationToken); + } + } + } + + private void OnMessageUpdate(TelegramMessage message, bool published, CancellationToken cancellationToken) + { + if (_messagesGroup.Count is not 0 && IsMessageGroupAppendableTo(message, published) is false) + { + ProcessMessageGroup(cancellationToken); + } + + if (message.MediaGroupId is null) + { + ProcessMessage(message, published, cancellationToken); + } + else + { + _messagesGroup.Add(message); + _isMessagesGroupAboutPublishedUpdates = published; + } + } + + private bool IsMessageGroupAppendableTo(TelegramMessage message, bool published) + { + if (_isMessagesGroupAboutPublishedUpdates != published) return false; + + if (message.MediaGroupId is null) return false; + + var first = _messagesGroup.First(); + + return message.MediaGroupId == first.MediaGroupId + && message.Chat?.Id == first.Chat?.Id + && message.From?.Id == first.From?.Id + && message.SenderChat?.Id == first.SenderChat?.Id; + } + + private void ProcessMessageGroup(CancellationToken cancellationToken) + { + if (_messagesGroup.TryGetIncomingMessage(platform, out var incomingMessage) is false) + { + return; + } + + PublishMessage(incomingMessage, _isMessagesGroupAboutPublishedUpdates, cancellationToken); + + _messagesGroup = []; + } + + private void ProcessMessage(TelegramMessage message, bool published, CancellationToken cancellationToken) + { + if (message.TryGetIncomingMessage(platform, out var incomingMessage) is false) + { + return; + } + + PublishMessage(incomingMessage, published, cancellationToken); + } + + private void PublishMessage(TelegramIncomingMessage incomingMessage, bool published, CancellationToken cancellationToken) + { + if (published) + { + flow.Publish(incomingMessage.ToMessagePublishedSignal(), cancellationToken); + } + else + { + flow.Publish(incomingMessage.ToMessageExchangedSignal(), cancellationToken); + } + } +} diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Connectors/TelegramSignalConnector.cs b/Sources/Falko.Talkie.Platforms.Telegram/Connectors/TelegramSignalConnector.cs index a096509..9e3c0fb 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Connectors/TelegramSignalConnector.cs +++ b/Sources/Falko.Talkie.Platforms.Telegram/Connectors/TelegramSignalConnector.cs @@ -4,11 +4,12 @@ namespace Talkie.Connectors; -public sealed class TelegramSignalConnector(TelegramServerConfiguration serverConfiguration, - TelegramClientConfiguration clientConfiguration) : ISignalConnector +public sealed class TelegramSignalConnector(TelegramConfiguration configuration) : ISignalConnector { public ISignalConnection Connect(ISignalFlow flow) { - return new TelegramSignalConnection(flow, serverConfiguration, clientConfiguration); + ArgumentNullException.ThrowIfNull(flow); + + return new TelegramSignalConnection(flow, configuration); } } diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Controllers/MessageControllers/TelegramMessageController.cs b/Sources/Falko.Talkie.Platforms.Telegram/Controllers/MessageControllers/TelegramMessageController.cs index d3bba52..b4d75b6 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Controllers/MessageControllers/TelegramMessageController.cs +++ b/Sources/Falko.Talkie.Platforms.Telegram/Controllers/MessageControllers/TelegramMessageController.cs @@ -3,9 +3,7 @@ using Talkie.Bridges.Telegram.Requests; using Talkie.Converters; using Talkie.Flows; -using Talkie.Models; using Talkie.Models.Identifiers; -using Talkie.Models.Messages; using Talkie.Models.Messages.Contents.Styles; using Talkie.Models.Messages.Incoming; using Talkie.Models.Messages.Outgoing; @@ -27,7 +25,7 @@ public async Task PublishMessageAsync(IOutgoingMessage message throw new ArgumentException("Message content is required."); } - if (environmentProfileIdentifier.TryGetValue(out long receiverId) is not true) + if (environmentProfileIdentifier.TryGetValue(out long receiverId) is false) { throw new ArgumentException("Environment id is required."); } @@ -42,16 +40,14 @@ public async Task PublishMessageAsync(IOutgoingMessage message var sentMessage = await platform.BotApiClient.SendMessageAsync(sendMessage, cancellationToken: cancellationToken); - var sentIncomingMessage = IncomingMessageConverter.Convert(platform, sentMessage) - ?? throw new InvalidOperationException("Failed to convert sent message."); - - _ = flow.PublishAsync(sentIncomingMessage.ToMessageReceivedSignal(), cancellationToken).ContinueWith((e, _) => + if (sentMessage.TryGetIncomingMessage(platform, out var incomingMessage) is false) { - flow.PublishUnobservedPublishingExceptionAsync(e.Exception - ?? new Exception("Failed to publish self sent incoming message."), cancellationToken); - }, TaskContinuationOptions.ExecuteSynchronously, TaskContinuationOptions.OnlyOnFaulted); + throw new InvalidOperationException("Failed to convert sent message."); + } - return sentIncomingMessage; + flow.Publish(incomingMessage.ToMessagePublishedSignal(), cancellationToken); + + return incomingMessage; } public async Task ExchangeMessageAsync(GlobalMessageIdentifier messageIdentifier, IOutgoingMessage message, @@ -81,16 +77,14 @@ public async Task ExchangeMessageAsync(GlobalMessageIdentifier var sentMessage = await platform.BotApiClient.EditMessageTextAsync(editMessageText, cancellationToken: cancellationToken); - var sentIncomingMessage = IncomingMessageConverter.Convert(platform, sentMessage) - ?? throw new InvalidOperationException("Failed to convert sent message."); - - _ = flow.PublishAsync(sentIncomingMessage.ToMessageReceivedSignal(), cancellationToken).ContinueWith((e, _) => + if (sentMessage.TryGetIncomingMessage(platform, out var incomingMessage) is false) { - flow.PublishUnobservedPublishingExceptionAsync(e.Exception - ?? new Exception("Failed to publish self sent incoming message."), cancellationToken); - }, TaskContinuationOptions.ExecuteSynchronously, TaskContinuationOptions.OnlyOnFaulted); + throw new InvalidOperationException("Failed to convert sent message."); + } + + flow.Publish(incomingMessage.ToMessageExchangedSignal(), cancellationToken); - return sentIncomingMessage; + return incomingMessage; } public async Task UnpublishMessageAsync(GlobalMessageIdentifier messageIdentifier, CancellationToken cancellationToken = default) @@ -135,10 +129,7 @@ public async Task UnpublishMessageAsync(GlobalMessageIdentifier messageIdentifie private TelegramReplyParameters? GetReplyParameters(IOutgoingMessage outgoingMessage) { - if (outgoingMessage.Reply is null) - { - return null; - } + if (outgoingMessage.Reply is null) return null; if (outgoingMessage.Reply.MessageIdentifier.TryGetValue(out long replyMessageTelegramId) is false) { diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Converters/IncomingMessageConverter.cs b/Sources/Falko.Talkie.Platforms.Telegram/Converters/IncomingMessageConverter.cs deleted file mode 100644 index 0f9b73b..0000000 --- a/Sources/Falko.Talkie.Platforms.Telegram/Converters/IncomingMessageConverter.cs +++ /dev/null @@ -1,228 +0,0 @@ -using Talkie.Bridges.Telegram.Clients; -using Talkie.Bridges.Telegram.Models; -using Talkie.Bridges.Telegram.Requests; -using Talkie.Common; -using Talkie.Localizations; -using Talkie.Models.Identifiers; -using Talkie.Models.Messages.Attachments; -using Talkie.Models.Messages.Attachments.Variants; -using Talkie.Models.Messages.Contents; -using Talkie.Models.Messages.Contents.Styles; -using Talkie.Models.Messages.Incoming; -using Talkie.Models.Profiles; -using Talkie.Platforms; -using Talkie.Sequences; - -namespace Talkie.Converters; - -internal static class IncomingMessageConverter -{ - public static TelegramIncomingMessage? Convert(TelegramPlatform platform, TelegramMessage message) - { - ArgumentNullException.ThrowIfNull(platform); - ArgumentNullException.ThrowIfNull(message); - - if (message.Text.IsNullOrEmpty() is false) - { - return Convert(message.Text!, platform, message); - } - - if (message.Sticker is { Type: TelegramStickerType.Regular } sticker) - { - return Convert(sticker, platform, message); - } - - return null; - } - - private static TelegramIncomingMessage? Convert(string text, TelegramPlatform platform, TelegramMessage message) - { - if (TryGetProfilesContext(message, out var profilesContext) is false) return null; - - return new TelegramIncomingMessage - { - Identifier = message.MessageId, - Content = new MessageContent(text, GetStyles(message.Entities)), - Platform = platform, - Reply = message.ReplyToMessage is { } reply - ? Convert(platform, reply) - : null, - PublisherProfile = profilesContext.PublisherProfile, - PublishedDate = message.Date ?? DateTime.UtcNow, - ReceiverProfile = platform.BotProfile, - ReceivedDate = DateTime.UtcNow, - EnvironmentProfile = profilesContext.EnvironmentProfile - }; - } - - private static TelegramIncomingMessage? Convert(TelegramSticker sticker, TelegramPlatform platform, TelegramMessage message) - { - if (TryGetProfilesContext(message, out var profilesContext) is false) return null; - - var client = platform.BotApiClient; - - var variants = new Sequence() - { - Convert(sticker, client) - }; - - if (sticker.Thumbnail is { } thumbnail) - { - variants.Add(Convert(thumbnail, client)); - } - - var telegramSticker = new TelegramMessageStickerAttachment - { - Identifier = Identifier.FromValue(sticker.FileUniqueId), - Variants = variants.ToFrozenSequence() - }; - - return new TelegramIncomingMessage - { - Identifier = message.MessageId, - Platform = platform, - Reply = message.ReplyToMessage is { } reply - ? Convert(platform, reply) - : null, - Content = MessageContent.Empty, - Attachments = new FrozenSequence([telegramSticker]), - PublisherProfile = profilesContext.PublisherProfile, - PublishedDate = message.Date ?? DateTime.UtcNow, - ReceiverProfile = platform.BotProfile, - ReceivedDate = DateTime.UtcNow, - EnvironmentProfile = profilesContext.EnvironmentProfile - }; - } - - private static TelegramMessageImageVariant Convert(TelegramPhotoSize photo, ITelegramClient client) - { - return new TelegramMessageImageVariant(async cancellation => - { - var file = await client.GetFileAsync(new TelegramGetFileRequest(photo.FileId), cancellation); - - if (file.FilePath is null) throw new InvalidOperationException(); - - return await client.DownloadAsync(file.FilePath, cancellation); - }) - { - Identifier = Identifier.FromValue(photo.FileUniqueId), - Size = photo.FileSize ?? 0, - Area = new Area(photo.Width, photo.Height) - }; - } - - private static bool TryGetProfilesContext(TelegramMessage message, out ProfilesContext context) - { - var sender = GetSender(message); - - if (sender is null) - { - context = default; - return false; - } - - var environment = GetEnvironment(message); - - if (environment is null) - { - context = default; - return false; - } - - context = new ProfilesContext(sender, environment); - return true; - } - - private static IReadOnlyCollection GetStyles(IReadOnlyCollection? entities) - { - if (entities is null || entities.Count is 0) return []; - - return entities - .Select(entity => entity.Type switch - { - TelegramMessageEntities.Bold => new BoldTextStyle(entity.Offset, entity.Length), - TelegramMessageEntities.Italic => new ItalicTextStyle(entity.Offset, entity.Length), - TelegramMessageEntities.Underline => new UnderlineTextStyle(entity.Offset, entity.Length), - TelegramMessageEntities.Strikethrough => new StrikethroughTextStyle(entity.Offset, entity.Length), - TelegramMessageEntities.Code => new MonospaceTextStyle(entity.Offset, entity.Length), - TelegramMessageEntities.BlockQuote => new QuotationTextStyle(entity.Offset, entity.Length), - _ => null - }) - .Where(style => style is not null) - .Cast() - .ToFrozenSequence(); - } - - private static IProfile? GetEnvironment(TelegramMessage message) - { - if (message.Chat is not { } chat) return null; - - if (chat.Type is TelegramChatType.Private) - { - return new TelegramUserProfile - { - Identifier = chat.Id, - NickName = chat.Username, - FirstName = chat.FirstName, - LastName = chat.LastName - }; - } - - return new TelegramChatProfile - { - Identifier = chat.Id, - Title = chat.Title, - }; - } - - private static IProfile? GetSender(TelegramMessage message) - { - if (message.From is { } sender) - { - var language = Language.Unknown; - - if (sender.LanguageCode is not null) - { - if (LanguageCodes.TryGetLanguageCode(sender.LanguageCode, out var languageCode)) - { - languageCode.TryGetLanguage(out language); - } - } - - if (sender.IsBot) - { - return new TelegramBotProfile - { - Identifier = sender.Id, - NickName = sender.Username, - FirstName = sender.FirstName, - LastName = sender.LastName, - Language = language - }; - } - - return new TelegramUserProfile - { - Identifier = sender.Id, - NickName = sender.Username, - FirstName = sender.FirstName, - LastName = sender.LastName, - Language = language - }; - } - - if (message.Chat is { } chat) - { - return new TelegramChatProfile - { - Identifier = chat.Id, - Title = chat.Title, - NickName = chat.Username - }; - } - - return null; - } - - private readonly record struct ProfilesContext(IProfile PublisherProfile, IProfile EnvironmentProfile); -} diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Converters/TelegramConverters.cs b/Sources/Falko.Talkie.Platforms.Telegram/Converters/TelegramConverters.cs new file mode 100644 index 0000000..bd89ddb --- /dev/null +++ b/Sources/Falko.Talkie.Platforms.Telegram/Converters/TelegramConverters.cs @@ -0,0 +1,437 @@ +using System.Diagnostics.CodeAnalysis; +using Talkie.Bridges.Telegram.Clients; +using Talkie.Bridges.Telegram.Models; +using Talkie.Bridges.Telegram.Requests; +using Talkie.Connections; +using Talkie.Localizations; +using Talkie.Models.Identifiers; +using Talkie.Models.Messages.Attachments; +using Talkie.Models.Messages.Attachments.Variants; +using Talkie.Models.Messages.Contents; +using Talkie.Models.Messages.Contents.Styles; +using Talkie.Models.Messages.Incoming; +using Talkie.Models.Profiles; +using Talkie.Platforms; +using Talkie.Sequences; + +namespace Talkie.Converters; + +internal static class TelegramConverters +{ + public static bool TryGetIncomingMessage + ( + this IReadOnlySequence messages, + TelegramPlatform platform, + [NotNullWhen(true)] out TelegramIncomingMessage? incomingMessage + ) + { + if (messages.Count is 0) + { + incomingMessage = null; + return false; + } + + var firstMessage = messages.Sequencing().First(); + + if (firstMessage.TryGetPublisherProfile(out var publisherProfile) is false) + { + incomingMessage = null; + return false; + } + + if (firstMessage.TryGetEnvironmentProfile(out var environmentProfile) is false) + { + incomingMessage = null; + return false; + } + + var context = new TelegramMessageBuildContext + ( + identifier: firstMessage.MessageId, + platform: platform, + environmentProfile: environmentProfile, + publisherProfile: publisherProfile, + publishedDate: firstMessage.Date, + reply: firstMessage.ReplyToMessage + ); + + var attachments = new Sequence(); + + foreach (var telegramMessage in messages) + { + if (telegramMessage.TryGetImageAttachment(platform.BotApiClient, out var messageImageAttachment) is false) + { + continue; + } + + attachments.Add(messageImageAttachment); + } + + if (attachments.Count is 0) + { + incomingMessage = null; + return false; + } + + incomingMessage = context.ToIncomingMessage(attachments: attachments.ToFrozenSequence()); + return true; + } + + public static bool TryGetIncomingMessage + ( + this TelegramMessage message, + TelegramPlatform platform, + [NotNullWhen(true)] out TelegramIncomingMessage? incomingMessage + ) + { + if (message.TryGetPublisherProfile(out var publisherProfile) is false) + { + incomingMessage = null; + return false; + } + + if (message.TryGetEnvironmentProfile(out var environmentProfile) is false) + { + incomingMessage = null; + return false; + } + + var context = new TelegramMessageBuildContext + ( + identifier: message.MessageId, + platform: platform, + environmentProfile: environmentProfile, + publisherProfile: publisherProfile, + publishedDate: message.Date, + reply: message.ReplyToMessage + ); + + if (message.TryGetMessageTextContent(out var messageContent)) + { + incomingMessage = context.ToIncomingMessage(messageContent); + + return true; + } + + if (message.TryGetImageAttachment(platform.BotApiClient, out var imageAttachment)) + { + var attachments = new FrozenSequence([imageAttachment]); + + incomingMessage = context.ToIncomingMessage(attachments: attachments); + + return true; + } + + if (message.TryGetStickerAttachment(platform.BotApiClient, out var stickerAttachment)) + { + var attachments = new FrozenSequence([stickerAttachment]); + + incomingMessage = context.ToIncomingMessage(attachments: attachments); + + return true; + } + + incomingMessage = null; + return false; + } + + public static TelegramIncomingMessage ToIncomingMessage + ( + this TelegramMessageBuildContext context, + MessageContent? content = null, + IReadOnlySequence? attachments = null + ) + { + var environmentProfile = context.EnvironmentProfile; + var publisherProfile = context.PublisherProfile; + var botProfile = context.Platform.BotProfile; + + return new TelegramIncomingMessage + { + Identifier = context.Identifier, + Platform = context.Platform, + Reply = context.Reply is { } replyMessage + && replyMessage.TryGetIncomingMessage(context.Platform, out var reply) + ? reply + : null, + EnvironmentProfile = environmentProfile.Identifier == botProfile.Identifier + ? publisherProfile + : environmentProfile, + PublisherProfile = publisherProfile, + ReceiverProfile = botProfile, + PublishedDate = context.PublishedDate, + ReceivedDate = context.ReceivedDate, + Content = content ?? MessageContent.Empty, + Attachments = attachments ?? FrozenSequence.Empty + }; + } + + public static bool TryGetImageAttachment + ( + this TelegramMessage message, + ITelegramClient client, + [NotNullWhen(true)] out IMessageImageAttachment? attachment + ) + { + if (message.Photo is not { } photo || photo.Count is 0) + { + attachment = null; + return false; + } + + var variants = new Sequence(); + + foreach (var size in photo) + { + variants.Add(size.ToImageVariant(client)); + } + + var identifier = Identifier.FromValue(message.MediaGroupId ?? photo.First().FileUniqueId); + + if (message.TryGetMessageCaptionContent(out var caption)) + { + attachment = new MessageImageAttachment + { + Identifier = identifier, + Content = caption, + Variants = variants.ToFrozenSequence() + }; + } + else + { + attachment = new MessageImageAttachment + { + Identifier = identifier, + Variants = variants.ToFrozenSequence() + }; + } + + return true; + } + + public static bool TryGetStickerAttachment + ( + this TelegramMessage message, + ITelegramClient client, + [NotNullWhen(true)] out IMessageStickerAttachment? attachment + ) + { + if (message.Sticker is not { } sticker) + { + attachment = null; + return false; + } + + var variants = new Sequence + { + sticker.ToImageVariant(client) + }; + + if (sticker.Thumbnail is { } thumbnail) + { + variants.Add(thumbnail.ToImageVariant(client)); + } + + attachment = new MessageStickerAttachment + { + Identifier = Identifier.FromValue(sticker.FileUniqueId), + Variants = variants.ToFrozenSequence() + }; + + return true; + } + + public static bool TryGetMessageTextContent + ( + this TelegramMessage message, + out MessageContent content + ) + { + if (message.Text is not { } text) + { + content = MessageContent.Empty; + return false; + } + + content = new MessageContent(text, message.Entities.GetMessageTextStyles()); + return true; + } + + public static bool TryGetMessageCaptionContent + ( + this TelegramMessage message, + out MessageContent content + ) + { + if (message.Caption is not { } text) + { + content = MessageContent.Empty; + return false; + } + + content = new MessageContent(text, message.CaptionEntities.GetMessageTextStyles()); + return true; + } + + public static IReadOnlyCollection GetMessageTextStyles + ( + this IReadOnlyCollection? entities + ) + { + if (entities is null || entities.Count is 0) + { + return FrozenSequence.Empty; + } + + var styles = new Sequence(); + + foreach (var entity in entities) + { + if (entity.TryGetMessageTextStyle(out var style) is false) continue; + + styles.Add(style); + } + + // The count will be validated in the 'ToFrozenSequence()' method, + // so no additional checks are needed before. + return styles.ToFrozenSequence(); + } + + public static bool TryGetPublisherProfile + ( + this TelegramMessage message, + [MaybeNullWhen(false)] out IProfile profile + ) + { + if (message.From is { } sender) + { + var language = Language.Unknown; + + if (sender.LanguageCode is not null) + { + Languages.TryGetFromLanguageCodeName(sender.LanguageCode, out language); + } + + profile = sender.IsBot + ? sender.ToUserProfile(language) + : sender.ToBotProfile(language); + + return true; + } + + if (message.SenderChat is { Type: not TelegramChatType.Private } chat) + { + profile = chat.ToChatProfile(); + return true; + } + + profile = null; + return false; + } + + public static bool TryGetEnvironmentProfile + ( + this TelegramMessage message, + [MaybeNullWhen(false)] out IProfile profile + ) + { + if (message.Chat is not { } chat) + { + profile = null; + return false; + } + + if (chat.Type is TelegramChatType.Private) + { + profile = chat.ToUserProfile(); + return true; + } + + profile = chat.ToChatProfile(); + return true; + } + + public static bool TryGetMessageTextStyle + ( + this TelegramMessageEntity entity, + [MaybeNullWhen(false)] out IMessageTextStyle style + ) + { + style = entity.Type switch + { + TelegramMessageEntities.Bold => new BoldTextStyle(entity.Offset, entity.Length), + TelegramMessageEntities.Italic => new ItalicTextStyle(entity.Offset, entity.Length), + TelegramMessageEntities.Underline => new UnderlineTextStyle(entity.Offset, entity.Length), + TelegramMessageEntities.Strikethrough => new StrikethroughTextStyle(entity.Offset, entity.Length), + TelegramMessageEntities.BlockQuote => new QuotationTextStyle(entity.Offset, entity.Length), + TelegramMessageEntities.Code => new MonospaceTextStyle(entity.Offset, entity.Length), + _ => null + }; + + return style is not null; + } + + public static IMessageImageVariant ToImageVariant(this TelegramPhotoSize photo, ITelegramClient client) + { + // TODO: Refactor 'streamFactory' to use controllers. + return new MessageImageVariant(async cancellation => + { + var file = await client.GetFileAsync(new TelegramGetFileRequest(photo.FileId), cancellation); + + if (file.FilePath is null) throw new InvalidOperationException(); + + return await client.DownloadAsync(file.FilePath, cancellation); + }) + { + Identifier = Identifier.FromValue(photo.FileUniqueId), + Size = photo.FileSize ?? 0, + Area = new Area(photo.Width, photo.Height) + }; + } + + public static IBotProfile ToBotProfile(this TelegramUser user, Language language = Language.Unknown) + { + return new BotProfile + { + Identifier = user.Id, + FirstName = user.FirstName, + LastName = user.LastName, + NickName = user.Username, + Language = language + }; + } + + public static IChatProfile ToChatProfile(this TelegramChat user, Language language = Language.Unknown) + { + return new ChatProfile + { + Identifier = user.Id, + Title = user.Title, + NickName = user.Username + }; + } + + public static IUserProfile ToUserProfile(this TelegramUser user, Language language = Language.Unknown) + { + return new UserProfile + { + Identifier = user.Id, + FirstName = user.FirstName, + LastName = user.LastName, + NickName = user.Username, + Language = language + }; + } + + public static IUserProfile ToUserProfile(this TelegramChat user, Language language = Language.Unknown) + { + return new UserProfile + { + Identifier = user.Id, + FirstName = user.FirstName, + LastName = user.LastName, + NickName = user.Username, + Language = language + }; + } +} diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Flows/SignalFlowExtensions.cs b/Sources/Falko.Talkie.Platforms.Telegram/Flows/SignalFlowExtensions.cs index 7d76c60..30c2066 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Flows/SignalFlowExtensions.cs +++ b/Sources/Falko.Talkie.Platforms.Telegram/Flows/SignalFlowExtensions.cs @@ -6,29 +6,41 @@ namespace Talkie.Flows; public static partial class SignalFlowExtensions { - public static ISignalConnection ConnectTelegram(this ISignalFlow flow, - TelegramServerConfiguration serverConfiguration, - TelegramClientConfiguration? clientConfiguration = default) + public static ISignalConnection ConnectTelegram + ( + this ISignalFlow flow, + TelegramConfiguration configuration + ) { - clientConfiguration ??= new TelegramClientConfiguration(); - - return flow.Connect(new TelegramSignalConnector(serverConfiguration, clientConfiguration)); + return flow.Connect(new TelegramSignalConnector(configuration)); } - public static ValueTask ConnectTelegramAsync(this ISignalFlow flow, - TelegramServerConfiguration serverConfiguration, - TelegramClientConfiguration? clientConfiguration = default, - CancellationToken cancellationToken = default) + public static ISignalConnection ConnectTelegram + ( + this ISignalFlow flow, + TelegramServerConfiguration configuration + ) { - clientConfiguration ??= new TelegramClientConfiguration(); + return flow.ConnectTelegram(new TelegramConfiguration(configuration)); + } - return flow.ConnectAsync(new TelegramSignalConnector(serverConfiguration, clientConfiguration), cancellationToken); + public static ValueTask ConnectTelegramAsync + ( + this ISignalFlow flow, + TelegramConfiguration configuration, + CancellationToken cancellationToken = default + ) + { + return flow.ConnectAsync(new TelegramSignalConnector(configuration), cancellationToken); } - public static ValueTask ConnectTelegramAsync(this ISignalFlow flow, - TelegramServerConfiguration serverConfiguration, - CancellationToken cancellationToken) + public static ValueTask ConnectTelegramAsync + ( + this ISignalFlow flow, + TelegramServerConfiguration configuration, + CancellationToken cancellationToken = default + ) { - return flow.ConnectTelegramAsync(serverConfiguration, default, cancellationToken); + return flow.ConnectTelegramAsync(new TelegramConfiguration(configuration), cancellationToken); } } diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Models/Messages/Attachments/TelegramMessageStickerAttachment.cs b/Sources/Falko.Talkie.Platforms.Telegram/Models/Messages/Attachments/TelegramMessageStickerAttachment.cs deleted file mode 100644 index 0ce90c4..0000000 --- a/Sources/Falko.Talkie.Platforms.Telegram/Models/Messages/Attachments/TelegramMessageStickerAttachment.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Talkie.Models.Identifiers; -using Talkie.Models.Messages.Attachments.Variants; -using Talkie.Sequences; - -namespace Talkie.Models.Messages.Attachments; - -public sealed record TelegramMessageStickerAttachment : IMessageStickerAttachment -{ - public required Identifier Identifier { get; init; } - - public IReadOnlySequence Variants { get; init; } - = FrozenSequence.Empty; - - IReadOnlySequence IMessageFileAttachment.Variants => - Variants.OfType().ToFrozenSequence(); - - IReadOnlySequence IMessageStickerAttachment.Variants => - Variants.OfType().ToFrozenSequence(); -} diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Platforms/TelegramPlatform.cs b/Sources/Falko.Talkie.Platforms.Telegram/Platforms/TelegramPlatform.cs index 57cbbea..7f6ebe9 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Platforms/TelegramPlatform.cs +++ b/Sources/Falko.Talkie.Platforms.Telegram/Platforms/TelegramPlatform.cs @@ -13,7 +13,7 @@ public TelegramPlatform ( ISignalFlow flow, ITelegramClient botApiClient, - TelegramBotProfile botProfile + IBotProfile botProfile ) { BotApiClient = botApiClient; @@ -30,7 +30,7 @@ TelegramBotProfile botProfile public ITelegramClient BotApiClient { get; } - public TelegramBotProfile BotProfile { get; } + public IBotProfile BotProfile { get; } public IControllerCreator ControllerCreator { get; } diff --git a/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreator.cs b/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreator.cs index 717c0cc..ae76706 100644 --- a/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreator.cs +++ b/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreator.cs @@ -3,7 +3,9 @@ namespace Talkie.Controllers; /// public sealed class ControllerCreator(IReadOnlyDictionary> factories) : IControllerCreator { - public TController Create(TContext context) where TController : class, IController where TContext : notnull + public TController Create(TContext context) + where TController : class, IController + where TContext : notnull { if (factories.TryGetValue(typeof(TController), out var factory) is false) { diff --git a/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorBuilder.cs b/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorBuilder.cs index 95b1a8a..749da1c 100644 --- a/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorBuilder.cs +++ b/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorBuilder.cs @@ -9,7 +9,9 @@ public sealed class ControllerCreatorBuilder : IControllerCreatorBuilder private ControllerCreatorBuilder() { } - public IControllerCreatorBuilder Add(Func factory) where TController : class, IController where TContext : notnull + public IControllerCreatorBuilder Add(Func factory) + where TController : class, IController + where TContext : notnull { _factories.Add(typeof(TController), context => { diff --git a/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorBuilderExtensions.AddMessageController.cs b/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorBuilderExtensions.AddMessageController.cs index 1349c9f..dd5a10c 100644 --- a/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorBuilderExtensions.AddMessageController.cs +++ b/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorBuilderExtensions.AddMessageController.cs @@ -1,13 +1,15 @@ using Talkie.Controllers.MessageControllers; -using Talkie.Models; using Talkie.Models.Identifiers; namespace Talkie.Controllers; public static partial class ControllerCreatorBuilderExtensions { - public static IControllerCreatorBuilder AddMessageController(this IControllerCreatorBuilder builder, - Func controllerFactory) + public static IControllerCreatorBuilder AddMessageController + ( + this IControllerCreatorBuilder builder, + Func controllerFactory + ) { builder.Add(controllerFactory); return builder; diff --git a/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorExtensions.CreateMessageController.cs b/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorExtensions.CreateMessageController.cs index 2d5ea07..8fbfc47 100644 --- a/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorExtensions.CreateMessageController.cs +++ b/Sources/Falko.Talkie.Platforms/Controllers/ControllerCreatorExtensions.CreateMessageController.cs @@ -1,13 +1,15 @@ using Talkie.Controllers.MessageControllers; -using Talkie.Models; using Talkie.Models.Identifiers; namespace Talkie.Controllers; public static partial class ControllerCreatorExtensions { - public static IMessageController CreateMessageController(this IControllerCreator creator, - Identifier environmentProfileIdentifier) + public static IMessageController CreateMessageController + ( + this IControllerCreator creator, + Identifier environmentProfileIdentifier + ) { return creator.Create(environmentProfileIdentifier); } diff --git a/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/IMessageController.cs b/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/IMessageController.cs index 1308723..c97ab3c 100644 --- a/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/IMessageController.cs +++ b/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/IMessageController.cs @@ -1,6 +1,4 @@ -using Talkie.Models; using Talkie.Models.Identifiers; -using Talkie.Models.Messages; using Talkie.Models.Messages.Incoming; using Talkie.Models.Messages.Outgoing; @@ -8,14 +6,23 @@ namespace Talkie.Controllers.MessageControllers; public interface IMessageController : IController { - Task PublishMessageAsync(IOutgoingMessage message, + Task PublishMessageAsync + ( + IOutgoingMessage message, MessagePublishingFeatures features = default, - CancellationToken cancellationToken = default); + CancellationToken cancellationToken = default + ); - Task ExchangeMessageAsync(GlobalMessageIdentifier messageIdentifier, + Task ExchangeMessageAsync + ( + GlobalMessageIdentifier messageIdentifier, IOutgoingMessage message, - CancellationToken cancellationToken = default); + CancellationToken cancellationToken = default + ); - Task UnpublishMessageAsync(GlobalMessageIdentifier messageIdentifier, - CancellationToken cancellationToken = default); + Task UnpublishMessageAsync + ( + GlobalMessageIdentifier messageIdentifier, + CancellationToken cancellationToken = default + ); } diff --git a/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessageControllerExtensions.ExchangeMessageAsync.cs b/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessageControllerExtensions.ExchangeMessageAsync.cs index e774f20..e7f0eb7 100644 --- a/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessageControllerExtensions.ExchangeMessageAsync.cs +++ b/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessageControllerExtensions.ExchangeMessageAsync.cs @@ -1,6 +1,4 @@ -using Talkie.Models; using Talkie.Models.Identifiers; -using Talkie.Models.Messages; using Talkie.Models.Messages.Contents; using Talkie.Models.Messages.Incoming; using Talkie.Models.Messages.Outgoing; @@ -9,43 +7,57 @@ namespace Talkie.Controllers.MessageControllers; public static partial class MessageControllerExtensions { - public static Task ExchangeMessageAsync(this IMessageController controller, + public static Task ExchangeMessageAsync + ( + this IMessageController controller, GlobalMessageIdentifier messageIdentifier, MessageContent content, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { - return controller.ExchangeMessageAsync(messageIdentifier, + return controller.ExchangeMessageAsync + ( + messageIdentifier, new OutgoingMessage { Content = content }, - cancellationToken); + cancellationToken + ); } - public static Task ExchangeMessageAsync(this IMessageController controller, + public static Task ExchangeMessageAsync + ( + this IMessageController controller, GlobalMessageIdentifier messageIdentifier, IOutgoingMessageMutator messageMutator, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { - return controller.ExchangeMessageAsync(messageIdentifier, - messageMutator.Mutate(), - cancellationToken); + return controller.ExchangeMessageAsync(messageIdentifier, messageMutator.Mutate(), cancellationToken); } - public static Task ExchangeMessageAsync(this IMessageController controller, + public static Task ExchangeMessageAsync + ( + this IMessageController controller, GlobalMessageIdentifier messageIdentifier, IOutgoingMessageBuilder messageBuilder, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { - return controller.ExchangeMessageAsync(messageIdentifier, - messageBuilder.Build(), - cancellationToken); + return controller.ExchangeMessageAsync(messageIdentifier, messageBuilder.Build(), cancellationToken); } - public static Task ExchangeMessageAsync(this IMessageController controller, + public static Task ExchangeMessageAsync + ( + this IMessageController controller, GlobalMessageIdentifier messageIdentifier, Func messageBuilderFactory, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { - return controller.ExchangeMessageAsync(messageIdentifier, + return controller.ExchangeMessageAsync + ( + messageIdentifier, messageBuilderFactory(new OutgoingMessageBuilder()).Build(), - cancellationToken); + cancellationToken + ); } } diff --git a/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessageControllerExtensions.PublishMessageAsync.cs b/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessageControllerExtensions.PublishMessageAsync.cs index ea1b630..7049349 100644 --- a/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessageControllerExtensions.PublishMessageAsync.cs +++ b/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessageControllerExtensions.PublishMessageAsync.cs @@ -6,69 +6,106 @@ namespace Talkie.Controllers.MessageControllers; public static partial class MessageControllerExtensions { - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, IOutgoingMessageMutator mutator, MessagePublishingFeatures features = default, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { return controller.PublishMessageAsync(mutator.Mutate(), features, cancellationToken); } - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, IOutgoingMessageMutator mutator, - CancellationToken cancellationToken) + CancellationToken cancellationToken + ) { return controller.PublishMessageAsync(mutator, default, cancellationToken); } - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, IOutgoingMessageBuilder builder, MessagePublishingFeatures features = default, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { return controller.PublishMessageAsync(builder.Build(), features, cancellationToken); } - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, IOutgoingMessageBuilder builder, - CancellationToken cancellationToken) + CancellationToken cancellationToken + ) { return controller.PublishMessageAsync(builder, default, cancellationToken); } - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, Func builderFactory, MessagePublishingFeatures features = default, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { - return controller.PublishMessageAsync(builderFactory(new OutgoingMessageBuilder()).Build(), features, cancellationToken); + return controller.PublishMessageAsync + ( + builderFactory(new OutgoingMessageBuilder()).Build(), + features, + cancellationToken + ); } - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, Func builderFactory, - CancellationToken cancellationToken) + CancellationToken cancellationToken + ) { return controller.PublishMessageAsync(builderFactory, default, cancellationToken); } - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, MessageContent content, MessagePublishingFeatures features = default, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { - return controller.PublishMessageAsync(new OutgoingMessage { Content = content }, features, cancellationToken); + return controller.PublishMessageAsync + ( + new OutgoingMessage { Content = content }, + features, + cancellationToken + ); } - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, MessageContent content, - CancellationToken cancellationToken) + CancellationToken cancellationToken + ) { return controller.PublishMessageAsync(content, default, cancellationToken); } - public static Task PublishMessageAsync(this IMessageController controller, + public static Task PublishMessageAsync + ( + this IMessageController controller, IOutgoingMessage message, - CancellationToken cancellationToken) + CancellationToken cancellationToken + ) { return controller.PublishMessageAsync(message, default, cancellationToken); } diff --git a/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessagePublishingFeatures.cs b/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessagePublishingFeatures.cs index fee1ae0..ef38b9a 100644 --- a/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessagePublishingFeatures.cs +++ b/Sources/Falko.Talkie.Platforms/Controllers/MessageControllers/MessagePublishingFeatures.cs @@ -1,6 +1,3 @@ namespace Talkie.Controllers.MessageControllers; -public readonly record struct MessagePublishingFeatures(bool PublishSilently = false) -{ - public static readonly MessagePublishingFeatures Default = new(); -} +public readonly record struct MessagePublishingFeatures(bool PublishSilently = false); diff --git a/Sources/Falko.Talkie.Platforms/Handlers/SignalFlowExtensions.GetMessageController.cs b/Sources/Falko.Talkie.Platforms/Handlers/SignalFlowExtensions.GetMessageController.cs index 9c3b7f3..74c1109 100644 --- a/Sources/Falko.Talkie.Platforms/Handlers/SignalFlowExtensions.GetMessageController.cs +++ b/Sources/Falko.Talkie.Platforms/Handlers/SignalFlowExtensions.GetMessageController.cs @@ -1,6 +1,5 @@ using Talkie.Controllers; using Talkie.Controllers.MessageControllers; -using Talkie.Models; using Talkie.Models.Identifiers; using Talkie.Models.Messages.Incoming; using Talkie.Models.Profiles; @@ -10,20 +9,29 @@ namespace Talkie.Handlers; public static partial class SignalContextExtensions { - public static IMessageController GetMessageController(this ISignalContext context, - Identifier environmentProfileIdentifier) + public static IMessageController GetMessageController + ( + this ISignalContext context, + Identifier environmentProfileIdentifier + ) { return context.GetMessage().GetMessageController(environmentProfileIdentifier); } - public static IMessageController GetMessageController(this ISignalContext context, - Identifier environmentProfileIdentifier) + public static IMessageController GetMessageController + ( + this ISignalContext context, + Identifier environmentProfileIdentifier + ) { return context.GetMessage().GetMessageController(environmentProfileIdentifier); } - private static IMessageController GetMessageController(this IIncomingMessage message, - Identifier environmentProfileIdentifier) + private static IMessageController GetMessageController + ( + this IIncomingMessage message, + Identifier environmentProfileIdentifier + ) { return message .Platform @@ -31,14 +39,20 @@ private static IMessageController GetMessageController(this IIncomingMessage mes .CreateMessageController(environmentProfileIdentifier); } - public static IMessageController GetMessageController(this ISignalContext context, - IProfile environmentProfile) + public static IMessageController GetMessageController + ( + this ISignalContext context, + IProfile environmentProfile + ) { return context.GetMessageController(environmentProfile.Identifier); } - public static IMessageController GetMessageController(this ISignalContext context, - IProfile environmentProfile) + public static IMessageController GetMessageController + ( + this ISignalContext context, + IProfile environmentProfile + ) { return context.GetMessageController(environmentProfile.Identifier); } diff --git a/Sources/Falko.Talkie.Platforms/Localizations/Language.cs b/Sources/Falko.Talkie.Platforms/Localizations/Language.cs index 8665686..9b91bf1 100644 --- a/Sources/Falko.Talkie.Platforms/Localizations/Language.cs +++ b/Sources/Falko.Talkie.Platforms/Localizations/Language.cs @@ -2,326 +2,326 @@ namespace Talkie.Localizations; public enum Language { - Unknown = 0, + Unknown = default, - [LanguageCode(LanguageCode.Af)] + [LanguageCode("af")] Afrikaans, - [LanguageCode(LanguageCode.Sq)] + [LanguageCode("sq")] Albanian, - [LanguageCode(LanguageCode.Am)] + [LanguageCode("am")] Amharic, - [LanguageCode(LanguageCode.Ar)] + [LanguageCode("ar")] Arabic, - [LanguageCode(LanguageCode.Hy)] + [LanguageCode("hy")] Armenian, - [LanguageCode(LanguageCode.Az)] + [LanguageCode("az")] Azerbaijani, - [LanguageCode(LanguageCode.Eu)] + [LanguageCode("eu")] Basque, - [LanguageCode(LanguageCode.Be)] + [LanguageCode("be")] Belarusian, - [LanguageCode(LanguageCode.Bn)] + [LanguageCode("bn")] Bengali, - [LanguageCode(LanguageCode.Bs)] + [LanguageCode("bs")] Bosnian, - [LanguageCode(LanguageCode.Bg)] + [LanguageCode("bg")] Bulgarian, - [LanguageCode(LanguageCode.Ca)] + [LanguageCode("ca")] Catalan, - [LanguageCode(LanguageCode.Ceb)] + [LanguageCode("ceb")] Cebuano, - [LanguageCode(LanguageCode.Ny)] + [LanguageCode("ny")] Chichewa, - [LanguageCode(LanguageCode.Zh)] + [LanguageCode("zh")] Chinese, - [LanguageCode(LanguageCode.Co)] + [LanguageCode("co")] Corsican, - [LanguageCode(LanguageCode.Hr)] + [LanguageCode("hr")] Croatian, - [LanguageCode(LanguageCode.Cs)] + [LanguageCode("cs")] Czech, - [LanguageCode(LanguageCode.Da)] + [LanguageCode("da")] Danish, - [LanguageCode(LanguageCode.Nl)] + [LanguageCode("nl")] Dutch, - [LanguageCode(LanguageCode.En)] + [LanguageCode("en")] English, - [LanguageCode(LanguageCode.Eo)] + [LanguageCode("eo")] Esperanto, - [LanguageCode(LanguageCode.Et)] + [LanguageCode("et")] Estonian, - [LanguageCode(LanguageCode.Tl)] + [LanguageCode("tl")] Filipino, - [LanguageCode(LanguageCode.Fi)] + [LanguageCode("fi")] Finnish, - [LanguageCode(LanguageCode.Fr)] + [LanguageCode("fr")] French, - [LanguageCode(LanguageCode.Fy)] + [LanguageCode("fy")] Frisian, - [LanguageCode(LanguageCode.Gl)] + [LanguageCode("gl")] Galician, - [LanguageCode(LanguageCode.Ka)] + [LanguageCode("ka")] Georgian, - [LanguageCode(LanguageCode.De)] + [LanguageCode("de")] German, - [LanguageCode(LanguageCode.El)] + [LanguageCode("el")] Greek, - [LanguageCode(LanguageCode.Gu)] + [LanguageCode("gu")] Gujarati, - [LanguageCode(LanguageCode.Ht)] + [LanguageCode("ht")] HaitianCreole, - [LanguageCode(LanguageCode.Ha)] + [LanguageCode("ha")] Hausa, - [LanguageCode(LanguageCode.Haw)] + [LanguageCode("haw")] Hawaiian, - [LanguageCode(LanguageCode.He)] + [LanguageCode("he")] Hebrew, - [LanguageCode(LanguageCode.Hi)] + [LanguageCode("hi")] Hindi, - [LanguageCode(LanguageCode.Hmn)] + [LanguageCode("hmn")] Hmong, - [LanguageCode(LanguageCode.Hu)] + [LanguageCode("hu")] Hungarian, - [LanguageCode(LanguageCode.Is)] + [LanguageCode("is")] Icelandic, - [LanguageCode(LanguageCode.Ig)] + [LanguageCode("ig")] Igbo, - [LanguageCode(LanguageCode.Id)] + [LanguageCode("id")] Indonesian, - [LanguageCode(LanguageCode.Ga)] + [LanguageCode("ga")] Irish, - [LanguageCode(LanguageCode.It)] + [LanguageCode("it")] Italian, - [LanguageCode(LanguageCode.Ja)] + [LanguageCode("ja")] Japanese, - [LanguageCode(LanguageCode.Jw)] + [LanguageCode("jw")] Javanese, - [LanguageCode(LanguageCode.Kn)] + [LanguageCode("kn")] Kannada, - [LanguageCode(LanguageCode.Kk)] + [LanguageCode("kk")] Kazakh, - [LanguageCode(LanguageCode.Km)] + [LanguageCode("km")] Khmer, - [LanguageCode(LanguageCode.Ko)] + [LanguageCode("ko")] Korean, - [LanguageCode(LanguageCode.Ku)] + [LanguageCode("ku")] Kurdish, - [LanguageCode(LanguageCode.Ky)] + [LanguageCode("ky")] Kyrgyz, - [LanguageCode(LanguageCode.Lo)] + [LanguageCode("lo")] Lao, - [LanguageCode(LanguageCode.La)] + [LanguageCode("la")] Latin, - [LanguageCode(LanguageCode.Lv)] + [LanguageCode("lv")] Latvian, - [LanguageCode(LanguageCode.Lt)] + [LanguageCode("lt")] Lithuanian, - [LanguageCode(LanguageCode.Lb)] + [LanguageCode("lb")] Luxembourgish, - [LanguageCode(LanguageCode.Mk)] + [LanguageCode("mk")] Macedonian, - [LanguageCode(LanguageCode.Mg)] + [LanguageCode("mg")] Malagasy, - [LanguageCode(LanguageCode.Ms)] + [LanguageCode("ms")] Malay, - [LanguageCode(LanguageCode.Ml)] + [LanguageCode("ml")] Malayalam, - [LanguageCode(LanguageCode.Mt)] + [LanguageCode("mt")] Maltese, - [LanguageCode(LanguageCode.Mi)] + [LanguageCode("mi")] Maori, - [LanguageCode(LanguageCode.Mr)] + [LanguageCode("mr")] Marathi, - [LanguageCode(LanguageCode.Mn)] + [LanguageCode("mn")] Mongolian, - [LanguageCode(LanguageCode.My)] + [LanguageCode("my")] MyanmarBurmese, - [LanguageCode(LanguageCode.Ne)] + [LanguageCode("ne")] Nepali, - [LanguageCode(LanguageCode.No)] + [LanguageCode("no")] Norwegian, - [LanguageCode(LanguageCode.Or)] + [LanguageCode("or")] OdiaOriya, - [LanguageCode(LanguageCode.Ps)] + [LanguageCode("ps")] Pashto, - [LanguageCode(LanguageCode.Fa)] + [LanguageCode("fa")] Persian, - [LanguageCode(LanguageCode.Pl)] + [LanguageCode("pl")] Polish, - [LanguageCode(LanguageCode.Pt)] + [LanguageCode("pt")] Portuguese, - [LanguageCode(LanguageCode.Pa)] + [LanguageCode("pa")] Punjabi, - [LanguageCode(LanguageCode.Ro)] + [LanguageCode("ro")] Romanian, - [LanguageCode(LanguageCode.Ru)] + [LanguageCode("ru")] Russian, - [LanguageCode(LanguageCode.Sm)] + [LanguageCode("sm")] Samoan, - [LanguageCode(LanguageCode.Gd)] + [LanguageCode("gd")] ScotsGaelic, - [LanguageCode(LanguageCode.Sr)] + [LanguageCode("sr")] Serbian, - [LanguageCode(LanguageCode.St)] + [LanguageCode("st")] Sesotho, - [LanguageCode(LanguageCode.Sn)] + [LanguageCode("sn")] Shona, - [LanguageCode(LanguageCode.Sd)] + [LanguageCode("sd")] Sindhi, - [LanguageCode(LanguageCode.Si)] + [LanguageCode("si")] Sinhala, - [LanguageCode(LanguageCode.Sk)] + [LanguageCode("sk")] Slovak, - [LanguageCode(LanguageCode.Sl)] + [LanguageCode("sl")] Slovenian, - [LanguageCode(LanguageCode.So)] + [LanguageCode("so")] Somali, - [LanguageCode(LanguageCode.Es)] + [LanguageCode("es")] Spanish, - [LanguageCode(LanguageCode.Su)] + [LanguageCode("su")] Sundanese, - [LanguageCode(LanguageCode.Sw)] + [LanguageCode("sw")] Swahili, - [LanguageCode(LanguageCode.Sv)] + [LanguageCode("sv")] Swedish, - [LanguageCode(LanguageCode.Tg)] + [LanguageCode("tg")] Tajik, - [LanguageCode(LanguageCode.Ta)] + [LanguageCode("ta")] Tamil, - [LanguageCode(LanguageCode.Tt)] + [LanguageCode("tt")] Tatar, - [LanguageCode(LanguageCode.Te)] + [LanguageCode("te")] Telugu, - [LanguageCode(LanguageCode.Th)] + [LanguageCode("th")] Thai, - [LanguageCode(LanguageCode.Tr)] + [LanguageCode("tr")] Turkish, - [LanguageCode(LanguageCode.Tk)] + [LanguageCode("tk")] Turkmen, - [LanguageCode(LanguageCode.Uk)] + [LanguageCode("uk")] Ukrainian, - [LanguageCode(LanguageCode.Ur)] + [LanguageCode("ur")] Urdu, - [LanguageCode(LanguageCode.Ug)] + [LanguageCode("ug")] Uyghur, - [LanguageCode(LanguageCode.Uz)] + [LanguageCode("uz")] Uzbek, - [LanguageCode(LanguageCode.Vi)] + [LanguageCode("vi")] Vietnamese, - [LanguageCode(LanguageCode.Cy)] + [LanguageCode("cy")] Welsh, - [LanguageCode(LanguageCode.Xh)] + [LanguageCode("xh")] Xhosa, - [LanguageCode(LanguageCode.Yi)] + [LanguageCode("yi")] Yiddish, - [LanguageCode(LanguageCode.Yo)] + [LanguageCode("yo")] Yoruba, - [LanguageCode(LanguageCode.Zu)] + [LanguageCode("zu")] Zulu } diff --git a/Sources/Falko.Talkie.Platforms/Localizations/LanguageAttribute.cs b/Sources/Falko.Talkie.Platforms/Localizations/LanguageAttribute.cs deleted file mode 100644 index 5bc3d8d..0000000 --- a/Sources/Falko.Talkie.Platforms/Localizations/LanguageAttribute.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Talkie.Localizations; - -[AttributeUsage(AttributeTargets.Field)] -public sealed class LanguageAttribute(Language language) : Attribute -{ - public readonly Language Language = language; - - public override string ToString() => Language.ToString(); - - public override int GetHashCode() => Language.GetHashCode(); - - public override bool Equals(object? obj) => obj is LanguageAttribute other && Language == other.Language; -} diff --git a/Sources/Falko.Talkie.Platforms/Localizations/LanguageCode.cs b/Sources/Falko.Talkie.Platforms/Localizations/LanguageCode.cs deleted file mode 100644 index 228006f..0000000 --- a/Sources/Falko.Talkie.Platforms/Localizations/LanguageCode.cs +++ /dev/null @@ -1,327 +0,0 @@ -namespace Talkie.Localizations; - -public enum LanguageCode -{ - Unknown = 0, - - [Language(Language.Afrikaans)] - Af, - - [Language(Language.Albanian)] - Sq, - - [Language(Language.Amharic)] - Am, - - [Language(Language.Arabic)] - Ar, - - [Language(Language.Armenian)] - Hy, - - [Language(Language.Azerbaijani)] - Az, - - [Language(Language.Basque)] - Eu, - - [Language(Language.Belarusian)] - Be, - - [Language(Language.Bengali)] - Bn, - - [Language(Language.Bosnian)] - Bs, - - [Language(Language.Bulgarian)] - Bg, - - [Language(Language.Catalan)] - Ca, - - [Language(Language.Cebuano)] - Ceb, - - [Language(Language.Chichewa)] - Ny, - - [Language(Language.Chinese)] - Zh, - - [Language(Language.Corsican)] - Co, - - [Language(Language.Croatian)] - Hr, - - [Language(Language.Czech)] - Cs, - - [Language(Language.Danish)] - Da, - - [Language(Language.Dutch)] - Nl, - - [Language(Language.English)] - En, - - [Language(Language.Esperanto)] - Eo, - - [Language(Language.Estonian)] - Et, - - [Language(Language.Filipino)] - Tl, - - [Language(Language.Finnish)] - Fi, - - [Language(Language.French)] - Fr, - - [Language(Language.Frisian)] - Fy, - - [Language(Language.Galician)] - Gl, - - [Language(Language.Georgian)] - Ka, - - [Language(Language.German)] - De, - - [Language(Language.Greek)] - El, - - [Language(Language.Gujarati)] - Gu, - - [Language(Language.HaitianCreole)] - Ht, - - [Language(Language.Hausa)] - Ha, - - [Language(Language.Hawaiian)] - Haw, - - [Language(Language.Hebrew)] - He, - - [Language(Language.Hindi)] - Hi, - - [Language(Language.Hmong)] - Hmn, - - [Language(Language.Hungarian)] - Hu, - - [Language(Language.Icelandic)] - Is, - - [Language(Language.Igbo)] - Ig, - - [Language(Language.Indonesian)] - Id, - - [Language(Language.Irish)] - Ga, - - [Language(Language.Italian)] - It, - - [Language(Language.Japanese)] - Ja, - - [Language(Language.Javanese)] - Jw, - - [Language(Language.Kannada)] - Kn, - - [Language(Language.Kazakh)] - Kk, - - [Language(Language.Khmer)] - Km, - - [Language(Language.Korean)] - Ko, - - [Language(Language.Kurdish)] - Ku, - - [Language(Language.Kyrgyz)] - Ky, - - [Language(Language.Lao)] - Lo, - - [Language(Language.Latin)] - La, - - [Language(Language.Latvian)] - Lv, - - [Language(Language.Lithuanian)] - Lt, - - [Language(Language.Luxembourgish)] - Lb, - - [Language(Language.Macedonian)] - Mk, - - [Language(Language.Malagasy)] - Mg, - - [Language(Language.Malay)] - Ms, - - [Language(Language.Malayalam)] - Ml, - - [Language(Language.Maltese)] - Mt, - - [Language(Language.Maori)] - Mi, - - [Language(Language.Marathi)] - Mr, - - [Language(Language.Mongolian)] - Mn, - - [Language(Language.MyanmarBurmese)] - My, - - [Language(Language.Nepali)] - Ne, - - [Language(Language.Norwegian)] - No, - - [Language(Language.OdiaOriya)] - Or, - - [Language(Language.Pashto)] - Ps, - - [Language(Language.Persian)] - Fa, - - [Language(Language.Polish)] - Pl, - - [Language(Language.Portuguese)] - Pt, - - [Language(Language.Punjabi)] - Pa, - - [Language(Language.Romanian)] - Ro, - - [Language(Language.Russian)] - Ru, - - [Language(Language.Samoan)] - Sm, - - [Language(Language.ScotsGaelic)] - Gd, - - [Language(Language.Serbian)] - Sr, - - [Language(Language.Sesotho)] - St, - - [Language(Language.Shona)] - Sn, - - [Language(Language.Sindhi)] - Sd, - - [Language(Language.Sinhala)] - Si, - - [Language(Language.Slovak)] - Sk, - - [Language(Language.Slovenian)] - Sl, - - [Language(Language.Somali)] - So, - - [Language(Language.Spanish)] - Es, - - [Language(Language.Sundanese)] - Su, - - [Language(Language.Swahili)] - Sw, - - [Language(Language.Swedish)] - Sv, - - [Language(Language.Tajik)] - Tg, - - [Language(Language.Tamil)] - Ta, - - [Language(Language.Tatar)] - Tt, - - [Language(Language.Telugu)] - Te, - - [Language(Language.Thai)] - Th, - - [Language(Language.Turkish)] - Tr, - - [Language(Language.Turkmen)] - Tk, - - [Language(Language.Ukrainian)] - Uk, - - [Language(Language.Urdu)] - Ur, - - [Language(Language.Uyghur)] - Ug, - - [Language(Language.Uzbek)] - Uz, - - [Language(Language.Vietnamese)] - Vi, - - [Language(Language.Welsh)] - Cy, - - [Language(Language.Xhosa)] - Xh, - - [Language(Language.Yiddish)] - Yi, - - [Language(Language.Yoruba)] - Yo, - - [Language(Language.Zulu)] - Zu -} diff --git a/Sources/Falko.Talkie.Platforms/Localizations/LanguageCodeAttribute.cs b/Sources/Falko.Talkie.Platforms/Localizations/LanguageCodeAttribute.cs index b42c66c..52086e1 100644 --- a/Sources/Falko.Talkie.Platforms/Localizations/LanguageCodeAttribute.cs +++ b/Sources/Falko.Talkie.Platforms/Localizations/LanguageCodeAttribute.cs @@ -1,11 +1,11 @@ namespace Talkie.Localizations; [AttributeUsage(AttributeTargets.Field)] -public sealed class LanguageCodeAttribute(LanguageCode languageCode) : Attribute +public sealed class LanguageCodeAttribute(string languageCode) : Attribute { - public readonly LanguageCode LanguageCode = languageCode; + public readonly string LanguageCode = languageCode; - public override string ToString() => LanguageCode.ToString(); + public override string ToString() => LanguageCode; public override int GetHashCode() => LanguageCode.GetHashCode(); diff --git a/Sources/Falko.Talkie.Platforms/Localizations/LanguageCodes.cs b/Sources/Falko.Talkie.Platforms/Localizations/LanguageCodes.cs deleted file mode 100644 index 5788725..0000000 --- a/Sources/Falko.Talkie.Platforms/Localizations/LanguageCodes.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections.Concurrent; -using System.Reflection; - -namespace Talkie.Localizations; - -public static class LanguageCodes -{ - private static readonly ConcurrentDictionary LanguageCodesByLanguage = new(); - - private static readonly ConcurrentDictionary LanguageCodesByLanguageCodeName = new(); - - public static bool TryGetLanguageCode(this Language language, out LanguageCode languageCode) - { - languageCode = LanguageCode.Unknown; - - if (language is Language.Unknown) return false; - - if (LanguageCodesByLanguage.TryGetValue(language, out languageCode)) return true; - - var field = typeof(Language).GetField(language.ToString()); - - if (field?.GetCustomAttribute() is not { } attribute) return false; - - languageCode = attribute.LanguageCode; - - LanguageCodesByLanguage.TryAdd(language, languageCode); - - return true; - } - - public static bool TryGetLanguageCode(string languageCodeName, out LanguageCode languageCode) - { - ArgumentException.ThrowIfNullOrWhiteSpace(languageCodeName); - - if (LanguageCodesByLanguageCodeName.TryGetValue(languageCodeName, out languageCode)) return true; - - if (Enum.TryParse(languageCodeName, true, out languageCode) is false) return false; - - LanguageCodesByLanguageCodeName.TryAdd(languageCodeName, languageCode); - - return true; - } -} diff --git a/Sources/Falko.Talkie.Platforms/Localizations/Languages.cs b/Sources/Falko.Talkie.Platforms/Localizations/Languages.cs index 728278d..9703348 100644 --- a/Sources/Falko.Talkie.Platforms/Localizations/Languages.cs +++ b/Sources/Falko.Talkie.Platforms/Localizations/Languages.cs @@ -1,43 +1,56 @@ using System.Collections.Concurrent; +using System.Collections.Frozen; using System.Reflection; namespace Talkie.Localizations; public static class Languages { - private static readonly ConcurrentDictionary LanguagesByLanguageCode = new(); - private static readonly ConcurrentDictionary LanguagesByLanguageName = new(); - public static bool TryGetLanguage(this LanguageCode languageCode, out Language language) + private static readonly FrozenDictionary LanguagesByLanguageCodeName; + + static Languages() { - language = Language.Unknown; + var fields = typeof(Language).GetFields(); - if (languageCode is LanguageCode.Unknown) return false; + var languages = new KeyValuePair[fields.Length]; - if (LanguagesByLanguageCode.TryGetValue(languageCode, out language)) return true; + var iterator = 0; - var field = typeof(LanguageCode).GetField(languageCode.ToString()); + foreach (var context in fields) + { + if (context.GetCustomAttribute() is not { } attribute) continue; - if (field?.GetCustomAttribute() is not { } attribute) return false; + if (context.GetValue(null) is not Language language) continue; - language = attribute.Language; + languages[iterator] = new KeyValuePair(attribute.LanguageCode, language); - LanguagesByLanguageCode.TryAdd(languageCode, language); + ++iterator; + } - return true; + if (iterator != languages.Length) languages = languages[..iterator]; + + LanguagesByLanguageCodeName = languages.ToFrozenDictionary(); } - public static bool TryGetLanguage(string languageName, out Language language) + public static bool TryGetFromLanguageName(string name, out Language language) { - ArgumentException.ThrowIfNullOrWhiteSpace(languageName); + ArgumentException.ThrowIfNullOrWhiteSpace(name); - if (LanguagesByLanguageName.TryGetValue(languageName, out language)) return true; + if (LanguagesByLanguageName.TryGetValue(name, out language)) return true; - if (Enum.TryParse(languageName, true, out language) is false) return false; + if (Enum.TryParse(name, true, out language) is false) return false; - LanguagesByLanguageName.TryAdd(languageName, language); + LanguagesByLanguageName.TryAdd(name, language); return true; } + + public static bool TryGetFromLanguageCodeName(string name, out Language language) + { + ArgumentException.ThrowIfNullOrWhiteSpace(name); + + return LanguagesByLanguageCodeName.TryGetValue(name, out language); + } } diff --git a/Sources/Falko.Talkie.Platforms/Models/Identifiers/Identifier.cs b/Sources/Falko.Talkie.Platforms/Models/Identifiers/Identifier.cs index 1c575ba..3d7dd37 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Identifiers/Identifier.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Identifiers/Identifier.cs @@ -5,7 +5,7 @@ namespace Talkie.Models.Identifiers; /// /// Represents an identifier that contains not type strongly value and provides a type-safe way to work with it. /// -public readonly struct Identifier +public readonly struct Identifier : IEquatable { /// /// Gets an empty . @@ -51,7 +51,7 @@ public bool IsValueType() where T : notnull /// Null or Default if the value type of the identifier is not the specified type; /// otherwise, the value of the identifier. /// - public T? GetValueOrDefault() where T : notnull + public T GetValueOrDefault() where T : notnull { return _value is T typedValue ? typedValue diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/IMessageImageAttachment.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/IMessageImageAttachment.cs new file mode 100644 index 0000000..c39d704 --- /dev/null +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/IMessageImageAttachment.cs @@ -0,0 +1,12 @@ +using Talkie.Models.Messages.Attachments.Variants; +using Talkie.Models.Messages.Contents; +using Talkie.Sequences; + +namespace Talkie.Models.Messages.Attachments; + +public interface IMessageImageAttachment : IMessageFileAttachment +{ + MessageContent Content { get; } + + new IReadOnlySequence Variants { get; } +} diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/MessageImageAttachment.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/MessageImageAttachment.cs new file mode 100644 index 0000000..4773dc7 --- /dev/null +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/MessageImageAttachment.cs @@ -0,0 +1,29 @@ +using Talkie.Models.Identifiers; +using Talkie.Models.Messages.Attachments.Variants; +using Talkie.Models.Messages.Contents; +using Talkie.Sequences; + +namespace Talkie.Models.Messages.Attachments; + +public sealed record MessageImageAttachment : IMessageImageAttachment +{ + private IReadOnlySequence? _fileVariants; + + public required Identifier Identifier { get; init; } + + public MessageContent Content { get; init; } = + MessageContent.Empty; + + public IReadOnlySequence Variants { get; init; } = + FrozenSequence.Empty; + + IReadOnlySequence IMessageFileAttachment.Variants => + _fileVariants ??= GetFileVariants(); + + private IReadOnlySequence GetFileVariants() + { + return Variants + .OfType() + .ToFrozenSequence(); + } +} diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/MessageStickerAttachment.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/MessageStickerAttachment.cs new file mode 100644 index 0000000..b8c0870 --- /dev/null +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/MessageStickerAttachment.cs @@ -0,0 +1,25 @@ +using Talkie.Models.Identifiers; +using Talkie.Models.Messages.Attachments.Variants; +using Talkie.Sequences; + +namespace Talkie.Models.Messages.Attachments; + +public sealed record MessageStickerAttachment : IMessageStickerAttachment +{ + private IReadOnlySequence? _fileVariants; + + public required Identifier Identifier { get; init; } + + public IReadOnlySequence Variants { get; init; } = + FrozenSequence.Empty; + + IReadOnlySequence IMessageFileAttachment.Variants => + _fileVariants ??= GetFileVariants(); + + private IReadOnlySequence GetFileVariants() + { + return Variants + .OfType() + .ToFrozenSequence(); + } +} diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Models/Messages/Attachments/Variants/TelegramMessageImageVariant.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/Variants/MessageImageVariant.cs similarity index 77% rename from Sources/Falko.Talkie.Platforms.Telegram/Models/Messages/Attachments/Variants/TelegramMessageImageVariant.cs rename to Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/Variants/MessageImageVariant.cs index 607a163..857ad0e 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Models/Messages/Attachments/Variants/TelegramMessageImageVariant.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Attachments/Variants/MessageImageVariant.cs @@ -2,7 +2,7 @@ namespace Talkie.Models.Messages.Attachments.Variants; -public sealed record TelegramMessageImageVariant(Func> streamFactory) : IMessageImageVariant +public sealed record MessageImageVariant(Func> streamFactory) : IMessageImageVariant { public required Identifier Identifier { get; init; } diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddContent.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddContent.cs index aca30b9..922eb71 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddContent.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddContent.cs @@ -4,7 +4,11 @@ namespace Talkie.Models.Messages.Contents; public static partial class MessageContentBuilderExtensions { - public static IMessageContentBuilder AddContent(this IMessageContentBuilder builder, MessageContent content) + public static IMessageContentBuilder AddContent + ( + this IMessageContentBuilder builder, + MessageContent content + ) { if (content.IsEmpty) return builder; @@ -15,8 +19,12 @@ public static IMessageContentBuilder AddContent(this IMessageContentBuilder buil return builder.AddText(content.Text); } - public static IMessageContentBuilder AddContent(this IMessageContentBuilder builder, MessageContent content, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddContent + ( + this IMessageContentBuilder builder, + MessageContent content, + params IReadOnlyCollection> styleFactories + ) { if (content.IsEmpty) return builder; @@ -29,7 +37,11 @@ public static IMessageContentBuilder AddContent(this IMessageContentBuilder buil return builder.AddText(content.Text); } - private static void AddStylesForText(IMessageContentBuilder builder, IReadOnlyCollection styles) + private static void AddStylesForText + ( + IMessageContentBuilder builder, + IReadOnlyCollection styles + ) { foreach (var style in styles) { diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddText.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddText.cs index f2fb497..f62d3c9 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddText.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddText.cs @@ -4,40 +4,61 @@ namespace Talkie.Models.Messages.Contents; public static partial class MessageContentBuilderExtensions { - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, char text, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + char text, + params IReadOnlyCollection> styleFactories + ) { AddStylesForText(builder, 1, styleFactories); return builder.AddText(text); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, string text, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + string text, + params IReadOnlyCollection> styleFactories + ) { AddStylesForText(builder, text.Length, styleFactories); return builder.AddText(text); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, ReadOnlyMemory text, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + ReadOnlyMemory text, + params IReadOnlyCollection> styleFactories + ) { AddStylesForText(builder, text.Length, styleFactories); return builder.AddText(text); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, ReadOnlySpan text, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + ReadOnlySpan text, + params IReadOnlyCollection> styleFactories + ) { AddStylesForText(builder, text.Length, styleFactories); return builder.AddText(text); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, string token, int repeat, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + string token, + int repeat, + params IReadOnlyCollection> styleFactories + ) { ArgumentOutOfRangeException.ThrowIfNegative(repeat, nameof(repeat)); @@ -52,8 +73,13 @@ public static IMessageContentBuilder AddText(this IMessageContentBuilder builder return builder.AddText(token, repeat); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, char token, int repeat, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + char token, + int repeat, + params IReadOnlyCollection> styleFactories + ) { ArgumentOutOfRangeException.ThrowIfNegative(repeat, nameof(repeat)); @@ -66,24 +92,39 @@ public static IMessageContentBuilder AddText(this IMessageContentBuilder builder return builder.AddText(token, repeat); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, ReadOnlySpan token, int repeat, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + ReadOnlySpan token, + int repeat, + params IReadOnlyCollection> styleFactories + ) { if (token.Length is 0) return builder; return builder.AddText(token.ToString(), repeat, styleFactories); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, ReadOnlyMemory token, int repeat, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + ReadOnlyMemory token, + int repeat, + params IReadOnlyCollection> styleFactories + ) { if (token.Length is 0) return builder; return builder.AddText(token.ToString(), repeat, styleFactories); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, string separator, IReadOnlyCollection tokens, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + string separator, + IReadOnlyCollection tokens, + params IReadOnlyCollection> styleFactories + ) { if (separator.Length is 0) return builder; @@ -94,8 +135,13 @@ public static IMessageContentBuilder AddText(this IMessageContentBuilder builder return builder.AddText(separator, tokens); } - public static IMessageContentBuilder AddText(this IMessageContentBuilder builder, char separator, IReadOnlyCollection tokens, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddText + ( + this IMessageContentBuilder builder, + char separator, + IReadOnlyCollection tokens, + params IReadOnlyCollection> styleFactories + ) { if (tokens.Count is 1) return builder.AddText(tokens.First(), styleFactories); @@ -109,8 +155,12 @@ private static int FindJoinLength(int separatorLength, IReadOnlyCollection token.Length) + separatorLength * (tokens.Count - 1); } - private static void AddStylesForText(IMessageContentBuilder builder, int length, - IReadOnlyCollection> styleFactories) + private static void AddStylesForText + ( + IMessageContentBuilder builder, + int length, + IReadOnlyCollection> styleFactories + ) { if (styleFactories.Count is 0) return; diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddTextLine.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddTextLine.cs index feca2be..26b7ac6 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddTextLine.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentBuilderExtensions.AddTextLine.cs @@ -6,45 +6,82 @@ public static partial class MessageContentBuilderExtensions { private const char NewLine = '\n'; - public static IMessageContentBuilder AddTextLine(this IMessageContentBuilder builder, string text) + public static IMessageContentBuilder AddTextLine + ( + this IMessageContentBuilder builder, + string text + ) { return builder.AddText(text).AddTextLine(); } - public static IMessageContentBuilder AddTextLine(this IMessageContentBuilder builder, ReadOnlyMemory text) + public static IMessageContentBuilder AddTextLine + ( + this IMessageContentBuilder builder, + ReadOnlyMemory text + ) { return builder.AddText(text).AddTextLine(); } - public static IMessageContentBuilder AddTextLine(this IMessageContentBuilder builder, ReadOnlySpan text) + public static IMessageContentBuilder AddTextLine + ( + this IMessageContentBuilder builder, + ReadOnlySpan text + ) { return builder.AddText(text).AddTextLine(); } - public static IMessageContentBuilder AddTextLine(this IMessageContentBuilder builder, char text, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddTextLine + ( + this IMessageContentBuilder builder, + char text, + params IReadOnlyCollection> styleFactories + ) { return builder.AddText(text, styleFactories).AddTextLine(); } - public static IMessageContentBuilder AddTextLine(this IMessageContentBuilder builder, string text, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddTextLine + ( + this IMessageContentBuilder builder, + string text, + params IReadOnlyCollection> styleFactories + ) { return builder.AddText(text, styleFactories).AddTextLine(); } - public static IMessageContentBuilder AddTextLine(this IMessageContentBuilder builder, ReadOnlyMemory text, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddTextLine + ( + this IMessageContentBuilder builder, + ReadOnlyMemory text, + params IReadOnlyCollection> styleFactories + ) { return builder.AddText(text, styleFactories).AddTextLine(); } - public static IMessageContentBuilder AddTextLine(this IMessageContentBuilder builder, ReadOnlySpan text, - params IReadOnlyCollection> styleFactories) + public static IMessageContentBuilder AddTextLine + ( + this IMessageContentBuilder builder, + ReadOnlySpan text, + params IReadOnlyCollection> styleFactories + ) { return builder.AddText(text, styleFactories).AddTextLine(); } + public static IMessageContentBuilder AddTextLine + ( + this IMessageContentBuilder builder, + int repeat + ) + { + return builder.AddText(NewLine, repeat); + } + public static IMessageContentBuilder AddTextLine(this IMessageContentBuilder builder) { return builder.AddText(NewLine); diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentExtensions.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentExtensions.cs index b3f64d5..51a98da 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentExtensions.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Contents/MessageContentExtensions.cs @@ -4,14 +4,20 @@ namespace Talkie.Models.Messages.Contents; public static partial class MessageContentExtensions { - public static MessageContent MutateText(this MessageContent content, - Func textMutationFactory) + public static MessageContent MutateText + ( + this MessageContent content, + Func textMutationFactory + ) { return content with { Text = textMutationFactory(content.Text) }; } - public static MessageContent MutateStyles(this MessageContent content, - Func, IReadOnlyCollection> stylesMutationFactory) + public static MessageContent MutateStyles + ( + this MessageContent content, + Func, IReadOnlyCollection> stylesMutationFactory + ) { return content with { Styles = stylesMutationFactory(content.Styles) }; } diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.IsSelfSent.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.IsSelfPublished.cs similarity index 88% rename from Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.IsSelfSent.cs rename to Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.IsSelfPublished.cs index ab49d2b..a2348ac 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.IsSelfSent.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.IsSelfPublished.cs @@ -7,7 +7,7 @@ public static partial class IncomingMessageExtensions /// /// The message. /// true if the message was published by the same profile that received it; otherwise, false. - public static bool IsSelf(this IIncomingMessage message) + public static bool IsSelfPublished(this IIncomingMessage message) { return message.ReceiverProfile.Identifier == message.PublisherProfile.Identifier; } diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.Mutate.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.Mutate.cs index 6e89766..09ebbe2 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.Mutate.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.Mutate.cs @@ -2,8 +2,11 @@ namespace Talkie.Models.Messages.Incoming; public static partial class IncomingMessageExtensions { - public static IIncomingMessage Mutate(this IIncomingMessage message, - Func mutationFactory) + public static IIncomingMessage Mutate + ( + this IIncomingMessage message, + Func mutationFactory + ) { return mutationFactory(message.ToMutator()).Mutate(); } diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessageEditedSignal.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessageEditedSignal.cs index fc8a9f0..8e3dac9 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessageEditedSignal.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessageEditedSignal.cs @@ -4,7 +4,7 @@ namespace Talkie.Models.Messages.Incoming; public static partial class IncomingMessageExtensions { - public static MessageExchangedSignal ToMessageEditedSignal(this IIncomingMessage message) + public static MessageExchangedSignal ToMessageExchangedSignal(this IIncomingMessage message) { return new MessageExchangedSignal(message); } diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessageReceivedSignal.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessagePublishedSignal.cs similarity index 66% rename from Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessageReceivedSignal.cs rename to Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessagePublishedSignal.cs index 91bb2cc..f1e3c81 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessageReceivedSignal.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Incoming/IncomingMessageExtensions.ToMessagePublishedSignal.cs @@ -4,7 +4,7 @@ namespace Talkie.Models.Messages.Incoming; public static partial class IncomingMessageExtensions { - public static MessagePublishedSignal ToMessageReceivedSignal(this IIncomingMessage message) + public static MessagePublishedSignal ToMessagePublishedSignal(this IIncomingMessage message) { return new MessagePublishedSignal(message); } diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/MessageMutatorExtensions.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/MessageMutatorExtensions.cs index 3c117ba..e832eba 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/MessageMutatorExtensions.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/MessageMutatorExtensions.cs @@ -13,8 +13,11 @@ public static partial class MessageMutatorExtensions /// The type of the mutator. /// The type of the message. /// The incoming mutator. - public static TMutator MutateContent(this IMessageMutator mutator, - Func contentMutationFactory) + public static TMutator MutateContent + ( + this IMessageMutator mutator, + Func contentMutationFactory + ) where TMutator : IMessageMutator where TMessage : IMessage { diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Outgoing/OutgoingMessageBuilderExtensions.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Outgoing/OutgoingMessageBuilderExtensions.cs index 26ad7b6..26037d2 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Outgoing/OutgoingMessageBuilderExtensions.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Outgoing/OutgoingMessageBuilderExtensions.cs @@ -6,8 +6,11 @@ namespace Talkie.Models.Messages.Outgoing; public static partial class OutgoingMessageBuilderExtensions { - public static IOutgoingMessageBuilder AddContent(this IOutgoingMessageBuilder builder, - MessageContent content) + public static IOutgoingMessageBuilder AddContent + ( + this IOutgoingMessageBuilder builder, + MessageContent content + ) { var previousContext = builder.Content; @@ -19,32 +22,47 @@ public static IOutgoingMessageBuilder AddContent(this IOutgoingMessageBuilder bu return builder.SetContent(newContext); } - public static IOutgoingMessageBuilder SetContent(this IOutgoingMessageBuilder builder, - IMessageContentBuilder contentBuilder) + public static IOutgoingMessageBuilder SetContent + ( + this IOutgoingMessageBuilder builder, + IMessageContentBuilder contentBuilder + ) { return builder.SetContent(contentBuilder.Build()); } - public static IOutgoingMessageBuilder AddContent(this IOutgoingMessageBuilder builder, - IMessageContentBuilder contentBuilder) + public static IOutgoingMessageBuilder AddContent + ( + this IOutgoingMessageBuilder builder, + IMessageContentBuilder contentBuilder + ) { return builder.AddContent(contentBuilder.Build()); } - public static IOutgoingMessageBuilder SetContent(this IOutgoingMessageBuilder builder, - Func contentBuilderFactory) + public static IOutgoingMessageBuilder SetContent + ( + this IOutgoingMessageBuilder builder, + Func contentBuilderFactory + ) { return builder.SetContent(contentBuilderFactory(new MessageContentBuilder()).Build()); } - public static IOutgoingMessageBuilder AddContent(this IOutgoingMessageBuilder builder, - Func contentBuilderFactory) + public static IOutgoingMessageBuilder AddContent + ( + this IOutgoingMessageBuilder builder, + Func contentBuilderFactory + ) { return builder.AddContent(contentBuilderFactory(new MessageContentBuilder()).Build()); } - public static IOutgoingMessageBuilder SetReply(this IOutgoingMessageBuilder builder, - IIncomingMessage message) + public static IOutgoingMessageBuilder SetReply + ( + this IOutgoingMessageBuilder builder, + IIncomingMessage message + ) { return builder.SetReply(message.ToGlobalMessageIdentifier()); } diff --git a/Sources/Falko.Talkie.Platforms/Models/Messages/Outgoing/OutgoingMessageExtensions.Mutate.cs b/Sources/Falko.Talkie.Platforms/Models/Messages/Outgoing/OutgoingMessageExtensions.Mutate.cs index 83d03ac..705425b 100644 --- a/Sources/Falko.Talkie.Platforms/Models/Messages/Outgoing/OutgoingMessageExtensions.Mutate.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Messages/Outgoing/OutgoingMessageExtensions.Mutate.cs @@ -2,8 +2,11 @@ namespace Talkie.Models.Messages.Outgoing; public static partial class OutgoingMessageExtensions { - public static IOutgoingMessage Mutate(this IOutgoingMessage message, - Func mutationFactory) + public static IOutgoingMessage Mutate + ( + this IOutgoingMessage message, + Func mutationFactory + ) { return mutationFactory(message.ToMutator()).Mutate(); } diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramBotProfile.cs b/Sources/Falko.Talkie.Platforms/Models/Profiles/BotProfile.cs similarity index 87% rename from Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramBotProfile.cs rename to Sources/Falko.Talkie.Platforms/Models/Profiles/BotProfile.cs index 3553bbf..2be5e9b 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramBotProfile.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Profiles/BotProfile.cs @@ -3,7 +3,7 @@ namespace Talkie.Models.Profiles; -public sealed record TelegramBotProfile : IBotProfile +public sealed class BotProfile : IBotProfile { public required Identifier Identifier { get; init; } diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramChatProfile.cs b/Sources/Falko.Talkie.Platforms/Models/Profiles/ChatProfile.cs similarity index 85% rename from Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramChatProfile.cs rename to Sources/Falko.Talkie.Platforms/Models/Profiles/ChatProfile.cs index c242038..b925765 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramChatProfile.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Profiles/ChatProfile.cs @@ -3,7 +3,7 @@ namespace Talkie.Models.Profiles; -public sealed record TelegramChatProfile : IChatProfile +public sealed class ChatProfile : IChatProfile { public required Identifier Identifier { get; init; } diff --git a/Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramUserProfile.cs b/Sources/Falko.Talkie.Platforms/Models/Profiles/UserProfile.cs similarity index 87% rename from Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramUserProfile.cs rename to Sources/Falko.Talkie.Platforms/Models/Profiles/UserProfile.cs index 6babe0e..00ead54 100644 --- a/Sources/Falko.Talkie.Platforms.Telegram/Models/Profiles/TelegramUserProfile.cs +++ b/Sources/Falko.Talkie.Platforms/Models/Profiles/UserProfile.cs @@ -3,7 +3,7 @@ namespace Talkie.Models.Profiles; -public sealed record TelegramUserProfile : IUserProfile +public sealed class UserProfile : IUserProfile { public required Identifier Identifier { get; init; } diff --git a/Sources/Falko.Talkie.Platforms/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.OnlySelfPublish.cs b/Sources/Falko.Talkie.Platforms/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.OnlySelfPublish.cs index af62e92..7ef12dd 100644 --- a/Sources/Falko.Talkie.Platforms/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.OnlySelfPublish.cs +++ b/Sources/Falko.Talkie.Platforms/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.OnlySelfPublish.cs @@ -7,11 +7,11 @@ public static partial class SignalInterceptingPipelineBuilderExtensions { public static ISignalInterceptingPipelineBuilder OnlySelfPublish(this ISignalInterceptingPipelineBuilder builder) { - return builder.Where(signal => signal.Message.IsSelf()); + return builder.Where(signal => signal.Message.IsSelfPublished()); } public static ISignalInterceptingPipelineBuilder OnlySelfPublish(this ISignalInterceptingPipelineBuilder builder) { - return builder.Where(signal => signal.Message.IsSelf()); + return builder.Where(signal => signal.Message.IsSelfPublished()); } } diff --git a/Sources/Falko.Talkie.Platforms/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.SkipSelfPublish.cs b/Sources/Falko.Talkie.Platforms/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.SkipSelfPublish.cs index 4c2744c..17bb5c1 100644 --- a/Sources/Falko.Talkie.Platforms/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.SkipSelfPublish.cs +++ b/Sources/Falko.Talkie.Platforms/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.SkipSelfPublish.cs @@ -7,11 +7,11 @@ public static partial class SignalInterceptingPipelineBuilderExtensions { public static ISignalInterceptingPipelineBuilder SkipSelfPublish(this ISignalInterceptingPipelineBuilder builder) { - return builder.Where(signal => signal.Message.IsSelf() is false); + return builder.Where(signal => signal.Message.IsSelfPublished() is false); } public static ISignalInterceptingPipelineBuilder SkipSelfPublish(this ISignalInterceptingPipelineBuilder builder) { - return builder.Where(signal => signal.Message.IsSelf() is false); + return builder.Where(signal => signal.Message.IsSelfPublished() is false); } } diff --git a/Sources/Falko.Talkie.Platforms/Platforms/IPlatform.cs b/Sources/Falko.Talkie.Platforms/Platforms/IPlatform.cs index ceb7af7..3c609cd 100644 --- a/Sources/Falko.Talkie.Platforms/Platforms/IPlatform.cs +++ b/Sources/Falko.Talkie.Platforms/Platforms/IPlatform.cs @@ -1,5 +1,4 @@ using Talkie.Controllers; -using Talkie.Models; using Talkie.Models.Identifiers; namespace Talkie.Platforms; diff --git a/Sources/Falko.Talkie.Platforms/Signals/MessageSignalsExtensions.cs b/Sources/Falko.Talkie.Platforms/Signals/MessageSignalsExtensions.cs index c2a7a03..b8142a4 100644 --- a/Sources/Falko.Talkie.Platforms/Signals/MessageSignalsExtensions.cs +++ b/Sources/Falko.Talkie.Platforms/Signals/MessageSignalsExtensions.cs @@ -4,15 +4,21 @@ namespace Talkie.Signals; public static partial class MessageSignalsExtensions { - public static MessagePublishedSignal MutateMessage(this MessagePublishedSignal signal, - Func messageMutationFactory) + public static MessagePublishedSignal MutateMessage + ( + this MessagePublishedSignal signal, + Func messageMutationFactory + ) { - return messageMutationFactory(signal.Message.ToMutator()).Mutate().ToMessageReceivedSignal(); + return messageMutationFactory(signal.Message.ToMutator()).Mutate().ToMessagePublishedSignal(); } - public static MessageExchangedSignal MutateMessage(this MessageExchangedSignal signal, - Func messageMutationFactory) + public static MessageExchangedSignal MutateMessage + ( + this MessageExchangedSignal signal, + Func messageMutationFactory + ) { - return messageMutationFactory(signal.Message.ToMutator()).Mutate().ToMessageEditedSignal(); + return messageMutationFactory(signal.Message.ToMutator()).Mutate().ToMessageExchangedSignal(); } } diff --git a/Sources/Falko.Talkie.Signals.Connections/Connections/ModernSignalConnection.cs b/Sources/Falko.Talkie.Signals.Connections/Connections/ModernSignalConnection.cs new file mode 100644 index 0000000..761e977 --- /dev/null +++ b/Sources/Falko.Talkie.Signals.Connections/Connections/ModernSignalConnection.cs @@ -0,0 +1,64 @@ +namespace Talkie.Connections; + +public abstract class ModernSignalConnection : ISignalConnection +{ + private readonly SemaphoreSlim _locker = new(1, 1); + + public bool IsInitialized { get; private set; } + + public bool IsDisposed { get; private set; } + + public async ValueTask InitializeAsync(CancellationToken cancellationToken = default) + { + ThrowIfInitialized(); + + try + { + await _locker.WaitAsync(cancellationToken); + + ThrowIfInitialized(); + + await InitializeCoreAsync(cancellationToken); + + IsInitialized = true; + } + finally + { + _locker.Release(); + } + } + + public async ValueTask DisposeAsync() + { + if (IsDisposedOrUninitialized()) return; + + try + { + await _locker.WaitAsync(); + + if (IsDisposedOrUninitialized()) return; + + await DisposeCoreAsync(); + + IsDisposed = true; + } + finally + { + _locker.Release(); + } + } + + protected abstract ValueTask InitializeCoreAsync(CancellationToken cancellationToken); + + protected abstract ValueTask DisposeCoreAsync(); + + private void ThrowIfInitialized() + { + if (IsInitialized) throw new InvalidOperationException("The connection is already initialized."); + } + + private bool IsDisposedOrUninitialized() + { + return IsDisposed || IsInitialized is false; + } +} diff --git a/Sources/Falko.Talkie.Signals.Connections/Flows/SignalFlowExtensions.ConnectAsync.cs b/Sources/Falko.Talkie.Signals.Connections/Flows/SignalFlowExtensions.ConnectAsync.cs index 5464327..b5976ba 100644 --- a/Sources/Falko.Talkie.Signals.Connections/Flows/SignalFlowExtensions.ConnectAsync.cs +++ b/Sources/Falko.Talkie.Signals.Connections/Flows/SignalFlowExtensions.ConnectAsync.cs @@ -4,8 +4,12 @@ namespace Talkie.Flows; public static partial class SignalFlowExtensions { - public static async ValueTask ConnectAsync(this ISignalFlow flow, ISignalConnector connector, - CancellationToken cancellationToken = default) + public static async ValueTask ConnectAsync + ( + this ISignalFlow flow, + ISignalConnector connector, + CancellationToken cancellationToken = default + ) { var connection = connector.Connect(flow); diff --git a/Sources/Falko.Talkie.Signals.Connections/Flows/SignalFlowExtensions.PublishUnobservedConnectionExceptionAsync.cs b/Sources/Falko.Talkie.Signals.Connections/Flows/SignalFlowExtensions.PublishUnobservedConnectionExceptionAsync.cs index 52756b5..14c03f7 100644 --- a/Sources/Falko.Talkie.Signals.Connections/Flows/SignalFlowExtensions.PublishUnobservedConnectionExceptionAsync.cs +++ b/Sources/Falko.Talkie.Signals.Connections/Flows/SignalFlowExtensions.PublishUnobservedConnectionExceptionAsync.cs @@ -5,9 +5,13 @@ namespace Talkie.Flows; public static partial class SignalFlowExtensions { - public static Task PublishUnobservedConnectionExceptionAsync(this ISignalFlow flow, ISignalConnection connection, + public static Task PublishUnobservedConnectionExceptionAsync + ( + this ISignalFlow flow, + ISignalConnection connection, Exception exception, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { return flow.PublishAsync(new UnobservedConnectionExceptionSignal(connection, exception), cancellationToken); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.Publish.cs b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.Publish.cs new file mode 100644 index 0000000..415eba9 --- /dev/null +++ b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.Publish.cs @@ -0,0 +1,43 @@ +using Talkie.Signals; + +namespace Talkie.Flows; + +public static partial class SignalFlowExtensions +{ + public static void Publish + ( + this ISignalFlow flow, + Signal signal, + CancellationToken cancellationToken = default + ) + { + _ = flow.PublishAsync(signal, cancellationToken) + .ContinueWith(task => HandlePublishingException(flow, task, cancellationToken), + TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnFaulted); + } + + public static void Publish + ( + this ISignalFlow flow, + CancellationToken cancellationToken = default + ) where T : Signal, new() + { + flow.Publish(SignalCache.Instance, cancellationToken); + } + + private static void HandlePublishingException + ( + ISignalFlow flow, + Task task, + CancellationToken cancellationToken + ) + { + if (task.IsFaulted is false || cancellationToken.IsCancellationRequested) return; + + Exception exception = task.Exception is { } taskException + ? taskException + : new InvalidOperationException("Failed to publish message."); + + _ = flow.PublishUnobservedPublishingExceptionAsync(exception, cancellationToken); + } +} diff --git a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.PublishUnobservedPublishingExceptionAsync.cs b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.PublishUnobservedPublishingExceptionAsync.cs index 3c95da8..bc8f58d 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.PublishUnobservedPublishingExceptionAsync.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.PublishUnobservedPublishingExceptionAsync.cs @@ -5,8 +5,12 @@ namespace Talkie.Flows; public static partial class SignalFlowExtensions { - public static Task PublishUnobservedPublishingExceptionAsync(this ISignalFlow flow, Exception exception, - CancellationToken cancellationToken = default) + public static Task PublishUnobservedPublishingExceptionAsync + ( + this ISignalFlow flow, + Exception exception, + CancellationToken cancellationToken = default + ) { if (exception is not SignalPublishingException publishingException || publishingException.Flow != flow) { diff --git a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.Subscribe.cs b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.Subscribe.cs index 485872c..a3e5823 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.Subscribe.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.Subscribe.cs @@ -6,19 +6,31 @@ namespace Talkie.Flows; public static partial class SignalFlowExtensions { - public static Subscription Subscribe(this ISignalFlow flow, IReadOnlySignalHandlingPipelineBuilder builder) + public static Subscription Subscribe + ( + this ISignalFlow flow, + IReadOnlySignalHandlingPipelineBuilder builder + ) { return flow.Subscribe(builder.Build()); } - public static Subscription Subscribe(this ISignalFlow flow, Func builderFactory) + public static Subscription Subscribe + ( + this ISignalFlow flow, + Func builderFactory + ) { return flow.Subscribe(builderFactory(SignalInterceptingPipelineBuilder.Empty)); } - public static Subscription Subscribe(this ISignalFlow flow, Func, - IReadOnlySignalHandlingPipelineBuilder> builderFactory) where T : Signal + public static Subscription Subscribe + ( + this ISignalFlow flow, + Func, + IReadOnlySignalHandlingPipelineBuilder> builderFactory + ) where T : Signal { return flow.Subscribe(builderFactory(SignalInterceptingPipelineBuilder.Empty)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.TakeAsync.cs b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.TakeAsync.cs index 4e24236..6713af6 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.TakeAsync.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.TakeAsync.cs @@ -6,9 +6,12 @@ namespace Talkie.Flows; public static partial class SignalFlowExtensions { - public static async Task TakeAsync(this ISignalFlow flow, + public static async Task TakeAsync + ( + this ISignalFlow flow, Func pipelineFactory, - CancellationToken cancellationToken = default) + CancellationToken cancellationToken = default + ) { var taskSource = new TaskCompletionSource(); @@ -27,9 +30,12 @@ public static async Task TakeAsync(this ISignalFlow flow, } } - public static async Task TakeAsync(this ISignalFlow flow, + public static async Task TakeAsync + ( + this ISignalFlow flow, Func> pipelineFactory, - CancellationToken cancellationToken = default) where T : Signal + CancellationToken cancellationToken = default + ) where T : Signal { var taskSource = new TaskCompletionSource(); @@ -48,9 +54,12 @@ public static async Task TakeAsync(this ISignalFlow flow, } } - public static async Task TakeAsync(this ISignalFlow flow, + public static async Task TakeAsync + ( + this ISignalFlow flow, Func, ISignalInterceptingPipelineBuilder> pipelineFactory, - CancellationToken cancellationToken = default) where TFrom : Signal where TTo : Signal + CancellationToken cancellationToken = default + ) where TFrom : Signal where TTo : Signal { var taskSource = new TaskCompletionSource(); @@ -69,20 +78,29 @@ public static async Task TakeAsync(this ISignalFlow flow, } } - public static async Task TakeAsync(this ISignalFlow flow, - CancellationToken cancellationToken = default) where T : Signal + public static async Task TakeAsync + ( + this ISignalFlow flow, + CancellationToken cancellationToken = default + ) where T : Signal { return await flow.TakeAsync(signals => signals.OfType(), cancellationToken); } - public static async Task TakeAsync(this ISignalFlow flow, - CancellationToken cancellationToken = default) + public static async Task TakeAsync + ( + this ISignalFlow flow, + CancellationToken cancellationToken = default + ) { return await flow.TakeAsync(signals => signals, cancellationToken); } - private static void SafeSetCancellationForTaskSource(TaskCompletionSource source, - CancellationToken cancellationToken) where T : Signal + private static void SafeSetCancellationForTaskSource + ( + TaskCompletionSource source, + CancellationToken cancellationToken + ) where T : Signal { if (cancellationToken == CancellationToken.None || cancellationToken.CanBeCanceled is false) { @@ -102,9 +120,12 @@ private static void SafeSetCancellationForTaskSource(TaskCompletionSource }); } - private static void SafeSetResultForTaskSource(TaskCompletionSource source, + private static void SafeSetResultForTaskSource + ( + TaskCompletionSource source, T result, - CancellationToken cancellationToken) where T : Signal + CancellationToken cancellationToken + ) where T : Signal { try { diff --git a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.TakeUnobservedExceptionAsync.cs b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.TakeUnobservedExceptionAsync.cs index c9ff9b2..3a81e35 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.TakeUnobservedExceptionAsync.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Flows/SignalFlowExtensions.TakeUnobservedExceptionAsync.cs @@ -6,8 +6,11 @@ namespace Talkie.Flows; public static partial class SignalFlowExtensions { - public static Task TakeUnobservedExceptionAsync(this ISignalFlow flow, - CancellationToken cancellationToken = default) + public static Task TakeUnobservedExceptionAsync + ( + this ISignalFlow flow, + CancellationToken cancellationToken = default + ) { return flow.TakeAsync(signals => signals .Where(signal => signal is IWithUnobservedExceptionSignal), diff --git a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegatedSignalInterceptor.cs b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegateSignalInterceptor.cs similarity index 68% rename from Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegatedSignalInterceptor.cs rename to Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegateSignalInterceptor.cs index d827688..1129707 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegatedSignalInterceptor.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegateSignalInterceptor.cs @@ -2,7 +2,7 @@ namespace Talkie.Interceptors; -internal sealed class DelegatedSignalInterceptor(Func intercept) +internal sealed class DelegateSignalInterceptor(Func intercept) : ISignalInterceptor { public InterceptionResult Intercept(Signal signal, CancellationToken cancellationToken) diff --git a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegatedSignalInterceptor{T}.cs b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegateSignalInterceptor{T}.cs similarity index 70% rename from Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegatedSignalInterceptor{T}.cs rename to Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegateSignalInterceptor{T}.cs index 2e49fa7..bdc9b20 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegatedSignalInterceptor{T}.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/DelegateSignalInterceptor{T}.cs @@ -2,7 +2,7 @@ namespace Talkie.Interceptors; -internal sealed class DelegatedSignalInterceptor(Func intercept) +internal sealed class DelegateSignalInterceptor(Func intercept) : SignalInterceptor where T : Signal { public override InterceptionResult Intercept(T signal, CancellationToken cancellationToken) diff --git a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/MergeSignalInterceptor.cs b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/MergeSignalInterceptor.cs index 5f94816..dcce0d2 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/MergeSignalInterceptor.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/MergeSignalInterceptor.cs @@ -3,8 +3,11 @@ namespace Talkie.Interceptors; -internal sealed class MergeSignalInterceptor(ISignalInterceptingPipeline targetPipeline, - ISignalInterceptingPipeline mergePipeline) : ISignalInterceptor where T : Signal +internal sealed class MergeSignalInterceptor +( + ISignalInterceptingPipeline targetPipeline, + ISignalInterceptingPipeline mergePipeline +) : ISignalInterceptor where T : Signal { public InterceptionResult Intercept(Signal signal, CancellationToken cancellationToken) { diff --git a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/SelectSignalInterceptor{T}.cs b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/SelectSignalInterceptor{T}.cs index aba32bb..3796627 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/SelectSignalInterceptor{T}.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/SelectSignalInterceptor{T}.cs @@ -2,7 +2,8 @@ namespace Talkie.Interceptors; -internal sealed class SelectSignalInterceptor(Func select) : SignalInterceptor +internal sealed class SelectSignalInterceptor(Func select) + : SignalInterceptor where TFrom : Signal where TTo : Signal { diff --git a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/TakeWhileSignalInterceptor{T}.cs b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/TakeWhileSignalInterceptor{T}.cs index f45f1d7..1ae3848 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/TakeWhileSignalInterceptor{T}.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/TakeWhileSignalInterceptor{T}.cs @@ -2,7 +2,8 @@ namespace Talkie.Interceptors; -internal sealed class TakeWhileSignalInterceptor(Func @while) : SignalInterceptor where T : Signal +internal sealed class TakeWhileSignalInterceptor(Func @while) + : SignalInterceptor where T : Signal { private readonly object _locker = new(); diff --git a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/WhereSignalInterceptor{T}.cs b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/WhereSignalInterceptor{T}.cs index 92824af..604e0b6 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Interceptors/WhereSignalInterceptor{T}.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Interceptors/WhereSignalInterceptor{T}.cs @@ -2,7 +2,8 @@ namespace Talkie.Interceptors; -internal sealed class WhereSignalInterceptor(Func where) : SignalInterceptor where T : Signal +internal sealed class WhereSignalInterceptor(Func where) + : SignalInterceptor where T : Signal { public override InterceptionResult Intercept(T signal, CancellationToken cancellationToken) { diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Handling/SignalHandlingPipelineBuilderExtensions.Handle.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Handling/SignalHandlingPipelineBuilderExtensions.Handle.cs index 53e1c04..823a254 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Handling/SignalHandlingPipelineBuilderExtensions.Handle.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Handling/SignalHandlingPipelineBuilderExtensions.Handle.cs @@ -6,8 +6,11 @@ namespace Talkie.Pipelines.Handling; public static partial class SignalHandlingPipelineBuilderExtensions { - public static ISignalHandlingPipelineBuilder Handle(this ISignalInterceptingPipelineBuilder builder, - Action handle) + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalInterceptingPipelineBuilder builder, + Action handle + ) { return builder.HandleAsync((context, cancellationToken) => { @@ -17,20 +20,29 @@ public static ISignalHandlingPipelineBuilder Handle(this ISignalInterceptingPipe }); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalInterceptingPipelineBuilder builder, - Action handle) + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalInterceptingPipelineBuilder builder, + Action handle + ) { return builder.Handle((context, _) => handle(context)); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalInterceptingPipelineBuilder builder, - Action handle) + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalInterceptingPipelineBuilder builder, + Action handle + ) { return builder.Handle((_, _) => handle()); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalHandlingPipelineBuilder builder, - Action handle) + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalHandlingPipelineBuilder builder, + Action handle + ) { return builder.HandleAsync((context, cancellationToken) => { @@ -40,20 +52,29 @@ public static ISignalHandlingPipelineBuilder Handle(this ISignalHandlingPipeline }); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalHandlingPipelineBuilder builder, - Action handle) + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalHandlingPipelineBuilder builder, + Action handle + ) { return builder.Handle((signal, _) => handle(signal)); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalHandlingPipelineBuilder builder, - Action handle) + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalHandlingPipelineBuilder builder, + Action handle + ) { return builder.Handle((_, _) => handle()); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalInterceptingPipelineBuilder builder, - Action, CancellationToken> handle) where T : Signal + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalInterceptingPipelineBuilder builder, + Action, CancellationToken> handle + ) where T : Signal { return builder.HandleAsync((context, cancellationToken) => { @@ -63,20 +84,29 @@ public static ISignalHandlingPipelineBuilder Handle(this ISignalIntercepti }); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalInterceptingPipelineBuilder builder, - Action> handle) where T : Signal + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalInterceptingPipelineBuilder builder, + Action> handle + ) where T : Signal { return builder.Handle((signal, _) => handle(signal)); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalInterceptingPipelineBuilder builder, - Action handle) where T : Signal + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalInterceptingPipelineBuilder builder, + Action handle + ) where T : Signal { return builder.Handle((_, _) => handle()); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalHandlingPipelineBuilder builder, - Action, CancellationToken> handle) where T : Signal + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalHandlingPipelineBuilder builder, + Action, CancellationToken> handle + ) where T : Signal { return builder.HandleAsync((context, cancellationToken) => { @@ -86,14 +116,20 @@ public static ISignalHandlingPipelineBuilder Handle(this ISignalHandlingPi }); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalHandlingPipelineBuilder builder, - Action> handle) where T : Signal + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalHandlingPipelineBuilder builder, + Action> handle + ) where T : Signal { return builder.Handle((signal, _) => handle(signal)); } - public static ISignalHandlingPipelineBuilder Handle(this ISignalHandlingPipelineBuilder builder, - Action handle) where T : Signal + public static ISignalHandlingPipelineBuilder Handle + ( + this ISignalHandlingPipelineBuilder builder, + Action handle + ) where T : Signal { return builder.Handle((_, _) => handle()); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Handling/SignalHandlingPipelineBuilderExtensions.HandleAsync.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Handling/SignalHandlingPipelineBuilderExtensions.HandleAsync.cs index b89e8e4..c91579d 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Handling/SignalHandlingPipelineBuilderExtensions.HandleAsync.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Handling/SignalHandlingPipelineBuilderExtensions.HandleAsync.cs @@ -6,8 +6,11 @@ namespace Talkie.Pipelines.Handling; public static partial class SignalHandlingPipelineBuilderExtensions { - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptingPipelineBuilder builder, - ISignalHandler handler) + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalInterceptingPipelineBuilder builder, + ISignalHandler handler + ) { var pipeline = builder.Build(); @@ -16,8 +19,11 @@ public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptin : SignalHandlingPipelineBuilder.Empty.HandleAsync(handler); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptingPipelineBuilder builder, - ISignalHandler handler) where T : Signal + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalInterceptingPipelineBuilder builder, + ISignalHandler handler + ) where T : Signal { var pipeline = builder.Build(); @@ -26,74 +32,110 @@ public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInter : SignalHandlingPipelineBuilder.Empty.HandleAsync(handler); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptingPipelineBuilder builder, - Func handleAsync) + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalInterceptingPipelineBuilder builder, + Func handleAsync + ) { return builder.HandleAsync(new DelegatedSignalHandler(handleAsync)); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptingPipelineBuilder builder, - Func handleAsync) + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalInterceptingPipelineBuilder builder, + Func handleAsync + ) { return builder.HandleAsync((signal, _) => handleAsync(signal)); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptingPipelineBuilder builder, - Func handleAsync) + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalInterceptingPipelineBuilder builder, + Func handleAsync + ) { return builder.HandleAsync((_, _) => handleAsync()); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalHandlingPipelineBuilder builder, - Func handleAsync) + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalHandlingPipelineBuilder builder, + Func handleAsync + ) { return builder.HandleAsync(new DelegatedSignalHandler(handleAsync)); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalHandlingPipelineBuilder builder, - Func handleAsync) + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalHandlingPipelineBuilder builder, + Func handleAsync + ) { return builder.HandleAsync((signal, _) => handleAsync(signal)); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalHandlingPipelineBuilder builder, - Func handleAsync) + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalHandlingPipelineBuilder builder, + Func handleAsync + ) { return builder.HandleAsync((_, _) => handleAsync()); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptingPipelineBuilder builder, - Func, CancellationToken, ValueTask> handleAsync) where T : Signal + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalInterceptingPipelineBuilder builder, + Func, CancellationToken, ValueTask> handleAsync + ) where T : Signal { return builder.HandleAsync(new DelegatedSignalHandler(handleAsync)); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptingPipelineBuilder builder, - Func, ValueTask> handleAsync) where T : Signal + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalInterceptingPipelineBuilder builder, + Func, ValueTask> handleAsync + ) where T : Signal { return builder.HandleAsync((signal, _) => handleAsync(signal)); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalInterceptingPipelineBuilder builder, - Func handleAsync) where T : Signal + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalInterceptingPipelineBuilder builder, + Func handleAsync + ) where T : Signal { return builder.HandleAsync((_, _) => handleAsync()); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalHandlingPipelineBuilder builder, - Func, CancellationToken, ValueTask> handleAsync) where T : Signal + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalHandlingPipelineBuilder builder, + Func, CancellationToken, ValueTask> handleAsync + ) where T : Signal { return builder.HandleAsync(new DelegatedSignalHandler(handleAsync)); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalHandlingPipelineBuilder builder, - Func, ValueTask> handleAsync) where T : Signal + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalHandlingPipelineBuilder builder, + Func, ValueTask> handleAsync + ) where T : Signal { return builder.HandleAsync((signal, _) => handleAsync(signal)); } - public static ISignalHandlingPipelineBuilder HandleAsync(this ISignalHandlingPipelineBuilder builder, - Func handleAsync) where T : Signal + public static ISignalHandlingPipelineBuilder HandleAsync + ( + this ISignalHandlingPipelineBuilder builder, + Func handleAsync + ) where T : Signal { return builder.HandleAsync((_, _) => handleAsync()); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Contact.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Contact.cs index 35cb50e..c7f1aaa 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Contact.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Contact.cs @@ -5,34 +5,49 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder Concat(this ISignalInterceptingPipelineBuilder builder, - ISignalInterceptingPipelineBuilder concatBuilder) + public static ISignalInterceptingPipelineBuilder Concat + ( + this ISignalInterceptingPipelineBuilder builder, + ISignalInterceptingPipelineBuilder concatBuilder + ) { return new SignalInterceptingPipelineBuilder(Concat(builder.InterceptorFactories, concatBuilder.InterceptorFactories)); } - public static ISignalInterceptingPipelineBuilder Concat(this ISignalInterceptingPipelineBuilder builder, - Func concatBuilderFactory) + public static ISignalInterceptingPipelineBuilder Concat + ( + this ISignalInterceptingPipelineBuilder builder, + Func concatBuilderFactory + ) { return builder.Concat(concatBuilderFactory(SignalInterceptingPipelineBuilder.Empty)); } - public static ISignalInterceptingPipelineBuilder Concat(this ISignalInterceptingPipelineBuilder builder, - ISignalInterceptingPipelineBuilder concatBuilder) where T : Signal + public static ISignalInterceptingPipelineBuilder Concat + ( + this ISignalInterceptingPipelineBuilder builder, + ISignalInterceptingPipelineBuilder concatBuilder + ) where T : Signal { return new SignalInterceptingPipelineBuilder(Concat(builder.InterceptorFactories, concatBuilder.InterceptorFactories)); } - public static ISignalInterceptingPipelineBuilder Concat(this ISignalInterceptingPipelineBuilder builder, - Func, ISignalInterceptingPipelineBuilder> concatBuilderFactory) where T : Signal + public static ISignalInterceptingPipelineBuilder Concat + ( + this ISignalInterceptingPipelineBuilder builder, + Func, ISignalInterceptingPipelineBuilder> concatBuilderFactory + ) where T : Signal { return builder.Concat(concatBuilderFactory(SignalInterceptingPipelineBuilder.Empty)); } - private static ImmutableStack Concat(ImmutableStack targetInterceptorFactories, - ImmutableStack concatInterceptorFactories) + private static ImmutableStack Concat + ( + ImmutableStack targetInterceptorFactories, + ImmutableStack concatInterceptorFactories + ) { var reversedConcatInterceptorFactories = new Stack(); diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.DistinctUntilChanged.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.DistinctUntilChanged.cs index 07854ca..d4d9d92 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.DistinctUntilChanged.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.DistinctUntilChanged.cs @@ -5,39 +5,54 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder DistinctUntilChanged(this ISignalInterceptingPipelineBuilder builder, - Func distinctUntilChanged) - where TSignal : Signal + public static ISignalInterceptingPipelineBuilder DistinctUntilChanged + ( + this ISignalInterceptingPipelineBuilder builder, + Func distinctUntilChanged + ) where TSignal : Signal { return builder.InterceptTransient(() => new DistinctUntilChangedSignalInterceptor(distinctUntilChanged)); } - public static ISignalInterceptingPipelineBuilder DistinctUntilChanged(this ISignalInterceptingPipelineBuilder builder, - Func distinctUntilChanged) + public static ISignalInterceptingPipelineBuilder DistinctUntilChanged + ( + this ISignalInterceptingPipelineBuilder builder, + Func distinctUntilChanged + ) { return builder.InterceptTransient(() => new DistinctUntilChangedSignalInterceptor(distinctUntilChanged)); } - public static ISignalInterceptingPipelineBuilder DistinctUntilChanged(this ISignalInterceptingPipelineBuilder builder, - Func distinctUntilChanged) - where TSignal : Signal + public static ISignalInterceptingPipelineBuilder DistinctUntilChanged + ( + this ISignalInterceptingPipelineBuilder builder, + Func distinctUntilChanged + ) where TSignal : Signal { return builder.DistinctUntilChanged((signal, _) => distinctUntilChanged(signal)); } - public static ISignalInterceptingPipelineBuilder DistinctUntilChanged(this ISignalInterceptingPipelineBuilder builder, - Func distinctUntilChanged) + public static ISignalInterceptingPipelineBuilder DistinctUntilChanged + ( + this ISignalInterceptingPipelineBuilder builder, + Func distinctUntilChanged + ) { return builder.DistinctUntilChanged((signal, _) => distinctUntilChanged(signal)); } - public static ISignalInterceptingPipelineBuilder DistinctUntilChanged(this ISignalInterceptingPipelineBuilder builder) - where TSignal : Signal + public static ISignalInterceptingPipelineBuilder DistinctUntilChanged + ( + this ISignalInterceptingPipelineBuilder builder + ) where TSignal : Signal { return builder.DistinctUntilChanged((signal, _) => signal); } - public static ISignalInterceptingPipelineBuilder DistinctUntilChanged(this ISignalInterceptingPipelineBuilder builder) + public static ISignalInterceptingPipelineBuilder DistinctUntilChanged + ( + this ISignalInterceptingPipelineBuilder builder + ) { return builder.DistinctUntilChanged((signal, _) => signal); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Do.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Do.cs index 5845b8e..1e91ff0 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Do.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Do.cs @@ -5,10 +5,13 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder Do(this ISignalInterceptingPipelineBuilder builder, - Action @do) + public static ISignalInterceptingPipelineBuilder Do + ( + this ISignalInterceptingPipelineBuilder builder, + Action @do + ) { - return builder.InterceptSingleton(() => new DelegatedSignalInterceptor((signal, cancellationToken) => + return builder.InterceptSingleton(() => new DelegateSignalInterceptor((signal, cancellationToken) => { @do(signal, cancellationToken); @@ -16,16 +19,22 @@ public static ISignalInterceptingPipelineBuilder Do(this ISignalInterceptingPipe })); } - public static ISignalInterceptingPipelineBuilder Do(this ISignalInterceptingPipelineBuilder builder, - Action @do) + public static ISignalInterceptingPipelineBuilder Do + ( + this ISignalInterceptingPipelineBuilder builder, + Action @do + ) { return builder.Do((signal, _) => @do(signal)); } - public static ISignalInterceptingPipelineBuilder Do(this ISignalInterceptingPipelineBuilder builder, - Action @do) where T : Signal + public static ISignalInterceptingPipelineBuilder Do + ( + this ISignalInterceptingPipelineBuilder builder, + Action @do + ) where T : Signal { - return builder.InterceptSingleton(() => new DelegatedSignalInterceptor((signal, cancellationToken) => + return builder.InterceptSingleton(() => new DelegateSignalInterceptor((signal, cancellationToken) => { @do(signal, cancellationToken); @@ -33,8 +42,11 @@ public static ISignalInterceptingPipelineBuilder Do(this ISignalIntercepti })); } - public static ISignalInterceptingPipelineBuilder Do(this ISignalInterceptingPipelineBuilder builder, - Action @do) where T : Signal + public static ISignalInterceptingPipelineBuilder Do + ( + this ISignalInterceptingPipelineBuilder builder, + Action @do + ) where T : Signal { return builder.Do((signal, _) => @do(signal)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Intercept.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Intercept.cs index 6670a7c..cab79ef 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Intercept.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Intercept.cs @@ -5,28 +5,38 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder Intercept(this ISignalInterceptingPipelineBuilder builder, - Func intercept) + public static ISignalInterceptingPipelineBuilder Intercept + ( + this ISignalInterceptingPipelineBuilder builder, + Func intercept + ) { - return builder.InterceptSingleton(() => new DelegatedSignalInterceptor(intercept)); + return builder.InterceptSingleton(() => new DelegateSignalInterceptor(intercept)); } - public static ISignalInterceptingPipelineBuilder Intercept(this ISignalInterceptingPipelineBuilder builder, - Func intercept) + public static ISignalInterceptingPipelineBuilder Intercept + ( + this ISignalInterceptingPipelineBuilder builder, + Func intercept + ) { return builder.Intercept((signal, _) => intercept(signal)); } - public static ISignalInterceptingPipelineBuilder Intercept(this ISignalInterceptingPipelineBuilder builder, - Func intercept) - where T : Signal + public static ISignalInterceptingPipelineBuilder Intercept + ( + this ISignalInterceptingPipelineBuilder builder, + Func intercept + ) where T : Signal { - return builder.InterceptSingleton(() => new DelegatedSignalInterceptor(intercept)); + return builder.InterceptSingleton(() => new DelegateSignalInterceptor(intercept)); } - public static ISignalInterceptingPipelineBuilder Intercept(this ISignalInterceptingPipelineBuilder builder, - Func intercept) - where T : Signal + public static ISignalInterceptingPipelineBuilder Intercept + ( + this ISignalInterceptingPipelineBuilder builder, + Func intercept + ) where T : Signal { return builder.Intercept((signal, _) => intercept(signal)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.InterceptSingleton.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.InterceptSingleton.cs index 9e9ff8b..911ec19 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.InterceptSingleton.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.InterceptSingleton.cs @@ -5,14 +5,20 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder InterceptSingleton(this ISignalInterceptingPipelineBuilder builder, - Func interceptorFactory) + public static ISignalInterceptingPipelineBuilder InterceptSingleton + ( + this ISignalInterceptingPipelineBuilder builder, + Func interceptorFactory + ) { return builder.Intercept(new SingletonSignalInterceptorFactory(interceptorFactory)); } - public static ISignalInterceptingPipelineBuilder InterceptSingleton(this ISignalInterceptingPipelineBuilder builder, - Func> interceptorFactory) where T : Signal + public static ISignalInterceptingPipelineBuilder InterceptSingleton + ( + this ISignalInterceptingPipelineBuilder builder, + Func> interceptorFactory + ) where T : Signal { return builder.Intercept(new SingletonSignalInterceptorFactory(interceptorFactory)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.InterceptTransient.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.InterceptTransient.cs index c118e26..1de3284 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.InterceptTransient.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.InterceptTransient.cs @@ -5,14 +5,20 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder InterceptTransient(this ISignalInterceptingPipelineBuilder builder, - Func interceptorFactory) + public static ISignalInterceptingPipelineBuilder InterceptTransient + ( + this ISignalInterceptingPipelineBuilder builder, + Func interceptorFactory + ) { return builder.Intercept(new TransientSignalInterceptorFactory(interceptorFactory)); } - public static ISignalInterceptingPipelineBuilder InterceptTransient(this ISignalInterceptingPipelineBuilder builder, - Func> interceptorFactory) where T : Signal + public static ISignalInterceptingPipelineBuilder InterceptTransient + ( + this ISignalInterceptingPipelineBuilder builder, + Func> interceptorFactory + ) where T : Signal { return builder.Intercept(new TransientSignalInterceptorFactory(interceptorFactory)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Merge.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Merge.cs index 290651b..1030c90 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Merge.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Merge.cs @@ -5,81 +5,108 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, - ISignalInterceptingPipelineBuilder mergeBuilder) + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, + ISignalInterceptingPipelineBuilder mergeBuilder + ) { return SignalInterceptingPipelineBuilder.Empty .InterceptSingleton(() => new MergeSignalInterceptor(builder.Build(), mergeBuilder.Build())); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, - Func mergeBuilderFactory) + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, + Func mergeBuilderFactory + ) { return builder.Merge(mergeBuilderFactory(SignalInterceptingPipelineBuilder.Empty)); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, ISignalInterceptingPipelineBuilder mergeSourceBuilder, - ISignalInterceptingPipelineBuilder mergeTargetBuilder) + ISignalInterceptingPipelineBuilder mergeTargetBuilder + ) { return builder.InterceptSingleton(() => new MergeSignalInterceptor(mergeSourceBuilder.Build(), mergeTargetBuilder.Build())); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, Func mergeSourceBuilderFactory, - Func mergeTargetBuilderFactory) + Func mergeTargetBuilderFactory + ) { return builder.Merge(mergeSourceBuilderFactory(SignalInterceptingPipelineBuilder.Empty), mergeTargetBuilderFactory(SignalInterceptingPipelineBuilder.Empty)); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, ISignalInterceptingPipelineBuilder mergeSourceBuilder, - ISignalInterceptingPipelineBuilder mergeTargetBuilder) where T : Signal + ISignalInterceptingPipelineBuilder mergeTargetBuilder + ) where T : Signal { return builder.InterceptSingleton(() => new MergeSignalInterceptor(mergeSourceBuilder.Build(), mergeTargetBuilder.Build())) .OfType(); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, Func> mergeSourceBuilderFactory, - Func> mergeTargetBuilderFactory) - where T : Signal + Func> mergeTargetBuilderFactory + ) where T : Signal { return builder.Merge(mergeSourceBuilderFactory(SignalInterceptingPipelineBuilder.Empty), mergeTargetBuilderFactory(SignalInterceptingPipelineBuilder.Empty)); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, - ISignalInterceptingPipelineBuilder mergeBuilder) where T : Signal + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, + ISignalInterceptingPipelineBuilder mergeBuilder + ) where T : Signal { return SignalInterceptingPipelineBuilder.Empty .InterceptSingleton(() => new MergeSignalInterceptor(builder.Build(), mergeBuilder.Build())); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, - Func, ISignalInterceptingPipelineBuilder> mergeBuilderFactory) - where T : Signal + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, + Func, ISignalInterceptingPipelineBuilder> mergeBuilderFactory + ) where T : Signal { return builder.Merge(mergeBuilderFactory(SignalInterceptingPipelineBuilder.Empty)); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, ISignalInterceptingPipelineBuilder mergeSourceBuilder, - ISignalInterceptingPipelineBuilder mergeTargetBuilder) where T : Signal + ISignalInterceptingPipelineBuilder mergeTargetBuilder + ) where T : Signal { return builder.InterceptSingleton(() => new MergeSignalInterceptor(mergeSourceBuilder.Build(), mergeTargetBuilder.Build())); } - public static ISignalInterceptingPipelineBuilder Merge(this ISignalInterceptingPipelineBuilder builder, + public static ISignalInterceptingPipelineBuilder Merge + ( + this ISignalInterceptingPipelineBuilder builder, Func, ISignalInterceptingPipelineBuilder> mergeSourceBuilderFactory, - Func, ISignalInterceptingPipelineBuilder> mergeTargetBuilderFactory) - where T : Signal + Func, ISignalInterceptingPipelineBuilder> mergeTargetBuilderFactory + ) where T : Signal { return builder.Merge(mergeSourceBuilderFactory(SignalInterceptingPipelineBuilder.Empty), mergeTargetBuilderFactory(SignalInterceptingPipelineBuilder.Empty)); diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Select.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Select.cs index 26e0e6a..b2d11ff 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Select.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Select.cs @@ -5,20 +5,29 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder Select(this ISignalInterceptingPipelineBuilder builder, - Func select) + public static ISignalInterceptingPipelineBuilder Select + ( + this ISignalInterceptingPipelineBuilder builder, + Func select + ) { return builder.InterceptSingleton(() => new SelectSignalInterceptor(select)); } - public static ISignalInterceptingPipelineBuilder Select(this ISignalInterceptingPipelineBuilder builder, - Func select) + public static ISignalInterceptingPipelineBuilder Select + ( + this ISignalInterceptingPipelineBuilder builder, + Func select + ) { return builder.Select((signal, _) => select(signal)); } - public static ISignalInterceptingPipelineBuilder Select(this ISignalInterceptingPipelineBuilder builder, - Func select) + public static ISignalInterceptingPipelineBuilder Select + ( + this ISignalInterceptingPipelineBuilder builder, + Func select + ) where TFrom : Signal where TTo : Signal { @@ -28,8 +37,11 @@ public static ISignalInterceptingPipelineBuilder Select(this IS .OfType(); } - public static ISignalInterceptingPipelineBuilder Select(this ISignalInterceptingPipelineBuilder builder, - Func select) + public static ISignalInterceptingPipelineBuilder Select + ( + this ISignalInterceptingPipelineBuilder builder, + Func select + ) where TFrom : Signal where TTo : Signal { diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Skip.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Skip.cs index 4c276a5..d4b7606 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Skip.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Skip.cs @@ -5,13 +5,20 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder Skip(this ISignalInterceptingPipelineBuilder builder, int count) + public static ISignalInterceptingPipelineBuilder Skip + ( + this ISignalInterceptingPipelineBuilder builder, + int count + ) { return builder.InterceptTransient(() => new SkipSignalInterceptor(count)); } - public static ISignalInterceptingPipelineBuilder Skip(this ISignalInterceptingPipelineBuilder builder, int count) - where T : Signal + public static ISignalInterceptingPipelineBuilder Skip + ( + this ISignalInterceptingPipelineBuilder builder, + int count + ) where T : Signal { return builder.InterceptTransient(() => new SkipSignalInterceptor(count)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.SkipWhile.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.SkipWhile.cs index ae47386..a81ca6d 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.SkipWhile.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.SkipWhile.cs @@ -5,28 +5,38 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder SkipWhile(this ISignalInterceptingPipelineBuilder builder, - Func @while) + public static ISignalInterceptingPipelineBuilder SkipWhile + ( + this ISignalInterceptingPipelineBuilder builder, + Func @while + ) { return builder.InterceptTransient(() => new SkipWhileSignalInterceptor(@while)); } - public static ISignalInterceptingPipelineBuilder SkipWhile(this ISignalInterceptingPipelineBuilder builder, - Func @while) + public static ISignalInterceptingPipelineBuilder SkipWhile + ( + this ISignalInterceptingPipelineBuilder builder, + Func @while + ) { return builder.SkipWhile((signal, _) => @while(signal)); } - public static ISignalInterceptingPipelineBuilder SkipWhile(this ISignalInterceptingPipelineBuilder builder, - Func @while) - where T : Signal + public static ISignalInterceptingPipelineBuilder SkipWhile + ( + this ISignalInterceptingPipelineBuilder builder, + Func @while + ) where T : Signal { return builder.InterceptTransient(() => new SkipWhileSignalInterceptor(@while)); } - public static ISignalInterceptingPipelineBuilder SkipWhile(this ISignalInterceptingPipelineBuilder builder, - Func @while) - where T : Signal + public static ISignalInterceptingPipelineBuilder SkipWhile + ( + this ISignalInterceptingPipelineBuilder builder, + Func @while + ) where T : Signal { return builder.SkipWhile((signal, _) => @while(signal)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Take.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Take.cs index 35399b0..7d4c6f7 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Take.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Take.cs @@ -5,13 +5,20 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder Take(this ISignalInterceptingPipelineBuilder builder, int count) + public static ISignalInterceptingPipelineBuilder Take + ( + this ISignalInterceptingPipelineBuilder builder, + int count + ) { return builder.InterceptTransient(() => new TakeSignalInterceptor(count)); } - public static ISignalInterceptingPipelineBuilder Take(this ISignalInterceptingPipelineBuilder builder, int count) - where T : Signal + public static ISignalInterceptingPipelineBuilder Take + ( + this ISignalInterceptingPipelineBuilder builder, + int count + ) where T : Signal { return builder.InterceptTransient(() => new TakeSignalInterceptor(count)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.TakeWhile.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.TakeWhile.cs index 1e9e3ef..da3b414 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.TakeWhile.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.TakeWhile.cs @@ -5,28 +5,38 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder TakeWhile(this ISignalInterceptingPipelineBuilder builder, - Func @while) + public static ISignalInterceptingPipelineBuilder TakeWhile + ( + this ISignalInterceptingPipelineBuilder builder, + Func @while + ) { return builder.InterceptTransient(() => new TakeWhileSignalInterceptor(@while)); } - public static ISignalInterceptingPipelineBuilder TakeWhile(this ISignalInterceptingPipelineBuilder builder, - Func @while) + public static ISignalInterceptingPipelineBuilder TakeWhile + ( + this ISignalInterceptingPipelineBuilder builder, + Func @while + ) { return builder.TakeWhile((signal, _) => @while(signal)); } - public static ISignalInterceptingPipelineBuilder TakeWhile(this ISignalInterceptingPipelineBuilder builder, - Func @while) - where T : Signal + public static ISignalInterceptingPipelineBuilder TakeWhile + ( + this ISignalInterceptingPipelineBuilder builder, + Func @while + ) where T : Signal { return builder.InterceptTransient(() => new TakeWhileSignalInterceptor(@while)); } - public static ISignalInterceptingPipelineBuilder TakeWhile(this ISignalInterceptingPipelineBuilder builder, - Func @while) - where T : Signal + public static ISignalInterceptingPipelineBuilder TakeWhile + ( + this ISignalInterceptingPipelineBuilder builder, + Func @while + ) where T : Signal { return builder.TakeWhile((signal, _) => @while(signal)); } diff --git a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Where.cs b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Where.cs index 20b125b..f199efd 100644 --- a/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Where.cs +++ b/Sources/Falko.Talkie.Signals.Extensions/Pipelines/Intercepting/SignalInterceptingPipelineBuilderExtensions.Where.cs @@ -5,26 +5,38 @@ namespace Talkie.Pipelines.Intercepting; public static partial class SignalInterceptingPipelineBuilderExtensions { - public static ISignalInterceptingPipelineBuilder Where(this ISignalInterceptingPipelineBuilder builder, - Func where) where T : Signal + public static ISignalInterceptingPipelineBuilder Where + ( + this ISignalInterceptingPipelineBuilder builder, + Func where + ) where T : Signal { return builder.InterceptSingleton(() => new WhereSignalInterceptor(where)); } - public static ISignalInterceptingPipelineBuilder Where(this ISignalInterceptingPipelineBuilder builder, - Func where) where T : Signal + public static ISignalInterceptingPipelineBuilder Where + ( + this ISignalInterceptingPipelineBuilder builder, + Func where + ) where T : Signal { return builder.Where((signal, _) => where(signal)); } - public static ISignalInterceptingPipelineBuilder Where(this ISignalInterceptingPipelineBuilder builder, - Func where) + public static ISignalInterceptingPipelineBuilder Where + ( + this ISignalInterceptingPipelineBuilder builder, + Func where + ) { return builder.InterceptSingleton(() => new WhereSignalInterceptor(where)); } - public static ISignalInterceptingPipelineBuilder Where(this ISignalInterceptingPipelineBuilder builder, - Func where) + public static ISignalInterceptingPipelineBuilder Where + ( + this ISignalInterceptingPipelineBuilder builder, + Func where + ) { return builder.Where((signal, _) => where(signal)); } diff --git a/Sources/Falko.Talkie.Signals/Flows/SubscriptionExtensions.cs b/Sources/Falko.Talkie.Signals/Flows/SubscriptionExtensions.cs index 1feb977..b710e1f 100644 --- a/Sources/Falko.Talkie.Signals/Flows/SubscriptionExtensions.cs +++ b/Sources/Falko.Talkie.Signals/Flows/SubscriptionExtensions.cs @@ -4,8 +4,11 @@ namespace Talkie.Flows; public static partial class SubscriptionExtensions { - public static void UnsubscribeWith(this Subscription subscription, - IRegisterOnlyDisposableScope disposables) + public static void UnsubscribeWith + ( + this Subscription subscription, + IRegisterOnlyDisposableScope disposables + ) { disposables.Register(new SubscriptionDisposableWrapper(subscription)); } diff --git a/Tests/Falko.Talkie.Tests.Sequences/Testers/FrozenSequenceTester.cs b/Tests/Falko.Talkie.Tests.Sequences/Testers/FrozenSequenceTester.cs index daee986..77fd75d 100644 --- a/Tests/Falko.Talkie.Tests.Sequences/Testers/FrozenSequenceTester.cs +++ b/Tests/Falko.Talkie.Tests.Sequences/Testers/FrozenSequenceTester.cs @@ -18,9 +18,9 @@ public void TestFrozenSequenceFrom0() [Test] public void TestFrozenSequenceFrom1() { - var frozenSequence = new FrozenSequence(new[] { 0 }); + var frozenSequence = new FrozenSequence([0]); - using var enumerator = frozenSequence.GetEnumerator(); + using var enumerator = frozenSequence.AsEnumerable().GetEnumerator(); Assert.Multiple(() => { @@ -45,7 +45,7 @@ public void TestFrozenSequenceFrom10() var frozenSequence = new FrozenSequence(sequence); - using var enumerator = frozenSequence.GetEnumerator(); + using var enumerator = frozenSequence.AsEnumerable().GetEnumerator(); for (var index = 0; index < capacity; index++) {