diff --git a/.gitignore b/.gitignore index e49c333..91d25bb 100644 --- a/.gitignore +++ b/.gitignore @@ -252,3 +252,8 @@ TelegramBotBase/Archive /TelegramBotBase/TelegramBotBase.1.5.2.zip /TelegramBotBase/cpush.ps1 /TelegramBotBase/cpack.ps1 +*.ps1 +*.exe +*.snupkg +*.zip +*.nuspec diff --git a/Examples/AsyncFormUpdates/App.config b/Examples/AsyncFormUpdates/App.config index 56efbc7..8ffc026 100644 --- a/Examples/AsyncFormUpdates/App.config +++ b/Examples/AsyncFormUpdates/App.config @@ -1,6 +1,378 @@ - + - - + + - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/AsyncFormUpdates/Program.cs b/Examples/AsyncFormUpdates/Program.cs index f249391..b12cb83 100644 --- a/Examples/AsyncFormUpdates/Program.cs +++ b/Examples/AsyncFormUpdates/Program.cs @@ -4,18 +4,21 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using System.Timers; +using TelegramBotBase.Builder; namespace AsyncFormUpdates { class Program { - static TelegramBotBase.BotBase bot = null; + static TelegramBotBase.BotBase bot = null; static void Main(string[] args) { String apiKey = "APIKey"; - bot = new TelegramBotBase.BotBase(apiKey); + bot = BotBaseBuilder.Create() + .QuickStart(apiKey) + .Build(); bot.Start(); diff --git a/Examples/EFCoreBot/Database/BotDbContext.cs b/Examples/EFCoreBot/Database/BotDbContext.cs new file mode 100644 index 0000000..18a3c4a --- /dev/null +++ b/Examples/EFCoreBot/Database/BotDbContext.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace EFCoreBot.Database; + +public class BotDbContext : DbContext +{ + public BotDbContext(DbContextOptions options) : base(options) + { + } + + public DbSet Users { get; set; } +} diff --git a/Examples/EFCoreBot/Database/User.cs b/Examples/EFCoreBot/Database/User.cs new file mode 100644 index 0000000..e106815 --- /dev/null +++ b/Examples/EFCoreBot/Database/User.cs @@ -0,0 +1,7 @@ +namespace EFCoreBot.Database; + +public class User +{ + public long Id { get; set; } + public string LastMessage { get; set; } +} diff --git a/Examples/EFCoreBot/EFCoreBot.csproj b/Examples/EFCoreBot/EFCoreBot.csproj new file mode 100644 index 0000000..7421594 --- /dev/null +++ b/Examples/EFCoreBot/EFCoreBot.csproj @@ -0,0 +1,19 @@ + + + + Exe + net6.0 + enable + disable + + + + + + + + + + + + diff --git a/Examples/EFCoreBot/Program.cs b/Examples/EFCoreBot/Program.cs new file mode 100644 index 0000000..fa427ee --- /dev/null +++ b/Examples/EFCoreBot/Program.cs @@ -0,0 +1,23 @@ +using EFCoreBot; +using EFCoreBot.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using TelegramBotBase.Builder; + +var serviceCollection = new ServiceCollection() + .AddDbContext(x => x.UseInMemoryDatabase("TelegramBotBase")); + +var serviceProvider = serviceCollection.BuildServiceProvider(); + +var bot = BotBaseBuilder.Create() + .WithAPIKey(Environment.GetEnvironmentVariable("API_KEY") ?? throw new Exception("API_KEY is not set")) + .DefaultMessageLoop() + .WithServiceProvider(serviceProvider) + .NoProxy() + .NoCommands() + .NoSerialization() + .DefaultLanguage() + .Build(); + +bot.Start(); +await Task.Delay(-1); diff --git a/Examples/EFCoreBot/StartForm.cs b/Examples/EFCoreBot/StartForm.cs new file mode 100644 index 0000000..1bfee77 --- /dev/null +++ b/Examples/EFCoreBot/StartForm.cs @@ -0,0 +1,36 @@ +using EFCoreBot.Database; +using TelegramBotBase.Base; +using TelegramBotBase.Form; + +namespace EFCoreBot; + +public class StartForm : FormBase +{ + private readonly BotDbContext _dbContext; + + public StartForm(BotDbContext dbContext) + { + _dbContext = dbContext; + } + + public override async Task Load(MessageResult message) + { + var user = await _dbContext.Users.FindAsync(Device.DeviceId); + if (user is null) + { + user = new User + { + Id = Device.DeviceId, + LastMessage = "" + }; + + _dbContext.Users.Add(user); + await _dbContext.SaveChangesAsync(); + } + + await Device.Send($"Your last message's text was: `{user.LastMessage}`"); + + user.LastMessage = string.IsNullOrWhiteSpace(message.MessageText) ? "" : message.MessageText; + await _dbContext.SaveChangesAsync(); + } +} diff --git a/Examples/JoinHiderBot/JoinHiderBot.csproj b/Examples/JoinHiderBot/JoinHiderBot.csproj index 1c137aa..aa8f8d7 100644 --- a/Examples/JoinHiderBot/JoinHiderBot.csproj +++ b/Examples/JoinHiderBot/JoinHiderBot.csproj @@ -2,11 +2,11 @@ Exe - netcoreapp3.1 + net6.0 - + diff --git a/Examples/JoinHiderBot/Program.cs b/Examples/JoinHiderBot/Program.cs index e3c2ec5..d2d05fe 100644 --- a/Examples/JoinHiderBot/Program.cs +++ b/Examples/JoinHiderBot/Program.cs @@ -1,4 +1,5 @@ using System; +using TelegramBotBase.Builder; namespace JoinHiderBot { @@ -9,7 +10,9 @@ namespace JoinHiderBot String apiKey = ""; - var bot = new TelegramBotBase.BotBase(apiKey); + var bot = BotBaseBuilder.Create() + .QuickStart(apiKey) + .Build(); bot.Start(); diff --git a/Examples/SystemCommandsBot/Program.cs b/Examples/SystemCommandsBot/Program.cs index efe0e93..17ff8b7 100644 --- a/Examples/SystemCommandsBot/Program.cs +++ b/Examples/SystemCommandsBot/Program.cs @@ -1,4 +1,5 @@ using System; +using TelegramBotBase.Builder; namespace SystemCommandsBot { @@ -19,7 +20,9 @@ namespace SystemCommandsBot return; } - var bot = new TelegramBotBase.BotBase(BotConfig.ApiKey); + var bot = BotBaseBuilder.Create() + .QuickStart(BotConfig.ApiKey) + .Build(); bot.Start(); diff --git a/TelegramBotBase.Extensions.Images/README.md b/TelegramBotBase.Extensions.Images/README.md index cdef1e3..2611a85 100644 --- a/TelegramBotBase.Extensions.Images/README.md +++ b/TelegramBotBase.Extensions.Images/README.md @@ -1,8 +1,8 @@ # TelegramBotBase.Extensions.Images [![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.Extensions.Images.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images/) -[![telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) +[![Telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) -[![license](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) -[![downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Images.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images) +[![License](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) +[![Package Downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Images.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Images) diff --git a/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj b/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj index 4b974c8..0b84053 100644 --- a/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj +++ b/TelegramBotBase.Extensions.Images/TelegramBotBase.Extensions.Images.csproj @@ -15,11 +15,10 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - \ No newline at end of file + diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs new file mode 100644 index 0000000..fbf22db --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/BotBaseBuilderExtensions.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TelegramBotBase.Builder; +using TelegramBotBase.Builder.Interfaces; + +namespace TelegramBotBase.Extensions.Serializer.Database.MSSQL +{ + public static class BotBaseBuilderExtensions + { + + /// + /// Uses an Microsoft SQL Server Database to save and restore sessions. + /// + /// + /// + /// + /// + /// + public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String ConnectionString, Type fallbackForm = null, String tablePrefix = "tgb_") + { + var serializer = new MSSQLSerializer(ConnectionString, tablePrefix, fallbackForm); + + builder.UseSerialization(serializer); + + return builder as BotBaseBuilder; + } + + + /// + /// Uses an Microsoft SQL Server Database to save and restore sessions. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String HostOrIP, String DatabaseName, String UserId, String Password, Type fallbackForm = null, String tablePrefix = "tgb_") + { + var connectionString = $"Server={HostOrIP}; Database={DatabaseName}; User Id={UserId}; Password={Password}; TrustServerCertificate=true;"; + + var serializer = new MSSQLSerializer(connectionString, tablePrefix, fallbackForm); + + builder.UseSerialization(serializer); + + return builder as BotBaseBuilder; + } + + /// + /// Uses an Microsoft SQL Server Database with Windows Authentication to save and restore sessions. + /// + /// + /// + /// + /// + /// + /// + public static ILanguageSelectionStage UseSQLDatabase(this ISessionSerializationStage builder, String HostOrIP, String DatabaseName, bool IntegratedSecurity = true, Type fallbackForm = null, String tablePrefix = "tgb_") + { + if (!IntegratedSecurity) + throw new ArgumentOutOfRangeException(); + + var connectionString = $"Server={HostOrIP}; Database={DatabaseName}; Integrated Security=true; TrustServerCertificate=true;"; + + var serializer = new MSSQLSerializer(connectionString, tablePrefix, fallbackForm); + + builder.UseSerialization(serializer); + + return builder as BotBaseBuilder; + } + } +} diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs new file mode 100644 index 0000000..5aca6e4 --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/MSSQLSerializer.cs @@ -0,0 +1,186 @@ +using TelegramBotBase.Interfaces; +using TelegramBotBase.Builder.Interfaces; +using System; +using TelegramBotBase.Base; +using TelegramBotBase.Args; +using TelegramBotBase.Form; +using Microsoft.Data.SqlClient; +using System.Data; + +namespace TelegramBotBase.Extensions.Serializer.Database.MSSQL +{ + public class MSSQLSerializer : IStateMachine + { + public Type FallbackStateForm { get; set; } + public string ConnectionString { get; } + public String TablePrefix { get; set; } + + /// + /// Will initialize the state machine. + /// + /// Path of the file and name where to save the session details. + /// Type of Form which will be saved instead of Form which has attribute declared. Needs to be subclass of . + /// Declares of the file could be overwritten. + public MSSQLSerializer(String ConnectionString, String tablePrefix = "tgb_", Type fallbackStateForm = null) + { + if (ConnectionString is null) + { + throw new ArgumentNullException(nameof(ConnectionString)); + } + + this.ConnectionString = ConnectionString; + + this.TablePrefix = tablePrefix; + + this.FallbackStateForm = fallbackStateForm; + + if (this.FallbackStateForm != null && !this.FallbackStateForm.IsSubclassOf(typeof(FormBase))) + { + throw new ArgumentException("FallbackStateForm is not a subclass of FormBase"); + } + } + + public StateContainer LoadFormStates() + { + var sc = new StateContainer(); + + using (var connection = new SqlConnection(ConnectionString)) + { + connection.Open(); + + var command = connection.CreateCommand(); + command.CommandText = "SELECT deviceId, deviceTitle, FormUri, QualifiedName FROM " + TablePrefix + "devices_sessions"; + + var dataTable = new DataTable(); + using (var dataAdapter = new SqlDataAdapter(command)) + { + dataAdapter.Fill(dataTable); + + foreach (DataRow r in dataTable.Rows) + { + var se = new StateEntry() + { + DeviceId = (long)r["deviceId"], + ChatTitle = r["deviceTitle"].ToString(), + FormUri = r["FormUri"].ToString(), + QualifiedName = r["QualifiedName"].ToString() + }; + + sc.States.Add(se); + + if (se.DeviceId > 0) + { + sc.ChatIds.Add(se.DeviceId); + } + else + { + sc.GroupIds.Add(se.DeviceId); + } + + var data_command = connection.CreateCommand(); + data_command.CommandText = "SELECT [key], value, type FROM " + TablePrefix + "devices_sessions_data WHERE deviceId = @deviceId"; + data_command.Parameters.Add(new SqlParameter("@deviceId", r["deviceId"])); + + var data_table = new DataTable(); + using (var dataAdapter2 = new SqlDataAdapter(data_command)) + { + dataAdapter2.Fill(data_table); + + foreach (DataRow r2 in data_table.Rows) + { + var key = r2["key"].ToString(); + var type = Type.GetType(r2["type"].ToString()); + + var value = Newtonsoft.Json.JsonConvert.DeserializeObject(r2["value"].ToString(), type); + + se.Values.Add(key, value); + } + } + + } + + } + + + + connection.Close(); + } + + return sc; + } + + public void SaveFormStates(SaveStatesEventArgs e) + { + var container = e.States; + + using (var connection = new SqlConnection(ConnectionString)) + { + connection.Open(); + + //Cleanup old Session data + var clear_command = connection.CreateCommand(); + + clear_command.CommandText = $"DELETE FROM {TablePrefix}devices_sessions_data"; + + clear_command.ExecuteNonQuery(); + + clear_command.CommandText = $"DELETE FROM {TablePrefix}devices_sessions"; + + clear_command.ExecuteNonQuery(); + + //Prepare new session commands + var session_command = connection.CreateCommand(); + var data_command = connection.CreateCommand(); + + session_command.CommandText = "INSERT INTO " + TablePrefix + "devices_sessions (deviceId, deviceTitle, FormUri, QualifiedName) VALUES (@deviceId, @deviceTitle, @FormUri, @QualifiedName)"; + session_command.Parameters.Add(new SqlParameter("@deviceId", "")); + session_command.Parameters.Add(new SqlParameter("@deviceTitle", "")); + session_command.Parameters.Add(new SqlParameter("@FormUri", "")); + session_command.Parameters.Add(new SqlParameter("@QualifiedName", "")); + + data_command.CommandText = "INSERT INTO " + TablePrefix + "devices_sessions_data (deviceId, [key], value, type) VALUES (@deviceId, @key, @value, @type)"; + data_command.Parameters.Add(new SqlParameter("@deviceId", "")); + data_command.Parameters.Add(new SqlParameter("@key", "")); + data_command.Parameters.Add(new SqlParameter("@value", "")); + data_command.Parameters.Add(new SqlParameter("@type", "")); + + //Store session data in database + foreach (var state in container.States) + { + session_command.Parameters["@deviceId"].Value = state.DeviceId; + session_command.Parameters["@deviceTitle"].Value = state.ChatTitle ?? ""; + session_command.Parameters["@FormUri"].Value = state.FormUri; + session_command.Parameters["@QualifiedName"].Value = state.QualifiedName; + + session_command.ExecuteNonQuery(); + + foreach (var data in state.Values) + { + data_command.Parameters["@deviceId"].Value = state.DeviceId; + data_command.Parameters["@key"].Value = data.Key; + + var type = data.Value.GetType(); + + if (type.IsPrimitive || type.Equals(typeof(string))) + { + data_command.Parameters["@value"].Value = data.Value; + } + else + { + data_command.Parameters["@value"].Value = Newtonsoft.Json.JsonConvert.SerializeObject(data.Value); + } + + data_command.Parameters["@type"].Value = type.AssemblyQualifiedName; + + data_command.ExecuteNonQuery(); + } + + } + + connection.Close(); + } + + + } + } +} \ No newline at end of file diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md new file mode 100644 index 0000000..1a7f027 --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/README.md @@ -0,0 +1,28 @@ +# TelegramBotBase.Extensions.Serializer.Database.MSSQL + +[![NuGet version (TelegramBotBase)](https://img.shields.io/nuget/v/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL/) +[![Telegram chat](https://img.shields.io/badge/Support_Chat-Telegram-blue.svg?style=flat-square)](https://www.t.me/tgbotbase) + + +[![License](https://img.shields.io/github/license/MajMcCloud/telegrambotframework.svg?style=flat-square&maxAge=2592000&label=License)](https://raw.githubusercontent.com/MajMcCloud/TelegramBotFramework/master/LICENCE.md) +[![Package Downloads](https://img.shields.io/nuget/dt/TelegramBotBase.Extensions.Serializer.Database.MSSQL.svg?style=flat-square&label=Package%20Downloads)](https://www.nuget.org/packages/TelegramBotBase.Extensions.Serializer.Database.MSSQL) + +## How to use + +```csharp +using TelegramBotBase.Extensions.Serializer.Database.MSSQL; + + +var bot = BotBaseBuilder + .Create() + .WithAPIKey(APIKey) + .DefaultMessageLoop() + .WithStartForm() + .NoProxy() + .OnlyStart() + .UseSQLDatabase("localhost", "telegram_bot") + .UseEnglish() + .Build(); + +bot.Start(); +``` diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj new file mode 100644 index 0000000..a0d40f7 --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj @@ -0,0 +1,30 @@ + + + + netstandard2.0;net5;netcoreapp3.1;net6 + True + https://github.com/MajMcCloud/TelegramBotFramework + https://github.com/MajMcCloud/TelegramBotFramework + MIT + true + snupkg + 1.0.1 + 1.0.1 + 1.0.1 + A session serializer for Microsoft SQL Server. + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql new file mode 100644 index 0000000..587eb4f --- /dev/null +++ b/TelegramBotBase.Extensions.Serializer.Database.MSSQL/create_tables.sql @@ -0,0 +1,37 @@ +USE [telegram_bot] +GO +/****** Object: Table [dbo].[tgb_devices_sessions] Script Date: 30.06.2022 16:22:09 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[tgb_devices_sessions]( + [deviceId] [bigint] NOT NULL, + [deviceTitle] [nvarchar](512) NOT NULL, + [FormUri] [nvarchar](512) NOT NULL, + [QualifiedName] [nvarchar](512) NOT NULL, + CONSTRAINT [PK_tgb_devices_sessions_1] PRIMARY KEY CLUSTERED +( + [deviceId] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO +/****** Object: Table [dbo].[tgb_devices_sessions_data] Script Date: 30.06.2022 16:22:09 ******/ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO +CREATE TABLE [dbo].[tgb_devices_sessions_data]( + [Id] [uniqueidentifier] NOT NULL, + [deviceId] [bigint] NOT NULL, + [key] [nvarchar](512) NOT NULL, + [value] [nvarchar](max) NOT NULL, + [type] [nvarchar](512) NOT NULL, + CONSTRAINT [PK_tgb_devices_session_data] PRIMARY KEY CLUSTERED +( + [Id] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO +ALTER TABLE [dbo].[tgb_devices_sessions_data] ADD CONSTRAINT [DF_tgb_devices_session_data_Id] DEFAULT (newid()) FOR [Id] +GO diff --git a/TelegramBotBase.Test/Program.cs b/TelegramBotBase.Test/Program.cs index 55ac0aa..6e3eb4c 100644 --- a/TelegramBotBase.Test/Program.cs +++ b/TelegramBotBase.Test/Program.cs @@ -14,7 +14,7 @@ namespace TelegramBotBaseTest { class Program { - static void Main(string[] args) + static async void Main(string[] args) { String APIKey = ""; @@ -28,6 +28,7 @@ namespace TelegramBotBaseTest .CustomCommands(a => { a.Start("Starts the bot"); + a.Add("myid", "Returns my Device ID"); a.Help("Should show you some help"); a.Settings("Should show you some settings"); a.Add("form1", "Opens test form 1"); @@ -39,48 +40,10 @@ namespace TelegramBotBaseTest .Build(); - bb.BotCommand += async (s, en) => - { - switch (en.Command) - { - case "/start": - - var start = new Menu(); - - await en.Device.ActiveForm.NavigateTo(start); - - break; - case "/form1": - - var form1 = new TestForm(); - - await en.Device.ActiveForm.NavigateTo(form1); - - break; - - case "/form2": - - var form2 = new TestForm2(); - - await en.Device.ActiveForm.NavigateTo(form2); - - break; - - case "/params": - - String m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b); - - await en.Device.Send("Your parameters are: " + m, replyTo: en.Device.LastMessageId); - - en.Handled = true; - - break; - } - - }; + bb.BotCommand += Bb_BotCommand; //Update Bot commands to botfather - bb.UploadBotCommands().Wait(); + await bb.UploadBotCommands(); bb.SetSetting(TelegramBotBase.Enums.eSettings.LogAllMessages, true); @@ -91,8 +54,6 @@ namespace TelegramBotBaseTest bb.Start(); - - Console.WriteLine("Telegram Bot started..."); Console.WriteLine("Press q to quit application."); @@ -104,6 +65,54 @@ namespace TelegramBotBaseTest } + private static async Task Bb_BotCommand(object sender, TelegramBotBase.Args.BotCommandEventArgs en) + { + switch (en.Command) + { + case "/start": + + var start = new Menu(); + + await en.Device.ActiveForm.NavigateTo(start); + + break; + case "/form1": + + var form1 = new TestForm(); + + await en.Device.ActiveForm.NavigateTo(form1); + + + break; + + + case "/form2": + + var form2 = new TestForm2(); + + await en.Device.ActiveForm.NavigateTo(form2); + + break; + + case "/myid": + + await en.Device.Send($"Your Device ID is: {en.DeviceId}"); + + en.Handled = true; + + break; + + case "/params": + + String m = en.Parameters.DefaultIfEmpty("").Aggregate((a, b) => a + " and " + b); + + await en.Device.Send("Your parameters are: " + m, replyTo: en.Device.LastMessageId); + + en.Handled = true; + + break; + } + } } } diff --git a/TelegramBotBase/Args/MessageSentEventArgs.cs b/TelegramBotBase/Args/MessageSentEventArgs.cs index d096db1..9cfe651 100644 --- a/TelegramBotBase/Args/MessageSentEventArgs.cs +++ b/TelegramBotBase/Args/MessageSentEventArgs.cs @@ -7,7 +7,7 @@ using Telegram.Bot.Types; namespace TelegramBotBase.Args { - public class MessageSentEventArgs + public class MessageSentEventArgs : EventArgs { public int MessageId { diff --git a/TelegramBotBase/Base/DataResult.cs b/TelegramBotBase/Base/DataResult.cs index 8fc9e34..fb87df0 100644 --- a/TelegramBotBase/Base/DataResult.cs +++ b/TelegramBotBase/Base/DataResult.cs @@ -108,8 +108,9 @@ namespace TelegramBotBase.Base public async Task DownloadDocument() { - var encryptedContent = new System.IO.MemoryStream(this.Document.FileSize.Value); - var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, encryptedContent); + var encryptedContent = new System.IO.MemoryStream(); + encryptedContent.SetLength(this.Document.FileSize.Value); + var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, this.Document.FileName); } @@ -122,9 +123,9 @@ namespace TelegramBotBase.Base /// public async Task DownloadDocument(String path) { - var file = await this.Client.TelegramClient.GetFileAsync(this.Document.FileId); + var file = await Device.Client.TelegramClient.GetFileAsync(this.Document.FileId); FileStream fs = new FileStream(path, FileMode.Create); - await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); + await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); fs.Close(); fs.Dispose(); } @@ -136,7 +137,7 @@ namespace TelegramBotBase.Base public async Task DownloadRawDocument() { MemoryStream ms = new MemoryStream(); - await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms); + await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms); return ms.ToArray(); } @@ -156,7 +157,7 @@ namespace TelegramBotBase.Base public async Task DownloadRawTextDocument(Encoding encoding) { MemoryStream ms = new MemoryStream(); - await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms); + await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Document.FileId, ms); ms.Position = 0; @@ -167,34 +168,36 @@ namespace TelegramBotBase.Base public async Task DownloadVideo() { - var encryptedContent = new System.IO.MemoryStream(this.Video.FileSize.Value); - var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Video.FileId, encryptedContent); + var encryptedContent = new System.IO.MemoryStream(); + encryptedContent.SetLength(this.Video.FileSize.Value); + var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Video.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); } public async Task DownloadVideo(String path) { - var file = await this.Client.TelegramClient.GetFileAsync(this.Video.FileId); + var file = await Device.Client.TelegramClient.GetFileAsync(this.Video.FileId); FileStream fs = new FileStream(path, FileMode.Create); - await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); + await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); fs.Close(); fs.Dispose(); } public async Task DownloadAudio() { - var encryptedContent = new System.IO.MemoryStream(this.Audio.FileSize.Value); - var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Audio.FileId, encryptedContent); + var encryptedContent = new System.IO.MemoryStream(); + encryptedContent.SetLength(this.Audio.FileSize.Value); + var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(this.Audio.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); } public async Task DownloadAudio(String path) { - var file = await this.Client.TelegramClient.GetFileAsync(this.Audio.FileId); + var file = await Device.Client.TelegramClient.GetFileAsync(this.Audio.FileId); FileStream fs = new FileStream(path, FileMode.Create); - await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); + await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); fs.Close(); fs.Dispose(); } @@ -202,8 +205,9 @@ namespace TelegramBotBase.Base public async Task DownloadPhoto(int index) { var photo = this.Photos[index]; - var encryptedContent = new System.IO.MemoryStream(photo.FileSize.Value); - var file = await this.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent); + var encryptedContent = new System.IO.MemoryStream(); + encryptedContent.SetLength(photo.FileSize.Value); + var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent); return new InputOnlineFile(encryptedContent, ""); } @@ -211,9 +215,9 @@ namespace TelegramBotBase.Base public async Task DownloadPhoto(int index, String path) { var photo = this.Photos[index]; - var file = await this.Client.TelegramClient.GetFileAsync(photo.FileId); + var file = await Device.Client.TelegramClient.GetFileAsync(photo.FileId); FileStream fs = new FileStream(path, FileMode.Create); - await this.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); + await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs); fs.Close(); fs.Dispose(); } diff --git a/TelegramBotBase/Base/FormBase.cs b/TelegramBotBase/Base/FormBase.cs index fb1cb69..291e733 100644 --- a/TelegramBotBase/Base/FormBase.cs +++ b/TelegramBotBase/Base/FormBase.cs @@ -55,9 +55,6 @@ namespace TelegramBotBase.Form public async Task OnInit(InitEventArgs e) { - if (this.Events[__evInit] == null) - return; - var handler = this.Events[__evInit]?.GetInvocationList().Cast>(); if (handler == null) return; @@ -87,9 +84,6 @@ namespace TelegramBotBase.Form public async Task OnOpened(EventArgs e) { - if (this.Events[__evOpened] == null) - return; - var handler = this.Events[__evOpened]?.GetInvocationList().Cast>(); if (handler == null) return; @@ -120,9 +114,6 @@ namespace TelegramBotBase.Form public async Task OnClosed(EventArgs e) { - if (this.Events[__evClosed] == null) - return; - var handler = this.Events[__evClosed]?.GetInvocationList().Cast>(); if (handler == null) return; diff --git a/TelegramBotBase/Base/MessageClient.cs b/TelegramBotBase/Base/MessageClient.cs index e252f35..85195f9 100644 --- a/TelegramBotBase/Base/MessageClient.cs +++ b/TelegramBotBase/Base/MessageClient.cs @@ -159,27 +159,35 @@ namespace TelegramBotBase.Base /// This will return the current list of bot commands. /// /// - public async Task GetBotCommands() + public async Task GetBotCommands(BotCommandScope scope = null, String languageCode = null) { - return await this.TelegramClient.GetMyCommandsAsync(); + return await this.TelegramClient.GetMyCommandsAsync(scope, languageCode); } + /// /// This will set your bot commands to the given list. /// /// /// - public async Task SetBotCommands(List botcommands) + public async Task SetBotCommands(List botcommands, BotCommandScope scope = null, String languageCode = null) { - await this.TelegramClient.SetMyCommandsAsync(botcommands); + await this.TelegramClient.SetMyCommandsAsync(botcommands, scope, languageCode); } - + /// + /// This will delete the current list of bot commands. + /// + /// + public async Task DeleteBotCommands(BotCommandScope scope = null, String languageCode = null) + { + await this.TelegramClient.DeleteMyCommandsAsync(scope, languageCode); + } #region "Events" - + public event Async.AsyncEventHandler MessageLoop { diff --git a/TelegramBotBase/Base/MessageResult.cs b/TelegramBotBase/Base/MessageResult.cs index 762ac8f..ed5d4d2 100644 --- a/TelegramBotBase/Base/MessageResult.cs +++ b/TelegramBotBase/Base/MessageResult.cs @@ -29,12 +29,6 @@ namespace TelegramBotBase.Base } } - public DeviceSession Device - { - get; - set; - } - /// /// The message id /// @@ -170,7 +164,7 @@ namespace TelegramBotBase.Base } /// - /// Confirm incomming action (i.e. Button click) + /// Confirm incoming action (i.e. Button click) /// /// /// diff --git a/TelegramBotBase/Base/ResultBase.cs b/TelegramBotBase/Base/ResultBase.cs index e5d37e8..adf8ecc 100644 --- a/TelegramBotBase/Base/ResultBase.cs +++ b/TelegramBotBase/Base/ResultBase.cs @@ -4,12 +4,17 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using Telegram.Bot; +using TelegramBotBase.Sessions; namespace TelegramBotBase.Base { public class ResultBase : EventArgs { - public MessageClient Client { get; set; } + public DeviceSession Device + { + get; + set; + } public virtual long DeviceId { get; set; } @@ -42,7 +47,7 @@ namespace TelegramBotBase.Base { try { - await this.Client.TelegramClient.DeleteMessageAsync(this.DeviceId, (messageId == -1 ? this.MessageId : messageId)); + await Device.Client.TelegramClient.DeleteMessageAsync(this.DeviceId, (messageId == -1 ? this.MessageId : messageId)); } catch { diff --git a/TelegramBotBase/BotBase.cs b/TelegramBotBase/BotBase.cs index c853c30..903505c 100644 --- a/TelegramBotBase/BotBase.cs +++ b/TelegramBotBase/BotBase.cs @@ -13,7 +13,7 @@ using TelegramBotBase.Args; using TelegramBotBase.Attributes; using TelegramBotBase.Base; using TelegramBotBase.Enums; -using TelegramBotBase.Factories.MessageLoops; +using TelegramBotBase.MessageLoops; using TelegramBotBase.Form; using TelegramBotBase.Interfaces; using TelegramBotBase.Sessions; @@ -24,7 +24,7 @@ namespace TelegramBotBase /// Bot base class for full Device/Context and Messagehandling /// /// - public class BotBase + public sealed class BotBase { public MessageClient Client { get; set; } @@ -36,17 +36,17 @@ namespace TelegramBotBase /// /// List of all running/active sessions /// - public SessionBase Sessions { get; set; } + public SessionManager 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; } + public Dictionary> BotCommandScopes { get; set; } = new Dictionary>(); #region "Events" - private EventHandlerList __Events = new EventHandlerList(); + private EventHandlerList __events = new EventHandlerList(); private static object __evSessionBegins = new object(); @@ -83,9 +83,9 @@ namespace TelegramBotBase /// public Dictionary SystemSettings { get; private set; } - public BotBase() + internal BotBase() { - this.SystemSettings = new Dictionary(); + SystemSettings = new Dictionary(); SetSetting(eSettings.MaxNumberOfRetries, 5); SetSetting(eSettings.NavigationMaximum, 10); @@ -93,10 +93,9 @@ namespace TelegramBotBase SetSetting(eSettings.SkipAllMessages, false); SetSetting(eSettings.SaveSessionsOnConsoleExit, false); - this.BotCommands = new List(); + BotCommandScopes = new Dictionary>(); - this.Sessions = new SessionBase(); - this.Sessions.BotBase = this; + Sessions = new SessionManager(this); } @@ -104,31 +103,22 @@ namespace TelegramBotBase /// /// Start your Bot /// - public void Start() + public async Task Start() { - if (this.Client == null) - return; - - this.Client.MessageLoop += Client_MessageLoop; + Client.MessageLoop += Client_MessageLoop; - if (this.StateMachine != null) - { - this.Sessions.LoadSessionStates(this.StateMachine); - } + if (StateMachine != null) await Sessions.LoadSessionStates(StateMachine); + //Enable auto session saving - if (this.GetSetting(eSettings.SaveSessionsOnConsoleExit, false)) - { - TelegramBotBase.Tools.Console.SetHandler(() => - { - this.Sessions.SaveSessionStates(); - }); - } + if (GetSetting(eSettings.SaveSessionsOnConsoleExit, false)) + TelegramBotBase.Tools.Console.SetHandler(() => { Task.Run(Sessions.SaveSessionStates); }); + - DeviceSession.MaxNumberOfRetries = this.GetSetting(eSettings.MaxNumberOfRetries, 5); + DeviceSession.MaxNumberOfRetries = GetSetting(eSettings.MaxNumberOfRetries, 5); - this.Client.StartReceiving(); + Client.StartReceiving(); } @@ -137,7 +127,7 @@ namespace TelegramBotBase DeviceSession ds = this.Sessions.GetSession(e.DeviceId); if (ds == null) { - ds = this.Sessions.StartSession(e.DeviceId).GetAwaiter().GetResult(); + ds = Sessions.StartSession(e.DeviceId).GetAwaiter().GetResult(); e.Device = ds; ds.LastMessage = e.RawData.Message; @@ -160,24 +150,24 @@ namespace TelegramBotBase mr.IsFirstHandler = false; - } while (ds.FormSwitched && i < this.GetSetting(eSettings.NavigationMaximum, 10)); + } while (ds.FormSwitched && i < GetSetting(eSettings.NavigationMaximum, 10)); } /// /// Stop your Bot /// - public void Stop() + public async Task Stop() { - if (this.Client == null) + if (Client == null) return; - this.Client.MessageLoop -= Client_MessageLoop; + Client.MessageLoop -= Client_MessageLoop; - this.Client.StopReceiving(); + Client.StopReceiving(); - this.Sessions.SaveSessionStates(); + await Sessions.SaveSessionStates(); } /// @@ -187,12 +177,12 @@ namespace TelegramBotBase /// public async Task SentToAll(String message) { - if (this.Client == null) + if (Client == null) return; - foreach (var s in this.Sessions.SessionList) + foreach (var s in Sessions.SessionList) { - await this.Client.TelegramClient.SendTextMessageAsync(s.Key, message); + await Client.TelegramClient.SendTextMessageAsync(s.Key, message); } } @@ -206,6 +196,11 @@ namespace TelegramBotBase { var mr = new MessageResult(); + mr.UpdateData = new Update() + { + Message = new Message() + }; + await InvokeMessageLoop(DeviceId, mr); } @@ -247,7 +242,34 @@ namespace TelegramBotBase /// public async Task UploadBotCommands() { - await this.Client.SetBotCommands(this.BotCommands); + foreach (var bs in BotCommandScopes) + { + if (bs.Value != null) + { + await Client.SetBotCommands(bs.Value, bs.Key); + } + else + { + await Client.DeleteBotCommands(bs.Key); + } + + } + } + + /// + /// Searching if parameter is a known command in all configured BotCommandScopes. + /// + /// + /// + public bool IsKnownBotCommand(String command) + { + foreach (var scope in BotCommandScopes) + { + if (scope.Value.Any(a => "/" + a.Command == command)) + return true; + } + + return false; } /// @@ -257,7 +279,7 @@ namespace TelegramBotBase /// public void SetSetting(eSettings set, uint Value) { - this.SystemSettings[set] = Value; + SystemSettings[set] = Value; } /// @@ -267,7 +289,7 @@ namespace TelegramBotBase /// public void SetSetting(eSettings set, bool Value) { - this.SystemSettings[set] = (Value ? 1u : 0u); + SystemSettings[set] = (Value ? 1u : 0u); } /// @@ -278,10 +300,10 @@ namespace TelegramBotBase /// public uint GetSetting(eSettings set, uint defaultValue) { - if (!this.SystemSettings.ContainsKey(set)) + if (!SystemSettings.ContainsKey(set)) return defaultValue; - return this.SystemSettings[set]; + return SystemSettings[set]; } /// @@ -292,10 +314,10 @@ namespace TelegramBotBase /// public bool GetSetting(eSettings set, bool defaultValue) { - if (!this.SystemSettings.ContainsKey(set)) + if (!SystemSettings.ContainsKey(set)) return defaultValue; - return this.SystemSettings[set] == 0u ? false : true; + return SystemSettings[set] == 0u ? false : true; } #region "Events" @@ -308,17 +330,17 @@ namespace TelegramBotBase { add { - this.__Events.AddHandler(__evSessionBegins, value); + __events.AddHandler(__evSessionBegins, value); } remove { - this.__Events.RemoveHandler(__evSessionBegins, value); + __events.RemoveHandler(__evSessionBegins, value); } } public void OnSessionBegins(SessionBeginEventArgs e) { - (this.__Events[__evSessionBegins] as EventHandler)?.Invoke(this, e); + (__events[__evSessionBegins] as EventHandler)?.Invoke(this, e); } @@ -329,17 +351,17 @@ namespace TelegramBotBase { add { - this.__Events.AddHandler(__evMessage, value); + __events.AddHandler(__evMessage, value); } remove { - this.__Events.RemoveHandler(__evMessage, value); + __events.RemoveHandler(__evMessage, value); } } public void OnMessage(MessageIncomeEventArgs e) { - (this.__Events[__evMessage] as EventHandler)?.Invoke(this, e); + (__events[__evMessage] as EventHandler)?.Invoke(this, e); } @@ -351,7 +373,7 @@ namespace TelegramBotBase public async Task OnBotCommand(BotCommandEventArgs e) { - if (this.BotCommand != null) + if (BotCommand != null) await BotCommand(this, e); } @@ -362,17 +384,17 @@ namespace TelegramBotBase { add { - this.__Events.AddHandler(__evException, value); + __events.AddHandler(__evException, value); } remove { - this.__Events.RemoveHandler(__evException, value); + __events.RemoveHandler(__evException, value); } } public void OnException(SystemExceptionEventArgs e) { - (this.__Events[__evException] as EventHandler)?.Invoke(this, e); + (__events[__evException] as EventHandler)?.Invoke(this, e); } @@ -383,17 +405,17 @@ namespace TelegramBotBase { add { - this.__Events.AddHandler(__evUnhandledCall, value); + __events.AddHandler(__evUnhandledCall, value); } remove { - this.__Events.RemoveHandler(__evUnhandledCall, value); + __events.RemoveHandler(__evUnhandledCall, value); } } public void OnUnhandledCall(UnhandledCallEventArgs e) { - (this.__Events[__evUnhandledCall] as EventHandler)?.Invoke(this, e); + (__events[__evUnhandledCall] as EventHandler)?.Invoke(this, e); } diff --git a/TelegramBotBase/Builder/BotBaseBuilder.cs b/TelegramBotBase/Builder/BotBaseBuilder.cs index 517a8fb..63b3658 100644 --- a/TelegramBotBase/Builder/BotBaseBuilder.cs +++ b/TelegramBotBase/Builder/BotBaseBuilder.cs @@ -7,6 +7,7 @@ using Telegram.Bot.Types; using TelegramBotBase.Base; using TelegramBotBase.Builder.Interfaces; using TelegramBotBase.Commands; +using TelegramBotBase.Factories; using TelegramBotBase.Form; using TelegramBotBase.Interfaces; using TelegramBotBase.Localizations; @@ -23,7 +24,12 @@ namespace TelegramBotBase.Builder MessageClient _client = null; - List _botcommands = new List(); + /// + /// Contains different Botcommands for different areas. + /// + Dictionary> _BotCommandScopes { get; set; } = new Dictionary>(); + + //List _botcommands = new List(); IStateMachine _statemachine = null; @@ -111,11 +117,20 @@ namespace TelegramBotBase.Builder public IStartFormSelectionStage DefaultMessageLoop() { - _messageloopfactory = new Factories.MessageLoops.FormBaseMessageLoop(); + _messageloopfactory = new MessageLoops.FormBaseMessageLoop(); return this; } + + public IStartFormSelectionStage MinimalMessageLoop() + { + _messageloopfactory = new MessageLoops.MinimalMessageLoop(); + + return this; + } + + public IStartFormSelectionStage CustomMessageLoop(IMessageLoopFactory messageLoopClass) { _messageloopfactory = messageLoopClass; @@ -134,7 +149,7 @@ namespace TelegramBotBase.Builder #endregion - #region "Step 3 (Start Form/Factory)" + #region "Step 3 (Start Form/Factory)" public INetworkingSelectionStage WithStartForm(Type startFormClass) { @@ -149,6 +164,19 @@ namespace TelegramBotBase.Builder return this; } + public INetworkingSelectionStage WithServiceProvider(Type startFormClass, IServiceProvider serviceProvider) + { + this._factory = new ServiceProviderStartFormFactory(startFormClass, serviceProvider); + return this; + } + + public INetworkingSelectionStage WithServiceProvider(IServiceProvider serviceProvider) + where T : FormBase + { + this._factory = new ServiceProviderStartFormFactory(serviceProvider); + return this; + } + public INetworkingSelectionStage WithStartFormFactory(IStartFormFactory factory) { this._factory = factory; @@ -212,7 +240,7 @@ namespace TelegramBotBase.Builder public ISessionSerializationStage OnlyStart() { - _botcommands.Start("Starts the bot"); + _BotCommandScopes.Start("Starts the bot"); return this; @@ -220,15 +248,15 @@ namespace TelegramBotBase.Builder public ISessionSerializationStage DefaultCommands() { - _botcommands.Start("Starts the bot"); - _botcommands.Help("Should show you some help"); - _botcommands.Settings("Should show you some settings"); + _BotCommandScopes.Start("Starts the bot"); + _BotCommandScopes.Help("Should show you some help"); + _BotCommandScopes.Settings("Should show you some settings"); return this; } - public ISessionSerializationStage CustomCommands(Action> action) + public ISessionSerializationStage CustomCommands(Action>> action) { - action?.Invoke(_botcommands); + action?.Invoke(_BotCommandScopes); return this; } @@ -307,9 +335,7 @@ namespace TelegramBotBase.Builder bb.Client = _client; - bb.Sessions.Client = bb.Client; - - bb.BotCommands = _botcommands; + bb.BotCommandScopes = _BotCommandScopes; bb.StateMachine = _statemachine; diff --git a/TelegramBotBase/Builder/Interfaces/IBotCommandsStage.cs b/TelegramBotBase/Builder/Interfaces/IBotCommandsStage.cs index cb1507c..a275090 100644 --- a/TelegramBotBase/Builder/Interfaces/IBotCommandsStage.cs +++ b/TelegramBotBase/Builder/Interfaces/IBotCommandsStage.cs @@ -33,7 +33,9 @@ namespace TelegramBotBase.Builder.Interfaces /// /// /// - ISessionSerializationStage CustomCommands(Action> action); + + ISessionSerializationStage CustomCommands(Action>> action); + } } diff --git a/TelegramBotBase/Builder/Interfaces/IMessageLoopSelectionStage.cs b/TelegramBotBase/Builder/Interfaces/IMessageLoopSelectionStage.cs index 02cf87e..429a81d 100644 --- a/TelegramBotBase/Builder/Interfaces/IMessageLoopSelectionStage.cs +++ b/TelegramBotBase/Builder/Interfaces/IMessageLoopSelectionStage.cs @@ -16,6 +16,14 @@ namespace TelegramBotBase.Builder.Interfaces /// IStartFormSelectionStage DefaultMessageLoop(); + + /// + /// Chooses a minimalistic message loop, which catches all update types and only calls the Load function. + /// + /// + IStartFormSelectionStage MinimalMessageLoop(); + + /// /// Chooses a custom message loop. /// diff --git a/TelegramBotBase/Builder/Interfaces/IStartFormSelectionStage.cs b/TelegramBotBase/Builder/Interfaces/IStartFormSelectionStage.cs index fec05b3..78692ea 100644 --- a/TelegramBotBase/Builder/Interfaces/IStartFormSelectionStage.cs +++ b/TelegramBotBase/Builder/Interfaces/IStartFormSelectionStage.cs @@ -23,6 +23,22 @@ namespace TelegramBotBase.Builder.Interfaces /// INetworkingSelectionStage WithStartForm() where T : FormBase, new(); + /// + /// Chooses a StartFormFactory which will be use for new sessions. + /// + /// + /// + /// + INetworkingSelectionStage WithServiceProvider(Type startFormClass, IServiceProvider serviceProvider); + + /// + /// Chooses a StartFormFactory which will be use for new sessions. + /// + /// + /// + /// + INetworkingSelectionStage WithServiceProvider(IServiceProvider serviceProvider) where T : FormBase; + /// /// Chooses a StartFormFactory which will be use for new sessions. /// diff --git a/TelegramBotBase/Commands/Extensions.cs b/TelegramBotBase/Commands/Extensions.cs index a07c031..8237d4f 100644 --- a/TelegramBotBase/Commands/Extensions.cs +++ b/TelegramBotBase/Commands/Extensions.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Data; +using System.Linq; using System.Text; using Telegram.Bot.Types; @@ -8,33 +10,28 @@ namespace TelegramBotBase.Commands public static class Extensions { /// - /// Adding the default /start command with a description. + /// Adding the command with a description. /// /// + /// /// - public static void Start(this List cmds, String description) + public static void Add(this Dictionary> cmds, String command, String description, BotCommandScope scope = null) { - cmds.Add(new BotCommand() { Command = "start", Description = description }); - } + if (scope == null) + { + scope = BotCommandScope.Default(); + } - /// - /// Adding the default /help command with a description. - /// - /// - /// - public static void Help(this List cmds, String description) - { - cmds.Add(new BotCommand() { Command = "help", Description = description }); - } + var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type); - /// - /// Adding the default /settings command with a description. - /// - /// - /// - public static void Settings(this List cmds, String description) - { - cmds.Add(new BotCommand() { Command = "settings", Description = description }); + if (item.Value != null) + { + item.Value.Add(new BotCommand() { Command = command, Description = description }); + } + else + { + cmds.Add(scope, new List { new BotCommand() { Command = command, Description = description } }); + } } /// @@ -43,9 +40,106 @@ namespace TelegramBotBase.Commands /// /// /// - public static void Add(this List cmds, String command, String description) + public static void Clear(this Dictionary> cmds, BotCommandScope scope = null) { - cmds.Add(new BotCommand() { Command = command, Description = description }); + if (scope == null) + { + scope = BotCommandScope.Default(); + } + + var item = cmds.FirstOrDefault(a => a.Key.Type == scope.Type); + + if (item.Key != null) + { + cmds[item.Key] = null; + } + else + { + cmds[scope] = null; + } } + + /// + /// Adding the default /start command with a description. + /// + /// + /// + public static void Start(this Dictionary> cmds, String description) => Add(cmds, "start", description, null); + + /// + /// Adding the default /help command with a description. + /// + /// + /// + public static void Help(this Dictionary> cmds, String description) => Add(cmds, "help", description, null); + + /// + /// Adding the default /settings command with a description. + /// + /// + /// + public static void Settings(this Dictionary> cmds, String description) => Add(cmds, "settings", description, null); + + /// + /// Clears all default commands. + /// + /// + public static void ClearDefaultCommands(this Dictionary> cmds) => Clear(cmds, null); + + /// + /// Clears all commands of a specific device. + /// + /// + public static void ClearChatCommands(this Dictionary> cmds, long DeviceId) => Clear(cmds, new BotCommandScopeChat() { ChatId = DeviceId }); + + /// + /// Adding a chat command with a description. + /// + /// + /// + /// + public static void AddChatCommand(this Dictionary> cmds, long DeviceId, String command, String description) => Add(cmds, command, description, new BotCommandScopeChat() { ChatId = DeviceId }); + + /// + /// Adding a group command with a description. + /// + /// + /// + /// + public static void AddGroupCommand(this Dictionary> cmds, String command, String description) => Add(cmds, command, description, new BotCommandScopeAllGroupChats()); + + /// + /// Clears all group commands. + /// + /// + public static void ClearGroupCommands(this Dictionary> cmds) => Clear(cmds, new BotCommandScopeAllGroupChats()); + + /// + /// Adding group admin command with a description. + /// + /// + /// + /// + public static void AddGroupAdminCommand(this Dictionary> cmds, String command, String description) => Add(cmds, command, description, new BotCommandScopeAllChatAdministrators()); + + /// + /// Clears all group admin commands. + /// + /// + public static void ClearGroupAdminCommand(this Dictionary> cmds) => Clear(cmds, new BotCommandScopeAllChatAdministrators()); + + /// + /// Adding a privat command with a description. + /// + /// + /// + /// + public static void AddPrivateChatCommand(this Dictionary> cmds, String command, String description) => Add(cmds, command, description, new BotCommandScopeAllPrivateChats()); + + /// + /// Clears all private commands. + /// + /// + public static void ClearPrivateChatCommand(this Dictionary> cmds) => Clear(cmds, new BotCommandScopeAllPrivateChats()); } } diff --git a/TelegramBotBase/Controls/Hybrid/MultiView.cs b/TelegramBotBase/Controls/Hybrid/MultiView.cs index 1f66264..83eb0e6 100644 --- a/TelegramBotBase/Controls/Hybrid/MultiView.cs +++ b/TelegramBotBase/Controls/Hybrid/MultiView.cs @@ -50,7 +50,7 @@ namespace TelegramBotBase.Controls.Hybrid } - private void Device_MessageSent(object sender, MessageSentEventArgs e) + private async Task Device_MessageSent(object sender, MessageSentEventArgs e) { if (e.Origin == null || !e.Origin.IsSubclassOf(typeof(MultiView))) return; diff --git a/TelegramBotBase/Datasources/ButtonFormDataSource.cs b/TelegramBotBase/Datasources/ButtonFormDataSource.cs index e8fbfd4..31ef4f6 100644 --- a/TelegramBotBase/Datasources/ButtonFormDataSource.cs +++ b/TelegramBotBase/Datasources/ButtonFormDataSource.cs @@ -35,7 +35,7 @@ namespace TelegramBotBase.Datasources /// - /// Returns the amount of rows exisiting. + /// Returns the amount of rows existing. /// /// public virtual int Count => ButtonForm.Count; diff --git a/TelegramBotBase/Factories/ServiceProviderStartFormFactory.cs b/TelegramBotBase/Factories/ServiceProviderStartFormFactory.cs new file mode 100644 index 0000000..4f2a0ef --- /dev/null +++ b/TelegramBotBase/Factories/ServiceProviderStartFormFactory.cs @@ -0,0 +1,35 @@ +using System; +using Microsoft.Extensions.DependencyInjection; +using TelegramBotBase.Form; +using TelegramBotBase.Interfaces; + +namespace TelegramBotBase.Factories +{ + public class ServiceProviderStartFormFactory : IStartFormFactory + { + private readonly Type _startFormClass; + private readonly IServiceProvider _serviceProvider; + + public ServiceProviderStartFormFactory(Type startFormClass, IServiceProvider serviceProvider) + { + if (!typeof(FormBase).IsAssignableFrom(startFormClass)) + throw new ArgumentException("startFormClass argument must be a FormBase type"); + + _startFormClass = startFormClass; + _serviceProvider = serviceProvider; + } + + public FormBase CreateForm() + { + return (FormBase)ActivatorUtilities.CreateInstance(_serviceProvider, _startFormClass); + } + } + + public class ServiceProviderStartFormFactory : ServiceProviderStartFormFactory + where T : FormBase + { + public ServiceProviderStartFormFactory(IServiceProvider serviceProvider) : base(typeof(T), serviceProvider) + { + } + } +} diff --git a/TelegramBotBase/Form/AutoCleanForm.cs b/TelegramBotBase/Form/AutoCleanForm.cs index 4e6a692..b05938e 100644 --- a/TelegramBotBase/Form/AutoCleanForm.cs +++ b/TelegramBotBase/Form/AutoCleanForm.cs @@ -67,7 +67,7 @@ namespace TelegramBotBase.Form this.OldMessages.Add(e.Message.MessageId); } - private void Device_MessageSent(object sender, MessageSentEventArgs e) + private async Task Device_MessageSent(object sender, MessageSentEventArgs e) { if (this.DeleteSide == eDeleteSide.UserOnly) return; diff --git a/TelegramBotBase/Localizations/English.cs b/TelegramBotBase/Localizations/English.cs index d340291..35ac031 100644 --- a/TelegramBotBase/Localizations/English.cs +++ b/TelegramBotBase/Localizations/English.cs @@ -28,10 +28,10 @@ namespace TelegramBotBase.Localizations Values["ToggleButton_OnIcon"] = "⚫"; Values["ToggleButton_OffIcon"] = "⚪"; Values["ToggleButton_Title"] = "Toggle"; - Values["ToggleButton_Changed"] = "Choosen"; + Values["ToggleButton_Changed"] = "Chosen"; Values["MultiToggleButton_SelectedIcon"] = "✅"; Values["MultiToggleButton_Title"] = "Multi-Toggle"; - Values["MultiToggleButton_Changed"] = "Choosen"; + Values["MultiToggleButton_Changed"] = "Chosen"; Values["PromptDialog_Back"] = "Back"; Values["ToggleButton_Changed"] = "Setting changed"; } diff --git a/TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs b/TelegramBotBase/MessageLoops/FormBaseMessageLoop.cs similarity index 93% rename from TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs rename to TelegramBotBase/MessageLoops/FormBaseMessageLoop.cs index 6568e19..3a6b00c 100644 --- a/TelegramBotBase/Factories/MessageLoops/FormBaseMessageLoop.cs +++ b/TelegramBotBase/MessageLoops/FormBaseMessageLoop.cs @@ -11,8 +11,11 @@ using TelegramBotBase.Enums; using TelegramBotBase.Interfaces; using TelegramBotBase.Sessions; -namespace TelegramBotBase.Factories.MessageLoops +namespace TelegramBotBase.MessageLoops { + /// + /// Thats the default message loop which reacts to Message, EditMessage and CallbackQuery. + /// public class FormBaseMessageLoop : IMessageLoopFactory { private static object __evUnhandledCall = new object(); @@ -37,7 +40,7 @@ namespace TelegramBotBase.Factories.MessageLoops } //Is this a bot command ? - if (mr.IsFirstHandler && mr.IsBotCommand && Bot.BotCommands.Count(a => "/" + a.Command == mr.BotCommand) > 0) + if (mr.IsFirstHandler && mr.IsBotCommand && Bot.IsKnownBotCommand(mr.BotCommand)) { var sce = new BotCommandEventArgs(mr.BotCommand, mr.BotCommandParameters, mr.Message, session.DeviceId, session); await Bot.OnBotCommand(sce); diff --git a/TelegramBotBase/MessageLoops/FullMessageLoop.cs b/TelegramBotBase/MessageLoops/FullMessageLoop.cs new file mode 100644 index 0000000..63e8160 --- /dev/null +++ b/TelegramBotBase/MessageLoops/FullMessageLoop.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using TelegramBotBase.Args; +using TelegramBotBase.Base; +using TelegramBotBase.Enums; +using TelegramBotBase.Interfaces; +using TelegramBotBase.Sessions; + +namespace TelegramBotBase.MessageLoops +{ + /// + /// This message loop reacts to all update types. + /// + public class FullMessageLoop : IMessageLoopFactory + { + private static object __evUnhandledCall = new object(); + + private EventHandlerList __Events = new EventHandlerList(); + + public FullMessageLoop() + { + + } + + public async Task MessageLoop(BotBase Bot, DeviceSession session, UpdateResult ur, MessageResult mr) + { + var update = ur.RawData; + + + //Is this a bot command ? + if (mr.IsFirstHandler && mr.IsBotCommand && Bot.IsKnownBotCommand(mr.BotCommand)) + { + var sce = new BotCommandEventArgs(mr.BotCommand, mr.BotCommandParameters, mr.Message, session.DeviceId, session); + await Bot.OnBotCommand(sce); + + if (sce.Handled) + return; + } + + mr.Device = session; + + var activeForm = session.ActiveForm; + + //Pre Loading Event + await activeForm.PreLoad(mr); + + //Send Load event to controls + await activeForm.LoadControls(mr); + + //Loading Event + await activeForm.Load(mr); + + + //Is Attachment ? (Photo, Audio, Video, Contact, Location, Document) (Ignore Callback Queries) + if (update.Type == Telegram.Bot.Types.Enums.UpdateType.Message) + { + if (mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Contact + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Document + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Location + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Photo + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Video + | mr.MessageType == Telegram.Bot.Types.Enums.MessageType.Audio) + { + await activeForm.SentData(new DataResult(ur)); + } + } + + //Action Event + if (!session.FormSwitched && mr.IsAction) + { + //Send Action event to controls + await activeForm.ActionControls(mr); + + //Send Action event to form itself + await activeForm.Action(mr); + + if (!mr.Handled) + { + var uhc = new UnhandledCallEventArgs(ur.Message.Text, mr.RawData, session.DeviceId, mr.MessageId, ur.Message, session); + OnUnhandledCall(uhc); + + if (uhc.Handled) + { + mr.Handled = true; + if (!session.FormSwitched) + { + return; + } + } + } + + } + + if (!session.FormSwitched) + { + //Render Event + await activeForm.RenderControls(mr); + + await activeForm.Render(mr); + } + + } + + /// + /// 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); + + } + } +} diff --git a/TelegramBotBase/MessageLoops/MinimalMessageLoop.cs b/TelegramBotBase/MessageLoops/MinimalMessageLoop.cs new file mode 100644 index 0000000..0be394b --- /dev/null +++ b/TelegramBotBase/MessageLoops/MinimalMessageLoop.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using TelegramBotBase.Args; +using TelegramBotBase.Base; +using TelegramBotBase.Enums; +using TelegramBotBase.Interfaces; +using TelegramBotBase.Sessions; + +namespace TelegramBotBase.MessageLoops +{ + /// + /// This is a minimal message loop which will react to all update types and just calling the Load method. + /// + public class MinimalMessageLoop : IMessageLoopFactory + { + private static object __evUnhandledCall = new object(); + + private EventHandlerList __Events = new EventHandlerList(); + + public MinimalMessageLoop() + { + + } + + public async Task MessageLoop(BotBase Bot, DeviceSession session, UpdateResult ur, MessageResult mr) + { + var update = ur.RawData; + + + mr.Device = session; + + var activeForm = session.ActiveForm; + + //Loading Event + await activeForm.Load(mr); + + } + + /// + /// 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); + + } + } +} diff --git a/TelegramBotBase/SessionBase.cs b/TelegramBotBase/SessionManager.cs similarity index 83% rename from TelegramBotBase/SessionBase.cs rename to TelegramBotBase/SessionManager.cs index b94f59a..0cceeda 100644 --- a/TelegramBotBase/SessionBase.cs +++ b/TelegramBotBase/SessionManager.cs @@ -14,14 +14,14 @@ using TelegramBotBase.Sessions; namespace TelegramBotBase { /// - /// Base class for managing all active sessions + /// Class for managing all active sessions /// - public class SessionBase + public sealed class SessionManager { /// /// The Basic message client. /// - public MessageClient Client { get; set; } + public MessageClient Client => BotBase.Client; /// /// A list of all active sessions. @@ -32,29 +32,13 @@ namespace TelegramBotBase /// /// Reference to the Main BotBase instance for later use. /// - public BotBase BotBase { get; set; } + public BotBase BotBase { get; } - public SessionBase() + public SessionManager(BotBase botBase) { - this.SessionList = new Dictionary(); - } - - /// - /// Get device session from Device/ChatId - /// - /// - /// - public DeviceSession this[long key] - { - get - { - return this.SessionList[key]; - } - set - { - this.SessionList[key] = value; - } + BotBase = botBase; + SessionList = new Dictionary(); } /// @@ -64,7 +48,7 @@ namespace TelegramBotBase /// public DeviceSession GetSession(long deviceId) { - DeviceSession ds = this.SessionList.FirstOrDefault(a => a.Key == deviceId).Value ?? null; + var ds = SessionList.FirstOrDefault(a => a.Key == deviceId).Value ?? null; return ds; } @@ -77,7 +61,6 @@ namespace TelegramBotBase public async Task StartSession(long deviceId) { var start = BotBase.StartFormFactory.CreateForm(); - //T start = typeof(T).GetConstructor(new Type[] { }).Invoke(new object[] { }) as T; start.Client = this.Client; @@ -88,7 +71,7 @@ namespace TelegramBotBase await start.OnOpened(new EventArgs()); - this[deviceId] = ds; + SessionList[deviceId] = ds; return ds; } @@ -98,12 +81,8 @@ namespace TelegramBotBase /// public void EndSession(long deviceId) { - var d = this[deviceId]; - if (d != null) - { - this.SessionList.Remove(deviceId); - - } + var d = SessionList[deviceId]; + if (d != null) SessionList.Remove(deviceId); } /// @@ -112,7 +91,7 @@ namespace TelegramBotBase /// public List GetUserSessions() { - return this.SessionList.Where(a => a.Key > 0).Select(a => a.Value).ToList(); + return SessionList.Where(a => a.Key > 0).Select(a => a.Value).ToList(); } /// @@ -121,27 +100,27 @@ namespace TelegramBotBase /// public List GetGroupSessions() { - return this.SessionList.Where(a => a.Key < 0).Select(a => a.Value).ToList(); + return SessionList.Where(a => a.Key < 0).Select(a => a.Value).ToList(); } /// /// Loads the previously saved states from the machine. /// - public async void LoadSessionStates() + public async Task LoadSessionStates() { if (BotBase.StateMachine == null) { return; } - LoadSessionStates(BotBase.StateMachine); + await LoadSessionStates(BotBase.StateMachine); } /// /// Loads the previously saved states from the machine. /// - public async void LoadSessionStates(IStateMachine statemachine) + public async Task LoadSessionStates(IStateMachine statemachine) { if (statemachine == null) { @@ -159,7 +138,7 @@ namespace TelegramBotBase } //Key already existing - if (this.SessionList.ContainsKey(s.DeviceId)) + if (SessionList.ContainsKey(s.DeviceId)) continue; var form = t.GetConstructor(new Type[] { })?.Invoke(new object[] { }) as FormBase; @@ -222,7 +201,7 @@ namespace TelegramBotBase device.ChatTitle = s.ChatTitle; - this.SessionList.Add(s.DeviceId, device); + SessionList.Add(s.DeviceId, device); //Is Subclass of IStateForm var iform = form as IStateForm; @@ -242,7 +221,7 @@ namespace TelegramBotBase catch { //Skip on exception - this.SessionList.Remove(s.DeviceId); + SessionList.Remove(s.DeviceId); } } @@ -254,7 +233,7 @@ namespace TelegramBotBase /// /// Saves all open states into the machine. /// - public void SaveSessionStates(IStateMachine statemachine) + public async Task SaveSessionStates(IStateMachine statemachine) { if (statemachine == null) { @@ -263,7 +242,7 @@ namespace TelegramBotBase var states = new List(); - foreach (var s in this.SessionList) + foreach (var s in SessionList) { if (s.Value == null) { @@ -333,13 +312,13 @@ namespace TelegramBotBase /// /// Saves all open states into the machine. /// - public void SaveSessionStates() + public async Task SaveSessionStates() { - if (this.BotBase.StateMachine == null) + if (BotBase.StateMachine == null) return; - this.SaveSessionStates(this.BotBase.StateMachine); + await SaveSessionStates(BotBase.StateMachine); } } } diff --git a/TelegramBotBase/Sessions/DeviceSession.cs b/TelegramBotBase/Sessions/DeviceSession.cs index 945abfd..17d52e8 100644 --- a/TelegramBotBase/Sessions/DeviceSession.cs +++ b/TelegramBotBase/Sessions/DeviceSession.cs @@ -84,7 +84,7 @@ namespace TelegramBotBase.Sessions /// public Message LastMessage { get; set; } - private MessageClient Client + public MessageClient Client { get { @@ -291,7 +291,8 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendTextMessageAsync(deviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -342,7 +343,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -380,7 +381,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendTextMessageAsync(this.DeviceId, text, parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -410,7 +411,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendPhotoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -440,7 +441,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendVideoAsync(this.DeviceId, file, caption: caption, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -453,7 +454,7 @@ namespace TelegramBotBase.Sessions /// /// Sends an video /// - /// + /// /// /// /// @@ -470,7 +471,79 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendVideoAsync(this.DeviceId, new InputOnlineFile(url), parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); + + return await t; + } + catch + { + return null; + } + } + + /// + /// Sends an video + /// + /// + /// + /// + /// + /// + /// + public async Task SendVideo(String filename, byte[] video, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Markdown) + { + if (this.ActiveForm == null) + return null; + + InlineKeyboardMarkup markup = buttons; + + try + { + MemoryStream ms = new MemoryStream(video); + + InputOnlineFile fts = new InputOnlineFile(ms, filename); + + var t = API(a => a.SendVideoAsync(this.DeviceId, fts, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); + + var o = GetOrigin(new StackTrace()); + await OnMessageSent(new MessageSentEventArgs(await t, o)); + + return await t; + } + catch + { + return null; + } + } + + /// + /// Sends an local file as video + /// + /// + /// + /// + /// + /// + /// + public async Task SendLocalVideo(String filepath, ButtonForm buttons = null, int replyTo = 0, bool disableNotification = false, ParseMode parseMode = ParseMode.Markdown) + { + if (this.ActiveForm == null) + return null; + + InlineKeyboardMarkup markup = buttons; + + try + { + FileStream fs = new FileStream(filepath, FileMode.Open); + + var filename = Path.GetFileName(filepath); + + InputOnlineFile fts = new InputOnlineFile(fs, filename); + + var t = API(a => a.SendVideoAsync(this.DeviceId, fts, parseMode: parseMode, replyToMessageId: replyTo, replyMarkup: markup, disableNotification: disableNotification)); + + var o = GetOrigin(new StackTrace()); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -547,7 +620,7 @@ namespace TelegramBotBase.Sessions var t = API(a => a.SendDocumentAsync(this.DeviceId, document, caption, replyMarkup: markup, disableNotification: disableNotification, replyToMessageId: replyTo)); var o = GetOrigin(new StackTrace()); - OnMessageSent(new MessageSentEventArgs(await t, o)); + await OnMessageSent(new MessageSentEventArgs(await t, o)); return await t; } @@ -810,7 +883,7 @@ namespace TelegramBotBase.Sessions /// /// Eventhandler for sent messages /// - public event EventHandler MessageSent + public event Base.Async.AsyncEventHandler MessageSent { add { @@ -823,9 +896,21 @@ namespace TelegramBotBase.Sessions } - public void OnMessageSent(MessageSentEventArgs e) + public async Task OnMessageSent(MessageSentEventArgs e) { - (this.__Events[__evMessageSent] as EventHandler)?.Invoke(this, e); + if (e.Message == null) + return; + + var handler = this.__Events[__evMessageSent]?.GetInvocationList().Cast>(); + if (handler == null) + return; + + foreach (var h in handler) + { + await Base.Async.InvokeAllAsync(h, this, e); + } + + //(this.__Events[__evMessageSent] as EventHandler)?.Invoke(this, e); } /// diff --git a/TelegramBotBase/TelegramBotBase.csproj b/TelegramBotBase/TelegramBotBase.csproj index 7d4eddc..a5b9666 100644 --- a/TelegramBotBase/TelegramBotBase.csproj +++ b/TelegramBotBase/TelegramBotBase.csproj @@ -23,6 +23,7 @@ + @@ -57,8 +58,8 @@ - - + + diff --git a/TelegramBotFramework.sln b/TelegramBotFramework.sln index 326160e..34eec3f 100644 --- a/TelegramBotFramework.sln +++ b/TelegramBotFramework.sln @@ -14,11 +14,19 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{BFA71E3F-31C0-4FC1-A320-4DCF704768C5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemCommandsBot", "Examples\SystemCommandsBot\SystemCommandsBot.csproj", "{FC484952-3060-4F87-9809-4CD66D6961C0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemCommandsBot", "Examples\SystemCommandsBot\SystemCommandsBot.csproj", "{FC484952-3060-4F87-9809-4CD66D6961C0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JoinHiderBot", "Examples\JoinHiderBot\JoinHiderBot.csproj", "{E804B9E5-7ACC-49D3-9253-806766C1D9A5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JoinHiderBot", "Examples\JoinHiderBot\JoinHiderBot.csproj", "{E804B9E5-7ACC-49D3-9253-806766C1D9A5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TelegramBotBase.Extensions.Images", "TelegramBotBase.Extensions.Images\TelegramBotBase.Extensions.Images.csproj", "{B5DDFA45-0E01-46A5-B67D-541300CDD606}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelegramBotBase.Extensions.Images", "TelegramBotBase.Extensions.Images\TelegramBotBase.Extensions.Images.csproj", "{B5DDFA45-0E01-46A5-B67D-541300CDD606}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsyncFormUpdates", "Examples\AsyncFormUpdates\AsyncFormUpdates.csproj", "{673A56F5-6110-4AED-A68D-562FD6ED3EA6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Extensions", "Extensions", "{E3193182-6FDA-4FA3-AD26-A487291E7681}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TelegramBotBase.Extensions.Serializer.Database.MSSQL", "TelegramBotBase.Extensions.Serializer.Database.MSSQL\TelegramBotBase.Extensions.Serializer.Database.MSSQL.csproj", "{889B170E-32E9-4F26-BB04-8D06EA367857}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EFCoreBot", "Examples\EFCoreBot\EFCoreBot.csproj", "{261BED47-0404-4A9A-86FC-047DE42A7D25}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -46,6 +54,18 @@ Global {B5DDFA45-0E01-46A5-B67D-541300CDD606}.Debug|Any CPU.Build.0 = Debug|Any CPU {B5DDFA45-0E01-46A5-B67D-541300CDD606}.Release|Any CPU.ActiveCfg = Release|Any CPU {B5DDFA45-0E01-46A5-B67D-541300CDD606}.Release|Any CPU.Build.0 = Release|Any CPU + {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {673A56F5-6110-4AED-A68D-562FD6ED3EA6}.Release|Any CPU.Build.0 = Release|Any CPU + {889B170E-32E9-4F26-BB04-8D06EA367857}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {889B170E-32E9-4F26-BB04-8D06EA367857}.Debug|Any CPU.Build.0 = Debug|Any CPU + {889B170E-32E9-4F26-BB04-8D06EA367857}.Release|Any CPU.ActiveCfg = Release|Any CPU + {889B170E-32E9-4F26-BB04-8D06EA367857}.Release|Any CPU.Build.0 = Release|Any CPU + {261BED47-0404-4A9A-86FC-047DE42A7D25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {261BED47-0404-4A9A-86FC-047DE42A7D25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {261BED47-0404-4A9A-86FC-047DE42A7D25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {261BED47-0404-4A9A-86FC-047DE42A7D25}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -53,6 +73,10 @@ Global GlobalSection(NestedProjects) = preSolution {FC484952-3060-4F87-9809-4CD66D6961C0} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} {E804B9E5-7ACC-49D3-9253-806766C1D9A5} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} + {B5DDFA45-0E01-46A5-B67D-541300CDD606} = {E3193182-6FDA-4FA3-AD26-A487291E7681} + {673A56F5-6110-4AED-A68D-562FD6ED3EA6} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} + {889B170E-32E9-4F26-BB04-8D06EA367857} = {E3193182-6FDA-4FA3-AD26-A487291E7681} + {261BED47-0404-4A9A-86FC-047DE42A7D25} = {BFA71E3F-31C0-4FC1-A320-4DCF704768C5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {59CB40E1-9FA7-4867-A56F-4F418286F057} diff --git a/images/alertdialog.PNG b/images/alertdialog.PNG deleted file mode 100644 index f03969c..0000000 Binary files a/images/alertdialog.PNG and /dev/null differ diff --git a/images/buttongrid.gif b/images/buttongrid.gif deleted file mode 100644 index 2deec60..0000000 Binary files a/images/buttongrid.gif and /dev/null differ diff --git a/images/buttongrid_pagingfilter.gif b/images/buttongrid_pagingfilter.gif deleted file mode 100644 index e887288..0000000 Binary files a/images/buttongrid_pagingfilter.gif and /dev/null differ diff --git a/images/calendarpicker.PNG b/images/calendarpicker.PNG deleted file mode 100644 index cd9018b..0000000 Binary files a/images/calendarpicker.PNG and /dev/null differ diff --git a/images/calendarpicker.gif b/images/calendarpicker.gif deleted file mode 100644 index b3642b1..0000000 Binary files a/images/calendarpicker.gif and /dev/null differ diff --git a/images/checkedbuttonlist.gif b/images/checkedbuttonlist.gif deleted file mode 100644 index f025fb8..0000000 Binary files a/images/checkedbuttonlist.gif and /dev/null differ diff --git a/images/confirmdialog.PNG b/images/confirmdialog.PNG deleted file mode 100644 index 29f311c..0000000 Binary files a/images/confirmdialog.PNG and /dev/null differ diff --git a/images/example1.PNG b/images/example1.PNG deleted file mode 100644 index e05722d..0000000 Binary files a/images/example1.PNG and /dev/null differ diff --git a/images/example2.PNG b/images/example2.PNG deleted file mode 100644 index e69ad61..0000000 Binary files a/images/example2.PNG and /dev/null differ diff --git a/images/example3.PNG b/images/example3.PNG deleted file mode 100644 index 2d43757..0000000 Binary files a/images/example3.PNG and /dev/null differ diff --git a/images/example4.1.PNG b/images/example4.1.PNG deleted file mode 100644 index 081adae..0000000 Binary files a/images/example4.1.PNG and /dev/null differ diff --git a/images/example4.2.PNG b/images/example4.2.PNG deleted file mode 100644 index f89d6b7..0000000 Binary files a/images/example4.2.PNG and /dev/null differ diff --git a/images/example4.3.PNG b/images/example4.3.PNG deleted file mode 100644 index 208784f..0000000 Binary files a/images/example4.3.PNG and /dev/null differ diff --git a/images/example4.4.PNG b/images/example4.4.PNG deleted file mode 100644 index 192157a..0000000 Binary files a/images/example4.4.PNG and /dev/null differ diff --git a/images/monthpicker1.PNG b/images/monthpicker1.PNG deleted file mode 100644 index 44c51a9..0000000 Binary files a/images/monthpicker1.PNG and /dev/null differ diff --git a/images/monthpicker2.PNG b/images/monthpicker2.PNG deleted file mode 100644 index 3201cac..0000000 Binary files a/images/monthpicker2.PNG and /dev/null differ diff --git a/images/multitogglebutton.gif b/images/multitogglebutton.gif deleted file mode 100644 index b399eae..0000000 Binary files a/images/multitogglebutton.gif and /dev/null differ diff --git a/images/progressbar.PNG b/images/progressbar.PNG deleted file mode 100644 index 556ab24..0000000 Binary files a/images/progressbar.PNG and /dev/null differ diff --git a/images/promptdialog.PNG b/images/promptdialog.PNG deleted file mode 100644 index b015067..0000000 Binary files a/images/promptdialog.PNG and /dev/null differ diff --git a/images/taggedbuttongrid.gif b/images/taggedbuttongrid.gif deleted file mode 100644 index 8313144..0000000 Binary files a/images/taggedbuttongrid.gif and /dev/null differ diff --git a/images/togglebutton.gif b/images/togglebutton.gif deleted file mode 100644 index 643ba9c..0000000 Binary files a/images/togglebutton.gif and /dev/null differ diff --git a/images/treeview1.PNG b/images/treeview1.PNG deleted file mode 100644 index 8e5055b..0000000 Binary files a/images/treeview1.PNG and /dev/null differ diff --git a/images/treeview2.PNG b/images/treeview2.PNG deleted file mode 100644 index 7a0f838..0000000 Binary files a/images/treeview2.PNG and /dev/null differ diff --git a/images/treeview3.PNG b/images/treeview3.PNG deleted file mode 100644 index 698d56b..0000000 Binary files a/images/treeview3.PNG and /dev/null differ diff --git a/images/treeview4.PNG b/images/treeview4.PNG deleted file mode 100644 index b73979d..0000000 Binary files a/images/treeview4.PNG and /dev/null differ