* Moved source code projects directory to 'src'
* Updatedt Solution format
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
namespace Telegrator.Hosting.Components
|
||||
{
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Telegrator;
|
||||
|
||||
namespace Telegrator.Hosting.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for Telegram bot hosts.
|
||||
/// Combines host application capabilities with reactive Telegram bot functionality.
|
||||
/// </summary>
|
||||
public interface ITelegramBotHost : IHost, ITelegratorBot
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegrator.MadiatorCore;
|
||||
|
||||
namespace Telegrator.Hosting.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for building Telegram bot hosts with dependency injection support.
|
||||
/// Combines host application building capabilities with handler collection functionality.
|
||||
/// </summary>
|
||||
public interface ITelegramBotHostBuilder : ICollectingProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the set of key/value configuration properties.
|
||||
/// </summary>
|
||||
IConfigurationManager Configuration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of logging providers for the application to compose. This is useful for adding new logging providers.
|
||||
/// </summary>
|
||||
ILoggingBuilder Logging { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of services for the application to compose. This is useful for adding user provided or framework provided services.
|
||||
/// </summary>
|
||||
IServiceCollection Services { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Telegrator.Hosting.Configuration
|
||||
{
|
||||
/// <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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Telegram.Bot;
|
||||
|
||||
namespace Telegrator.Hosting.Configuration
|
||||
{
|
||||
/// <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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Style", "IDE0290")]
|
||||
[assembly: SuppressMessage("Style", "IDE0090")]
|
||||
[assembly: SuppressMessage("Usage", "CA2254")]
|
||||
@@ -0,0 +1,30 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegrator.Configuration;
|
||||
|
||||
namespace Telegrator.Hosting
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="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>
|
||||
public class HostedTelegramBotInfo(ITelegramBotClient client, IServiceProvider services, IConfigurationManager configuration) : ITelegramBotInfo
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public User User { get; } = client.GetMe().Result;
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to services of this Hosted telegram bot
|
||||
/// </summary>
|
||||
public IServiceProvider Services { get; } = services;
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to configuration of this Hosted telegram bot
|
||||
/// </summary>
|
||||
public IConfigurationManager Configuration { get; } = configuration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegrator.Logging;
|
||||
|
||||
namespace Telegrator.Hosting.Logging
|
||||
{
|
||||
/// <summary>
|
||||
/// Adapter for Microsoft.Extensions.Logging to work with Telegrator logging system.
|
||||
/// This allows seamless integration with ASP.NET Core logging infrastructure.
|
||||
/// </summary>
|
||||
public class MicrosoftLoggingAdapter : ITelegratorLogger
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of MicrosoftLoggingAdapter.
|
||||
/// </summary>
|
||||
/// <param name="logger">The Microsoft.Extensions.Logging logger instance.</param>
|
||||
public MicrosoftLoggingAdapter(ILogger logger)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Log(Telegrator.Logging.LogLevel level, string message, Exception? exception = null)
|
||||
{
|
||||
var msLogLevel = level switch
|
||||
{
|
||||
Telegrator.Logging.LogLevel.Trace => Microsoft.Extensions.Logging.LogLevel.Trace,
|
||||
Telegrator.Logging.LogLevel.Debug => Microsoft.Extensions.Logging.LogLevel.Debug,
|
||||
Telegrator.Logging.LogLevel.Information => Microsoft.Extensions.Logging.LogLevel.Information,
|
||||
Telegrator.Logging.LogLevel.Warning => Microsoft.Extensions.Logging.LogLevel.Warning,
|
||||
Telegrator.Logging.LogLevel.Error => Microsoft.Extensions.Logging.LogLevel.Error,
|
||||
_ => Microsoft.Extensions.Logging.LogLevel.Information
|
||||
};
|
||||
|
||||
if (exception != null)
|
||||
{
|
||||
_logger.Log(msLogLevel, default, message, exception, (str, exc) => string.Format("{0} : {1}", str, exc));
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(msLogLevel, default, message, null, (str, _) => str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.Polling;
|
||||
|
||||
namespace Telegrator.Hosting.Polling
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class HostUpdateHandlersPool(IUpdateRouter router, IOptions<TelegratorOptions> options)
|
||||
: UpdateHandlersPool(router, options.Value, options.Value.GlobalCancellationToken)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Polling;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.Polling;
|
||||
|
||||
namespace Telegrator.Hosting.Polling
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class HostUpdateRouter : UpdateRouter
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="ILogger"/> of this router
|
||||
/// </summary>
|
||||
protected readonly ILogger<HostUpdateRouter> Logger;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public HostUpdateRouter(
|
||||
IHandlersProvider handlersProvider,
|
||||
IAwaitingProvider awaitingProvider,
|
||||
IOptions<TelegratorOptions> options,
|
||||
IUpdateHandlersPool handlersPool,
|
||||
ITelegramBotInfo botInfo,
|
||||
ILogger<HostUpdateRouter> logger) : base(handlersProvider, awaitingProvider, options.Value, handlersPool, botInfo)
|
||||
{
|
||||
Logger = logger;
|
||||
ExceptionHandler = new DefaultRouterExceptionHandler(HandleException);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
|
||||
{
|
||||
//Logger.LogInformation("Received update of type \"{type}\"", update.Type);
|
||||
return base.HandleUpdateAsync(botClient, update, 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>
|
||||
public void HandleException(ITelegramBotClient botClient, Exception exception, HandleErrorSource source, CancellationToken cancellationToken)
|
||||
{
|
||||
if (exception is HandlerFaultedException handlerFaultedException)
|
||||
{
|
||||
Logger.LogError("\"{handler}\" handler's execution was faulted :\n{exception}",
|
||||
handlerFaultedException.HandlerInfo.ToString(),
|
||||
handlerFaultedException.InnerException?.ToString() ?? "No inner exception");
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.LogError("Exception was thrown during update routing faulted :\n{exception}", exception.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Polling;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.Polling;
|
||||
|
||||
namespace Telegrator.Hosting.Polling
|
||||
{
|
||||
/// <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>
|
||||
public class HostedUpdateReceiver(ITelegramBotHost botHost, ITelegramBotClient botClient, IUpdateRouter updateRouter, IOptions<ReceiverOptions> options, ILogger<HostedUpdateReceiver> logger) : BackgroundService
|
||||
{
|
||||
private readonly ReceiverOptions _receiverOptions = options.Value;
|
||||
private readonly IUpdateRouter _updateRouter = updateRouter;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
logger.LogInformation("Starting receiving updates via long-polling");
|
||||
_receiverOptions.AllowedUpdates = botHost.UpdateRouter.HandlersProvider.AllowedTypes.ToArray();
|
||||
DefaultUpdateReceiver updateReceiver = new DefaultUpdateReceiver(botClient, _receiverOptions);
|
||||
await updateReceiver.ReceiveAsync(_updateRouter, stoppingToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Telegrator.MadiatorCore;
|
||||
|
||||
namespace Telegrator.Hosting.Providers.Components
|
||||
{
|
||||
/// <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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegrator.Providers;
|
||||
|
||||
namespace Telegrator.Hosting.Providers
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class HostAwaitingProvider(IOptions<TelegratorOptions> options, ILogger<HostAwaitingProvider> logger) : AwaitingProvider(options.Value)
|
||||
{
|
||||
private readonly ILogger<HostAwaitingProvider> _logger = logger;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Reflection;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.Hosting.Providers.Components;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.MadiatorCore.Descriptors;
|
||||
using Telegrator.Providers;
|
||||
|
||||
namespace Telegrator.Hosting.Providers
|
||||
{
|
||||
/// <summary>
|
||||
/// Pre host building task
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
public delegate void PreBuildingRoutine(ITelegramBotHostBuilder builder);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public class HostHandlersCollection(IServiceCollection hostServiceColletion, ITelegratorOptions options) : HandlersCollection(options), IHostHandlersCollection
|
||||
{
|
||||
private readonly IServiceCollection Services = hostServiceColletion;
|
||||
|
||||
/// <inheritdoc/>
|
||||
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/>
|
||||
public override IHandlersCollection AddDescriptor(HandlerDescriptor descriptor)
|
||||
{
|
||||
if (descriptor.HandlerType.IsPreBuildingRoutine(out MethodInfo? routineMethod))
|
||||
PreBuilderRoutines.Add(routineMethod.CreateDelegate<PreBuildingRoutine>(null));
|
||||
|
||||
switch (descriptor.Type)
|
||||
{
|
||||
case DescriptorType.General:
|
||||
{
|
||||
if (descriptor.InstanceFactory != null)
|
||||
Services.AddScoped(descriptor.HandlerType, _ => descriptor.InstanceFactory.Invoke());
|
||||
else
|
||||
Services.AddScoped(descriptor.HandlerType);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DescriptorType.Keyed:
|
||||
{
|
||||
if (descriptor.InstanceFactory != null)
|
||||
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey, (_, _) => descriptor.InstanceFactory.Invoke());
|
||||
else
|
||||
Services.AddKeyedScoped(descriptor.HandlerType, descriptor.ServiceKey);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DescriptorType.Singleton:
|
||||
{
|
||||
Services.AddSingleton(descriptor.HandlerType, descriptor.SingletonInstance ?? (descriptor.InstanceFactory != null
|
||||
? descriptor.InstanceFactory.Invoke()
|
||||
: throw new Exception()));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DescriptorType.Implicit:
|
||||
{
|
||||
Services.AddKeyedSingleton(descriptor.HandlerType, descriptor.ServiceKey, descriptor.SingletonInstance ?? (descriptor.InstanceFactory != null
|
||||
? descriptor.InstanceFactory.Invoke()
|
||||
: throw new Exception()));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return base.AddDescriptor(descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegrator.Handlers.Components;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.MadiatorCore.Descriptors;
|
||||
using Telegrator.Providers;
|
||||
|
||||
namespace Telegrator.Hosting.Providers
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public class HostHandlersProvider : HandlersProvider
|
||||
{
|
||||
private readonly IServiceProvider Services;
|
||||
private readonly ILogger<HostHandlersProvider> Logger;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public HostHandlersProvider(
|
||||
IHandlersCollection handlers,
|
||||
IOptions<TelegratorOptions> options,
|
||||
IServiceProvider serviceProvider,
|
||||
ILogger<HostHandlersProvider> logger) : base(handlers, options.Value)
|
||||
{
|
||||
Services = serviceProvider;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override UpdateHandlerBase GetHandlerInstance(HandlerDescriptor descriptor, CancellationToken cancellationToken = default)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
IServiceScope scope = Services.CreateScope();
|
||||
|
||||
object handlerInstance = descriptor.ServiceKey == null
|
||||
? scope.ServiceProvider.GetRequiredService(descriptor.HandlerType)
|
||||
: scope.ServiceProvider.GetRequiredKeyedService(descriptor.HandlerType, descriptor.ServiceKey);
|
||||
|
||||
if (handlerInstance is not UpdateHandlerBase updateHandler)
|
||||
throw new InvalidOperationException("Failed to resolve " + descriptor.HandlerType + " as UpdateHandlerBase");
|
||||
|
||||
descriptor.LazyInitialization?.Invoke(updateHandler);
|
||||
updateHandler.LifetimeToken.OnLifetimeEnded += _ => scope.Dispose();
|
||||
return updateHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
# Telegrator.Hosting
|
||||
|
||||
**Telegrator.Hosting** is an extension for the Telegrator framework that provides seamless integration with the .NET Generic Host, enabling production-ready, scalable, and maintainable Telegram bot applications.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
- Integration with `Microsoft.Extensions.Hosting` (background services, DI, configuration, logging)
|
||||
- Automatic handler discovery and registration
|
||||
- Strongly-typed configuration via `appsettings.json` and environment variables
|
||||
- Graceful startup/shutdown and lifecycle management
|
||||
- Advanced error handling and logging
|
||||
- Supports all Telegrator handler/filter/state features
|
||||
|
||||
---
|
||||
|
||||
## Requirements
|
||||
- .NET 8.0 or later
|
||||
- [Telegrator](https://github.com/Rikitav/Telegrator)
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
dotnet add package Telegrator.Hosting
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Quick Start Example
|
||||
|
||||
**Program.cs:**
|
||||
```csharp
|
||||
using Telegrator.Hosting;
|
||||
|
||||
// Creating builder
|
||||
TelegramBotHostBuilder builder = TelegramBotHost.CreateBuilder(new TelegramBotHostBuilderSettings()
|
||||
{
|
||||
Args = args,
|
||||
ExceptIntersectingCommandAliases = true
|
||||
});
|
||||
|
||||
// Registerring handlers
|
||||
builder.Handlers.CollectHandlersAssemblyWide();
|
||||
|
||||
// Register your services
|
||||
builder.Services.AddSingleton<IMyService, MyService>();
|
||||
|
||||
// Building and running application
|
||||
TelegramBotHost telegramBot = builder.Build();
|
||||
telegramBot.SetBotCommands();
|
||||
telegramBot.Run();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration (appsettings.json)
|
||||
|
||||
```json
|
||||
{
|
||||
"TelegramBotClientOptions": {
|
||||
"Token": "YOUR_BOT_TOKEN"
|
||||
},
|
||||
|
||||
"HostOptions": {
|
||||
"ShutdownTimeout": 10,
|
||||
"BackgroundServiceExceptionBehavior": "StopHost"
|
||||
},
|
||||
|
||||
"ReceiverOptions": {
|
||||
"DropPendingUpdates": true,
|
||||
"Limit": 10
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `TelegramBotClientOptions`: Bot token and client settings
|
||||
- `HostOptions`: Host lifecycle and shutdown behavior
|
||||
- `ReceiverOptions`: Long-polling configuration
|
||||
|
||||
---
|
||||
|
||||
## Documentation
|
||||
- [Telegrator Main Docs](https://github.com/Rikitav/Telegrator)
|
||||
- [Getting Started Guide](https://github.com/Rikitav/Telegrator/wiki/Getting-started)
|
||||
- [Annotation Overview](https://github.com/Rikitav/Telegrator/wiki/Annotation-overview)
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
GPLv3
|
||||
@@ -0,0 +1,136 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.MadiatorCore;
|
||||
|
||||
namespace Telegrator.Hosting
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a hosted telegram bot
|
||||
/// </summary>
|
||||
public class TelegramBotHost : ITelegramBotHost
|
||||
{
|
||||
private readonly IHost _innerHost;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IUpdateRouter _updateRouter;
|
||||
private readonly ILogger<TelegramBotHost> _logger;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IServiceProvider Services => _serviceProvider;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IUpdateRouter UpdateRouter => _updateRouter;
|
||||
|
||||
/// <summary>
|
||||
/// This application's logger
|
||||
/// </summary>
|
||||
public ILogger<TelegramBotHost> Logger => _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TelegramBotHost"/> class.
|
||||
/// </summary>
|
||||
/// <param name="hostApplicationBuilder">The proxied instance of host builder.</param>
|
||||
/// <param name="handlers"></param>
|
||||
public TelegramBotHost(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers)
|
||||
{
|
||||
// Registering this host in services for easy access
|
||||
RegisterHostServices(hostApplicationBuilder.Services, handlers);
|
||||
|
||||
// Building proxy hoster
|
||||
_innerHost = hostApplicationBuilder.Build();
|
||||
_serviceProvider = _innerHost.Services;
|
||||
_innerHost.UseTelegrator();
|
||||
|
||||
// Reruesting services for this host
|
||||
_updateRouter = Services.GetRequiredService<IUpdateRouter>();
|
||||
_logger = Services.GetRequiredService<ILogger<TelegramBotHost>>();
|
||||
|
||||
// Logging registering handlers in DEBUG purposes
|
||||
_logger.LogHandlers(handlers);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates new <see cref="TelegramBotHostBuilder"/> with default configuration, services and long-polling update receiving scheme
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static TelegramBotHostBuilder CreateBuilder()
|
||||
{
|
||||
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings: null);
|
||||
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, null);
|
||||
builder.Services.AddTelegramBotHostDefaults();
|
||||
builder.Services.AddTelegramReceiver();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates new <see cref="TelegramBotHostBuilder"/> with default services and long-polling update receiving scheme
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static TelegramBotHostBuilder CreateBuilder(TelegramBotHostBuilderSettings? settings)
|
||||
{
|
||||
HostApplicationBuilder innerBuilder = new HostApplicationBuilder(settings?.ToApplicationBuilderSettings());
|
||||
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(innerBuilder, settings);
|
||||
builder.Services.AddTelegramBotHostDefaults();
|
||||
builder.Services.AddTelegramReceiver();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static TelegramBotHostBuilder CreateEmptyBuilder()
|
||||
{
|
||||
HostApplicationBuilder innerBuilder = Host.CreateEmptyApplicationBuilder(null);
|
||||
return new TelegramBotHostBuilder(innerBuilder, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates new EMPTY <see cref="TelegramBotHostBuilder"/> WITHOUT any services or update receiving schemes
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static TelegramBotHostBuilder CreateEmptyBuilder(TelegramBotHostBuilderSettings? settings)
|
||||
{
|
||||
HostApplicationBuilder innerBuilder = Host.CreateEmptyApplicationBuilder(null);
|
||||
return new TelegramBotHostBuilder(innerBuilder, settings);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task StartAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _innerHost.StartAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public async Task StopAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _innerHost.StopAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the host.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
|
||||
_innerHost.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
private void RegisterHostServices(IServiceCollection services, IHandlersCollection handlers)
|
||||
{
|
||||
//services.RemoveAll<IHost>();
|
||||
//services.AddSingleton<IHost>(this);
|
||||
|
||||
services.AddSingleton<ITelegramBotHost>(this);
|
||||
services.AddSingleton<ITelegratorBot>(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.Hosting.Providers;
|
||||
using Telegrator.MadiatorCore;
|
||||
|
||||
#pragma warning disable IDE0001
|
||||
namespace Telegrator.Hosting
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a hosted telegram bots and services builder that helps manage configuration, logging, lifetime, and more.
|
||||
/// </summary>
|
||||
public class TelegramBotHostBuilder : ITelegramBotHostBuilder
|
||||
{
|
||||
private readonly HostApplicationBuilder _innerBuilder;
|
||||
private readonly TelegramBotHostBuilderSettings _settings;
|
||||
private readonly IHandlersCollection _handlers;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IHandlersCollection Handlers => _handlers;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IServiceCollection Services => _innerBuilder.Services;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IConfigurationManager Configuration => _innerBuilder.Configuration;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ILoggingBuilder Logging => _innerBuilder.Logging;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IHostEnvironment Environment => _innerBuilder.Environment;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="hostApplicationBuilder"></param>
|
||||
/// <param name="settings"></param>
|
||||
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, TelegramBotHostBuilderSettings? settings = null)
|
||||
{
|
||||
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
||||
_settings = settings ?? new TelegramBotHostBuilderSettings();
|
||||
_handlers = new HostHandlersCollection(Services, _settings);
|
||||
|
||||
_innerBuilder.AddTelegrator(_settings, _handlers);
|
||||
_innerBuilder.Logging.ClearProviders();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TelegramBotHostBuilder"/> class.
|
||||
/// </summary>
|
||||
/// <param name="hostApplicationBuilder"></param>
|
||||
/// <param name="handlers"></param>
|
||||
/// <param name="settings"></param>
|
||||
public TelegramBotHostBuilder(HostApplicationBuilder hostApplicationBuilder, IHandlersCollection handlers, TelegramBotHostBuilderSettings? settings = null)
|
||||
{
|
||||
_innerBuilder = hostApplicationBuilder ?? throw new ArgumentNullException(nameof(hostApplicationBuilder));
|
||||
_settings = settings ?? new TelegramBotHostBuilderSettings();
|
||||
_handlers = handlers ?? throw new ArgumentNullException(nameof(handlers));
|
||||
|
||||
_innerBuilder.AddTelegrator(_settings, _handlers);
|
||||
_innerBuilder.Logging.ClearProviders();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the host.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TelegramBotHost Build()
|
||||
{
|
||||
return new TelegramBotHost(_innerBuilder, _handlers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<BaseOutputPath>..\..\bin</BaseOutputPath>
|
||||
<DocumentationFile>..\..\docs\$(AssemblyName).xml</DocumentationFile>
|
||||
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<EnableNETAnalyzers>True</EnableNETAnalyzers>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
|
||||
<Title>Telegrator.Hosting</Title>
|
||||
<Version>1.16.0</Version>
|
||||
<Authors>Rikitav Tim4ik</Authors>
|
||||
<Company>Rikitav Tim4ik</Company>
|
||||
<RepositoryUrl>https://github.com/Rikitav/Telegrator</RepositoryUrl>
|
||||
<PackageTags>telegram;bot;mediator;attributes;aspect;hosting;host;framework;easy;simple;handlers</PackageTags>
|
||||
|
||||
<PackageIcon>telegrator_nuget.png</PackageIcon>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="10.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="..\LICENSE" Pack="True" PackagePath="\" />
|
||||
<None Include="..\README.md" Pack="True" PackagePath="\" />
|
||||
<None Include="..\resources\telegrator_nuget.png" Pack="True" PackagePath="\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Telegrator\Telegrator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,250 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Polling;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.Hosting.Configuration;
|
||||
using Telegrator.Hosting.Logging;
|
||||
using Telegrator.Hosting.Polling;
|
||||
using Telegrator.Hosting.Providers;
|
||||
using Telegrator.Hosting.Providers.Components;
|
||||
using Telegrator.Logging;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.MadiatorCore.Descriptors;
|
||||
|
||||
namespace Telegrator.Hosting
|
||||
{
|
||||
public static class HostBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Replaces TelegramBotWebHostBuilder. Configures DI, options, and handlers.
|
||||
/// </summary>
|
||||
public static IHostApplicationBuilder AddTelegrator(this IHostApplicationBuilder builder, TelegramBotHostBuilderSettings settings, IHandlersCollection? handlers = null)
|
||||
{
|
||||
if (settings is null)
|
||||
throw new ArgumentNullException(nameof(settings));
|
||||
|
||||
IServiceCollection services = builder.Services;
|
||||
IConfigurationManager configuration = builder.Configuration;
|
||||
|
||||
handlers ??= new HostHandlersCollection(services, settings);
|
||||
|
||||
if (handlers is IHostHandlersCollection hostHandlers)
|
||||
{
|
||||
foreach (PreBuildingRoutine preBuildRoutine in hostHandlers.PreBuilderRoutines)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: fix
|
||||
//preBuildRoutine.Invoke(builder);
|
||||
Debug.WriteLine("Pre-Building routine was not executed");
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
_ = 0xBAD + 0xC0DE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!settings.DisableAutoConfigure)
|
||||
{
|
||||
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)
|
||||
{
|
||||
ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IHandlersProvider), manager);
|
||||
services.Replace(descriptor);
|
||||
services.AddSingleton(manager);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Contains extensions for <see cref="IServiceCollection"/>
|
||||
/// Provides method to configure <see cref="ITelegramBotHost"/>
|
||||
/// </summary>
|
||||
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>
|
||||
/// Registers <see cref="TelegramBotHost"/> default services
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddTelegramBotHostDefaults(this IServiceCollection services)
|
||||
{
|
||||
services.AddLogging(builder => builder.AddConsole().AddDebug());
|
||||
services.AddSingleton<IUpdateHandlersPool, HostUpdateHandlersPool>();
|
||||
services.AddSingleton<IAwaitingProvider, HostAwaitingProvider>();
|
||||
services.AddSingleton<IHandlersProvider, HostHandlersProvider>();
|
||||
services.AddSingleton<IUpdateRouter, HostUpdateRouter>();
|
||||
services.AddSingleton<ITelegramBotInfo, HostedTelegramBotInfo>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers <see cref="ITelegramBotClient"/> service with <see cref="HostedUpdateReceiver"/> to receive updates using long polling
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <returns></returns>
|
||||
public static IServiceCollection AddTelegramReceiver(this IServiceCollection services)
|
||||
{
|
||||
services.AddHttpClient<ITelegramBotClient>("tgreceiver").RemoveAllLoggers().AddTypedClient(TypedTelegramBotClientFactory);
|
||||
services.AddHostedService<HostedUpdateReceiver>();
|
||||
return services;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="ITelegramBotClient"/> factory method
|
||||
/// </summary>
|
||||
/// <param name="httpClient"></param>
|
||||
/// <param name="provider"></param>
|
||||
/// <returns></returns>
|
||||
private static ITelegramBotClient TypedTelegramBotClientFactory(HttpClient httpClient, IServiceProvider provider)
|
||||
=> new TelegramBotClient(provider.GetRequiredService<IOptions<TelegramBotClientOptions>>().Value, httpClient);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides useful methods to adjust <see cref="ITelegramBotHost"/>
|
||||
/// </summary>
|
||||
public static class TelegramBotHostExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Replaces the initialization logic from TelegramBotWebHost constructor.
|
||||
/// Initializes the bot and logs handlers on application startup.
|
||||
/// </summary>
|
||||
public static IHost UseTelegrator(this IHost botHost)
|
||||
{
|
||||
ITelegramBotInfo info = botHost.Services.GetRequiredService<ITelegramBotInfo>();
|
||||
IHandlersCollection handlers = botHost.Services.GetRequiredService<IHandlersCollection>();
|
||||
ILoggerFactory loggerFactory = botHost.Services.GetRequiredService<ILoggerFactory>();
|
||||
ILogger logger = loggerFactory.CreateLogger("Telegrator.Hosting.Web.TelegratorHost");
|
||||
|
||||
logger.LogInformation("Telegrator Bot .NET Host started");
|
||||
logger.LogHandlers(handlers);
|
||||
|
||||
return botHost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures bots available commands depending on what handlers was registered
|
||||
/// </summary>
|
||||
/// <param name="botHost"></param>
|
||||
/// <returns></returns>
|
||||
public static IHost SetBotCommands(this IHost botHost)
|
||||
{
|
||||
ITelegramBotClient client = botHost.Services.GetRequiredService<ITelegramBotClient>();
|
||||
IUpdateRouter router = botHost.Services.GetRequiredService<IUpdateRouter>();
|
||||
|
||||
IEnumerable<BotCommand> aliases = router.HandlersProvider.GetBotCommands();
|
||||
client.SetMyCommands(aliases).Wait();
|
||||
return botHost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a Microsoft.Extensions.Logging adapter to Alligator using a logger factory.
|
||||
/// </summary>
|
||||
/// <param name="host"></param>
|
||||
public static IHost AddLoggingAdapter(this IHost host)
|
||||
{
|
||||
ILoggerFactory loggerFactory = host.Services.GetRequiredService<ILoggerFactory>();
|
||||
ILogger logger = loggerFactory.CreateLogger("Telegrator");
|
||||
|
||||
MicrosoftLoggingAdapter adapter = new MicrosoftLoggingAdapter(logger);
|
||||
Alligator.AddAdapter(adapter);
|
||||
return host;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoggerExtensions
|
||||
{
|
||||
public static void LogHandlers(this ILogger logger, IHandlersCollection handlers)
|
||||
{
|
||||
StringBuilder logBuilder = new StringBuilder("Registered handlers : ");
|
||||
if (!handlers.Keys.Any())
|
||||
throw new Exception();
|
||||
|
||||
foreach (UpdateType updateType in handlers.Keys)
|
||||
{
|
||||
HandlerDescriptorList descriptors = handlers[updateType];
|
||||
logBuilder.Append("\n\tUpdateType." + updateType + " :");
|
||||
|
||||
foreach (HandlerDescriptor descriptor in descriptors.Reverse())
|
||||
{
|
||||
logBuilder.AppendFormat("\n\t* {0} - {1}",
|
||||
descriptor.Indexer.ToString(),
|
||||
descriptor.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
logger.LogInformation(logBuilder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user