mirror of
https://github.com/yawaflua/Telegram.Net.git
synced 2025-12-08 19:49:30 +02:00
Merge pull request #1 from yawaflua/develop
Pull request from Develop to master
This commit is contained in:
25
.github/workflows/dotnet.yml
vendored
Normal file
25
.github/workflows/dotnet.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
name: .NET Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "*" ]
|
||||
pull_request:
|
||||
branches: [ "*" ]
|
||||
env:
|
||||
"telegram_test_token": ${{secrets.TELEGRAM_TEST_TOKEN}}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 7.0.x
|
||||
- name: Restore dependencies
|
||||
run: dotnet restore
|
||||
- name: Build
|
||||
run: dotnet build --no-restore /p:TreatWarningsAsErrors=false
|
||||
- name: Test
|
||||
run: dotnet test --no-build --verbosity normal -e telegram_test_token=${{secrets.TELEGRAM_TEST_TOKEN}}
|
||||
@@ -1,14 +1,18 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegram.Net;
|
||||
|
||||
var webHost = Host.CreateDefaultBuilder()
|
||||
.ConfigureLogging(l => l.ClearProviders().AddConsole())
|
||||
.ConfigureServices(k =>
|
||||
{
|
||||
k.ConnectTelegram(new("YOUR-TOKEN")
|
||||
k.ConnectTelegram(new("TOKEN")
|
||||
{
|
||||
errorHandler = async (client, exception, ctx) =>
|
||||
{
|
||||
await Console.Out.WriteLineAsync(exception.Message);
|
||||
Console.WriteLine(exception);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
webHost.Build().Run();
|
||||
@@ -5,6 +5,7 @@
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -5,7 +5,7 @@ using Telegram.Net.Interfaces;
|
||||
|
||||
namespace Telegram.Examples.UpdatePolling;
|
||||
|
||||
public class Update : IUpdatePollingSerivce
|
||||
public class Update : IUpdatePollingService
|
||||
{
|
||||
[Update]
|
||||
public async Task UpdateExample(ITelegramBotClient client, Bot.Types.Update update, CancellationToken ctx)
|
||||
|
||||
@@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegram.Net", "Telegram.Ne
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegram.Examples", "Examples\Telegram.Examples\Telegram.Examples.csproj", "{073E66F2-F82E-4378-B390-C2364DFDC491}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Telegram.Tests", "tests\Telegram.Tests\Telegram.Tests.csproj", "{1FF230D6-7DDC-48B6-8D56-2E14726FDD9E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -18,5 +20,9 @@ Global
|
||||
{073E66F2-F82E-4378-B390-C2364DFDC491}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{073E66F2-F82E-4378-B390-C2364DFDC491}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{073E66F2-F82E-4378-B390-C2364DFDC491}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1FF230D6-7DDC-48B6-8D56-2E14726FDD9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1FF230D6-7DDC-48B6-8D56-2E14726FDD9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1FF230D6-7DDC-48B6-8D56-2E14726FDD9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1FF230D6-7DDC-48B6-8D56-2E14726FDD9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
3
Telegram.Net/AssemblyInfo.cs
Normal file
3
Telegram.Net/AssemblyInfo.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Telegram.Tests")]
|
||||
@@ -29,31 +29,5 @@ public class CallbackAttribute : Attribute
|
||||
public CallbackAttribute(string queryId)
|
||||
{
|
||||
this.QueryId = queryId;
|
||||
|
||||
var methods = typeof(IUpdatePollingSerivce).GetMethods()
|
||||
.Where(m => m.GetCustomAttribute(this.GetType()) != null);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (IsValidHandlerMethod(method))
|
||||
{
|
||||
var attr = method.GetCustomAttribute<CallbackAttribute>();
|
||||
var handler = (Func<ITelegramBotClient, CallbackQuery, CancellationToken, Task>)
|
||||
Delegate.CreateDelegate(typeof(Func<ITelegramBotClient, CallbackQuery, CancellationToken, Task>), null,
|
||||
method);
|
||||
|
||||
TelegramHostedService.CallbackQueryHandler.Add(attr!.QueryId, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsValidHandlerMethod(MethodInfo method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return method.ReturnType == typeof(Task) &&
|
||||
parameters.Length == 3 &&
|
||||
parameters[0].ParameterType == typeof(ITelegramBotClient) &&
|
||||
parameters[1].ParameterType == typeof(CallbackQuery) &&
|
||||
parameters[2].ParameterType == typeof(CancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -29,31 +29,5 @@ public class CommandAttribute : Attribute
|
||||
public CommandAttribute(string command)
|
||||
{
|
||||
Command = command;
|
||||
|
||||
var methods = typeof(IUpdatePollingSerivce).GetMethods()
|
||||
.Where(m => m.GetCustomAttribute(this.GetType()) != null);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (IsValidHandlerMethod(method))
|
||||
{
|
||||
var attr = method.GetCustomAttribute<CommandAttribute>();
|
||||
var handler = (Func<ITelegramBotClient, Message, CancellationToken, Task>)
|
||||
Delegate.CreateDelegate(typeof(Func<ITelegramBotClient, Message, CancellationToken, Task>), null,
|
||||
method);
|
||||
|
||||
TelegramHostedService.CommandHandler.Add(attr!.Command, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsValidHandlerMethod(MethodInfo method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return method.ReturnType == typeof(Task) &&
|
||||
parameters.Length == 3 &&
|
||||
parameters[0].ParameterType == typeof(ITelegramBotClient) &&
|
||||
parameters[1].ParameterType == typeof(Message) &&
|
||||
parameters[2].ParameterType == typeof(CancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -26,29 +26,5 @@ public class EditMessageAttribute : Attribute
|
||||
/// </summary>
|
||||
public EditMessageAttribute()
|
||||
{
|
||||
var methods = typeof(IUpdatePollingSerivce).GetMethods()
|
||||
.Where(m => m.GetCustomAttribute(this.GetType()) != null);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (IsValidHandlerMethod(method))
|
||||
{
|
||||
var handler = (Func<ITelegramBotClient, Message, CancellationToken, Task>)
|
||||
Delegate.CreateDelegate(typeof(Func<ITelegramBotClient, Message, CancellationToken, Task>), null,
|
||||
method);
|
||||
|
||||
TelegramHostedService.EditedMessageHandler.Add(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsValidHandlerMethod(MethodInfo method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return method.ReturnType == typeof(Task) &&
|
||||
parameters.Length == 3 &&
|
||||
parameters[0].ParameterType == typeof(ITelegramBotClient) &&
|
||||
parameters[1].ParameterType == typeof(Message) &&
|
||||
parameters[2].ParameterType == typeof(CancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -31,30 +31,5 @@ public class InlineAttribute : Attribute
|
||||
public InlineAttribute(string inlineId)
|
||||
{
|
||||
this.InlineId = inlineId;
|
||||
var methods = typeof(IUpdatePollingSerivce).GetMethods()
|
||||
.Where(m => m.GetCustomAttribute(this.GetType()) != null);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (IsValidHandlerMethod(method))
|
||||
{
|
||||
var attr = method.GetCustomAttribute<InlineAttribute>();
|
||||
var handler = (Func<ITelegramBotClient, InlineQuery, CancellationToken, Task>)
|
||||
Delegate.CreateDelegate(typeof(Func<ITelegramBotClient, InlineQuery, CancellationToken, Task>), null,
|
||||
method);
|
||||
|
||||
TelegramHostedService.InlineHandler.Add(attr!.InlineId, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsValidHandlerMethod(MethodInfo method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return method.ReturnType == typeof(Task) &&
|
||||
parameters.Length == 3 &&
|
||||
parameters[0].ParameterType == typeof(ITelegramBotClient) &&
|
||||
parameters[1].ParameterType == typeof(InlineQuery) &&
|
||||
parameters[2].ParameterType == typeof(CancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -22,29 +22,5 @@ public class PreCheckoutAttribute : Attribute
|
||||
public bool IsReusable => true;
|
||||
public PreCheckoutAttribute()
|
||||
{
|
||||
var methods = typeof(IUpdatePollingSerivce).GetMethods()
|
||||
.Where(m => m.GetCustomAttribute(this.GetType()) != null);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (IsValidHandlerMethod(method))
|
||||
{
|
||||
var handler = (Func<ITelegramBotClient, PreCheckoutQuery, CancellationToken, Task>)
|
||||
Delegate.CreateDelegate(typeof(Func<ITelegramBotClient, PreCheckoutQuery, CancellationToken, Task>), null,
|
||||
method);
|
||||
|
||||
TelegramHostedService.PreCheckoutHandler = (handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsValidHandlerMethod(MethodInfo method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return method.ReturnType == typeof(Task) &&
|
||||
parameters.Length == 3 &&
|
||||
parameters[0].ParameterType == typeof(ITelegramBotClient) &&
|
||||
parameters[1].ParameterType == typeof(PreCheckoutQuery) &&
|
||||
parameters[2].ParameterType == typeof(CancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -21,29 +21,5 @@ public class UpdateAttribute : Attribute
|
||||
public bool IsReusable => true;
|
||||
public UpdateAttribute()
|
||||
{
|
||||
var methods = typeof(IUpdatePollingSerivce).GetMethods()
|
||||
.Where(m => m.GetCustomAttribute(this.GetType()) != null);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
if (IsValidHandlerMethod(method))
|
||||
{
|
||||
var handler = (Func<ITelegramBotClient, Update, CancellationToken, Task>)
|
||||
Delegate.CreateDelegate(typeof(Func<ITelegramBotClient, Update, CancellationToken, Task>), null,
|
||||
method);
|
||||
|
||||
TelegramHostedService.DefaultUpdateHandler.Add(handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsValidHandlerMethod(MethodInfo method)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return method.ReturnType == typeof(Task) &&
|
||||
parameters.Length == 3 &&
|
||||
parameters[0].ParameterType == typeof(ITelegramBotClient) &&
|
||||
parameters[1].ParameterType == typeof(Update) &&
|
||||
parameters[2].ParameterType == typeof(CancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ public interface ITelegramBotConfig
|
||||
/// <summary>
|
||||
/// Token of telegram bot. You can take it from @BotFather
|
||||
/// </summary>
|
||||
public string Token { internal get; init; }
|
||||
public string Token { get; set; }
|
||||
/// <summary>
|
||||
/// Custom error handler for bot. You can add custom logger or anything.
|
||||
/// </summary>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// You should implement this interface in all your classes with update polling logic
|
||||
/// </summary>
|
||||
public interface IUpdatePollingSerivce
|
||||
public interface IUpdatePollingService
|
||||
{
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ public class TelegramBotConfig : ITelegramBotConfig
|
||||
Token = token;
|
||||
}
|
||||
|
||||
public string Token { get; init; }
|
||||
public string Token { get; set; }
|
||||
public Func<ITelegramBotClient, Exception, CancellationToken, Task>? errorHandler { get; init; }
|
||||
public ReceiverOptions? ReceiverOptions { get; init; }
|
||||
}
|
||||
@@ -8,7 +8,7 @@ public static class ServiceBindings
|
||||
{
|
||||
public static IServiceCollection ConnectTelegram(this IServiceCollection isc, TelegramBotConfig config)
|
||||
{
|
||||
isc.AddHostedService<TelegramHostedService>(k => new(config));
|
||||
isc.AddHostedService<TelegramHostedService>(k => new(config, isc));
|
||||
return isc;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Payments;
|
||||
using Telegram.Net.Attributes;
|
||||
using Telegram.Net.Interfaces;
|
||||
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
|
||||
|
||||
@@ -10,52 +13,171 @@ namespace Telegram.Net.Services;
|
||||
|
||||
public class TelegramHostedService : IHostedService
|
||||
{
|
||||
private TelegramBotClient Client { get; }
|
||||
private IServiceCollection isc { get; }
|
||||
internal TelegramBotClient Client { get; set; }
|
||||
private ITelegramBotConfig Config { get; }
|
||||
internal static Dictionary<string, Func<ITelegramBotClient, Message, CancellationToken, Task>> CommandHandler { get; } = new();
|
||||
internal static List<Func<ITelegramBotClient, Message, CancellationToken, Task>> EditedMessageHandler { get; } = new();
|
||||
internal static Dictionary<string, Func<ITelegramBotClient, CallbackQuery,CancellationToken, Task>> CallbackQueryHandler { get; } = new();
|
||||
internal static Dictionary<string, Func<ITelegramBotClient, InlineQuery ,CancellationToken, Task>> InlineHandler { get; } = new();
|
||||
internal static Func<ITelegramBotClient, PreCheckoutQuery,CancellationToken, Task>? PreCheckoutHandler { get; set; }
|
||||
internal static List<Func<ITelegramBotClient, Update, CancellationToken, Task>> DefaultUpdateHandler { get; } = new();
|
||||
internal Dictionary<string, Func<ITelegramBotClient, Message, CancellationToken, Task>> CommandHandler { get; } = new();
|
||||
internal List<Func<ITelegramBotClient, Message, CancellationToken, Task>> EditedMessageHandler { get; } = new();
|
||||
internal Dictionary<string, Func<ITelegramBotClient, CallbackQuery,CancellationToken, Task>> CallbackQueryHandler { get; } = new();
|
||||
internal Dictionary<string, Func<ITelegramBotClient, InlineQuery ,CancellationToken, Task>> InlineHandler { get; } = new();
|
||||
internal Func<ITelegramBotClient, PreCheckoutQuery,CancellationToken, Task>? PreCheckoutHandler { get; set; }
|
||||
internal List<Func<ITelegramBotClient, Update, CancellationToken, Task>> DefaultUpdateHandler { get; } = new();
|
||||
|
||||
public TelegramHostedService(ITelegramBotConfig config)
|
||||
public TelegramHostedService(ITelegramBotConfig config, IServiceCollection isc)
|
||||
{
|
||||
Client = new TelegramBotClient(config.Token);
|
||||
Config = config;
|
||||
this.isc = isc;
|
||||
}
|
||||
internal static bool IsValidHandlerMethod(MethodInfo method, Type parameterType)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
return method.ReturnType == typeof(Task) &&
|
||||
parameters.Length == 3 &&
|
||||
parameters[0].ParameterType == typeof(ITelegramBotClient) &&
|
||||
parameters[1].ParameterType == parameterType &&
|
||||
parameters[2].ParameterType == typeof(CancellationToken);
|
||||
}
|
||||
|
||||
internal static Func<ITelegramBotClient, T, CancellationToken, Task> CreateDelegate<T>(MethodInfo method)
|
||||
{
|
||||
var delegateType = typeof(Func<ITelegramBotClient, T, CancellationToken, Task>);
|
||||
return (Delegate.CreateDelegate(delegateType, null, method) as Func<ITelegramBotClient, T, CancellationToken, Task>)!;
|
||||
}
|
||||
|
||||
internal async Task AddAttributes(CancellationToken cancellationToken)
|
||||
{
|
||||
await Task.Run(async () =>
|
||||
{
|
||||
var implementations = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(a => a.GetTypes())
|
||||
.Where(t => typeof(IUpdatePollingService).IsAssignableFrom(t) && !t.IsInterface);
|
||||
|
||||
foreach (var implementation in implementations)
|
||||
{
|
||||
isc.AddSingleton(implementation);
|
||||
}
|
||||
|
||||
var methods = implementations
|
||||
.SelectMany(t => t.GetMethods(
|
||||
BindingFlags.Instance |
|
||||
BindingFlags.Public | BindingFlags.NonPublic |
|
||||
BindingFlags.DeclaredOnly))
|
||||
.Where(m =>
|
||||
m.GetCustomAttribute<CommandAttribute>() != null ||
|
||||
m.GetCustomAttribute<CallbackAttribute>() != null ||
|
||||
m.GetCustomAttribute<EditMessageAttribute>() != null ||
|
||||
m.GetCustomAttribute<InlineAttribute>() != null ||
|
||||
m.GetCustomAttribute<PreCheckoutAttribute>() != null ||
|
||||
m.GetCustomAttribute<UpdateAttribute>() != null);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
|
||||
var commandAttr = method.GetCustomAttribute<CommandAttribute>();
|
||||
if (commandAttr != null)
|
||||
{
|
||||
if (IsValidHandlerMethod(method, typeof(Message)))
|
||||
{
|
||||
var handler = CreateDelegate<Message>(method);
|
||||
CommandHandler.TryAdd(commandAttr.Command, handler);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var callbackAttr = method.GetCustomAttribute<CallbackAttribute>();
|
||||
if (callbackAttr != null)
|
||||
{
|
||||
if (IsValidHandlerMethod(method, typeof(CallbackQuery)))
|
||||
{
|
||||
var handler = CreateDelegate<CallbackQuery>(method);
|
||||
CallbackQueryHandler.TryAdd(callbackAttr.QueryId, handler);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var editMessageAttr = method.GetCustomAttribute<EditMessageAttribute>();
|
||||
if (editMessageAttr != null)
|
||||
{
|
||||
if (IsValidHandlerMethod(method, typeof(Message)))
|
||||
{
|
||||
var handler = CreateDelegate<Message>(method);
|
||||
EditedMessageHandler.Add(handler);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var inlineAttr = method.GetCustomAttribute<InlineAttribute>();
|
||||
if (inlineAttr != null)
|
||||
{
|
||||
if (IsValidHandlerMethod(method, typeof(InlineQuery)))
|
||||
{
|
||||
var handler = CreateDelegate<InlineQuery>(method);
|
||||
InlineHandler.TryAdd(inlineAttr.InlineId, handler);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var preCheckoutAttr = method.GetCustomAttribute<PreCheckoutAttribute>();
|
||||
if (preCheckoutAttr != null)
|
||||
{
|
||||
if (IsValidHandlerMethod(method, typeof(PreCheckoutQuery)))
|
||||
{
|
||||
var handler = CreateDelegate<PreCheckoutQuery>(method);
|
||||
PreCheckoutHandler = handler;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
var updateAttr = method.GetCustomAttribute<UpdateAttribute>();
|
||||
if (updateAttr != null)
|
||||
{
|
||||
if (IsValidHandlerMethod(method, typeof(Update)))
|
||||
{
|
||||
var handler = CreateDelegate<Update>(method);
|
||||
DefaultUpdateHandler.Add(handler);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}, cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
internal async Task UpdateHandler(ITelegramBotClient client, Update update, CancellationToken ctx)
|
||||
{
|
||||
switch (update)
|
||||
{
|
||||
case { Message: { } message }:
|
||||
await CommandHandler.FirstOrDefault(k => message.Text!.StartsWith(k.Key)).Value(client, message, ctx);
|
||||
break;
|
||||
case { EditedMessage: { } message }:
|
||||
EditedMessageHandler.ForEach(async k => await k(client, message, ctx));
|
||||
break;
|
||||
case { CallbackQuery: { } callbackQuery }:
|
||||
await CallbackQueryHandler.FirstOrDefault(k => callbackQuery.Data!.StartsWith(k.Key)).Value(client, callbackQuery, ctx);
|
||||
break;
|
||||
case { InlineQuery: { } inlineQuery }:
|
||||
await InlineHandler.FirstOrDefault(k => inlineQuery.Id.StartsWith(k.Key)).Value(client, inlineQuery, ctx);
|
||||
break;
|
||||
case { PreCheckoutQuery: { } preCheckoutQuery }:
|
||||
if (PreCheckoutHandler != null) await PreCheckoutHandler(client, preCheckoutQuery, ctx);
|
||||
break;
|
||||
default:
|
||||
DefaultUpdateHandler.ForEach(async k => await k(client, update, ctx));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "AsyncVoidLambda")]
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await AddAttributes(cancellationToken);
|
||||
|
||||
|
||||
|
||||
Client.StartReceiving(
|
||||
async (client, update, ctx) =>
|
||||
{
|
||||
switch (update)
|
||||
{
|
||||
case { Message: { } message }:
|
||||
await CommandHandler.FirstOrDefault(k => message.Text!.StartsWith(k.Key)).Value(client, message, cancellationToken);
|
||||
break;
|
||||
case { EditedMessage: { } message }:
|
||||
EditedMessageHandler.ForEach(async k => await k(client, message, cancellationToken));
|
||||
break;
|
||||
case { CallbackQuery: { } callbackQuery }:
|
||||
await CallbackQueryHandler.FirstOrDefault(k => callbackQuery.Data!.StartsWith(k.Key)).Value(client, callbackQuery, cancellationToken);
|
||||
break;
|
||||
case { InlineQuery: { } inlineQuery }:
|
||||
await InlineHandler.FirstOrDefault(k => inlineQuery.Id.StartsWith(k.Key)).Value(client, inlineQuery, cancellationToken);
|
||||
break;
|
||||
case {PreCheckoutQuery: { } preCheckoutQuery}:
|
||||
if (PreCheckoutHandler != null)
|
||||
await PreCheckoutHandler(client, preCheckoutQuery, cancellationToken);
|
||||
break;
|
||||
default:
|
||||
DefaultUpdateHandler.ForEach(async k => await k(client, update, ctx));
|
||||
break;
|
||||
}
|
||||
|
||||
},
|
||||
UpdateHandler,
|
||||
Config.errorHandler ?? ((_, _, _) => Task.CompletedTask),
|
||||
Config.ReceiverOptions,
|
||||
cancellationToken);
|
||||
|
||||
@@ -1,9 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>1.0.0</Version>
|
||||
<Authors>yawaflua</Authors>
|
||||
<Title>Telegram.Net</Title>
|
||||
<Description>Telegram.Bots extender pack, what provides to user attributes, which can used with services</Description>
|
||||
<Copyright>Dmitrii Shimanskii</Copyright>
|
||||
<PackageProjectUrl>https://github.com/yawaflua/telegram.Net</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/yawaflua/telegram.Net</RepositoryUrl>
|
||||
<PackageTags>telegram</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
7
global.json
Normal file
7
global.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "7.0.0",
|
||||
"rollForward": "latestMinor",
|
||||
"allowPrerelease": false
|
||||
}
|
||||
}
|
||||
1
tests/Telegram.Tests/GlobalUsings.cs
Normal file
1
tests/Telegram.Tests/GlobalUsings.cs
Normal file
@@ -0,0 +1 @@
|
||||
global using NUnit.Framework;
|
||||
33
tests/Telegram.Tests/Telegram.Tests.csproj
Normal file
33
tests/Telegram.Tests/Telegram.Tests.csproj
Normal file
@@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
|
||||
<IsPackable>false</IsPackable>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.1"/>
|
||||
<PackageReference Include="Moq" Version="4.20.72" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3"/>
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2"/>
|
||||
<PackageReference Include="NUnit.Analyzers" Version="3.6.1"/>
|
||||
<PackageReference Include="coverlet.collector" Version="3.2.0"/>
|
||||
<PackageReference Include="Telegram.Bot" Version="22.4.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Telegram.Net\Telegram.Net.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="appsettings.json">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
</Project>
|
||||
175
tests/Telegram.Tests/TestTelegramHostedService.cs
Normal file
175
tests/Telegram.Tests/TestTelegramHostedService.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Polling;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.InlineQueryResults;
|
||||
using Telegram.Bot.Types.Payments;
|
||||
using Telegram.Net.Attributes;
|
||||
using Telegram.Net.Interfaces;
|
||||
using Telegram.Net.Services;
|
||||
|
||||
using System.Reflection;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using Telegram.Bot.Types.ReplyMarkups;
|
||||
using Telegram.Net.Models;
|
||||
|
||||
namespace Telegram.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class TelegramHostedServiceTests
|
||||
{
|
||||
private TelegramBotConfig _configMock;
|
||||
private ServiceCollection _services;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var conf = new ConfigurationBuilder()
|
||||
.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json", false)
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
_configMock = new TelegramBotConfig(conf.GetValue<string>("telegram_test_token") ?? throw new Exception("Provide telegram token first"));
|
||||
_services = new ServiceCollection();
|
||||
}
|
||||
|
||||
public class TestHandler : IUpdatePollingService
|
||||
{
|
||||
[Command("/start")]
|
||||
public async Task HandleStart(ITelegramBotClient client, Message message, CancellationToken ct)
|
||||
=> await client.SendTextMessageAsync(message.Chat.Id, "Started", cancellationToken: ct);
|
||||
|
||||
[Callback("test_callback")]
|
||||
public async Task HandleCallback(ITelegramBotClient client, CallbackQuery query, CancellationToken ct)
|
||||
=> await client.AnswerCallbackQueryAsync(query.Id, "Callback handled", cancellationToken: ct);
|
||||
|
||||
[EditMessage]
|
||||
public async Task HandleEdit(ITelegramBotClient client, Message message, CancellationToken ct)
|
||||
=> await client.EditMessageTextAsync(message.Chat.Id, message.MessageId, "Edited", cancellationToken: ct);
|
||||
|
||||
[Inline("search")]
|
||||
public async Task HandleInline(ITelegramBotClient client, InlineQuery query, CancellationToken ct)
|
||||
=> await client.AnswerInlineQueryAsync(query.Id, new[] { new InlineQueryResultArticle("1", "Test", new InputTextMessageContent("Test")) }, cancellationToken: ct);
|
||||
|
||||
[PreCheckout]
|
||||
public async Task HandlePayment(ITelegramBotClient client, PreCheckoutQuery query, CancellationToken ct)
|
||||
=> await client.AnswerPreCheckoutQueryAsync(query.Id, cancellationToken: ct);
|
||||
|
||||
[Update]
|
||||
public async Task HandleUpdate(ITelegramBotClient client, Update update, CancellationToken ct)
|
||||
=> await client.SendTextMessageAsync(123, "Update handled", cancellationToken: ct);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AddAttributes_RegistersCommandHandlersCorrectly()
|
||||
{
|
||||
_services.AddSingleton<TestHandler>();
|
||||
var service = new TelegramHostedService(_configMock, _services);
|
||||
|
||||
service.AddAttributes(CancellationToken.None).Wait();
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(service.CommandHandler, Contains.Key("/start"));
|
||||
Assert.That(service.CallbackQueryHandler, Contains.Key("test_callback"));
|
||||
Assert.That(service.EditedMessageHandler, Has.Count.EqualTo(1));
|
||||
Assert.That(service.InlineHandler, Contains.Key("search"));
|
||||
Assert.That(service.PreCheckoutHandler, Is.Not.Null);
|
||||
Assert.That(service.DefaultUpdateHandler, Has.Count.EqualTo(1));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsValidHandlerMethod_ValidMessageHandler_ReturnsTrue()
|
||||
{
|
||||
// Arrange
|
||||
var method = typeof(TestHandler).GetMethod("HandleStart");
|
||||
|
||||
// Act
|
||||
var result = TelegramHostedService.IsValidHandlerMethod(method, typeof(Message));
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsValidHandlerMethod_InvalidParameters_ReturnsFalse()
|
||||
{
|
||||
// Arrange
|
||||
var method = typeof(TestHandler).GetMethod("HandleStart");
|
||||
|
||||
// Act
|
||||
var result = TelegramHostedService.IsValidHandlerMethod(method, typeof(CallbackQuery));
|
||||
|
||||
// Assert
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class IntegrationTests
|
||||
{
|
||||
private Mock<ITelegramBotClient> _botClientMock;
|
||||
private TelegramHostedService _hostedService;
|
||||
private Mock<ITelegramBotConfig> _configMock;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
var conf = new ConfigurationBuilder()
|
||||
.SetBasePath(AppContext.BaseDirectory)
|
||||
.AddJsonFile("appsettings.json", false)
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
_configMock = new Mock<ITelegramBotConfig>();
|
||||
_configMock.Setup(c => c.Token).Returns(conf.GetValue<string>("telegram_test_token") ?? throw new Exception("Provide token first"));
|
||||
_configMock.Setup(c => c.ReceiverOptions).Returns(new ReceiverOptions());
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddSingleton<TelegramHostedServiceTests.TestHandler>();
|
||||
_botClientMock = new Mock<ITelegramBotClient>();
|
||||
|
||||
_hostedService = new TelegramHostedService(_configMock.Object, services);
|
||||
_hostedService.AddAttributes(CancellationToken.None).Wait();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task HandleMessage_ValidCommand_ExecutesHandler()
|
||||
{
|
||||
// Arrange
|
||||
var message = new Message { Text = "/start", Chat = new Chat { Id = 123 } };
|
||||
var update = new Update { Message = message };
|
||||
|
||||
// Act
|
||||
await _hostedService.StartAsync(CancellationToken.None);
|
||||
await InvokeUpdateHandler(update);
|
||||
|
||||
// Assert
|
||||
_botClientMock.Verify();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task HandleCallback_ValidQuery_ExecutesHandler()
|
||||
{
|
||||
// Arrange
|
||||
var callback = new CallbackQuery { Data = "test_callback", Id = "cb_id" };
|
||||
var update = new Update { CallbackQuery = callback };
|
||||
|
||||
// Act
|
||||
await _hostedService.StartAsync(CancellationToken.None);
|
||||
await InvokeUpdateHandler(update);
|
||||
|
||||
// Assert
|
||||
_botClientMock.Verify();
|
||||
}
|
||||
|
||||
private async Task InvokeUpdateHandler(Update update)
|
||||
{
|
||||
await _hostedService.UpdateHandler(_botClientMock.Object, update, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
tests/Telegram.Tests/appsettings.json
Normal file
3
tests/Telegram.Tests/appsettings.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"_telegram_test_token": "PROVIDE_YOUR_TOKEN"
|
||||
}
|
||||
Reference in New Issue
Block a user