Merge pull request #4 from yawaflua/develop

pre-v1.0.2 fix
This commit is contained in:
Dmitri Shimanski
2025-03-21 01:07:42 +02:00
committed by GitHub
7 changed files with 113 additions and 112 deletions

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Telegram.Net; using Telegram.Net;
@@ -7,12 +8,11 @@ var webHost = Host.CreateDefaultBuilder()
.ConfigureLogging(l => l.ClearProviders().AddConsole()) .ConfigureLogging(l => l.ClearProviders().AddConsole())
.ConfigureServices(k => .ConfigureServices(k =>
{ {
k.ConnectTelegram(new("TOKEN") var _conf = new ConfigurationBuilder()
{ .AddJsonFile("appsettings.json")
errorHandler = async (client, exception, ctx) => .AddEnvironmentVariables()
{ .Build();
Console.WriteLine(exception); k.AddSingleton(_conf);
} k.ConnectTelegram(new(_conf.GetValue<string>("telegram_test_token")));
});
}); });
webHost.Build().Run(); webHost.Build().Run();

View File

@@ -12,6 +12,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.3" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.3" />
<ProjectReference Include="..\..\Telegram.Net\Telegram.Net.csproj" /> <ProjectReference Include="..\..\Telegram.Net\Telegram.Net.csproj" />
<None CopyToOutputDirectory="Always" Include="appsettings.json"></None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -1,4 +1,5 @@
using Telegram.Bot; using Microsoft.Extensions.Configuration;
using Telegram.Bot;
using Telegram.Bot.Types; using Telegram.Bot.Types;
using Telegram.Net.Attributes; using Telegram.Net.Attributes;
using Telegram.Net.Interfaces; using Telegram.Net.Interfaces;
@@ -7,6 +8,11 @@ namespace Telegram.Examples.UpdatePolling;
public class Update : IUpdatePollingService public class Update : IUpdatePollingService
{ {
private static IConfiguration _conf;
public Update(IConfiguration conf)
{
_conf = conf;
}
[Update] [Update]
public async Task UpdateExample(ITelegramBotClient client, Bot.Types.Update update, CancellationToken ctx) public async Task UpdateExample(ITelegramBotClient client, Bot.Types.Update update, CancellationToken ctx)
{ {
@@ -31,6 +37,12 @@ public class Update : IUpdatePollingService
await client.SendMessage(message.From!.Id, "Hello, I`m example bot.", cancellationToken: ctx); await client.SendMessage(message.From!.Id, "Hello, I`m example bot.", cancellationToken: ctx);
} }
[Command("/test_conf")]
public async Task TestConfigurationBuilder(ITelegramBotClient client, Message message, CancellationToken cts)
{
await client.SendMessage(message.Chat.Id, _conf.GetValue<string>("ExampleMessage") ?? throw new Exception("Not found"));
}
[EditMessage] [EditMessage]
public async Task EditMessageExmaple(ITelegramBotClient client, Message message, CancellationToken ctx) public async Task EditMessageExmaple(ITelegramBotClient client, Message message, CancellationToken ctx)
{ {

View File

@@ -0,0 +1,4 @@
{
"ExampleMessage": "Test!",
"telegram_test_token": "PROVIDE_TOKEN"
}

View File

@@ -20,6 +20,20 @@ Ensure you have the required dependencies installed:
## Usage ## Usage
### Provide dependencies in class
You can provide dependencies in class from constructor, and after it use it like `static`.
```csharp
public class Example : IUpdatePollingService
{
private static MyCoolService _service; // It should to be static!
public Example(MyCoolService service)
{
_service = service;
}
}
```
### Inline Query Handling ### Inline Query Handling
Use the `InlineAttribute` to register a method as an inline query handler. Use the `InlineAttribute` to register a method as an inline query handler.

View File

@@ -9,6 +9,8 @@ using Telegram.Bot.Types;
using Telegram.Bot.Types.Payments; using Telegram.Bot.Types.Payments;
using Telegram.Net.Attributes; using Telegram.Net.Attributes;
using Telegram.Net.Interfaces; using Telegram.Net.Interfaces;
using static System.Reflection.BindingFlags;
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously #pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
namespace Telegram.Net.Services; namespace Telegram.Net.Services;
@@ -18,12 +20,12 @@ public class TelegramHostedService : IHostedService
private IServiceCollection isc { get; } private IServiceCollection isc { get; }
internal TelegramBotClient Client { get; set; } internal TelegramBotClient Client { get; set; }
private ITelegramBotConfig Config { get; } private ITelegramBotConfig Config { get; }
internal Dictionary<string, Func<ITelegramBotClient, Message, CancellationToken, Task>> CommandHandler { get; } = new(); internal Dictionary<string, Func<ITelegramBotClient, Message, CancellationToken, Task>> CommandHandler { get; set; } = new();
internal List<Func<ITelegramBotClient, Message, CancellationToken, Task>> EditedMessageHandler { get; } = new(); internal List<Func<ITelegramBotClient, Message, CancellationToken, Task>> EditedMessageHandler { get; set; } = new();
internal Dictionary<string, Func<ITelegramBotClient, CallbackQuery,CancellationToken, Task>> CallbackQueryHandler { get; } = new(); internal Dictionary<string, Func<ITelegramBotClient, CallbackQuery,CancellationToken, Task>> CallbackQueryHandler { get; set; } = new();
internal Dictionary<string, Func<ITelegramBotClient, InlineQuery ,CancellationToken, Task>> InlineHandler { get; } = new(); internal Dictionary<string, Func<ITelegramBotClient, InlineQuery ,CancellationToken, Task>> InlineHandler { get; set; } = new();
internal Func<ITelegramBotClient, PreCheckoutQuery,CancellationToken, Task>? PreCheckoutHandler { get; set; } internal Func<ITelegramBotClient, PreCheckoutQuery,CancellationToken, Task>? PreCheckoutHandler { get; set; }
internal List<Func<ITelegramBotClient, Update, CancellationToken, Task>> DefaultUpdateHandler { get; } = new(); internal List<Func<ITelegramBotClient, Update, CancellationToken, Task>> DefaultUpdateHandler { get; set; } = new();
internal static ILogger<TelegramHostedService> _logger; internal static ILogger<TelegramHostedService> _logger;
public TelegramHostedService(ITelegramBotConfig config, IServiceCollection isc, ILogger<TelegramHostedService> logger) public TelegramHostedService(ITelegramBotConfig config, IServiceCollection isc, ILogger<TelegramHostedService> logger)
@@ -74,115 +76,81 @@ public class TelegramHostedService : IHostedService
} }
internal async Task AddAttributes(CancellationToken cancellationToken) internal async Task AddAttributes(CancellationToken cancellationToken)
{ {
await Task.Run(async () => await Task.Run(async () =>
{ {
try try
{ {
var implementations = AppDomain.CurrentDomain.GetAssemblies() var attributeTypes = new HashSet<Type>
{
typeof(CommandAttribute),
typeof(CallbackAttribute),
typeof(EditMessageAttribute),
typeof(InlineAttribute),
typeof(PreCheckoutAttribute),
typeof(UpdateAttribute)
};
var methods = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetTypes()) .SelectMany(a => a.GetTypes())
.Where(t => typeof(IUpdatePollingService).IsAssignableFrom(t) && !t.IsInterface); .Where(t => typeof(IUpdatePollingService).IsAssignableFrom(t) && !t.IsInterface)
.SelectMany(t => t.GetMethods(Instance |
Public |
NonPublic |
DeclaredOnly))
.Where(m => m.GetCustomAttributes().Any(a => attributeTypes.Contains(a.GetType())))
.ToList();
foreach (var implementation in implementations) if (methods.Count == 0)
{ {
isc.AddScoped(implementation); _logger.LogWarning("No methods found with required attributes");
} }
var methods = implementations var isp = isc.BuildServiceProvider();
.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);
if (methods.Count() == 0)
{
_logger.LogWarning("Not founded methods with attributes.");
}
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
foreach (var method in methods) foreach (var method in methods)
{ {
var commandAttr = method.GetCustomAttribute<CommandAttribute>(); var declaringType = method.DeclaringType!;
if (commandAttr != null) var constructor = declaringType.GetConstructors()[0];
{ var parameters = constructor.GetParameters()
if (IsValidHandlerMethod(method, typeof(Message))) .Select(param => isp.GetRequiredService(param.ParameterType))
{ .ToArray();
var handler = CreateDelegate<Message>(method);
if (!CommandHandler.TryAdd(commandAttr.Command, handler))
throw new Exception($"Failed to add in commandHandler: {commandAttr.Command}");
}
continue; constructor.Invoke(parameters);
}
var callbackAttr = method.GetCustomAttribute<CallbackAttribute>(); switch (method.GetCustomAttributes().First(t => attributeTypes.Contains(t.GetType())))
if (callbackAttr != null)
{ {
if (IsValidHandlerMethod(method, typeof(CallbackQuery))) case CommandAttribute command when IsValidHandlerMethod(method, typeof(Message)):
{ var commandHandler = CreateDelegate<Message>(method);
var handler = CreateDelegate<CallbackQuery>(method); if (!CommandHandler.TryAdd(command.Command, commandHandler))
if (!CallbackQueryHandler.TryAdd(callbackAttr.QueryId, handler)) throw new Exception($"Failed to add command: {command.Command}");
throw new Exception($"Failed to add in callbacKQuery: {callbackAttr.QueryId}");; break;
}
continue; case CallbackAttribute callback when IsValidHandlerMethod(method, typeof(CallbackQuery)):
} var callbackHandler = CreateDelegate<CallbackQuery>(method);
if (!CallbackQueryHandler.TryAdd(callback.QueryId, callbackHandler))
throw new Exception($"Failed to add callback: {callback.QueryId}");
break;
var editMessageAttr = method.GetCustomAttribute<EditMessageAttribute>(); case EditMessageAttribute _ when IsValidHandlerMethod(method, typeof(Message)):
if (editMessageAttr != null) EditedMessageHandler.Add(CreateDelegate<Message>(method));
{ break;
if (IsValidHandlerMethod(method, typeof(Message)))
{
var handler = CreateDelegate<Message>(method);
EditedMessageHandler.Add(handler);
}
continue; case InlineAttribute inline when IsValidHandlerMethod(method, typeof(InlineQuery)):
} var inlineHandler = CreateDelegate<InlineQuery>(method);
if (!InlineHandler.TryAdd(inline.InlineId, inlineHandler))
throw new Exception($"Failed to add inline: {inline.InlineId}");
break;
var inlineAttr = method.GetCustomAttribute<InlineAttribute>(); case PreCheckoutAttribute _ when IsValidHandlerMethod(method, typeof(PreCheckoutQuery)):
if (inlineAttr != null) PreCheckoutHandler = CreateDelegate<PreCheckoutQuery>(method);
{ break;
if (IsValidHandlerMethod(method, typeof(InlineQuery)))
{
var handler = CreateDelegate<InlineQuery>(method);
if (!InlineHandler.TryAdd(inlineAttr.InlineId, handler))
throw new Exception($"Failed to add in inlineHandler: {inlineAttr.InlineId}");;
}
continue; case UpdateAttribute _ when IsValidHandlerMethod(method, typeof(Update)):
} DefaultUpdateHandler.Add(CreateDelegate<Update>(method));
break;
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;
} }
} }
} }

View File

@@ -5,7 +5,7 @@
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>1.0.0</Version> <Version>1.0.2</Version>
<Authors>yawaflua</Authors> <Authors>yawaflua</Authors>
<Title>yawaflua.Telegram.Net</Title> <Title>yawaflua.Telegram.Net</Title>
<Description>Telegram.Bots extender pack, what provides to user attributes, which can used with services</Description> <Description>Telegram.Bots extender pack, what provides to user attributes, which can used with services</Description>