diff --git a/TelegramBotBase.Test/Program.cs b/TelegramBotBase.Test/Program.cs index 9276cbd..a9236a1 100644 --- a/TelegramBotBase.Test/Program.cs +++ b/TelegramBotBase.Test/Program.cs @@ -32,6 +32,7 @@ internal class Program }) .NoSerialization() .UseEnglish() + .UseThreadPool() .Build(); diff --git a/TelegramBotBase/Base/MessageClient.cs b/TelegramBotBase/Base/MessageClient.cs index 10a724e..5271dc4 100644 --- a/TelegramBotBase/Base/MessageClient.cs +++ b/TelegramBotBase/Base/MessageClient.cs @@ -28,6 +28,12 @@ public class MessageClient private CancellationTokenSource _cancellationTokenSource; + public string ApiKey { get; } + + public ITelegramBotClient TelegramClient { get; set; } + + private EventHandlerList Events { get; } = new(); + /// /// Indicates if all pending Telegram.Bot.Types.Updates should be thrown out before // start polling. If set to true Telegram.Bot.Polling.ReceiverOptions.AllowedUpdates @@ -36,6 +42,12 @@ public class MessageClient /// public bool ThrowPendingUpdates { get; set; } + public bool UseThreadPool { get; set; } = false; + + public int ThreadPool_WorkerThreads { get; set; } = 1; + + public int ThreadPool_IOThreads { get; set; } = 1; + public MessageClient(string apiKey) { @@ -103,11 +115,6 @@ public class MessageClient } - public string ApiKey { get; } - - public ITelegramBotClient TelegramClient { get; set; } - - private EventHandlerList Events { get; } = new(); public void Prepare() @@ -124,8 +131,19 @@ public class MessageClient receiverOptions.ThrowPendingUpdates = ThrowPendingUpdates; - TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions, - _cancellationTokenSource.Token); + if (UseThreadPool) + { + ThreadPool.SetMaxThreads(ThreadPool_WorkerThreads, ThreadPool_IOThreads); + + TelegramClient.StartReceiving(HandleUpdateAsyncThreadPool, HandleErrorAsyncThreadPool, receiverOptions, + _cancellationTokenSource.Token); + } + else + { + TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions, + _cancellationTokenSource.Token); + } + } public void StopReceiving() @@ -133,6 +151,7 @@ public class MessageClient _cancellationTokenSource.Cancel(); } + #region "Single Thread" public async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) { @@ -145,6 +164,33 @@ public class MessageClient await OnReceiveError(new ErrorResult(exception)); } + #endregion + + #region "Thread Pool" + + public Task HandleUpdateAsyncThreadPool(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) + { + ThreadPool.QueueUserWorkItem(async a => + { + await OnMessageLoop(new UpdateResult(update, null)); + }); + + return Task.CompletedTask; + } + + public Task HandleErrorAsyncThreadPool(ITelegramBotClient botClient, Exception exception, + CancellationToken cancellationToken) + { + ThreadPool.QueueUserWorkItem(async a => + { + await OnReceiveError(new ErrorResult(exception)); + }); + + return Task.CompletedTask; + } + + #endregion + /// /// This will return the current list of bot commands. /// diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index c3d9394..85b5621 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -18,7 +18,7 @@ namespace TelegramBotBase.Builder; public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, IStartFormSelectionStage, IBuildingStage, INetworkingSelectionStage, IBotCommandsStage, ISessionSerializationStage, - ILanguageSelectionStage + ILanguageSelectionStage, IThreadingStage { private string _apiKey; @@ -87,6 +87,8 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, DefaultLanguage(); + UseSingleThread(); + return this; } @@ -107,6 +109,8 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, DefaultLanguage(); + UseSingleThread(); + return this; } @@ -125,6 +129,8 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, DefaultLanguage(); + UseSingleThread(); + return this; } @@ -391,34 +397,58 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, #region "Step 7 (Language)" - public IBuildingStage DefaultLanguage() + public IThreadingStage DefaultLanguage() { return this; } - public IBuildingStage UseEnglish() + public IThreadingStage UseEnglish() { Default.Language = new English(); return this; } - public IBuildingStage UseGerman() + public IThreadingStage UseGerman() { Default.Language = new German(); return this; } - public IBuildingStage UsePersian() + public IThreadingStage UsePersian() { Default.Language = new Persian(); return this; } - public IBuildingStage Custom(Localization language) + public IThreadingStage Custom(Localization language) { Default.Language = language; return this; } + #endregion + + #region "Step 8 (Threading)" + + public IBuildingStage UseSingleThread() + { + _client.UseThreadPool = false; + + return this; + } + + public IBuildingStage UseThreadPool(int workerThreads = 2, int ioThreads = 1) + { + _client.UseThreadPool = true; + _client.ThreadPool_WorkerThreads = workerThreads; + _client.ThreadPool_IOThreads = ioThreads; + + return this; + } + + + + #endregion + } diff --git a/TelegramBotBase/Builder/Interfaces/ILanguageSelectionStage.cs b/TelegramBotBase/Builder/Interfaces/ILanguageSelectionStage.cs index 8021ee2..1a43a52 100644 --- a/TelegramBotBase/Builder/Interfaces/ILanguageSelectionStage.cs +++ b/TelegramBotBase/Builder/Interfaces/ILanguageSelectionStage.cs @@ -8,29 +8,29 @@ public interface ILanguageSelectionStage /// Selects the default language for control usage. (English) /// /// - IBuildingStage DefaultLanguage(); + IThreadingStage DefaultLanguage(); /// /// Selects english as the default language for control labels. /// /// - IBuildingStage UseEnglish(); + IThreadingStage UseEnglish(); /// /// Selects german as the default language for control labels. /// /// - IBuildingStage UseGerman(); + IThreadingStage UseGerman(); /// /// Selects persian as the default language for control labels. /// /// - IBuildingStage UsePersian(); + IThreadingStage UsePersian(); /// /// Selects a custom language as the default language for control labels. /// /// - IBuildingStage Custom(Localization language); + IThreadingStage Custom(Localization language); } \ No newline at end of file diff --git a/TelegramBotBase/Builder/Interfaces/IThreadingStage.cs b/TelegramBotBase/Builder/Interfaces/IThreadingStage.cs new file mode 100644 index 0000000..f53c087 --- /dev/null +++ b/TelegramBotBase/Builder/Interfaces/IThreadingStage.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace TelegramBotBase.Builder.Interfaces +{ + public interface IThreadingStage + { + /// + /// Uses one single thread for message loop. (Default) + /// + /// + public IBuildingStage UseSingleThread(); + + /// + /// Using the threadpool for managing requests. + /// + /// Number of concurrent working threads. + /// Number of concurrent I/O threads. + /// + public IBuildingStage UseThreadPool(int workerThreads = 2, int ioThreads = 1); + + } +}