diff --git a/README.md b/README.md index de6c301..2095ea6 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,7 @@ BitTorrent: `TYVZSykaVT1nKZnz9hjDgBRNB9VavU1bpW` * [TaggedButtonGrid](#tagged-button-grid) * [CheckedButtonList](#checked-button-list) * [MultiToggleButton](#multi-toggle-button) +- [Localizations](#localizations) - [Groups](#groups) * [SplitterForm](#splitter-form) * [GroupForm](#group-form) @@ -714,6 +715,19 @@ Check the example project [TelegramBotBase.Test/Tests/Controls/CheckedButtonList Check the example project [TelegramBotBase.Test/Tests/Controls/MultiToggleButtonForm.cs](TelegramBotBase.Test/Tests/Controls/MultiToggleButtonForm.cs) + +## Localizations + +The current available languages for controls are: + +- English +- German +- Persian + +You can add other languages easily by creating a subclass of the [TelegramBotBase/Localizations/Localization.cs](TelegramBotBase/Localizations/Localization.cs) class. + +To set the default language set the *Language* property on the static [TelegramBotBase/Localizations/Default.cs](TelegramBotBase/Localizations/Default.cs) instance. + ## Groups For groups, there are multiple different tools which help to work with and allows bot also to manage diff --git a/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj b/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj index c181fa8..347e740 100644 --- a/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj +++ b/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj @@ -15,11 +15,14 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + + + + diff --git a/TelegramBotBase/Base/ErrorResult.cs b/TelegramBotBase/Base/ErrorResult.cs new file mode 100644 index 0000000..00d7c04 --- /dev/null +++ b/TelegramBotBase/Base/ErrorResult.cs @@ -0,0 +1,14 @@ +using System; + +namespace TelegramBotBase.Base +{ + public class ErrorResult : EventArgs + { + public ErrorResult(Exception exception) + { + Exception = exception; + } + + public Exception Exception { get; } + } +} diff --git a/TelegramBotBase/Base/MessageClient.cs b/TelegramBotBase/Base/MessageClient.cs index b5f9b3a..10a724e 100644 --- a/TelegramBotBase/Base/MessageClient.cs +++ b/TelegramBotBase/Base/MessageClient.cs @@ -18,6 +18,7 @@ namespace TelegramBotBase.Base; public class MessageClient { private static readonly object EvOnMessageLoop = new(); + private static readonly object EvOnReceiveError = new(); private static object __evOnMessage = new(); @@ -27,6 +28,14 @@ public class 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 bool ThrowPendingUpdates { get; set; } + public MessageClient(string apiKey) { @@ -113,6 +122,8 @@ public class MessageClient var receiverOptions = new ReceiverOptions(); + receiverOptions.ThrowPendingUpdates = ThrowPendingUpdates; + TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions, _cancellationTokenSource.Token); } @@ -128,22 +139,12 @@ public class MessageClient await OnMessageLoop(new UpdateResult(update, null)); } - public Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, + public async Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken) { - if (exception is ApiRequestException exApi) - { - Console.WriteLine($"Telegram API Error:\n[{exApi.ErrorCode}]\n{exApi.Message}"); - } - else - { - Console.WriteLine(exception.ToString()); - } - - return Task.CompletedTask; + await OnReceiveError(new ErrorResult(exception)); } - /// /// This will return the current list of bot commands. /// @@ -186,7 +187,41 @@ public class MessageClient public async Task OnMessageLoop(UpdateResult update) { - await (Events[EvOnMessageLoop] as Async.AsyncEventHandler)?.Invoke(this, update); + var eventHandlers = (Events[EvOnMessageLoop] as Async.AsyncEventHandler)?.Invoke(this, update); + + if (eventHandlers != null) + { + await eventHandlers; + } + } + + + public event Async.AsyncEventHandler ReceiveError + { + add => Events.AddHandler(EvOnReceiveError, value); + remove => Events.RemoveHandler(EvOnReceiveError, value); + } + + public async Task OnReceiveError(ErrorResult update) + { + var eventHandlers = (Events[EvOnReceiveError] as Async.AsyncEventHandler)?.Invoke(this, update); + + if (eventHandlers != null) + { + await eventHandlers; + return; + } + + //Fallback when no event handler is used. + if (update.Exception is ApiRequestException exApi) + { + Console.WriteLine($"Telegram API Error:\n[{exApi.ErrorCode}]\n{exApi.Message}"); + } + else + { + Console.WriteLine(update.Exception.ToString()); + } + } #endregion diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index 497bed0..c3d9394 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -207,7 +207,7 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, #region "Step 4 (Network Settings)" - public IBotCommandsStage WithProxy(string proxyAddress) + public IBotCommandsStage WithProxy(string proxyAddress, bool throwPendingUpdates = false) { var url = new Uri(proxyAddress); _client = new MessageClient(_apiKey, url) @@ -217,11 +217,12 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, Timeout = new TimeSpan(0, 1, 0) }, }; + _client.ThrowPendingUpdates = throwPendingUpdates; return this; } - public IBotCommandsStage NoProxy() + public IBotCommandsStage NoProxy(bool throwPendingUpdates = false) { _client = new MessageClient(_apiKey) { @@ -230,11 +231,12 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, Timeout = new TimeSpan(0, 1, 0) } }; + _client.ThrowPendingUpdates = throwPendingUpdates; return this; } - public IBotCommandsStage WithBotClient(TelegramBotClient tgclient) + public IBotCommandsStage WithBotClient(TelegramBotClient tgclient, bool throwPendingUpdates = false) { _client = new MessageClient(_apiKey, tgclient) { @@ -243,11 +245,12 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, Timeout = new TimeSpan(0, 1, 0) } }; + _client.ThrowPendingUpdates = throwPendingUpdates; return this; } - public IBotCommandsStage WithHostAndPort(string proxyHost, int proxyPort) + public IBotCommandsStage WithHostAndPort(string proxyHost, int proxyPort, bool throwPendingUpdates = false) { _client = new MessageClient(_apiKey, proxyHost, proxyPort) { @@ -256,10 +259,11 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, Timeout = new TimeSpan(0, 1, 0) } }; + _client.ThrowPendingUpdates = throwPendingUpdates; return this; } - public IBotCommandsStage WithHttpClient(HttpClient tgclient) + public IBotCommandsStage WithHttpClient(HttpClient tgclient, bool throwPendingUpdates = false) { _client = new MessageClient(_apiKey, tgclient) { @@ -268,6 +272,7 @@ public class BotBaseBuilder : IAPIKeySelectionStage, IMessageLoopSelectionStage, Timeout = new TimeSpan(0, 1, 0) } }; + _client.ThrowPendingUpdates = throwPendingUpdates; return this; } diff --git a/TelegramBotBase/Builder/Interfaces/INetworkingSelectionStage.cs b/TelegramBotBase/Builder/Interfaces/INetworkingSelectionStage.cs index 3e48b21..cd17e9d 100644 --- a/TelegramBotBase/Builder/Interfaces/INetworkingSelectionStage.cs +++ b/TelegramBotBase/Builder/Interfaces/INetworkingSelectionStage.cs @@ -9,22 +9,25 @@ public interface INetworkingSelectionStage /// Chooses a proxy as network configuration. /// /// + /// Indicates if all pending Telegram.Bot.Types.Updates should be thrown out before start polling. /// - IBotCommandsStage WithProxy(string proxyAddress); + IBotCommandsStage WithProxy(string proxyAddress, bool throwPendingUpdates = false); /// /// Do not choose a proxy as network configuration. /// + /// Indicates if all pending Telegram.Bot.Types.Updates should be thrown out before start polling. /// - IBotCommandsStage NoProxy(); + IBotCommandsStage NoProxy(bool throwPendingUpdates = false); /// /// Chooses a custom instance of TelegramBotClient. /// /// + /// Indicates if all pending Telegram.Bot.Types.Updates should be thrown out before start polling. /// - IBotCommandsStage WithBotClient(TelegramBotClient client); + IBotCommandsStage WithBotClient(TelegramBotClient client, bool throwPendingUpdates = false); /// @@ -32,13 +35,15 @@ public interface INetworkingSelectionStage /// /// /// + /// Indicates if all pending Telegram.Bot.Types.Updates should be thrown out before start polling. /// - IBotCommandsStage WithHostAndPort(string proxyHost, int Port); + IBotCommandsStage WithHostAndPort(string proxyHost, int Port, bool throwPendingUpdates = false); /// /// Uses a custom http client. /// /// + /// Indicates if all pending Telegram.Bot.Types.Updates should be thrown out before start polling. /// - IBotCommandsStage WithHttpClient(HttpClient client); + IBotCommandsStage WithHttpClient(HttpClient client, bool throwPendingUpdates = false); } \ No newline at end of file