Rewrote hosts again

This commit is contained in:
2026-03-07 02:35:53 +04:00
parent 3cdc058fb5
commit 370c0cecda
24 changed files with 184 additions and 10040 deletions
View File
-692
View File
@@ -1,692 +0,0 @@
# Getting Started with Telegrator
---
This guide will walk you through the core concepts and advanced features of **Telegrator** — a modern, aspect-oriented, mediator-based framework for building powerful and maintainable Telegram bots in C#.
- [1. Installation](#1-installation)
- [2. Framework Mechanics Overview](#2-framework-mechanics-overview)
- [2.1. Basic Concepts](#21-basic-concepts)
- [2.2. Practice: Minimal Bot](#22-practice-minimal-bot)
- [2.3. Working with Filters](#23-working-with-filters)
- [2.4. State Management](#24-state-management)
- [2.5. Concurrency & Awaiting](#25-concurrency--awaiting)
- [2.6. Extensibility](#26-extensibility)
- [2.7. Integration](#27-integration)
- [3. Step-by-Step Tutorials](#3-step-by-step-tutorials)
- [3.1. Minimal Bot Creation](#31-minimal-bot-creation)
- [3.2. Command Filtering](#32-command-filtering)
- [3.3. State Management Wizard](#33-state-management-wizard)
- [3.4. Awaiting CallbackQuery](#34-awaiting-callbackquery)
- [3.5. Adding a Custom Filter](#35-adding-a-custom-filter)
- [4. Advanced Topics](#4-advanced-topics)
- [4.1. Handler Priority](#41-handler-priority)
- [4.2. Dependency Injection (DI)](#42-dependency-injection-di)
- [4.3. Custom State Keepers](#43-custom-state-keepers)
- [4.4. Automatic Handler Discovery](#44-automatic-handler-discovery)
- [4.5. Hosting Integration](#45-hosting-integration)
- [4.6. Error Handling and Logging](#46-error-handling-and-logging)
- [4.7. Performance Optimization](#47-performance-optimization)
- [4.8. Best Practices](#48-best-practices)
- [5. FAQ & Best Practices](#5-faq--best-practices)
- [Q: My handler is not being triggered. What should I do?](#q-my-handler-is-not-being-triggered-what-should-i-do)
- [Q: How can I access the `ITelegramBotClient` or the original `Update` object inside a handler?](#q-how-can-i-access-the-itelegrambotclient-or-the-original-update-object-inside-a-handler)
- [Q: How do I handle errors?](#q-how-do-i-handle-errors)
- [Q: How can I organize my code for a large bot?](#q-how-can-i-organize-my-code-for-a-large-bot)
- [6. Links](#6-links)
---
## 1. Installation
**Telegrator** is distributed as a NuGet package. You can install it using the .NET CLI, the NuGet Package Manager Console, or by managing NuGet packages in Visual Studio.
### Prerequisites
- .NET >= 5.0 `or` .NET Core >= 2.0 `or` Framework >= 4.6.1 (.NET Standart 2.0 compatible)
- A Telegram Bot Token from [@BotFather](https://t.me/BotFather).
### .NET CLI
```shell
dotnet add package Telegrator
```
### Package Manager Console
```shell
Install-Package Telegrator
```
### Hosting Integrations
- .NET Core >= 8.0
- `Telegrator.Hosting`: For console/background services
- `Telegrator.Hosting.Web`: For ASP.NET Core/Webhook (WIP)
---
## 2. Framework Mechanics Overview
### 2.1. Basic Concepts
Telegrator is built around several core ideas:
- **Aspect-Oriented Handlers**: Each handler is a focused, reusable class that reacts to a specific type of update (message, command, callback, etc.).
- **Mediator Pattern**: All updates are routed through a central `UpdateRouter`, which dispatches them to the appropriate handlers based on filters and priorities.
- **Filters as Attributes**: Handler classes are decorated with filter attributes that declaratively specify when the handler should run.
- **State Management**: Built-in mechanisms for managing user/chat state without external storage.
- **Concurrency Control**: Fine-grained control over how many handlers run in parallel, both globally and per-handler.
### 2.2. Practice: Minimal Bot
Here's how to create a minimal bot that replies to any private message containing "hello":
```csharp
using Telegrator;
using Telegrator.Handlers;
using Telegrator.Annotations;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
[MessageHandler]
[ChatType(ChatType.Private)]
[TextContains("hello", StringComparison.InvariantCultureIgnoreCase)]
public class HelloHandler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply("Hello! Nice to meet you!", cancellationToken: cancellation);
}
}
class Program
{
static void Main(string[] args)
{
var bot = new TelegratorClient("<YOUR_BOT_TOKEN>");
bot.Handlers.AddHandler<HelloHandler>();
bot.StartReceiving();
Console.ReadLine();
}
}
```
> **How is it working?**
> 1. **`[MessageHandler]`**: This attribute marks `HelloHandler` as a handler for `Message` updates.
> 2. **`[ChatType(ChatType.Private)]`**: This filter ensures the handler only runs for private chat messages.
> 3. **`[TextContains("hello")]`**: This filter checks if the message contains "hello" (case-insensitive).
> 4. **`TelegratorClient`**: The main bot client that manages the connection to Telegram and the update processing pipeline.
> 5. **`bot.Handlers.AddHandler<HelloHandler>()`**: Registers the handler with the bot.
> 6. **`bot.StartReceiving()`**: Starts the long-polling loop to fetch updates from Telegram.
> 7. **`Reply(...)`**: A helper method that sends a reply to the original message.
### 2.3. Working with Filters
Filters are the gatekeepers of your bot logic. They are applied as attributes to handler classes and determine when a handler should be executed.
**Common Filters:**
- `[CommandAllias("start")]` — Only for the `/start` command
- `[TextContains("hello")]` — Message contains "hello"
- `[ChatType(ChatType.Private)]` — Only private chats
- `[FromUserId(123456789)]` — Only from a specific user
- `[HasReply]` — Only if the message is a reply
**Combining Filters:**
You can combine filters using logical modifiers:
- Multiple filters on a handler, by default, are combined with logical AND
- `Modifiers = FilterModifier.OrNext` - will combine this and next filter with OR logic
- `Modifiers = FilterModifier.Not` - Inverts the filter
- This flags can be combined using bit OR (`Modifiers = FilterModifier.Not | FilterModifier.OrNext`)
**Example:**
```csharp
[MessageHandler]
[ChatType(ChatType.Private)]
[TextContains("hello", Modifiers = FilterModifier.Not)]
public class NotHelloHandler : MessageHandler
{
// Runs for private messages that do NOT contain "hello"
}
[MessageHandler]
[TextContains("bot", Modifiers = FilterModifier.OrNext)]
[Mentioned()]
public class NotHelloHandler : MessageHandler
{
// Runs for messages that contains "bot" or if bot was mentioned using @
}
```
> **How is it working?**
> 1. **Multiple Filters**: The handler has two filters that work together with logical AND.
> 2. **`[ChatType(ChatType.Private)]`**: Ensures only private chat messages are processed.
> 3. **`[TextContains("hello", Modifiers = FilterModifier.Not)]`**: The `Not` modifier inverts the filter, so it matches messages that do NOT contain "hello".
> 4. **Combined Logic**: The handler will only run for private messages that don't contain "hello".
### 2.4. State Management
Telegrator provides built-in state management for multi-step conversations (wizards, forms, quizzes) without a database.
> [!NOTE]
> Each type of `StateKeeper`'s (EnumStateKeeper, NumericStateKeeper) is shared beetwen **EVERY** handler in project.
**Types of State:**
- **NumericState**: Integer-based steps
- **StringState**: Named steps
- **EnumState**: Enum-based scenarios
**How to Use:**
1. Define your state (enum/int/string)
2. Use a state filter attribute on your handler:
- `[EnumState<MyEnum>(MyEnum.Step1)]`
- `[NumericState(1)]`
3. Change state inside the handler using extension methods:
- `container.ForwardEnumState<MyEnum>()`
- `container.ForwardNumericState()`
- `container.DeleteEnumState<MyEnum>()`
**Example:**
```csharp
public enum QuizState
{
Start = SpecialState.NoState, Q1, Q2
}
[CommandHandler]
[CommandAllias("quiz")]
[EnumState<QuizState>(QuizState.Start)]
public class StartQuizHandler : CommandHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
container.ForwardEnumState<QuizState>();
await Reply("Quiz started! Question 1: What is the capital of France?");
}
}
[MessageHandler]
[EnumState<QuizState>(QuizState.Q1)]
public class Q1Handler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
if (Input.Text.Trim().Equals("Paris", StringComparison.InvariantCultureIgnoreCase))
await Reply("Correct!");
else
await Reply("Incorrect. The answer is Paris.");
container.ForwardEnumState<QuizState>();
await Reply("Question 2: What is 2 + 2?");
}
}
```
> **How is it working?**
> 1. **Enum State Definition**: `QuizState` enum defines the conversation flow with `Start = SpecialState.NoState` indicating no initial state.
> 2. **State Filter**: `[EnumState<QuizState>(QuizState.Start)]` ensures the handler only runs when the user is in the "Start" state.
> 3. **State Transition**: `container.ForwardEnumState<QuizState>()` moves the user to the next state (Q1).
> 4. **Next Handler**: The `Q1Handler` will only run when the user is in state `QuizState.Q1`.
> 5. **State Management**: Each handler manages its own state transition, creating a clear conversation flow.
### 2.5. Concurrency & Awaiting
**Concurrency Control:**
- Limit the number of concurrent executions globally using `MaximumParallelWorkingHandlers` in `TelegramBotOptions`
**Awaiting Other Updates:**
- Use `AwaitingProvider` to wait for a user's next update (message or callback) inside a handler:
```csharp
[CommandHandler]
[CommandAllias("ask")]
public class AskHandler : CommandHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply("What is your name?");
var nextMessage = await container.AwaitMessage().BySenderId(cancellation);
await Reply($"Hello, {nextMessage.Text}!");
}
}
```
> **How is it working?**
> 1. **Awaiting Provider**: `container.AwaitMessage()` creates a temporary handler that waits for the next message.
> 2. **Sender Filter**: `.BySenderId(cancellation)` ensures only messages from the same user are captured.
> 3. **Async Flow**: The handler pauses execution until the user responds, then continues with the conversation.
> 4. **Context Preservation**: The original handler context is maintained during the awaiting process.
### 2.6. Extensibility
You can extend Telegrator by creating custom filters, attributes, and state keepers.
**Custom Filter Attribute Example:**
```csharp
using Telegram.Bot.Types;
using Telgrator.Attributes;
using Telegrator.Handlers;
public class AdminOnlyAttribute() : FilterAnnotation<Message>
{
private readonly List<long> _adminIds = [];
public void AddAdmin(long id) => _adminIds.Add(id);
public void RemoveAdmin(long id) => _adminIds.Remove(id);
public override bool CanPass(FilterExecutionContext<Message> context)
=> _adminIds.Contains(context.Input.From?.Id);
}
[MessageHandler]
[AdminOnly]
public class AdminHandler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply("Hello, admin!");
}
}
// ...
AdminOnlyAttribute.AddAdmin(123456789);
bot.StartReceiving();
```
> **How is it working?**
> 1. **Custom Filter**: `AdminOnlyAttribute` inherits from `FilterAnnotation<Message>` to create a reusable filter attribute.
> 2. **Filter Logic**: `CanPass()` method checks if the message sender's ID matches the admin ID.
> 4. **Usage**: The filter is applied as an attribute `[AdminOnly]` to restrict access users that not registered as admins.
### 2.7. Integration
Telegrator works in console, hosted applications, --and ASP.NET Core (webhook)-- (WIP) projects.
**Console App Example:**
```csharp
var bot = new TelegratorClient("<YOUR_BOT_TOKEN>");
bot.Handlers.CollectHandlersDomainWide();
bot.StartReceiving();
```
**Hosting Example:**
```csharp
using Telegrator.Hosting;
var builder = TelegramBotHost.CreateBuilder();
builder.Handlers.AddHandler<StartHandler>();
var host = builder.Build();
await host.StartAsync();
```
> **How is it working?**
> 1. **Console Integration**: `TelegratorClient` provides a simple way to create bots in console applications.
> 2. **Domain-Wide Collection**: `CollectHandlersDomainWide()` automatically discovers and registers all handlers in the current assembly.
> 3. **ASP.NET Core Integration**: `TelegramBotHost.CreateBuilder()` provides a builder pattern for hosting bots in ASP.NET Core applications.
> 4. **Dependency Injection**: Handlers and their dependencies are automatically registered with the DI container.
---
## 3. Step-by-Step Tutorials
### 3.1. Minimal Bot Creation
See [Practice: Minimal Bot](#practice-minimal-bot).
### 3.2. Command Filtering
Message is considered command if is start with '/' and has not null or empty name.
Instead of using the `MessageHandler` for command (such as `/start`) you should use `CommandHandler`.
```csharp
[CommandHandler]
[CommandAllias("start")]
public class StartHandler : CommandHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply("Welcome! Use /help to see available commands.");
}
}
[CommandHandler]
[CommandAllias("help")]
public class HelpHandler : CommandHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply("Available commands:\n/start - Start the bot\n/help - Show this help");
}
}
[MessageHandler]
[TextStartsWith("/", Modifiers = FilterModifier.Not)]
public class EchoHandler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply($"You said: \"{Input.Text}\"");
}
}
```
> **How is it working?**
> 1. **Command Handlers**: `[CommandHandler]` and `[CommandAllias]` work together to handle specific commands like `/start` and `/help`.
> 2. **Echo Handler**: `[TextStartsWith("/", Modifiers = FilterModifier.Not)]` catches all messages that don't start with "/" (non-commands).
> 3. **Handler Separation**: Each command has its own dedicated handler, making the code modular and maintainable.
> 4. **Filter Modifiers**: The `Not` modifier inverts the filter logic to exclude command messages.
### 3.3. State Management Wizard
```csharp
[CommandHandler]
[CommandAllias("wizard")]
[NumericState(SpecialState.NoState)]
public class StartWizardHandler : CommandHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
container.CreateNumericState(); // This code is not necesary, as "Forward" method can automatically creates state if needed, but its recomended to use
container.ForwardNumericState();
await Reply("What is your name?");
}
}
[MessageHandler]
[NumericState(1)]
public class NameHandler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
container.ForwardNumericState();
await Reply($"Nice to meet you, {Input.Text}! How old are you?");
}
}
[MessageHandler]
[NumericState(2)]
public class AgeHandler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
if (int.TryParse(Input.Text, out int age))
{
await Reply($"Thank you! You are {age} years old. Wizard completed!");
container.DeleteNumericState();
}
else
{
await Reply("Please enter a valid age (number).");
}
}
}
```
> **How is it working?**
> 1. **Numeric State**: `[NumericState(SpecialState.NoState)]` starts the wizard when no state exists.
> 2. **State Creation**: `container.CreateNumericState()` initializes the numeric state for the user.
> 3. **State Progression**: `container.ForwardNumericState()` moves to the next step (1, then 2).
> 4. **State Cleanup**: `container.DeleteNumericState()` removes the state when the wizard completes.
> 5. **Input Validation**: The age handler validates numeric input and provides feedback.
### 3.4. Awaiting CallbackQuery
```csharp
[CommandHandler]
[CommandAllias("menu")]
public class MenuHandler : CommandHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
var keyboard = new InlineKeyboardMarkup(new[]
{
InlineKeyboardButton.WithCallbackData("Option 1", "option1"),
InlineKeyboardButton.WithCallbackData("Option 2", "option2")
});
await Reply("Choose an option:", replyMarkup: keyboard, cancellationToken: cancellation);
}
}
[CallbackQueryHandler]
[CallbackData("option1")]
public class Option1Handler : CallbackQueryHandler
{
public override async Task Execute(IAbstractHandlerContainer<CallbackQuery> container, CancellationToken cancellation)
{
await AnswerCallbackQuery("You selected Option 1!", cancellationToken: cancellation);
await EditMessageText("You selected Option 1!");
}
}
[CallbackQueryHandler]
[CallbackData("option2")]
public class Option2Handler : CallbackQueryHandler
{
public override async Task Execute(IAbstractHandlerContainer<CallbackQuery> container, CancellationToken cancellation)
{
await AnswerCallbackQuery("You selected Option 2!", cancellationToken: cancellation);
await EditMessageText("You selected Option 2!");
}
}
```
> **How is it working?**
> 1. **Inline Keyboard**: `InlineKeyboardMarkup` creates interactive buttons with `CallbackData` identifiers.
> 2. **CallbackQuery Handlers**: `[CallbackQueryHandler]` and `[CallbackData]` work together to handle button clicks.
> 3. **Response Methods**: `AnswerCallbackQuery()` provides immediate feedback, while `EditMessageText()` updates the message.
> 4. **Handler Separation**: Each button option has its own dedicated handler for clean code organization.
### 3.5. Adding a Custom Filter
```csharp
public class PremiumUserAttribute : UpdateFilterAttribute<Message>
{
public override Message? GetFilterringTarget(Update update) => update.Message;
public override bool CanPass(FilterExecutionContext<Message> context) => context.Input.From?.IsPremium == true;
}
[MessageHandler]
[PremiumUser]
public class PremiumFeatureHandler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply("This feature is only available for premium users!");
}
}
```
> **How is it working?**
> 1. **Custom Filter**: `PremiumUserAttribute` inherits from `UpdateFilterAttribute<Message>` to create a reusable filter.
> 2. **Premium Check**: `context.Input.From?.IsPremium == true` checks if the user has Telegram Premium.
> 3. **Target Extraction**: `GetFilterringTarget()` extracts the `Message` from the `Update` object.
> 4. **Usage**: The filter is applied as `[PremiumUser]` to restrict features to premium users only.
---
## 4. Advanced Topics
### 4.1. Handler Priority
By default, handlers are processed in the order they are added. However, you can control the execution order using the `Priority` property in the handler attribute. A greater number means higher priority.
```csharp
[MessageHandler(Priority = 1)] // Runs before default priority (0)
public class HighPriorityHandler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply("This handler runs first!");
}
}
[MessageHandler(Priority = 0)] // Default priority
public class NormalPriorityHandler : MessageHandler
{
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
await Reply("This handler runs second!");
}
}
```
> **How is it working?**
> 1. **Priority System**: The `Priority` property in handler attributes controls execution order.
> 2. **Higher Priority First**: Handlers with higher priority numbers (1) run before those with lower numbers (0).
> 3. **Default Priority**: When not specified, handlers have priority 0.
> 4. **Execution Order**: This ensures critical handlers (like admin commands) run before general handlers.
### 4.2. Dependency Injection (DI)
Telegrator is designed to work seamlessly with DI containers (e.g., ASP.NET Core). Handlers and their dependencies are automatically registered.
```csharp
[MessageHandler]
public class MyHandler : MessageHandler
{
private readonly IMyService _myService;
private readonly ILogger<MyHandler> _logger;
public MyHandler(IMyService myService, ILogger<MyHandler> logger)
{
_myService = myService;
_logger = logger;
}
public override async Task Execute(IAbstractHandlerContainer<Message> container, CancellationToken cancellation)
{
_logger.LogInformation("MyHandler executed!");
var result = _myService.DoSomething();
await Reply(result);
}
}
```
> **How is it working?**
> 1. **Constructor Injection**: Dependencies (`IMyService`, `ILogger`) are automatically injected by the DI container.
> 2. **Service Registration**: When using `Telegrator.Hosting`, services are automatically registered with the DI container.
> 3. **Handler Instantiation**: Telegrator creates handler instances through the DI container, resolving all dependencies.
> 4. **Logging Integration**: Built-in logging support allows for comprehensive debugging and monitoring.
### 4.3. Custom State Keepers
You can implement your own state keeper by inheriting from `StateKeeperBase<TKey, TState>`. This allows for advanced scenarios (e.g., per-message state, custom key resolution).
### 4.4. Automatic Handler Discovery
Telegrator provides automatic discovery and registration of handlers across your entire application domain using the `CollectHandlersDomainWide()` method.
**How it works:**
- Scans all loaded assemblies in the current domain
- Automatically discovers classes decorated with handler attributes
- Registers them with the bot without manual registration
-
**Example:**
```csharp
var bot = new TelegratorClient("<YOUR_BOT_TOKEN>");
bot.Handlers.CollectHandlersDomainWide(); // Automatically finds and registers all handlers
bot.StartReceiving();
```
**Benefits:**
- No need to manually register each handler
- Reduces boilerplate code
- Ensures all handlers are discovered automatically
- Perfect for large applications with many handlers
> **How is it working?**
> 1. **Domain Scanning**: `CollectHandlersDomainWide()` scans all assemblies loaded in the current AppDomain.
> 2. **Reflection Discovery**: Uses reflection to find all classes decorated with handler attributes.
> 3. **Automatic Registration**: Each discovered handler is automatically registered with the `HandlersCollection`.
> 4. **Handler Types**: Supports all handler types: `MessageHandler`, `CommandHandler`, `CallbackQueryHandler`, etc.
### 4.5. Hosting Integration
Telegrator provides seamless integration with .NET's generic host through the `Telegrator.Hosting` package, making it easy to build production-ready bot applications.
**Installation:**
```shell
dotnet add package Telegrator.Hosting
```
**Dependencies:**
- `Microsoft.Extensions.Hosting` - .NET Generic Host
- `Microsoft.Extensions.DependencyInjection` - Dependency Injection
- `Microsoft.Extensions.Configuration` - Configuration management
- `Microsoft.Extensions.Logging` - Logging infrastructure
**Core Components:**
- `TelegramBotHost` - The main hosted service that manages the bot lifecycle
- `TelegramBotHostBuilder` - Builder pattern for configuring the bot host
- `TelegramBotOptions` - Configuration options for the bot
**Basic Example:**
```csharp
var builder = TelegramBotHost.CreateBuilder();
// Configure services
builder.Services.AddSingleton<IMyService, MyService>();
// Configure handlers
builder.Handlers.CollectHandlersDomainWide();
// Building host
var host = builder.Build();
await host.Run();
```
> **How is it working?**
> 1. **Generic Host Integration**: `TelegramBotHost` implements `IHost` and integrates with .NET's generic host.
> 2. **Lifecycle Management**: The host manages the bot's startup, shutdown, and graceful termination.
> 3. **Dependency Injection**: All handlers and services are automatically registered with the DI container.
> 4. **Configuration**: Supports standard .NET configuration patterns (appsettings.json, environment variables, etc.).
> 5. **Logging**: Integrates with .NET's logging infrastructure for comprehensive monitoring.
> 6. **Health Checks**: Can be integrated with .NET's health check system for production monitoring.
### 4.6. Error Handling and Logging
You can subscribe to error events or set a custom exception handler:
```csharp
bot.UpdateRouter.ExceptionHandler = new DefaultRouterExceptionHandler((client, exception, source, cancellationToken) =>
{
Console.WriteLine($"An error occurred: {exception.Message}");
return Task.CompletedTask;
});
```
> **How is it working?**
> 1. **Exception Handler**: `ExceptionHandler` property allows you to set a custom exception handler for the entire bot.
> 2. **Error Context**: The handler receives the bot client, exception, source information, and cancellation token.
> 3. **Global Error Handling**: This provides a centralized way to handle all exceptions that occur during update processing.
> 4. **Logging Integration**: Perfect place to log errors or send notifications to administrators.
### 4.7. Performance Optimization
- Use appropriate concurrency limits for resource-intensive operations
- Avoid thread-blocking operations in handlers
- Use state management for multi-step processes
- Use `AwaitingProvider` for complex conversation flows
### 4.8. Best Practices
- Organize handlers, filters, and state keepers in separate folders
- Use feature modules for large bots
- Prefer declarative filters over manual `if` statements
- Keep handlers focused and single-responsibility
---
## 5. FAQ & Best Practices
### 5.1. Q: My handler is not being triggered. What should I do?
- Check handler registration (use `bot.Handlers.AddHandler<MyHandler>()` or domain-wide collection)
- Check filter attributes and update types
- Enable debug logging
### 5.2. Q: How can I access the `ITelegramBotClient` or the original `Update` object inside a handler?
- Use `Client`, `Update`, and `Input` properties in your handler
### 5.3. Q: How do I handle errors?
- Set a custom exception handler or subscribe to error events
### 5.4. Q: How can I organize my code for a large bot?
- Use folders, feature modules, and namespaces
- Keep handlers focused and modular
---
## 6. Links
- [API Reference](./TelegramReactive_Api.md)
- [Main Repository](https://github.com/Rikitav/Telegrator)
- [Wiki & Examples](https://github.com/Rikitav/Telegrator/wiki/)
- [NuGet Package](https://www.nuget.org/packages/Telegrator)
- [Issues & Discussions](https://github.com/Rikitav/Telegrator/issues)
---
> **Feel free to contribute, ask questions, or open issues!**
-243
View File
@@ -1,243 +0,0 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Telegrator.Hosting.Web</name>
</assembly>
<members>
<member name="T:Telegrator.Hosting.Web.ITelegramBotWebHost">
<summary>
Interface for Telegram bot hosts with Webhook update receiving.
Combines wbe application capabilities with reactive Telegram bot functionality.
</summary>
</member>
<member name="T:Telegrator.Hosting.Web.TelegramBotWebHost">
<summary>
Represents a web hosted telegram bot
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.Services">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.UpdateRouter">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.DataSources">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.Lifetime">
<summary>
Allows consumers to be notified of application lifetime events.
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHost.Logger">
<summary>
This application's logger
</summary>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.#ctor(Microsoft.AspNetCore.Builder.WebApplicationBuilder)">
<summary>
Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Builder.WebApplicationBuilder"/> class.
</summary>
<param name="webApplicationBuilder">The proxied instance of host builder.</param>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.CreateBuilder(Telegrator.Hosting.Web.TelegramBotWebOptions)">
<summary>
Creates new <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.CreateSlimBuilder(Telegrator.Hosting.Web.TelegramBotWebOptions)">
<summary>
Creates new SLIM <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.CreateEmptyBuilder(Telegrator.Hosting.Web.TelegramBotWebOptions)">
<summary>
Creates new EMPTY <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.StartAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.StopAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.CreateApplicationBuilder">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.Use(System.Func{Microsoft.AspNetCore.Http.RequestDelegate,Microsoft.AspNetCore.Http.RequestDelegate})">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.New">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.Build">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.DisposeAsync">
<summary>
Disposes the host.
</summary>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHost.Dispose">
<summary>
Disposes the host.
</summary>
</member>
<member name="T:Telegrator.Hosting.Web.TelegramBotWebHostBuilder">
<summary>
Represents a web hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Handlers">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Configuration">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Logging">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Services">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Environment">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.#ctor(Microsoft.AspNetCore.Builder.WebApplicationBuilder,Telegrator.Hosting.Web.TelegramBotWebOptions)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.Web.TelegramBotWebHostBuilder"/> class.
</summary>
<param name="webApplicationBuilder"></param>
<param name="settings"></param>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.#ctor(Microsoft.AspNetCore.Builder.WebApplicationBuilder,Telegrator.Hosting.Web.TelegramBotWebOptions,Telegrator.Core.IHandlersCollection)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.Web.TelegramBotWebHostBuilder"/> class.
</summary>
<param name="webApplicationBuilder"></param>
<param name="handlers"></param>
<param name="settings"></param>
</member>
<member name="M:Telegrator.Hosting.Web.TelegramBotWebHostBuilder.Build">
<summary>
Builds the host.
</summary>
<returns></returns>
</member>
<member name="T:Telegrator.Hosting.Web.TelegramBotWebOptions">
<summary>
Options for configuring the behavior for TelegramBotWebHost.
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebOptions.DisableAutoConfigure">
<summary>
Disables automatic configuration for all of required <see cref="T:Microsoft.Extensions.Options.IOptions`1"/> instances
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebOptions.Args">
<inheritdoc cref="P:Microsoft.AspNetCore.Builder.WebApplicationOptions.Args"/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebOptions.EnvironmentName">
<inheritdoc cref="P:Microsoft.AspNetCore.Builder.WebApplicationOptions.EnvironmentName"/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebOptions.ApplicationName">
<inheritdoc cref="P:Microsoft.AspNetCore.Builder.WebApplicationOptions.ApplicationName"/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebOptions.ContentRootPath">
<inheritdoc cref="P:Microsoft.AspNetCore.Builder.WebApplicationOptions.ContentRootPath"/>
</member>
<member name="P:Telegrator.Hosting.Web.TelegramBotWebOptions.WebRootPath">
<inheritdoc cref="P:Microsoft.AspNetCore.Builder.WebApplicationOptions.WebRootPath"/>
</member>
<member name="T:Telegrator.Hosting.Web.TelegratorWebOptions">
<summary>
Configuration options for Telegram bot behavior and execution settings.
Controls various aspects of bot operation including concurrency, routing, webhook receiving, and execution policies.
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegratorWebOptions.WebhookUri">
<summary>
Gets or sets HTTPS URL to send updates to. Use an empty string to remove webhook integration
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegratorWebOptions.SecretToken">
<summary>
A secret token to be sent in a header “X-Telegram-Bot-Api-Secret-Token” in every webhook request, 1-256 characters.
Only characters A-Z, a-z, 0-9, _ and - are allowed.
The header is useful to ensure that the request comes from a webhook set by you.
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegratorWebOptions.MaxConnections">
<summary>
The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to 40.
Use lower values to limit the load on your bot's server, and higher values to increase your bot's throughput.
</summary>
</member>
<member name="P:Telegrator.Hosting.Web.TelegratorWebOptions.DropPendingUpdates">
<summary>
Pass true to drop all pending updates
</summary>
</member>
<member name="T:Telegrator.Mediation.HostedUpdateWebhooker">
<summary>
Service for receiving updates for Hosted telegram bots via Webhooks
</summary>
</member>
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.#ctor(Microsoft.AspNetCore.Routing.IEndpointRouteBuilder,Telegram.Bot.ITelegramBotClient,Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegrator.Hosting.Web.TelegratorWebOptions})">
<summary>
Initiallizes new instance of <see cref="T:Telegrator.Mediation.HostedUpdateWebhooker"/>
</summary>
<param name="botHost"></param>
<param name="botClient"></param>
<param name="updateRouter"></param>
<param name="options"></param>
<exception cref="T:System.ArgumentNullException"></exception>
</member>
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.StartAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Mediation.HostedUpdateWebhooker.StopAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="T:Telegrator.ServicesCollectionExtensions">
<summary>
Contains extensions for <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/>
Provides method to configure <see cref="T:Telegrator.Hosting.Web.ITelegramBotWebHost"/>
</summary>
</member>
<member name="F:Telegrator.ServicesCollectionExtensions.HandlersCollectionPropertyKey">
<summary>
The key used to store the <see cref="T:Telegrator.Core.IHandlersCollection"/> in the builder properties.
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.get_Handlers(Microsoft.Extensions.Hosting.IHostApplicationBuilder)">
<inheritdoc cref="P:Telegrator.ServicesCollectionExtensions.&lt;G&gt;$605D8CCF64349EA050C790D67C500BD9.Handlers"/>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegratorWeb(Microsoft.AspNetCore.Builder.WebApplicationBuilder,Telegrator.Hosting.Web.TelegramBotWebOptions,Telegrator.Core.IHandlersCollection)">
<summary>
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.UseTelegratorWeb(Microsoft.AspNetCore.Builder.WebApplication)">
<summary>
Replaces the initialization logic from TelegramBotWebHost constructor.
Initializes the bot and logs handlers on application startup.
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegramWebhook(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<summary>
Registers <see cref="T:Telegram.Bot.ITelegramBotClient"/> service with <see cref="T:Telegrator.Mediation.HostedUpdateWebhooker"/> to receive updates using webhook
</summary>
<param name="services"></param>
<returns></returns>
</member>
<member name="P:Telegrator.ServicesCollectionExtensions.&lt;G&gt;$605D8CCF64349EA050C790D67C500BD9.Handlers">
<summary>
Gets the <see cref="T:Telegrator.Core.IHandlersCollection"/> from the builder properties.
</summary>
</member>
</members>
</doc>
-510
View File
@@ -1,510 +0,0 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>Telegrator.Hosting</name>
</assembly>
<members>
<member name="T:Telegrator.ConfigureOptionsProxy`1">
<summary>
Abstract base class for configuring options from configuration sources.
Provides a proxy pattern for binding configuration to strongly-typed options classes.
</summary>
<typeparam name="TOptions">The type of options to configure.</typeparam>
</member>
<member name="M:Telegrator.ConfigureOptionsProxy`1.Configure(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Configuration.IConfiguration)">
<summary>
Configures the options using the default configuration section.
</summary>
<param name="services">The service collection to configure.</param>
<param name="configuration">The configuration source.</param>
</member>
<member name="M:Telegrator.ConfigureOptionsProxy`1.Configure(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.String,Microsoft.Extensions.Configuration.IConfiguration)">
<summary>
Configures the options using a named configuration section.
</summary>
<param name="services">The service collection to configure.</param>
<param name="name">The name of the configuration section.</param>
<param name="configuration">The configuration source.</param>
</member>
<member name="M:Telegrator.ConfigureOptionsProxy`1.Configure(Microsoft.Extensions.DependencyInjection.IServiceCollection,System.String,Microsoft.Extensions.Configuration.IConfiguration,System.Action{Microsoft.Extensions.Configuration.BinderOptions})">
<summary>
Configures the options using a named configuration section with custom binder options.
</summary>
<param name="services">The service collection to configure.</param>
<param name="name">The name of the configuration section.</param>
<param name="configuration">The configuration source.</param>
<param name="configureBinder">Optional action to configure the binder options.</param>
</member>
<member name="M:Telegrator.ConfigureOptionsProxy`1.Realize">
<summary>
Creates the actual options instance from the configuration.
</summary>
<returns>The configured options instance.</returns>
</member>
<member name="T:Telegrator.Core.IHostHandlersCollection">
<summary>
Collection class for managing handler descriptors organized by update type for host apps.
Provides functionality for collecting, adding, scanning, and organizing handlers.
</summary>
</member>
<member name="P:Telegrator.Core.IHostHandlersCollection.PreBuilderRoutines">
<summary>
List of tasks that should be completed right before building the bot
</summary>
</member>
<member name="T:Telegrator.Handlers.IPreBuildingRoutine">
<summary>
Interface for pre-building routines that can be executed during host construction.
Allows for custom initialization and configuration steps before the bot host is built.
</summary>
</member>
<member name="M:Telegrator.Handlers.IPreBuildingRoutine.PreBuildingRoutine(Telegrator.Hosting.ITelegramBotHostBuilder)">
<summary>
Executes the pre-building routine on the specified host builder.
</summary>
<param name="hostBuilder">The host builder to configure.</param>
</member>
<member name="T:Telegrator.Hosting.HostedTelegramBotInfo">
<summary>
Implementation of <see cref="T:Telegrator.Core.ITelegramBotInfo"/> that provides bot information.
Contains metadata about the Telegram bot including user details and service provider for wider filterring abilities
</summary>
<param name="client"></param>
<param name="services"></param>
<param name="configuration"></param>
</member>
<member name="M:Telegrator.Hosting.HostedTelegramBotInfo.#ctor(Telegram.Bot.ITelegramBotClient,System.IServiceProvider,Microsoft.Extensions.Configuration.IConfigurationManager)">
<summary>
Implementation of <see cref="T:Telegrator.Core.ITelegramBotInfo"/> that provides bot information.
Contains metadata about the Telegram bot including user details and service provider for wider filterring abilities
</summary>
<param name="client"></param>
<param name="services"></param>
<param name="configuration"></param>
</member>
<member name="P:Telegrator.Hosting.HostedTelegramBotInfo.User">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.HostedTelegramBotInfo.Services">
<summary>
Provides access to services of this Hosted telegram bot
</summary>
</member>
<member name="P:Telegrator.Hosting.HostedTelegramBotInfo.Configuration">
<summary>
Provides access to configuration of this Hosted telegram bot
</summary>
</member>
<member name="T:Telegrator.Hosting.ITelegramBotHost">
<summary>
Interface for Telegram bot hosts.
Combines host application capabilities with reactive Telegram bot functionality.
</summary>
</member>
<member name="T:Telegrator.Hosting.ITelegramBotHostBuilder">
<summary>
Interface for building Telegram bot hosts with dependency injection support.
Combines host application building capabilities with handler collection functionality.
</summary>
</member>
<member name="P:Telegrator.Hosting.ITelegramBotHostBuilder.Configuration">
<summary>
Gets the set of key/value configuration properties.
</summary>
</member>
<member name="P:Telegrator.Hosting.ITelegramBotHostBuilder.Logging">
<summary>
Gets a collection of logging providers for the application to compose. This is useful for adding new logging providers.
</summary>
</member>
<member name="P:Telegrator.Hosting.ITelegramBotHostBuilder.Services">
<summary>
Gets a collection of services for the application to compose. This is useful for adding user provided or framework provided services.
</summary>
</member>
<member name="T:Telegrator.Hosting.TelegramBotHost">
<summary>
Represents a hosted telegram bot
</summary>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHost.Services">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHost.UpdateRouter">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHost.Logger">
<summary>
This application's logger
</summary>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.#ctor(Microsoft.Extensions.Hosting.HostApplicationBuilder,Telegrator.Core.IHandlersCollection)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.TelegramBotHost"/> class.
</summary>
<param name="hostApplicationBuilder">The proxied instance of host builder.</param>
<param name="handlers"></param>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.CreateBuilder">
<summary>
Creates new <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> with default configuration, services and long-polling update receiving scheme
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.CreateBuilder(Telegrator.Hosting.TelegramBotHostBuilderSettings)">
<summary>
Creates new <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> with default services and long-polling update receiving scheme
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.CreateEmptyBuilder">
<summary>
Creates new EMPTY <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.CreateEmptyBuilder(Telegrator.Hosting.TelegramBotHostBuilderSettings)">
<summary>
Creates new EMPTY <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
</summary>
<returns></returns>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.StartAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.StopAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHost.Dispose">
<summary>
Disposes the host.
</summary>
</member>
<member name="T:Telegrator.Hosting.TelegramBotHostBuilder">
<summary>
Represents a hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
</summary>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilder.Handlers">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilder.Services">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilder.Configuration">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilder.Logging">
<inheritdoc/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilder.Environment">
<inheritdoc/>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.#ctor(Microsoft.Extensions.Hosting.HostApplicationBuilder,Telegrator.Hosting.TelegramBotHostBuilderSettings)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> class.
</summary>
<param name="hostApplicationBuilder"></param>
<param name="settings"></param>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.#ctor(Microsoft.Extensions.Hosting.HostApplicationBuilder,Telegrator.Core.IHandlersCollection,Telegrator.Hosting.TelegramBotHostBuilderSettings)">
<summary>
Initializes a new instance of the <see cref="T:Telegrator.Hosting.TelegramBotHostBuilder"/> class.
</summary>
<param name="hostApplicationBuilder"></param>
<param name="handlers"></param>
<param name="settings"></param>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHostBuilder.Build">
<summary>
Builds the host.
</summary>
<returns></returns>
</member>
<member name="T:Telegrator.Hosting.TelegramBotHostBuilderSettings">
<summary>
Settings os hosted Telegram bot
</summary>
</member>
<member name="M:Telegrator.Hosting.TelegramBotHostBuilderSettings.#ctor">
<summary>
Settings os hosted Telegram bot
</summary>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilderSettings.DisableAutoConfigure">
<summary>
Disables automatic configuration for all of required <see cref="T:Microsoft.Extensions.Options.IOptions`1"/> instances
</summary>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilderSettings.DisableDefaults">
<inheritdoc cref="P:Microsoft.Extensions.Hosting.HostApplicationBuilderSettings.DisableDefaults"/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilderSettings.Args">
<inheritdoc cref="P:Microsoft.Extensions.Hosting.HostApplicationBuilderSettings.Args"/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilderSettings.Configuration">
<inheritdoc cref="P:Microsoft.Extensions.Hosting.HostApplicationBuilderSettings.Configuration"/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilderSettings.EnvironmentName">
<inheritdoc cref="P:Microsoft.Extensions.Hosting.HostApplicationBuilderSettings.EnvironmentName"/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilderSettings.ApplicationName">
<inheritdoc cref="P:Microsoft.Extensions.Hosting.HostApplicationBuilderSettings.ApplicationName"/>
</member>
<member name="P:Telegrator.Hosting.TelegramBotHostBuilderSettings.ContentRootPath">
<inheritdoc cref="P:Microsoft.Extensions.Hosting.HostApplicationBuilderSettings.ContentRootPath"/>
</member>
<member name="T:Telegrator.Logging.MicrosoftLoggingAdapter">
<summary>
Adapter for Microsoft.Extensions.Logging to work with Telegrator logging system.
This allows seamless integration with ASP.NET Core logging infrastructure.
</summary>
</member>
<member name="M:Telegrator.Logging.MicrosoftLoggingAdapter.#ctor(Microsoft.Extensions.Logging.ILogger)">
<summary>
Initializes a new instance of MicrosoftLoggingAdapter.
</summary>
<param name="logger">The Microsoft.Extensions.Logging logger instance.</param>
</member>
<member name="M:Telegrator.Logging.MicrosoftLoggingAdapter.Log(Telegrator.Logging.LogLevel,System.String,System.Exception)">
<inheritdoc/>
</member>
<member name="T:Telegrator.Polling.HostedUpdateReceiver">
<summary>
Service for receiving updates for Hosted telegram bots
</summary>
<param name="botHost"></param>
<param name="botClient"></param>
<param name="updateRouter"></param>
<param name="options"></param>
<param name="logger"></param>
</member>
<member name="M:Telegrator.Polling.HostedUpdateReceiver.#ctor(Telegrator.Hosting.ITelegramBotHost,Telegram.Bot.ITelegramBotClient,Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegram.Bot.Polling.ReceiverOptions},Microsoft.Extensions.Logging.ILogger{Telegrator.Polling.HostedUpdateReceiver})">
<summary>
Service for receiving updates for Hosted telegram bots
</summary>
<param name="botHost"></param>
<param name="botClient"></param>
<param name="updateRouter"></param>
<param name="options"></param>
<param name="logger"></param>
</member>
<member name="M:Telegrator.Polling.HostedUpdateReceiver.ExecuteAsync(System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="T:Telegrator.Polling.HostUpdateHandlersPool">
<inheritdoc/>
</member>
<member name="M:Telegrator.Polling.HostUpdateHandlersPool.#ctor(Telegrator.Core.IUpdateRouter,Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions})">
<inheritdoc/>
</member>
<member name="T:Telegrator.Polling.HostUpdateRouter">
<inheritdoc/>
</member>
<member name="F:Telegrator.Polling.HostUpdateRouter.Logger">
<summary>
<see cref="T:Microsoft.Extensions.Logging.ILogger"/> of this router
</summary>
</member>
<member name="M:Telegrator.Polling.HostUpdateRouter.#ctor(Telegrator.Core.IHandlersProvider,Telegrator.Core.IAwaitingProvider,Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions},Telegrator.Core.IUpdateHandlersPool,Telegrator.Core.ITelegramBotInfo,Microsoft.Extensions.Logging.ILogger{Telegrator.Polling.HostUpdateRouter})">
<inheritdoc/>
</member>
<member name="M:Telegrator.Polling.HostUpdateRouter.HandleUpdateAsync(Telegram.Bot.ITelegramBotClient,Telegram.Bot.Types.Update,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="M:Telegrator.Polling.HostUpdateRouter.HandleException(Telegram.Bot.ITelegramBotClient,System.Exception,Telegram.Bot.Polling.HandleErrorSource,System.Threading.CancellationToken)">
<summary>
Default exception handler of this router
</summary>
<param name="botClient"></param>
<param name="exception"></param>
<param name="source"></param>
<param name="cancellationToken"></param>
</member>
<member name="T:Telegrator.Providers.HostAwaitingProvider">
<inheritdoc/>
</member>
<member name="M:Telegrator.Providers.HostAwaitingProvider.#ctor(Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions},Microsoft.Extensions.Logging.ILogger{Telegrator.Providers.HostAwaitingProvider})">
<inheritdoc/>
</member>
<member name="T:Telegrator.Providers.PreBuildingRoutine">
<summary>
Pre host building task
</summary>
<param name="builder"></param>
</member>
<member name="T:Telegrator.Providers.HostHandlersCollection">
<inheritdoc/>
</member>
<member name="M:Telegrator.Providers.HostHandlersCollection.#ctor(Microsoft.Extensions.DependencyInjection.IServiceCollection,Telegrator.TelegratorOptions)">
<inheritdoc/>
</member>
<member name="P:Telegrator.Providers.HostHandlersCollection.MustHaveParameterlessCtor">
<inheritdoc/>
</member>
<member name="P:Telegrator.Providers.HostHandlersCollection.PreBuilderRoutines">
<summary>
List of tasks that should be completed right before building the bot
</summary>
</member>
<member name="M:Telegrator.Providers.HostHandlersCollection.AddDescriptor(Telegrator.Core.Descriptors.HandlerDescriptor)">
<inheritdoc/>
</member>
<member name="T:Telegrator.Providers.HostHandlersProvider">
<inheritdoc/>
</member>
<member name="M:Telegrator.Providers.HostHandlersProvider.#ctor(Telegrator.Core.IHandlersCollection,Microsoft.Extensions.Options.IOptions{Telegrator.TelegratorOptions},System.IServiceProvider,Microsoft.Extensions.Logging.ILogger{Telegrator.Providers.HostHandlersProvider})">
<inheritdoc/>
</member>
<member name="M:Telegrator.Providers.HostHandlersProvider.GetHandlerInstance(Telegrator.Core.Descriptors.HandlerDescriptor,System.Threading.CancellationToken)">
<inheritdoc/>
</member>
<member name="T:Telegrator.TelegramBotClientOptionsProxy">
<summary>
Internal proxy class for configuring Telegram bot client options from configuration.
Extends ConfigureOptionsProxy to provide specific configuration for Telegram bot client options.
</summary>
</member>
<member name="P:Telegrator.TelegramBotClientOptionsProxy.Token">
<summary>
Gets or sets the bot token.
</summary>
</member>
<member name="P:Telegrator.TelegramBotClientOptionsProxy.BaseUrl">
<summary>
Gets or sets the base URL for the bot API.
</summary>
</member>
<member name="P:Telegrator.TelegramBotClientOptionsProxy.UseTestEnvironment">
<summary>
Gets or sets whether to use the test environment.
</summary>
</member>
<member name="P:Telegrator.TelegramBotClientOptionsProxy.RetryThreshold">
<summary>
Gets or sets the retry threshold in seconds.
</summary>
</member>
<member name="P:Telegrator.TelegramBotClientOptionsProxy.RetryCount">
<summary>
Gets or sets the number of retry attempts.
</summary>
</member>
<member name="M:Telegrator.TelegramBotClientOptionsProxy.Realize">
<summary>
Creates a TelegramBotClientOptions instance from the proxy configuration.
</summary>
<returns>The configured TelegramBotClientOptions instance.</returns>
</member>
<member name="T:Telegrator.HostBuilderExtensions">
<summary>
Provides extension methods for <see cref="T:Microsoft.Extensions.Hosting.IHostApplicationBuilder"/> to configure Telegrator.
</summary>
</member>
<member name="F:Telegrator.HostBuilderExtensions.HandlersCollectionPropertyKey">
<summary>
The key used to store the <see cref="T:Telegrator.Core.IHandlersCollection"/> in the builder properties.
</summary>
</member>
<member name="M:Telegrator.HostBuilderExtensions.get_Handlers(Microsoft.Extensions.Hosting.IHostApplicationBuilder)">
<inheritdoc cref="P:Telegrator.HostBuilderExtensions.&lt;G&gt;$605D8CCF64349EA050C790D67C500BD9.Handlers"/>
</member>
<member name="M:Telegrator.HostBuilderExtensions.AddTelegrator(Microsoft.Extensions.Hosting.IHostApplicationBuilder,Telegrator.Hosting.TelegramBotHostBuilderSettings,Telegrator.Core.IHandlersCollection)">
<summary>
Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
</summary>
</member>
<member name="P:Telegrator.HostBuilderExtensions.&lt;G&gt;$605D8CCF64349EA050C790D67C500BD9.Handlers">
<summary>
Gets the <see cref="T:Telegrator.Core.IHandlersCollection"/> from the builder properties.
</summary>
</member>
<member name="T:Telegrator.ServicesCollectionExtensions">
<summary>
Contains extensions for <see cref="T:Microsoft.Extensions.DependencyInjection.IServiceCollection"/>
Provides method to configure <see cref="T:Telegrator.Hosting.ITelegramBotHost"/>
</summary>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.Configure``1(Microsoft.Extensions.DependencyInjection.IServiceCollection,Microsoft.Extensions.Configuration.IConfiguration,Telegrator.ConfigureOptionsProxy{``0})">
<summary>
Registers a configuration instance that strongly-typed <typeparamref name="TOptions"/> will bind against using <see cref="T:Telegrator.ConfigureOptionsProxy`1"/>.
</summary>
<typeparam name="TOptions"></typeparam>
<param name="services"></param>
<param name="configuration"></param>
<param name="optionsProxy"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegramBotHostDefaults(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<summary>
Registers <see cref="T:Telegrator.Hosting.TelegramBotHost"/> default services
</summary>
<param name="services"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.AddTelegramReceiver(Microsoft.Extensions.DependencyInjection.IServiceCollection)">
<summary>
Registers <see cref="T:Telegram.Bot.ITelegramBotClient"/> service with <see cref="T:Telegrator.Polling.HostedUpdateReceiver"/> to receive updates using long polling
</summary>
<param name="services"></param>
<returns></returns>
</member>
<member name="M:Telegrator.ServicesCollectionExtensions.TypedTelegramBotClientFactory(System.Net.Http.HttpClient,System.IServiceProvider)">
<summary>
<see cref="T:Telegram.Bot.ITelegramBotClient"/> factory method
</summary>
<param name="httpClient"></param>
<param name="provider"></param>
<returns></returns>
</member>
<member name="T:Telegrator.TelegramBotHostExtensions">
<summary>
Provides useful methods to adjust <see cref="T:Telegrator.Hosting.ITelegramBotHost"/>
</summary>
</member>
<member name="M:Telegrator.TelegramBotHostExtensions.UseTelegrator(Microsoft.Extensions.Hosting.IHost)">
<summary>
Replaces the initialization logic from TelegramBotWebHost constructor.
Initializes the bot and logs handlers on application startup.
</summary>
</member>
<member name="M:Telegrator.TelegramBotHostExtensions.SetBotCommands(Microsoft.Extensions.Hosting.IHost)">
<summary>
Configures bots available commands depending on what handlers was registered
</summary>
<param name="botHost"></param>
<returns></returns>
</member>
<member name="M:Telegrator.TelegramBotHostExtensions.AddLoggingAdapter(Microsoft.Extensions.Hosting.IHost)">
<summary>
Adds a Microsoft.Extensions.Logging adapter to Alligator using a logger factory.
</summary>
<param name="host"></param>
</member>
<member name="T:Telegrator.ReflectionExtensions">
<summary>
Provides extension methods for reflection and type inspection.
</summary>
</member>
<member name="M:Telegrator.ReflectionExtensions.IsPreBuildingRoutine(System.Type,System.Reflection.MethodInfo@)">
<summary>
Checks if a type implements the <see cref="T:Telegrator.Handlers.IPreBuildingRoutine"/> interface.
</summary>
<param name="handlerType">The type to check.</param>
<param name="routineMethod"></param>
<returns>True if the type implements IPreBuildingRoutine; otherwise, false.</returns>
</member>
<member name="T:Telegrator.LoggerExtensions">
<summary>
Provides extension methods for logging Telegrator-related information.
</summary>
</member>
<member name="M:Telegrator.LoggerExtensions.LogHandlers(Microsoft.Extensions.Logging.ILogger,Telegrator.Core.IHandlersCollection)">
<summary>
Logs the registered handlers to the specified logger.
</summary>
<param name="logger">The logger to write to.</param>
<param name="handlers">The collection of handlers to log.</param>
</member>
</members>
</doc>
-8152
View File
File diff suppressed because it is too large Load Diff
@@ -1,14 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Routing;
namespace Telegrator.Hosting.Web
{
/// <summary>
/// Interface for Telegram bot hosts with Webhook update receiving.
/// Combines wbe application capabilities with reactive Telegram bot functionality.
/// </summary>
public interface ITelegramBotWebHost : ITelegramBotHost, IEndpointRouteBuilder, IApplicationBuilder, IAsyncDisposable
{
}
}
@@ -12,7 +12,7 @@ namespace Telegrator.Hosting.Web
/// <summary> /// <summary>
/// Represents a web hosted telegram bot /// Represents a web hosted telegram bot
/// </summary> /// </summary>
public class TelegramBotWebHost : ITelegramBotWebHost public class TelegramBotWebHost : IHost, IApplicationBuilder, IEndpointRouteBuilder, IAsyncDisposable
{ {
private readonly WebApplication _innerApp; private readonly WebApplication _innerApp;
private readonly IUpdateRouter _updateRouter; private readonly IUpdateRouter _updateRouter;
@@ -51,11 +51,6 @@ namespace Telegrator.Hosting.Web
/// <param name="webApplicationBuilder">The proxied instance of host builder.</param> /// <param name="webApplicationBuilder">The proxied instance of host builder.</param>
public TelegramBotWebHost(WebApplicationBuilder webApplicationBuilder) public TelegramBotWebHost(WebApplicationBuilder webApplicationBuilder)
{ {
// Registering this host in services for easy access
webApplicationBuilder.Services.AddSingleton<ITelegramBotHost>(this);
webApplicationBuilder.Services.AddSingleton<ITelegramBotWebHost>(this);
webApplicationBuilder.Services.AddSingleton<ITelegratorBot>(this);
// Building proxy application // Building proxy application
_innerApp = webApplicationBuilder.Build(); _innerApp = webApplicationBuilder.Build();
_innerApp.UseTelegratorWeb(); _innerApp.UseTelegratorWeb();
@@ -69,11 +64,12 @@ namespace Telegrator.Hosting.Web
/// Creates new <see cref="TelegramBotHostBuilder"/> with default services and webhook update receiving scheme /// Creates new <see cref="TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static TelegramBotWebHostBuilder CreateBuilder(TelegramBotWebOptions settings) public static TelegramBotWebHostBuilder CreateBuilder(WebApplicationOptions settings)
{ {
ArgumentNullException.ThrowIfNull(settings, nameof(settings)); ArgumentNullException.ThrowIfNull(settings, nameof(settings));
WebApplicationBuilder innerApp = WebApplication.CreateBuilder(settings.ToWebApplicationOptions()); WebApplicationBuilder innerApp = WebApplication.CreateBuilder(settings);
TelegramBotWebHostBuilder builder = new TelegramBotWebHostBuilder(innerApp, settings); TelegramBotWebHostBuilder builder = new TelegramBotWebHostBuilder(innerApp, settings);
builder.Services.AddTelegramBotHostDefaults(); builder.Services.AddTelegramBotHostDefaults();
builder.Services.AddTelegramWebhook(); builder.Services.AddTelegramWebhook();
return builder; return builder;
@@ -83,11 +79,12 @@ namespace Telegrator.Hosting.Web
/// Creates new SLIM <see cref="TelegramBotHostBuilder"/> with default services and webhook update receiving scheme /// Creates new SLIM <see cref="TelegramBotHostBuilder"/> with default services and webhook update receiving scheme
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static TelegramBotWebHostBuilder CreateSlimBuilder(TelegramBotWebOptions settings) public static TelegramBotWebHostBuilder CreateSlimBuilder(WebApplicationOptions settings)
{ {
ArgumentNullException.ThrowIfNull(settings, nameof(settings)); ArgumentNullException.ThrowIfNull(settings, nameof(settings));
WebApplicationBuilder innerApp = WebApplication.CreateSlimBuilder(settings.ToWebApplicationOptions()); WebApplicationBuilder innerApp = WebApplication.CreateSlimBuilder(settings);
TelegramBotWebHostBuilder builder = new TelegramBotWebHostBuilder(innerApp, settings); TelegramBotWebHostBuilder builder = new TelegramBotWebHostBuilder(innerApp, settings);
builder.Services.AddTelegramBotHostDefaults(); builder.Services.AddTelegramBotHostDefaults();
builder.Services.AddTelegramWebhook(); builder.Services.AddTelegramWebhook();
return builder; return builder;
@@ -97,10 +94,10 @@ namespace Telegrator.Hosting.Web
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes /// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static TelegramBotWebHostBuilder CreateEmptyBuilder(TelegramBotWebOptions settings) public static TelegramBotWebHostBuilder CreateEmptyBuilder(WebApplicationOptions settings)
{ {
ArgumentNullException.ThrowIfNull(settings, nameof(settings)); ArgumentNullException.ThrowIfNull(settings, nameof(settings));
WebApplicationBuilder innerApp = WebApplication.CreateEmptyBuilder(settings.ToWebApplicationOptions()); WebApplicationBuilder innerApp = WebApplication.CreateEmptyBuilder(settings);
return new TelegramBotWebHostBuilder(innerApp, settings); return new TelegramBotWebHostBuilder(innerApp, settings);
} }
@@ -154,10 +151,8 @@ namespace Telegrator.Hosting.Web
if (_disposed) if (_disposed)
return; return;
// Sorry for this, i really dont know how to handle such cases
ValueTask disposeTask = _innerApp.DisposeAsync(); ValueTask disposeTask = _innerApp.DisposeAsync();
while (!disposeTask.IsCompleted) disposeTask.AsTask().Wait();
Thread.Sleep(100);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
_disposed = true; _disposed = true;
@@ -18,8 +18,8 @@ namespace Telegrator.Hosting.Web
public class TelegramBotWebHostBuilder : ITelegramBotHostBuilder public class TelegramBotWebHostBuilder : ITelegramBotHostBuilder
{ {
private readonly WebApplicationBuilder _innerBuilder; private readonly WebApplicationBuilder _innerBuilder;
private readonly TelegramBotWebOptions _settings; private readonly WebApplicationOptions _settings;
private readonly IHandlersCollection _handlers; internal IHandlersCollection _handlers = null!;
/// <inheritdoc/> /// <inheritdoc/>
public IHandlersCollection Handlers => _handlers; public IHandlersCollection Handlers => _handlers;
@@ -41,11 +41,10 @@ namespace Telegrator.Hosting.Web
/// </summary> /// </summary>
/// <param name="webApplicationBuilder"></param> /// <param name="webApplicationBuilder"></param>
/// <param name="settings"></param> /// <param name="settings"></param>
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, TelegramBotWebOptions settings) public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, WebApplicationOptions settings)
{ {
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder)); _innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
_settings = settings ?? throw new ArgumentNullException(nameof(settings)); _settings = settings ?? throw new ArgumentNullException(nameof(settings));
_handlers = new HostHandlersCollection(Services, _settings);
_innerBuilder.AddTelegratorWeb(settings); _innerBuilder.AddTelegratorWeb(settings);
} }
@@ -56,13 +55,12 @@ namespace Telegrator.Hosting.Web
/// <param name="webApplicationBuilder"></param> /// <param name="webApplicationBuilder"></param>
/// <param name="handlers"></param> /// <param name="handlers"></param>
/// <param name="settings"></param> /// <param name="settings"></param>
public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, TelegramBotWebOptions settings, IHandlersCollection handlers) public TelegramBotWebHostBuilder(WebApplicationBuilder webApplicationBuilder, IHandlersCollection handlers, WebApplicationOptions settings)
{ {
_innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder)); _innerBuilder = webApplicationBuilder ?? throw new ArgumentNullException(nameof(webApplicationBuilder));
_settings = settings ?? throw new ArgumentNullException(nameof(settings)); _settings = settings ?? throw new ArgumentNullException(nameof(settings));
_handlers = handlers ?? throw new ArgumentNullException(nameof(settings));
_innerBuilder.AddTelegratorWeb(settings, handlers); _innerBuilder.AddTelegratorWeb(settings, null, handlers);
} }
/// <summary> /// <summary>
@@ -71,7 +69,9 @@ namespace Telegrator.Hosting.Web
/// <returns></returns> /// <returns></returns>
public TelegramBotWebHost Build() public TelegramBotWebHost Build()
{ {
return new TelegramBotWebHost(_innerBuilder); TelegramBotWebHost host = new TelegramBotWebHost(_innerBuilder);
host.UseTelegrator();
return host;
} }
} }
} }
@@ -1,40 +0,0 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Options;
namespace Telegrator.Hosting.Web
{
/// <summary>
/// Options for configuring the behavior for TelegramBotWebHost.
/// </summary>
public class TelegramBotWebOptions : TelegratorOptions
{
/// <summary>
/// Disables automatic configuration for all of required <see cref="IOptions{TOptions}"/> instances
/// </summary>
public bool DisableAutoConfigure { get; set; }
/// <inheritdoc cref="WebApplicationOptions.Args"/>
public string[]? Args { get; init; }
/// <inheritdoc cref="WebApplicationOptions.EnvironmentName"/>
public string? EnvironmentName { get; init; }
/// <inheritdoc cref="WebApplicationOptions.ApplicationName"/>
public string? ApplicationName { get; init; }
/// <inheritdoc cref="WebApplicationOptions.ContentRootPath"/>
public string? ContentRootPath { get; init; }
/// <inheritdoc cref="WebApplicationOptions.WebRootPath"/>
public string? WebRootPath { get; init; }
internal WebApplicationOptions ToWebApplicationOptions() => new WebApplicationOptions()
{
ApplicationName = ApplicationName,
Args = Args,
ContentRootPath = ContentRootPath,
EnvironmentName = EnvironmentName,
WebRootPath = WebRootPath
};
}
}
@@ -6,20 +6,20 @@ namespace Telegrator.Hosting.Web
/// Configuration options for Telegram bot behavior and execution settings. /// Configuration options for Telegram bot behavior and execution settings.
/// Controls various aspects of bot operation including concurrency, routing, webhook receiving, and execution policies. /// Controls various aspects of bot operation including concurrency, routing, webhook receiving, and execution policies.
/// </summary> /// </summary>
public class TelegratorWebOptions public class WebhookerOptions
{ {
/// <summary> /// <summary>
/// Gets or sets HTTPS URL to send updates to. Use an empty string to remove webhook integration /// Gets or sets HTTPS URL to send updates to. Use an empty string to remove webhook integration
/// </summary> /// </summary>
[StringSyntax(StringSyntaxAttribute.Uri)] [StringSyntax(StringSyntaxAttribute.Uri)]
public required string WebhookUri { get; set; } public string WebhookUri { get; set; } = string.Empty;
/// <summary> /// <summary>
/// A secret token to be sent in a header “X-Telegram-Bot-Api-Secret-Token” in every webhook request, 1-256 characters. /// A secret token to be sent in a header “X-Telegram-Bot-Api-Secret-Token” in every webhook request, 1-256 characters.
/// Only characters A-Z, a-z, 0-9, _ and - are allowed. /// Only characters A-Z, a-z, 0-9, _ and - are allowed.
/// The header is useful to ensure that the request comes from a webhook set by you. /// The header is useful to ensure that the request comes from a webhook set by you.
/// </summary> /// </summary>
public string? SecretToken { get; set; } public string? SecretToken { get; set; } = null;
/// <summary> /// <summary>
/// The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to 40. /// The maximum allowed number of simultaneous HTTPS connections to the webhook for update delivery, 1-100. Defaults to 40.
@@ -30,6 +30,6 @@ namespace Telegrator.Hosting.Web
/// <summary> /// <summary>
/// Pass true to drop all pending updates /// Pass true to drop all pending updates
/// </summary> /// </summary>
public bool DropPendingUpdates { get; set; } public bool DropPendingUpdates { get; set; } = false;
} }
} }
@@ -22,7 +22,7 @@ namespace Telegrator.Mediation
private readonly IEndpointRouteBuilder _botHost; private readonly IEndpointRouteBuilder _botHost;
private readonly ITelegramBotClient _botClient; private readonly ITelegramBotClient _botClient;
private readonly IUpdateRouter _updateRouter; private readonly IUpdateRouter _updateRouter;
private readonly TelegratorWebOptions _options; private readonly WebhookerOptions _options;
/// <summary> /// <summary>
/// Initiallizes new instance of <see cref="HostedUpdateWebhooker"/> /// Initiallizes new instance of <see cref="HostedUpdateWebhooker"/>
@@ -32,7 +32,7 @@ namespace Telegrator.Mediation
/// <param name="updateRouter"></param> /// <param name="updateRouter"></param>
/// <param name="options"></param> /// <param name="options"></param>
/// <exception cref="ArgumentNullException"></exception> /// <exception cref="ArgumentNullException"></exception>
public HostedUpdateWebhooker(IEndpointRouteBuilder botHost, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<TelegratorWebOptions> options) public HostedUpdateWebhooker(IEndpointRouteBuilder botHost, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<WebhookerOptions> options)
{ {
if (string.IsNullOrEmpty(options.Value.WebhookUri)) if (string.IsNullOrEmpty(options.Value.WebhookUri))
throw new ArgumentNullException(nameof(options), "Option \"WebhookUrl\" must be set to subscribe for update recieving"); throw new ArgumentNullException(nameof(options), "Option \"WebhookUrl\" must be set to subscribe for update recieving");
+50 -42
View File
@@ -5,10 +5,9 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Diagnostics;
using Telegram.Bot; using Telegram.Bot;
using Telegrator;
using Telegrator.Core; using Telegrator.Core;
using Telegrator.Hosting;
using Telegrator.Hosting.Web; using Telegrator.Hosting.Web;
using Telegrator.Mediation; using Telegrator.Mediation;
using Telegrator.Providers; using Telegrator.Providers;
@@ -17,7 +16,7 @@ namespace Telegrator
{ {
/// <summary> /// <summary>
/// Contains extensions for <see cref="IServiceCollection"/> /// Contains extensions for <see cref="IServiceCollection"/>
/// Provides method to configure <see cref="ITelegramBotWebHost"/> /// Provides method to configure Telegram Bot WebHost
/// </summary> /// </summary>
public static class ServicesCollectionExtensions public static class ServicesCollectionExtensions
{ {
@@ -31,69 +30,78 @@ namespace Telegrator
/// <summary> /// <summary>
/// Gets the <see cref="IHandlersCollection"/> from the builder properties. /// Gets the <see cref="IHandlersCollection"/> from the builder properties.
/// </summary> /// </summary>
public IHandlersCollection Handlers => (IHandlersCollection)builder.Properties[HandlersCollectionPropertyKey]; public IHandlersCollection Handlers
{
get
{
if (builder is TelegramBotHostBuilder botHostBuilder)
return botHostBuilder.Handlers;
if (builder is TelegramBotWebHostBuilder webBotHostBuilder)
return webBotHostBuilder.Handlers;
return (IHandlersCollection)builder.Properties[HandlersCollectionPropertyKey];
}
}
} }
/// <summary> /// <summary>
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers. /// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
/// </summary> /// </summary>
public static WebApplicationBuilder AddTelegratorWeb(this WebApplicationBuilder builder, TelegramBotWebOptions settings, IHandlersCollection? handlers = null) public static IHostApplicationBuilder AddTelegratorWeb(this IHostApplicationBuilder builder, WebApplicationOptions settings, TelegratorOptions? options = null, IHandlersCollection? handlers = null)
{ {
if (settings is null) if (settings is null)
throw new ArgumentNullException(nameof(settings)); throw new ArgumentNullException(nameof(settings));
IServiceCollection services = builder.Services; IServiceCollection services = builder.Services;
ConfigurationManager configuration = builder.Configuration; IConfigurationManager configuration = builder.Configuration;
handlers ??= new HostHandlersCollection(services, settings); if (options == null)
builder.Host.Properties.Add(HandlersCollectionPropertyKey, handlers);
if (handlers is IHostHandlersCollection hostHandlers)
{ {
foreach (PreBuildingRoutine preBuildRoutine in hostHandlers.PreBuilderRoutines) options = configuration.GetSection(nameof(TelegratorOptions)).Get<TelegratorOptions>();
{ if (options == null)
try throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegratorOptions' wasn't registered. This configuration is runtime required!");
{
// TODO: fix
//preBuildRoutine.Invoke(builder);
Debug.WriteLine("Pre-Building routine was not executed");
}
catch (NotImplementedException)
{
_ = 0xBAD + 0xC0DE;
}
}
} }
if (!settings.DisableAutoConfigure) services.AddSingleton(Options.Create(options));
if (handlers != null)
{ {
services.Configure<TelegratorWebOptions>(configuration.GetSection(nameof(TelegratorWebOptions)));
services.Configure<TelegratorWebOptions>(configuration.GetSection(nameof(TelegramBotClientOptions)));
}
else
{
if (!services.Any(srvc => srvc.ImplementationType == typeof(IOptions<TelegratorWebOptions>)))
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegratorWebOptions' wasn't registered. This configuration is runtime required!");
if (!services.Any(srvc => srvc.ImplementationType == typeof(IOptions<TelegramBotClientOptions>)))
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegramBotClientOptions' wasn't registered. This configuration is runtime required!");
}
IOptions<TelegramBotWebOptions> options = Options.Create(settings);
services.AddSingleton((IOptions<TelegratorOptions>)options);
services.AddSingleton(options);
services.AddSingleton(handlers);
if (handlers is IHandlersManager manager) if (handlers is IHandlersManager manager)
{ {
ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IHandlersProvider), manager); ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IHandlersProvider), manager);
services.Replace(descriptor); services.Replace(descriptor);
services.AddSingleton(manager); services.AddSingleton(manager);
} }
}
handlers ??= new HostHandlersCollection(services, options);
services.AddSingleton(handlers);
builder.Properties.Add(HandlersCollectionPropertyKey, handlers);
if (builder is TelegramBotWebHostBuilder botHostBuilder)
botHostBuilder._handlers = handlers;
if (!services.Any(srvc => srvc.ImplementationType == typeof(IOptions<WebhookerOptions>)))
{
WebhookerOptions? webhookerOptions = configuration.GetSection(nameof(WebhookerOptions)).Get<WebhookerOptions>();
if (webhookerOptions == null)
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'WebhookerOptions' wasn't registered. This configuration is runtime required!");
services.AddSingleton(Options.Create(webhookerOptions));
}
if (!services.Any(srvc => srvc.ImplementationType == typeof(IOptions<TelegramBotClientOptions>)))
{
services.AddSingleton(Options.Create(new TelegramBotClientOptions(options.Token, options.BaseUrl, options.UseTestEnvironment)
{
RetryCount = options.RetryCount,
RetryThreshold = options.RetryThreshold
}));
}
services.AddTelegramBotHostDefaults(); services.AddTelegramBotHostDefaults();
services.AddTelegramWebhook(); services.AddTelegramWebhook();
return builder; return builder;
} }
@@ -1,53 +0,0 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace Telegrator
{
/// <summary>
/// Abstract base class for configuring options from configuration sources.
/// Provides a proxy pattern for binding configuration to strongly-typed options classes.
/// </summary>
/// <typeparam name="TOptions">The type of options to configure.</typeparam>
public abstract class ConfigureOptionsProxy<TOptions> where TOptions : class
{
/// <summary>
/// Configures the options using the default configuration section.
/// </summary>
/// <param name="services">The service collection to configure.</param>
/// <param name="configuration">The configuration source.</param>
public void Configure(IServiceCollection services, IConfiguration configuration)
=> Configure(services, Options.DefaultName, configuration, null);
/// <summary>
/// Configures the options using a named configuration section.
/// </summary>
/// <param name="services">The service collection to configure.</param>
/// <param name="name">The name of the configuration section.</param>
/// <param name="configuration">The configuration source.</param>
public void Configure(IServiceCollection services, string? name, IConfiguration configuration)
=> Configure(services, name, configuration, null);
/// <summary>
/// Configures the options using a named configuration section with custom binder options.
/// </summary>
/// <param name="services">The service collection to configure.</param>
/// <param name="name">The name of the configuration section.</param>
/// <param name="configuration">The configuration source.</param>
/// <param name="configureBinder">Optional action to configure the binder options.</param>
public void Configure(IServiceCollection services, string? name, IConfiguration configuration, Action<BinderOptions>? configureBinder)
{
var namedConfigure = new NamedConfigureFromConfigurationOptions<ConfigureOptionsProxy<TOptions>>(name, configuration, configureBinder);
namedConfigure.Configure(name, this);
services.AddOptions();
services.AddSingleton(Options.Create(Realize()));
}
/// <summary>
/// Creates the actual options instance from the configuration.
/// </summary>
/// <returns>The configured options instance.</returns>
protected abstract TOptions Realize();
}
}
@@ -1,16 +0,0 @@
using Telegrator.Providers;
namespace Telegrator.Core
{
/// <summary>
/// Collection class for managing handler descriptors organized by update type for host apps.
/// Provides functionality for collecting, adding, scanning, and organizing handlers.
/// </summary>
public interface IHostHandlersCollection : IHandlersCollection
{
/// <summary>
/// List of tasks that should be completed right before building the bot
/// </summary>
public List<PreBuildingRoutine> PreBuilderRoutines { get; }
}
}
@@ -1,17 +0,0 @@
using Telegrator.Hosting;
namespace Telegrator.Handlers
{
/// <summary>
/// Interface for pre-building routines that can be executed during host construction.
/// Allows for custom initialization and configuration steps before the bot host is built.
/// </summary>
public interface IPreBuildingRoutine
{
/// <summary>
/// Executes the pre-building routine on the specified host builder.
/// </summary>
/// <param name="hostBuilder">The host builder to configure.</param>
public static abstract void PreBuildingRoutine(ITelegramBotHostBuilder hostBuilder);
}
}
@@ -1,13 +0,0 @@
using Microsoft.Extensions.Hosting;
namespace Telegrator.Hosting
{
/// <summary>
/// Interface for Telegram bot hosts.
/// Combines host application capabilities with reactive Telegram bot functionality.
/// </summary>
public interface ITelegramBotHost : IHost, ITelegratorBot
{
}
}
@@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Telegrator.Core; using Telegrator.Core;
@@ -8,7 +9,7 @@ namespace Telegrator.Hosting
/// <summary> /// <summary>
/// Represents a hosted telegram bot /// Represents a hosted telegram bot
/// </summary> /// </summary>
public class TelegramBotHost : ITelegramBotHost public class TelegramBotHost : IHost, ITelegratorBot
{ {
private readonly IHost _innerHost; private readonly IHost _innerHost;
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
@@ -33,10 +34,9 @@ namespace Telegrator.Hosting
/// </summary> /// </summary>
/// <param name="hostApplicationBuilder">The proxied instance of host builder.</param> /// <param name="hostApplicationBuilder">The proxied instance of host builder.</param>
/// <param name="handlers"></param> /// <param name="handlers"></param>
public TelegramBotHost(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers) public TelegramBotHost(HostApplicationBuilder hostApplicationBuilder)
{ {
// Registering this host in services for easy access // Registering this host in services for easy access
hostApplicationBuilder.Services.AddSingleton<ITelegramBotHost>(this);
hostApplicationBuilder.Services.AddSingleton<ITelegratorBot>(this); hostApplicationBuilder.Services.AddSingleton<ITelegratorBot>(this);
// Building proxy hoster // Building proxy hoster
@@ -47,9 +47,6 @@ namespace Telegrator.Hosting
// Reruesting services for this host // Reruesting services for this host
_updateRouter = Services.GetRequiredService<IUpdateRouter>(); _updateRouter = Services.GetRequiredService<IUpdateRouter>();
_logger = Services.GetRequiredService<ILogger<TelegramBotHost>>(); _logger = Services.GetRequiredService<ILogger<TelegramBotHost>>();
// Logging registering handlers in DEBUG purposes
_logger.LogHandlers(handlers);
} }
/// <summary> /// <summary>
@@ -60,6 +57,7 @@ namespace Telegrator.Hosting
{ {
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings: null); HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings: null);
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, null); TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, null);
builder.Services.AddTelegramBotHostDefaults(); builder.Services.AddTelegramBotHostDefaults();
builder.Services.AddTelegramReceiver(); builder.Services.AddTelegramReceiver();
return builder; return builder;
@@ -69,10 +67,11 @@ namespace Telegrator.Hosting
/// Creates new <see cref="TelegramBotHostBuilder"/> with default services and long-polling update receiving scheme /// Creates new <see cref="TelegramBotHostBuilder"/> with default services and long-polling update receiving scheme
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static TelegramBotHostBuilder CreateBuilder(TelegramBotHostBuilderSettings? settings) public static TelegramBotHostBuilder CreateBuilder(HostApplicationBuilderSettings? settings)
{ {
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings?.ToApplicationBuilderSettings()); HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings);
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, settings); TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, settings);
builder.Services.AddTelegramBotHostDefaults(); builder.Services.AddTelegramBotHostDefaults();
builder.Services.AddTelegramReceiver(); builder.Services.AddTelegramReceiver();
return builder; return builder;
@@ -92,7 +91,7 @@ namespace Telegrator.Hosting
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes /// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public static TelegramBotHostBuilder CreateEmptyBuilder(TelegramBotHostBuilderSettings? settings) public static TelegramBotHostBuilder CreateEmptyBuilder(HostApplicationBuilderSettings? settings)
{ {
HostApplicationBuilder innerBuilder = Host.CreateEmptyApplicationBuilder(null); HostApplicationBuilder innerBuilder = Host.CreateEmptyApplicationBuilder(null);
return new TelegramBotHostBuilder(innerBuilder, settings); return new TelegramBotHostBuilder(innerBuilder, settings);
@@ -11,11 +11,11 @@ namespace Telegrator.Hosting
/// <summary> /// <summary>
/// Represents a hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more. /// Represents a hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
/// </summary> /// </summary>
public class TelegramBotHostBuilder : ITelegramBotHostBuilder public class TelegramBotHostBuilder : ICollectingProvider
{ {
private readonly HostApplicationBuilder _innerBuilder; private readonly HostApplicationBuilder _innerBuilder;
private readonly TelegramBotHostBuilderSettings _settings; private readonly HostApplicationBuilderSettings _settings;
private readonly IHandlersCollection _handlers; internal IHandlersCollection _handlers = null!;
/// <inheritdoc/> /// <inheritdoc/>
public IHandlersCollection Handlers => _handlers; public IHandlersCollection Handlers => _handlers;
@@ -37,13 +37,12 @@ namespace Telegrator.Hosting
/// </summary> /// </summary>
/// <param name="hostApplicationBuilder"></param> /// <param name="hostApplicationBuilder"></param>
/// <param name="settings"></param> /// <param name="settings"></param>
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, TelegramBotHostBuilderSettings? settings = null) public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, HostApplicationBuilderSettings? settings = null)
{ {
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder)); _innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
_settings = settings ?? new TelegramBotHostBuilderSettings(); _settings = settings ?? new HostApplicationBuilderSettings();
_handlers = new HostHandlersCollection(Services, _settings);
_innerBuilder.AddTelegrator(_settings, _handlers); _innerBuilder.AddTelegrator(_settings);
_innerBuilder.Logging.ClearProviders(); _innerBuilder.Logging.ClearProviders();
} }
@@ -53,13 +52,12 @@ namespace Telegrator.Hosting
/// <param name="hostApplicationBuilder"></param> /// <param name="hostApplicationBuilder"></param>
/// <param name="handlers"></param> /// <param name="handlers"></param>
/// <param name="settings"></param> /// <param name="settings"></param>
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers, TelegramBotHostBuilderSettings? settings = null) public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers, HostApplicationBuilderSettings? settings = null)
{ {
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder)); _innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
_settings = settings ?? new TelegramBotHostBuilderSettings(); _settings = settings ?? new HostApplicationBuilderSettings();
_handlers = handlers ?? throw new ArgumentNullException(nameof(handlers));
_innerBuilder.AddTelegrator(_settings, _handlers); _innerBuilder.AddTelegrator(_settings, null, handlers);
_innerBuilder.Logging.ClearProviders(); _innerBuilder.Logging.ClearProviders();
} }
@@ -69,7 +67,9 @@ namespace Telegrator.Hosting
/// <returns></returns> /// <returns></returns>
public TelegramBotHost Build() public TelegramBotHost Build()
{ {
return new TelegramBotHost(_innerBuilder, _handlers); TelegramBotHost host = new TelegramBotHost(_innerBuilder);
host.UseTelegrator();
return host;
} }
} }
} }
@@ -1,45 +0,0 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace Telegrator.Hosting
{
/// <summary>
/// Settings os hosted Telegram bot
/// </summary>
public class TelegramBotHostBuilderSettings() : TelegratorOptions
{
/// <summary>
/// Disables automatic configuration for all of required <see cref="IOptions{TOptions}"/> instances
/// </summary>
public bool DisableAutoConfigure { get; set; }
/// <inheritdoc cref="HostApplicationBuilderSettings.DisableDefaults"/>
public bool DisableDefaults { get; set; }
/// <inheritdoc cref="HostApplicationBuilderSettings.Args"/>
public string[]? Args { get; set; }
/// <inheritdoc cref="HostApplicationBuilderSettings.Configuration"/>
public ConfigurationManager? Configuration { get; set; }
/// <inheritdoc cref="HostApplicationBuilderSettings.EnvironmentName"/>
public string? EnvironmentName { get; set; }
/// <inheritdoc cref="HostApplicationBuilderSettings.ApplicationName"/>
public string? ApplicationName { get; set; }
/// <inheritdoc cref="HostApplicationBuilderSettings.ContentRootPath"/>
public string? ContentRootPath { get; set; }
internal HostApplicationBuilderSettings ToApplicationBuilderSettings() => new HostApplicationBuilderSettings()
{
DisableDefaults = DisableDefaults,
Args = Args,
Configuration = Configuration,
EnvironmentName = EnvironmentName,
ApplicationName = ApplicationName,
ContentRootPath = ContentRootPath
};
}
}
@@ -4,7 +4,6 @@ using Microsoft.Extensions.Options;
using Telegram.Bot; using Telegram.Bot;
using Telegram.Bot.Polling; using Telegram.Bot.Polling;
using Telegrator.Core; using Telegrator.Core;
using Telegrator.Hosting;
using Telegrator.Mediation; using Telegrator.Mediation;
namespace Telegrator.Polling namespace Telegrator.Polling
@@ -17,7 +16,7 @@ namespace Telegrator.Polling
/// <param name="updateRouter"></param> /// <param name="updateRouter"></param>
/// <param name="options"></param> /// <param name="options"></param>
/// <param name="logger"></param> /// <param name="logger"></param>
public class HostedUpdateReceiver(ITelegramBotHost botHost, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<ReceiverOptions> options, ILogger<HostedUpdateReceiver> logger) : BackgroundService public class HostedUpdateReceiver(ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<ReceiverOptions> options, ILogger<HostedUpdateReceiver> logger) : BackgroundService
{ {
private readonly ReceiverOptions _receiverOptions = options.Value; private readonly ReceiverOptions _receiverOptions = options.Value;
private readonly IUpdateRouter _updateRouter = updateRouter; private readonly IUpdateRouter _updateRouter = updateRouter;
@@ -26,7 +25,7 @@ namespace Telegrator.Polling
protected override async Task ExecuteAsync(CancellationToken stoppingToken) protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{ {
logger.LogInformation("Starting receiving updates via long-polling"); logger.LogInformation("Starting receiving updates via long-polling");
_receiverOptions.AllowedUpdates = botHost.UpdateRouter.HandlersProvider.AllowedTypes.ToArray(); _receiverOptions.AllowedUpdates = _updateRouter.HandlersProvider.AllowedTypes.ToArray();
DefaultUpdateReceiver updateReceiver = new DefaultUpdateReceiver(botClient, _receiverOptions); DefaultUpdateReceiver updateReceiver = new DefaultUpdateReceiver(botClient, _receiverOptions);
await updateReceiver.ReceiveAsync(_updateRouter, stoppingToken).ConfigureAwait(false); await updateReceiver.ReceiveAsync(_updateRouter, stoppingToken).ConfigureAwait(false);
} }
@@ -1,36 +1,20 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
using Telegrator.Core; using Telegrator.Core;
using Telegrator.Core.Descriptors; using Telegrator.Core.Descriptors;
using Telegrator.Hosting;
namespace Telegrator.Providers namespace Telegrator.Providers
{ {
/// <summary>
/// Pre host building task
/// </summary>
/// <param name="builder"></param>
public delegate void PreBuildingRoutine(ITelegramBotHostBuilder builder);
/// <inheritdoc/> /// <inheritdoc/>
public class HostHandlersCollection(IServiceCollection hostServiceColletion, TelegratorOptions options) : HandlersCollection(options), IHostHandlersCollection public class HostHandlersCollection(IServiceCollection hostServiceColletion, TelegratorOptions options) : HandlersCollection(options)
{ {
private readonly IServiceCollection Services = hostServiceColletion; private readonly IServiceCollection Services = hostServiceColletion;
/// <inheritdoc/> /// <inheritdoc/>
protected override bool MustHaveParameterlessCtor => false; protected override bool MustHaveParameterlessCtor => false;
/// <summary>
/// List of tasks that should be completed right before building the bot
/// </summary>
public List<PreBuildingRoutine> PreBuilderRoutines { get; } = [];
/// <inheritdoc/> /// <inheritdoc/>
public override IHandlersCollection AddDescriptor(HandlerDescriptor descriptor) public override IHandlersCollection AddDescriptor(HandlerDescriptor descriptor)
{ {
if (descriptor.HandlerType.IsPreBuildingRoutine(out MethodInfo? routineMethod))
PreBuilderRoutines.Add(routineMethod.CreateDelegate<PreBuildingRoutine>(null));
switch (descriptor.Type) switch (descriptor.Type)
{ {
case DescriptorType.General: case DescriptorType.General:
@@ -1,46 +0,0 @@
using Telegram.Bot;
namespace Telegrator
{
/// <summary>
/// Internal proxy class for configuring Telegram bot client options from configuration.
/// Extends ConfigureOptionsProxy to provide specific configuration for Telegram bot client options.
/// </summary>
public class TelegramBotClientOptionsProxy : ConfigureOptionsProxy<TelegramBotClientOptions>
{
/// <summary>
/// Gets or sets the bot token.
/// </summary>
public string Token { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the base URL for the bot API.
/// </summary>
public string? BaseUrl { get; set; } = null;
/// <summary>
/// Gets or sets whether to use the test environment.
/// </summary>
public bool UseTestEnvironment { get; set; } = false;
/// <summary>
/// Gets or sets the retry threshold in seconds.
/// </summary>
public int RetryThreshold { get; set; } = 60;
/// <summary>
/// Gets or sets the number of retry attempts.
/// </summary>
public int RetryCount { get; set; } = 3;
/// <summary>
/// Creates a TelegramBotClientOptions instance from the proxy configuration.
/// </summary>
/// <returns>The configured TelegramBotClientOptions instance.</returns>
protected override TelegramBotClientOptions Realize() => new TelegramBotClientOptions(Token, BaseUrl, UseTestEnvironment)
{
RetryCount = RetryCount,
RetryThreshold = RetryThreshold
};
}
}
+47 -80
View File
@@ -4,18 +4,13 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text; using System.Text;
using Telegram.Bot; using Telegram.Bot;
using Telegram.Bot.Polling; using Telegram.Bot.Polling;
using Telegram.Bot.Types; using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums; using Telegram.Bot.Types.Enums;
using Telegrator;
using Telegrator.Core; using Telegrator.Core;
using Telegrator.Core.Descriptors; using Telegrator.Core.Descriptors;
using Telegrator.Handlers;
using Telegrator.Hosting; using Telegrator.Hosting;
using Telegrator.Logging; using Telegrator.Logging;
using Telegrator.Polling; using Telegrator.Polling;
@@ -38,13 +33,22 @@ public static class HostBuilderExtensions
/// <summary> /// <summary>
/// Gets the <see cref="IHandlersCollection"/> from the builder properties. /// Gets the <see cref="IHandlersCollection"/> from the builder properties.
/// </summary> /// </summary>
public IHandlersCollection Handlers => (IHandlersCollection)builder.Properties[HandlersCollectionPropertyKey]; public IHandlersCollection Handlers
{
get
{
if (builder is TelegramBotHostBuilder botHostBuilder)
return botHostBuilder.Handlers;
return (IHandlersCollection)builder.Properties[HandlersCollectionPropertyKey];
}
}
} }
/// <summary> /// <summary>
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers. /// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
/// </summary> /// </summary>
public static IHostApplicationBuilder AddTelegrator(this IHostApplicationBuilder builder, TelegramBotHostBuilderSettings settings, IHandlersCollection? handlers = null) public static IHostApplicationBuilder AddTelegrator(this IHostApplicationBuilder builder, HostApplicationBuilderSettings settings, TelegratorOptions? options = null, IHandlersCollection? handlers = null)
{ {
if (settings is null) if (settings is null)
throw new ArgumentNullException(nameof(settings)); throw new ArgumentNullException(nameof(settings));
@@ -52,53 +56,52 @@ public static class HostBuilderExtensions
IServiceCollection services = builder.Services; IServiceCollection services = builder.Services;
IConfigurationManager configuration = builder.Configuration; IConfigurationManager configuration = builder.Configuration;
handlers ??= new HostHandlersCollection(services, settings); if (options == null)
builder.Properties.Add(HandlersCollectionPropertyKey, handlers);
if (handlers is IHostHandlersCollection hostHandlers)
{ {
foreach (PreBuildingRoutine preBuildRoutine in hostHandlers.PreBuilderRoutines) options = configuration.GetSection(nameof(TelegratorOptions)).Get<TelegratorOptions>();
{ if (options == null)
try throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegratorOptions' wasn't registered. This configuration is runtime required!");
{
// TODO: fix
//preBuildRoutine.Invoke(builder);
Debug.WriteLine("Pre-Building routine was not executed");
}
catch (NotImplementedException)
{
_ = 0xBAD + 0xC0DE;
}
}
} }
if (!settings.DisableAutoConfigure) services.AddSingleton(Options.Create(options));
if (handlers != null)
{ {
services.Configure<ReceiverOptions>(configuration.GetSection(nameof(ReceiverOptions)));
services.Configure(configuration.GetSection(nameof(TelegramBotClientOptions)), new TelegramBotClientOptionsProxy());
}
else
{
if (null == services.SingleOrDefault(srvc => srvc.ImplementationType == typeof(IOptions<ReceiverOptions>)))
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'ReceiverOptions' wasn't registered. This configuration is runtime required!");
if (null == services.SingleOrDefault(srvc => srvc.ImplementationType == typeof(IOptions<TelegramBotClientOptions>)))
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'TelegramBotClientOptions' wasn't registered. This configuration is runtime required!");
}
IOptions<TelegramBotHostBuilderSettings> options = Options.Create(settings);
services.AddSingleton((IOptions<TelegratorOptions>)options);
services.AddTelegramBotHostDefaults();
services.AddSingleton(options);
services.AddSingleton(handlers);
if (handlers is IHandlersManager manager) if (handlers is IHandlersManager manager)
{ {
ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IHandlersProvider), manager); ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IHandlersProvider), manager);
services.Replace(descriptor); services.Replace(descriptor);
services.AddSingleton(manager); services.AddSingleton(manager);
} }
}
handlers ??= new HostHandlersCollection(services, options);
services.AddSingleton(handlers);
builder.Properties.Add(HandlersCollectionPropertyKey, handlers);
if (builder is TelegramBotHostBuilder botHostBuilder)
botHostBuilder._handlers = handlers;
if (!services.Any(srvc => srvc.ImplementationType == typeof(IOptions<ReceiverOptions>)))
{
ReceiverOptions? receiverOptions = configuration.GetSection(nameof(ReceiverOptions)).Get<ReceiverOptions>();
if (receiverOptions == null)
throw new MissingMemberException("Auto configuration disabled, yet no options of type 'ReceiverOptions' wasn't registered. This configuration is runtime required!");
services.AddSingleton(Options.Create(receiverOptions));
}
if (!services.Any(srvc => srvc.ImplementationType == typeof(IOptions<TelegramBotClientOptions>)))
{
services.AddSingleton(Options.Create(new TelegramBotClientOptions(options.Token, options.BaseUrl, options.UseTestEnvironment)
{
RetryCount = options.RetryCount,
RetryThreshold = options.RetryThreshold
}));
}
services.AddTelegramReceiver();
services.AddTelegramBotHostDefaults();
return builder; return builder;
} }
} }
@@ -109,20 +112,6 @@ public static class HostBuilderExtensions
/// </summary> /// </summary>
public static class ServicesCollectionExtensions public static class ServicesCollectionExtensions
{ {
/// <summary>
/// Registers a configuration instance that strongly-typed <typeparamref name="TOptions"/> will bind against using <see cref="ConfigureOptionsProxy{TOptions}"/>.
/// </summary>
/// <typeparam name="TOptions"></typeparam>
/// <param name="services"></param>
/// <param name="configuration"></param>
/// <param name="optionsProxy"></param>
/// <returns></returns>
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration configuration, ConfigureOptionsProxy<TOptions> optionsProxy) where TOptions : class
{
optionsProxy.Configure(services, configuration);
return services;
}
/// <summary> /// <summary>
/// Registers <see cref="TelegramBotHost"/> default services /// Registers <see cref="TelegramBotHost"/> default services
/// </summary> /// </summary>
@@ -163,7 +152,7 @@ public static class ServicesCollectionExtensions
} }
/// <summary> /// <summary>
/// Provides useful methods to adjust <see cref="ITelegramBotHost"/> /// Provides useful methods to adjust Telegram bot Host
/// </summary> /// </summary>
public static class TelegramBotHostExtensions public static class TelegramBotHostExtensions
{ {
@@ -218,28 +207,6 @@ public static class TelegramBotHostExtensions
} }
} }
/// <summary>
/// Provides extension methods for reflection and type inspection.
/// </summary>
public static class ReflectionExtensions
{
/// <summary>
/// Checks if a type implements the <see cref="IPreBuildingRoutine"/> interface.
/// </summary>
/// <param name="handlerType">The type to check.</param>
/// <param name="routineMethod"></param>
/// <returns>True if the type implements IPreBuildingRoutine; otherwise, false.</returns>
public static bool IsPreBuildingRoutine(this Type handlerType, [NotNullWhen(true)] out MethodInfo? routineMethod)
{
routineMethod = null;
if (handlerType.GetInterface(nameof(IPreBuildingRoutine)) == null)
return false;
routineMethod = handlerType.GetMethod(nameof(IPreBuildingRoutine.PreBuildingRoutine), BindingFlags.Static | BindingFlags.Public);
return routineMethod != null;
}
}
/// <summary> /// <summary>
/// Provides extension methods for logging Telegrator-related information. /// Provides extension methods for logging Telegrator-related information.
/// </summary> /// </summary>
+38 -5
View File
@@ -6,16 +6,49 @@
/// </summary> /// </summary>
public class TelegratorOptions public class TelegratorOptions
{ {
/// <inheritdoc/> /// <summary>
/// Gets or sets the bot token.
/// </summary>
public string Token { get; set; } = string.Empty;
/// <summary>
/// Gets or sets the base URL for the bot API.
/// </summary>
public string? BaseUrl { get; set; } = null;
/// <summary>
/// Gets or sets whether to use the test environment.
/// </summary>
public bool UseTestEnvironment { get; set; } = false;
/// <summary>
/// Gets or sets the retry threshold in seconds.
/// </summary>
public int RetryThreshold { get; set; } = 60;
/// <summary>
/// Gets or sets the number of retry attempts.
/// </summary>
public int RetryCount { get; set; } = 3;
/// <summary>
/// Gets or sets the maximum number of parallel working handlers. Null means no limit.
/// </summary>
public int? MaximumParallelWorkingHandlers { get; set; } = null; public int? MaximumParallelWorkingHandlers { get; set; } = null;
/// <inheritdoc/> /// <summary>
/// Gets or sets a value indicating whether awaiting handlers should be routed separately from regular handlers.
/// </summary>
public bool ExclusiveAwaitingHandlerRouting { get; set; } = false; public bool ExclusiveAwaitingHandlerRouting { get; set; } = false;
/// <inheritdoc/> /// <summary>
/// Gets or sets a value indicating whether to exclude intersecting command aliases.
/// </summary>
public bool ExceptIntersectingCommandAliases { get; set; } = true; public bool ExceptIntersectingCommandAliases { get; set; } = true;
/// <inheritdoc/> /// <summary>
public CancellationToken GlobalCancellationToken { get; set; } /// Gets or sets the global cancellation token for all bot operations.
/// </summary>
public CancellationToken GlobalCancellationToken { get; set; } = default;
} }
} }