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.
@@ -91,4 +105,4 @@ public static async Task HandleUpdate(ITelegramBotClient bot, Update update, Can
Try to not use provided dependencies in class. We are should to fix it in v1.0.2. Try to not use provided dependencies in class. We are should to fix it in v1.0.2.
## License ## License
This project is open-source and available under the [Apache 2.0 License](LICENSE). This project is open-source and available under the [Apache 2.0 License](LICENSE).

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)
@@ -73,116 +75,82 @@ 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
.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); var isp = isc.BuildServiceProvider();
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()
.Select(param => isp.GetRequiredService(param.ParameterType))
.ToArray();
constructor.Invoke(parameters);
switch (method.GetCustomAttributes().First(t => attributeTypes.Contains(t.GetType())))
{ {
if (IsValidHandlerMethod(method, typeof(Message))) case CommandAttribute command when IsValidHandlerMethod(method, typeof(Message)):
{ var commandHandler = CreateDelegate<Message>(method);
var handler = CreateDelegate<Message>(method); if (!CommandHandler.TryAdd(command.Command, commandHandler))
if (!CommandHandler.TryAdd(commandAttr.Command, handler)) throw new Exception($"Failed to add command: {command.Command}");
throw new Exception($"Failed to add in commandHandler: {commandAttr.Command}"); break;
}
case CallbackAttribute callback when IsValidHandlerMethod(method, typeof(CallbackQuery)):
continue; var callbackHandler = CreateDelegate<CallbackQuery>(method);
} if (!CallbackQueryHandler.TryAdd(callback.QueryId, callbackHandler))
throw new Exception($"Failed to add callback: {callback.QueryId}");
var callbackAttr = method.GetCustomAttribute<CallbackAttribute>(); break;
if (callbackAttr != null)
{ case EditMessageAttribute _ when IsValidHandlerMethod(method, typeof(Message)):
if (IsValidHandlerMethod(method, typeof(CallbackQuery))) EditedMessageHandler.Add(CreateDelegate<Message>(method));
{ break;
var handler = CreateDelegate<CallbackQuery>(method);
if (!CallbackQueryHandler.TryAdd(callbackAttr.QueryId, handler)) case InlineAttribute inline when IsValidHandlerMethod(method, typeof(InlineQuery)):
throw new Exception($"Failed to add in callbacKQuery: {callbackAttr.QueryId}");; var inlineHandler = CreateDelegate<InlineQuery>(method);
} if (!InlineHandler.TryAdd(inline.InlineId, inlineHandler))
throw new Exception($"Failed to add inline: {inline.InlineId}");
continue; break;
}
case PreCheckoutAttribute _ when IsValidHandlerMethod(method, typeof(PreCheckoutQuery)):
var editMessageAttr = method.GetCustomAttribute<EditMessageAttribute>(); PreCheckoutHandler = CreateDelegate<PreCheckoutQuery>(method);
if (editMessageAttr != null) break;
{
if (IsValidHandlerMethod(method, typeof(Message))) case UpdateAttribute _ when IsValidHandlerMethod(method, typeof(Update)):
{ DefaultUpdateHandler.Add(CreateDelegate<Update>(method));
var handler = CreateDelegate<Message>(method); break;
EditedMessageHandler.Add(handler);
}
continue;
}
var inlineAttr = method.GetCustomAttribute<InlineAttribute>();
if (inlineAttr != null)
{
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;
}
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>