diff --git a/TelegramBotBase.Test/TelegramBotBase.Example.csproj b/TelegramBotBase.Test/TelegramBotBase.Example.csproj index 6fdb766..3affa0a 100644 --- a/TelegramBotBase.Test/TelegramBotBase.Example.csproj +++ b/TelegramBotBase.Test/TelegramBotBase.Example.csproj @@ -8,8 +8,11 @@ - + + + + diff --git a/TelegramBotBase/Base/MessageClient.cs b/TelegramBotBase/Base/MessageClient.cs index 5271dc4..62c083d 100644 --- a/TelegramBotBase/Base/MessageClient.cs +++ b/TelegramBotBase/Base/MessageClient.cs @@ -9,6 +9,7 @@ using Telegram.Bot; using Telegram.Bot.Exceptions; using Telegram.Bot.Polling; using Telegram.Bot.Types; +using TelegramBotBase.Interfaces; namespace TelegramBotBase.Base; @@ -17,22 +18,18 @@ namespace TelegramBotBase.Base; /// public class MessageClient { + private EventHandlerList Events { get; } = new(); + private static readonly object EvOnMessageLoop = new(); private static readonly object EvOnReceiveError = new(); - private static object __evOnMessage = new(); - - private static object __evOnMessageEdit = new(); - - private static object __evCallbackQuery = new(); - 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 @@ -42,27 +39,17 @@ 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) { ApiKey = apiKey; TelegramClient = new TelegramBotClient(apiKey); - - Prepare(); } public MessageClient(string apiKey, HttpClient proxy) { ApiKey = apiKey; TelegramClient = new TelegramBotClient(apiKey, proxy); - - Prepare(); } @@ -80,8 +67,6 @@ public class MessageClient ); TelegramClient = new TelegramBotClient(apiKey, httpClient); - - Prepare(); } /// @@ -101,8 +86,6 @@ public class MessageClient ); TelegramClient = new TelegramBotClient(apiKey, httpClient); - - Prepare(); } @@ -110,20 +93,10 @@ public class MessageClient { ApiKey = apiKey; TelegramClient = client; - - Prepare(); } - - - public void Prepare() - { - TelegramClient.Timeout = new TimeSpan(0, 0, 30); - } - - - public void StartReceiving() + public virtual void StartReceiving() { _cancellationTokenSource = new CancellationTokenSource(); @@ -131,66 +104,32 @@ public class MessageClient receiverOptions.ThrowPendingUpdates = ThrowPendingUpdates; - if (UseThreadPool) - { - ThreadPool.SetMaxThreads(ThreadPool_WorkerThreads, ThreadPool_IOThreads); - - TelegramClient.StartReceiving(HandleUpdateAsyncThreadPool, HandleErrorAsyncThreadPool, receiverOptions, - _cancellationTokenSource.Token); - } - else - { - TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions, - _cancellationTokenSource.Token); - } + TelegramClient.Timeout = new TimeSpan(0, 1, 0); + TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions, _cancellationTokenSource.Token); } - public void StopReceiving() + + public virtual void StopReceiving() { _cancellationTokenSource.Cancel(); } - #region "Single Thread" public async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken) { await OnMessageLoop(new UpdateResult(update, null)); } + public async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) { 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 + #region "BotCommands" /// /// This will return the current list of bot commands. /// @@ -222,6 +161,8 @@ public class MessageClient await TelegramClient.DeleteMyCommandsAsync(scope, languageCode); } + #endregion + #region "Events" @@ -231,6 +172,7 @@ public class MessageClient remove => Events.RemoveHandler(EvOnMessageLoop, value); } + public async Task OnMessageLoop(UpdateResult update) { var eventHandlers = (Events[EvOnMessageLoop] as Async.AsyncEventHandler)?.Invoke(this, update); @@ -248,6 +190,7 @@ public class MessageClient remove => Events.RemoveHandler(EvOnReceiveError, value); } + public async Task OnReceiveError(ErrorResult update) { var eventHandlers = (Events[EvOnReceiveError] as Async.AsyncEventHandler)?.Invoke(this, update); @@ -271,4 +214,5 @@ public class MessageClient } #endregion + } diff --git a/TelegramBotBase/Base/ThreadPoolMessageClient.cs b/TelegramBotBase/Base/ThreadPoolMessageClient.cs new file mode 100644 index 0000000..7808850 --- /dev/null +++ b/TelegramBotBase/Base/ThreadPoolMessageClient.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Telegram.Bot; +using Telegram.Bot.Exceptions; +using Telegram.Bot.Polling; +using Telegram.Bot.Types; +using TelegramBotBase.Interfaces; + +namespace TelegramBotBase.Base; + +/// +/// Base class for message handling +/// +public class ThreadPoolMessageClient : MessageClient +{ + private CancellationTokenSource _cancellationTokenSource; + + /// + /// Indicates if all pending Telegram.Bot.Types.Updates should be thrown out before + // start polling. If set to true Telegram.Bot.Polling.ReceiverOptions.AllowedUpdates + // should be set to not null, otherwise Telegram.Bot.Polling.ReceiverOptions.AllowedUpdates + // will effectively be set to receive all Telegram.Bot.Types.Updates. + /// + + public int ThreadPool_WorkerThreads { get; set; } = 1; + + public int ThreadPool_IOThreads { get; set; } = 1; + + + public ThreadPoolMessageClient(string apiKey) : base(apiKey) + { + + } + + public ThreadPoolMessageClient(string apiKey, HttpClient proxy) : base(apiKey, proxy) + { + + } + + + public ThreadPoolMessageClient(string apiKey, Uri proxyUrl, NetworkCredential credential = null) : base(apiKey, proxyUrl, credential) + { + + } + + /// + /// Initializes the client with a proxy + /// + /// + /// i.e. 127.0.0.1 + /// i.e. 10000 + public ThreadPoolMessageClient(string apiKey, string proxyHost, int proxyPort) : base(apiKey, proxyHost, proxyPort) + { + + } + + + public ThreadPoolMessageClient(string apiKey, TelegramBotClient client) : base(apiKey, client) + { + + } + + + + public override void StartReceiving() + { + _cancellationTokenSource = new CancellationTokenSource(); + + var receiverOptions = new ReceiverOptions(); + + receiverOptions.ThrowPendingUpdates = ThrowPendingUpdates; + + ThreadPool.SetMaxThreads(ThreadPool_WorkerThreads, ThreadPool_IOThreads); + + TelegramClient.Timeout = new TimeSpan(0, 1, 0); + + TelegramClient.StartReceiving(HandleUpdateAsyncThreadPool, HandleErrorAsyncThreadPool, receiverOptions, _cancellationTokenSource.Token); + } + + public override void StopReceiving() + { + _cancellationTokenSource.Cancel(); + } + + + 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; + } + +} diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index 85b5621..4291063 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -32,6 +32,7 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, private BotBaseBuilder() { + } /// @@ -429,26 +430,26 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, #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; + var c = new ThreadPoolMessageClient(_apiKey, (TelegramBotClient)_client.TelegramClient); + + c.ThreadPool_WorkerThreads = workerThreads; + c.ThreadPool_IOThreads = ioThreads; + + _client = c; return this; } - - #endregion }