using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Exceptions; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using TelegramBotBase.Args; using TelegramBotBase.Attributes; using TelegramBotBase.Base; using TelegramBotBase.Enums; using TelegramBotBase.Factories.MessageLoops; using TelegramBotBase.Form; using TelegramBotBase.Interfaces; using TelegramBotBase.Sessions; namespace TelegramBotBase { /// /// Bot base class for full Device/Context and Messagehandling /// /// public class BotBase { public MessageClient Client { get; set; } /// /// Your TelegramBot APIKey /// public String APIKey { get; set; } = ""; /// /// List of all running/active sessions /// public SessionBase Sessions { get; set; } /// /// Contains System commands which will be available at everytime and didnt get passed to forms, i.e. /start /// public List BotCommands { get; set; } #region "Events" private EventHandlerList __Events = new EventHandlerList(); private static object __evSessionBegins = new object(); private static object __evMessage = new object(); private static object __evSystemCall = new object(); public delegate Task BotCommandEventHandler(object sender, BotCommandEventArgs e); private static object __evException = new object(); private static object __evUnhandledCall = new object(); #endregion /// /// Enable the SessionState (you need to implement on call forms the IStateForm interface) /// public IStateMachine StateMachine { get; set; } /// /// Offers functionality to manage the creation process of the start form. /// public IStartFormFactory StartFormFactory { get; set; } public IMessageLoopFactory MessageLoopFactory { get; set; } public Dictionary SystemSettings { get; private set; } public BotBase() { this.SystemSettings = new Dictionary(); SetSetting(eSettings.MaxNumberOfRetries, 5); SetSetting(eSettings.NavigationMaximum, 10); SetSetting(eSettings.LogAllMessages, false); SetSetting(eSettings.SkipAllMessages, false); SetSetting(eSettings.SaveSessionsOnConsoleExit, false); this.BotCommands = new List(); this.Sessions = new SessionBase(); this.Sessions.BotBase = this; } /// /// Start your Bot /// public void Start() { if (this.Client == null) return; this.Client.MessageLoop += Client_MessageLoop; //this.Client.Message += Client_Message; //this.Client.MessageEdit += Client_MessageEdit; //this.Client.Action += Client_Action; if (this.StateMachine != null) { this.Sessions.LoadSessionStates(this.StateMachine); } //Enable auto session saving if (this.GetSetting(eSettings.SaveSessionsOnConsoleExit, false)) { TelegramBotBase.Tools.Console.SetHandler(() => { this.Sessions.SaveSessionStates(); }); } DeviceSession.MaxNumberOfRetries = this.GetSetting(eSettings.MaxNumberOfRetries, 5); this.Client.StartReceiving(); } private async Task Client_MessageLoop(object sender, UpdateResult e) { DeviceSession ds = this.Sessions.GetSession(e.DeviceId); if (ds == null) { ds = this.Sessions.StartSession(e.DeviceId).GetAwaiter().GetResult(); e.Device = ds; ds.LastMessage = e.RawData.Message; OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds)); } var mr = new MessageResult(e.RawData); int i = 0; //Should formulars get navigated (allow maximum of 10, to dont get loops) do { i++; //Reset navigation ds.FormSwitched = false; await MessageLoopFactory.MessageLoop(this, ds, e, mr); mr.IsFirstHandler = false; } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10)); } /// /// Stop your Bot /// public void Stop() { if (this.Client == null) return; this.Client.MessageLoop -= Client_MessageLoop; //this.Client.Message -= Client_Message; //this.Client.MessageEdit -= Client_MessageEdit; //this.Client.Action -= Client_Action; this.Client.StopReceiving(); this.Sessions.SaveSessionStates(); } /// /// Send a message to all active Sessions. /// /// /// public async Task SentToAll(String message) { if (this.Client == null) return; foreach (var s in this.Sessions.SessionList) { await this.Client.TelegramClient.SendTextMessageAsync(s.Key, message); } } //private async void Client_Message(object sender, MessageResult e) //{ // if (this.GetSetting(eSettings.SkipAllMessages, false)) // return; // try // { // DeviceSession ds = this.Sessions.GetSession(e.DeviceId); // e.Device = ds; // if (this.GetSetting(eSettings.LogAllMessages, false)) // { // OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e)); // } // ds?.OnMessageReceived(new MessageReceivedEventArgs(e.Message)); // await Client_Loop(sender, e); // } // catch (Telegram.Bot.Exceptions.ApiRequestException ex) // { // } // catch (Exception ex) // { // DeviceSession ds = this.Sessions.GetSession(e.DeviceId); // OnException(new SystemExceptionEventArgs(e.Message.Text, ds?.DeviceId ?? -1, ds, ex)); // } //} //private async Task Client_TryMessage(object sender, MessageResult e) //{ // DeviceSession ds = e.Device; // if (ds == null) // { // ds = await this.Sessions.StartSession(e.DeviceId); // e.Device = ds; // ds.LastMessage = e.Message; // OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds)); // } // ds.LastAction = DateTime.Now; // ds.LastMessage = e.Message; // //Is this a bot command ? // if (e.IsBotCommand && this.BotCommands.Count(a => "/" + a.Command == e.BotCommand) > 0) // { // var sce = new BotCommandEventArgs(e.BotCommand, e.BotCommandParameters, e.Message, ds.DeviceId, ds); // await OnBotCommand(sce); // if (sce.Handled) // return; // } // FormBase activeForm = null; // int i = 0; // //Should formulars get navigated (allow maximum of 10, to dont get loops) // do // { // i++; // //Reset navigation // ds.FormSwitched = false; // activeForm = ds.ActiveForm; // //Pre Loading Event // await activeForm.PreLoad(e); // //Send Load event to controls // await activeForm.LoadControls(e); // //Loading Event // await activeForm.Load(e); // //Is Attachment ? (Photo, Audio, Video, Contact, Location, Document) // if (e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Contact | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Document | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Location | // e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Photo | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Video | e.Message.Type == Telegram.Bot.Types.Enums.MessageType.Audio) // { // await activeForm.SentData(new DataResult(e)); // } // //Render Event // if (!ds.FormSwitched) // { // await activeForm.RenderControls(e); // await activeForm.Render(e); // } // e.IsFirstHandler = false; // } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10)); //} //private async Task Client_Loop(object sender, MessageResult e) //{ // DeviceSession ds = e.Device; // if (ds == null) // { // ds = await this.Sessions.StartSession(e.DeviceId); // e.Device = ds; // ds.LastMessage = e.Message; // OnSessionBegins(new SessionBeginEventArgs(e.DeviceId, ds)); // } // ds.LastAction = DateTime.Now; // ds.LastMessage = e.Message; // //Is this a bot command ? // if (e.IsBotCommand && this.BotCommands.Count(a => "/" + a.Command == e.BotCommand) > 0) // { // var sce = new BotCommandEventArgs(e.BotCommand, e.BotCommandParameters, e.Message, ds.DeviceId, ds); // await OnBotCommand(sce); // if (sce.Handled) // return; // } // FormBase activeForm = null; // int i = 0; // //Should formulars get navigated (allow maximum of 10, to dont get loops) // do // { // i++; // //Reset navigation // ds.FormSwitched = false; // activeForm = ds.ActiveForm; // //Pre Loading Event // await activeForm.PreLoad(e); // //Send Load event to controls // await activeForm.LoadControls(e); // //Loading Event // await activeForm.Load(e); // //Is Attachment ? (Photo, Audio, Video, Contact, Location, Document) // if (e.MessageType == Telegram.Bot.Types.Enums.MessageType.Contact | e.MessageType == Telegram.Bot.Types.Enums.MessageType.Document | e.MessageType == Telegram.Bot.Types.Enums.MessageType.Location | // e.MessageType == Telegram.Bot.Types.Enums.MessageType.Photo | e.MessageType == Telegram.Bot.Types.Enums.MessageType.Video | e.MessageType == Telegram.Bot.Types.Enums.MessageType.Audio) // { // await activeForm.SentData(new DataResult(e)); // } // //Action Event // if (!ds.FormSwitched && e.IsAction) // { // //Send Action event to controls // await activeForm.ActionControls(e); // //Send Action event to form itself // await activeForm.Action(e); // if (!e.Handled) // { // var uhc = new UnhandledCallEventArgs(e.Message.Text, e.RawData, ds.DeviceId, e.MessageId, e.Message, ds); // OnUnhandledCall(uhc); // if (uhc.Handled) // { // e.Handled = true; // if (!ds.FormSwitched) // { // break; // } // } // } // } // if (!ds.FormSwitched) // { // //Render Event // await activeForm.RenderControls(e); // await activeForm.Render(e); // } // e.IsFirstHandler = false; // } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10)); //} /// /// This will invoke the full message loop for the device even when no "userevent" like message or action has been raised. /// /// Contains the device/chat id of the device to update. public async Task InvokeMessageLoop(long DeviceId) { var mr = new MessageResult(); await InvokeMessageLoop(DeviceId, mr); } /// /// This will invoke the full message loop for the device even when no "userevent" like message or action has been raised. /// /// Contains the device/chat id of the device to update. /// public async Task InvokeMessageLoop(long DeviceId, MessageResult e) { try { DeviceSession ds = this.Sessions.GetSession(DeviceId); e.Device = ds; await MessageLoopFactory.MessageLoop(this, ds, new UpdateResult(e.UpdateData, ds), e); //await Client_Loop(this, e); } catch (Exception ex) { DeviceSession ds = this.Sessions.GetSession(DeviceId); OnException(new SystemExceptionEventArgs(e.Message.Text, DeviceId, ds, ex)); } } //private async void Client_MessageEdit(object sender, MessageResult e) //{ // if (this.GetSetting(eSettings.SkipAllMessages, false)) // return; // try // { // DeviceSession ds = this.Sessions.GetSession(e.DeviceId); // e.Device = ds; // if (this.GetSetting(eSettings.LogAllMessages, false)) // { // OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e)); // } // //Call same, to handle received liked edited // ds?.OnMessageReceived(new MessageReceivedEventArgs(e.Message)); // await Client_TryMessageEdit(sender, e); // } // catch (Telegram.Bot.Exceptions.ApiRequestException ex) // { // } // catch (Exception ex) // { // DeviceSession ds = this.Sessions.GetSession(e.DeviceId); // OnException(new SystemExceptionEventArgs(e.Message.Text, ds?.DeviceId ?? -1, ds, ex)); // } //} //private async Task Client_TryMessageEdit(object sender, MessageResult e) //{ // DeviceSession ds = e.Device; // if (ds == null) // { // ds = await this.Sessions.StartSession(e.DeviceId); // e.Device = ds; // } // ds.LastAction = DateTime.Now; // ds.LastMessage = e.Message; // //Pre Loading Event // await ds.ActiveForm.Edited(e); // //When form has been switched due navigation within the edit method, reopen Client_Message // if (ds.FormSwitched) // { // await Client_Loop(sender, e); // } //} //private async void Client_Action(object sender, MessageResult e) //{ // try // { // DeviceSession ds = this.Sessions.GetSession(e.DeviceId); // e.Device = ds; // if (this.GetSetting(eSettings.LogAllMessages, false)) // { // OnMessage(new MessageIncomeEventArgs(e.DeviceId, ds, e)); // } // await Client_Loop(sender, e); // } // catch (Exception ex) // { // DeviceSession ds = this.Sessions.GetSession(e.DeviceId); // OnException(new SystemExceptionEventArgs(e.Message.Text, ds?.DeviceId ?? -1, ds, ex)); // } //} public void MessageLoopFactory_UnhandledCall(object sender, UnhandledCallEventArgs e) { OnUnhandledCall(e); } //private async void Client_TryAction(object sender, MessageResult e) //{ // DeviceSession ds = e.Device; // if (ds == null) // { // ds = await this.Sessions.StartSession(e.DeviceId); // e.Device = ds; // } // ds.LastAction = DateTime.Now; // ds.LastMessage = e.Message; // FormBase activeForm = null; // int i = 0; // //Should formulars get navigated (allow maximum of 10, to dont get loops) // do // { // i++; // //Reset navigation // ds.FormSwitched = false; // activeForm = ds.ActiveForm; // //Pre Loading Event // await activeForm.PreLoad(e); // //Send Load event to controls // await activeForm.LoadControls(e); // //Loading Event // await activeForm.Load(e); // //Action Event // if (!ds.FormSwitched) // { // //Send Action event to controls // await activeForm.ActionControls(e); // //Send Action event to form itself // await activeForm.Action(e); // if (!e.Handled) // { // var uhc = new UnhandledCallEventArgs(e.Message.Text, e.RawData, ds.DeviceId, e.MessageId, e.Message, ds); // OnUnhandledCall(uhc); // if (uhc.Handled) // { // e.Handled = true; // if (!ds.FormSwitched) // { // break; // } // } // } // } // //Render Event // if (!ds.FormSwitched) // { // await activeForm.RenderControls(e); // await activeForm.Render(e); // } // e.IsFirstHandler = false; // } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10)); //} /// /// This method will update all local created bot commands to the botfather. /// public async Task UploadBotCommands() { await this.Client.SetBotCommands(this.BotCommands); } /// /// Could set a variety of settings to improve the bot handling. /// /// /// public void SetSetting(eSettings set, uint Value) { this.SystemSettings[set] = Value; } /// /// Could set a variety of settings to improve the bot handling. /// /// /// public void SetSetting(eSettings set, bool Value) { this.SystemSettings[set] = (Value ? 1u : 0u); } /// /// Could get the current value of a setting /// /// /// /// public uint GetSetting(eSettings set, uint defaultValue) { if (!this.SystemSettings.ContainsKey(set)) return defaultValue; return this.SystemSettings[set]; } /// /// Could get the current value of a setting /// /// /// /// public bool GetSetting(eSettings set, bool defaultValue) { if (!this.SystemSettings.ContainsKey(set)) return defaultValue; return this.SystemSettings[set] == 0u ? false : true; } #region "Events" /// /// Will be called if a session/context gets started /// public event EventHandler SessionBegins { add { this.__Events.AddHandler(__evSessionBegins, value); } remove { this.__Events.RemoveHandler(__evSessionBegins, value); } } public void OnSessionBegins(SessionBeginEventArgs e) { (this.__Events[__evSessionBegins] as EventHandler)?.Invoke(this, e); } /// /// Will be called on incomming message /// public event EventHandler Message { add { this.__Events.AddHandler(__evMessage, value); } remove { this.__Events.RemoveHandler(__evMessage, value); } } public void OnMessage(MessageIncomeEventArgs e) { (this.__Events[__evMessage] as EventHandler)?.Invoke(this, e); } /// /// Will be called if a bot command gets raised /// public event BotCommandEventHandler BotCommand; public async Task OnBotCommand(BotCommandEventArgs e) { if (this.BotCommand != null) await BotCommand(this, e); } /// /// Will be called on an inner exception /// public event EventHandler Exception { add { this.__Events.AddHandler(__evException, value); } remove { this.__Events.RemoveHandler(__evException, value); } } public void OnException(SystemExceptionEventArgs e) { (this.__Events[__evException] as EventHandler)?.Invoke(this, e); } /// /// Will be called if no form handeled this call /// public event EventHandler UnhandledCall { add { this.__Events.AddHandler(__evUnhandledCall, value); } remove { this.__Events.RemoveHandler(__evUnhandledCall, value); } } public void OnUnhandledCall(UnhandledCallEventArgs e) { (this.__Events[__evUnhandledCall] as EventHandler)?.Invoke(this, e); } #endregion } }