Добавьте файлы проекта.
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(TelegramBotHostBuilder 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, IReactiveTelegramBot
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
internal 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,8 @@
|
||||
// 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")]
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.MadiatorCore.Descriptors;
|
||||
using Telegrator.Polling;
|
||||
|
||||
namespace Telegrator.Hosting.Polling
|
||||
{
|
||||
public class HostUpdateHandlersPool(IOptions<TelegramBotOptions> options, ILogger<HostUpdateHandlersPool> logger)
|
||||
: UpdateHandlersPool(options.Value, options.Value.GlobalCancellationToken)
|
||||
{
|
||||
private readonly ILogger<HostUpdateHandlersPool> _logger = logger;
|
||||
|
||||
protected override async Task ExecuteHandlerWrapper(DescribedHandlerInfo enqueuedHandler)
|
||||
{
|
||||
_logger.LogInformation("Handler \"{0}\" has entered execution pool", enqueuedHandler.DisplayString);
|
||||
await base.ExecuteHandlerWrapper(enqueuedHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Polling;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegrator;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.Polling;
|
||||
|
||||
namespace Telegrator.Hosting.Polling
|
||||
{
|
||||
public class HostUpdateRouter : UpdateRouter
|
||||
{
|
||||
protected readonly ILogger<HostUpdateRouter> Logger;
|
||||
|
||||
public HostUpdateRouter(IHandlersProvider handlersProvider, IAwaitingProvider awaitingProvider, IOptions<TelegramBotOptions> options, IUpdateHandlersPool handlersPool, ILogger<HostUpdateRouter> logger)
|
||||
: base(handlersProvider, awaitingProvider, options.Value, handlersPool)
|
||||
{
|
||||
Logger = logger;
|
||||
ExceptionHandler = new HostExceptionHandler(logger);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private class HostExceptionHandler(ILogger<HostUpdateRouter> logger) : IRouterExceptionHandler
|
||||
{
|
||||
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.DisplayString,
|
||||
handlerFaultedException.InnerException?.ToString() ?? "No inner exception");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogError("Exception was thrown during update routing faulted :\n{exception}", exception.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
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
|
||||
{
|
||||
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;
|
||||
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
logger.LogInformation("Starting receiving updates via long-polling");
|
||||
ReceiverOptions.AllowedUpdates = botHost.UpdateRouter.HandlersProvider.AllowedTypes.ToArray();
|
||||
ReactiveUpdateReceiver updateReceiver = new ReactiveUpdateReceiver(botClient, ReceiverOptions);
|
||||
await updateReceiver.ReceiveAsync(UpdateRouter, stoppingToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.MadiatorCore.Descriptors;
|
||||
using Telegrator.Providers;
|
||||
|
||||
namespace Telegrator.Hosting.Providers
|
||||
{
|
||||
public class HostAwaitingProvider(IOptions<TelegramBotOptions> options, ITelegramBotInfo botInfo, ILogger<HostAwaitingProvider> logger) : AwaitingProvider(options.Value, botInfo)
|
||||
{
|
||||
public override IEnumerable<DescribedHandlerInfo> GetHandlers(IUpdateRouter updateRouter, ITelegramBotClient client, Update update, CancellationToken cancellationToken = default)
|
||||
{
|
||||
IEnumerable<DescribedHandlerInfo> handlers = base.GetHandlers(updateRouter, client, update, cancellationToken).ToArray();
|
||||
logger.LogInformation("Described awaiting handlers : {handlers}", string.Join(", ", handlers.Select(hndlr => hndlr.HandlerInstance.GetType().Name)));
|
||||
return handlers;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Reflection;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.MadiatorCore.Descriptors;
|
||||
using Telegrator.Providers;
|
||||
|
||||
namespace Telegrator.Hosting.Providers
|
||||
{
|
||||
public class HostHandlersCollection(IServiceCollection hostServiceColletion, IHandlersCollectingOptions options) : HandlersCollection(options)
|
||||
{
|
||||
private readonly IServiceCollection Services = hostServiceColletion;
|
||||
public readonly List<Action<TelegramBotHostBuilder>> PreBuilderRoutines = [];
|
||||
protected override bool MustHaveParameterlessCtor => false;
|
||||
|
||||
public override IHandlersCollection AddHandler(Type handlerType)
|
||||
{
|
||||
//
|
||||
if (handlerType.GetInterface(nameof(IPreBuildingRoutine)) != null)
|
||||
{
|
||||
MethodInfo? methodInfo = handlerType.GetMethod(nameof(IPreBuildingRoutine.PreBuildingRoutine), BindingFlags.Static | BindingFlags.Public);
|
||||
if (methodInfo != null)
|
||||
{
|
||||
Action<TelegramBotHostBuilder> routineDelegate = methodInfo.CreateDelegate<Action<TelegramBotHostBuilder>>(null);
|
||||
PreBuilderRoutines.Add(routineDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
return base.AddHandler(handlerType);
|
||||
}
|
||||
|
||||
public override IHandlersCollection AddDescriptor(HandlerDescriptor descriptor)
|
||||
{
|
||||
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,48 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.Handlers.Components;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.MadiatorCore.Descriptors;
|
||||
using Telegrator.Providers;
|
||||
|
||||
namespace Telegrator.Hosting.Providers
|
||||
{
|
||||
public class HostHandlersProvider : HandlersProvider
|
||||
{
|
||||
private readonly IServiceProvider Services;
|
||||
private readonly ILogger<HostHandlersProvider> Logger;
|
||||
|
||||
public HostHandlersProvider(IHandlersCollection handlers, IOptions<TelegramBotOptions> options, ITelegramBotInfo botInfo, IServiceProvider serviceProvider, ILogger<HostHandlersProvider> logger)
|
||||
: base(handlers, options.Value, botInfo)
|
||||
{
|
||||
Services = serviceProvider;
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public override IEnumerable<DescribedHandlerInfo> GetHandlers(IUpdateRouter updateRouter, ITelegramBotClient client, Update update, CancellationToken cancellationToken = default)
|
||||
{
|
||||
IEnumerable<DescribedHandlerInfo> handlers = base.GetHandlers(updateRouter, client, update, cancellationToken).ToArray();
|
||||
Logger.LogInformation("Described handlers : {handlers}", string.Join(", ", handlers.Select(hndlr => hndlr.DisplayString ?? hndlr.HandlerInstance.GetType().Name)));
|
||||
return handlers;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
updateHandler.LifetimeToken.OnLifetimeEnded += _ => scope.Dispose();
|
||||
return updateHandler;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.Hosting.Providers;
|
||||
using Telegrator.MadiatorCore;
|
||||
using Telegrator.MadiatorCore.Descriptors;
|
||||
|
||||
namespace Telegrator.Hosting
|
||||
{
|
||||
public class TelegramBotHost : ITelegramBotHost
|
||||
{
|
||||
private readonly IHost _innerHost;
|
||||
private readonly IUpdateRouter _updateRouter;
|
||||
private readonly ILogger<TelegramBotHost> _logger;
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public IServiceProvider Services => _innerHost.Services;
|
||||
|
||||
/// <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="serviceProvider">The service provider.</param>
|
||||
internal TelegramBotHost(HostApplicationBuilder hostApplicationBuilder, HostHandlersCollection handlers)
|
||||
{
|
||||
RegisterHostServices(hostApplicationBuilder, handlers);
|
||||
_innerHost = hostApplicationBuilder.Build();
|
||||
|
||||
_updateRouter = Services.GetRequiredService<IUpdateRouter>();
|
||||
_logger = Services.GetRequiredService<ILogger<TelegramBotHost>>();
|
||||
|
||||
LogHandlers(handlers);
|
||||
}
|
||||
|
||||
public static TelegramBotHostBuilder CreateBuilder()
|
||||
{
|
||||
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(null);
|
||||
builder.Services.AddTelegramBotHostDefaults();
|
||||
builder.Services.AddTelegramReceiver();
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static TelegramBotHostBuilder CreateBuilder(TelegramBotHostBuilderSettings? settings)
|
||||
{
|
||||
TelegramBotHostBuilder builder = new TelegramBotHostBuilder(settings);
|
||||
builder.Services.AddTelegramBotHostDefaults();
|
||||
builder.Services.AddTelegramReceiver();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
private void LogHandlers(HostHandlersCollection 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.AppendLine("\n\tUpdateType." + updateType + " :");
|
||||
|
||||
foreach (HandlerDescriptor descriptor in descriptors.Reverse())
|
||||
{
|
||||
string indexerString = descriptor.Indexer.ToString();
|
||||
logBuilder.AppendLine("* " + indexerString + " " + (descriptor.DisplayString ?? descriptor.HandlerType.Name));
|
||||
}
|
||||
}
|
||||
|
||||
Logger.LogInformation(logBuilder.ToString());
|
||||
}
|
||||
|
||||
private void RegisterHostServices(HostApplicationBuilder hostApplicationBuilder, HostHandlersCollection handlers)
|
||||
{
|
||||
//hostApplicationBuilder.Services.RemoveAll<IHost>();
|
||||
//hostApplicationBuilder.Services.AddSingleton<IHost>(this);
|
||||
|
||||
hostApplicationBuilder.Services.AddSingleton<ITelegramBotHost>(this);
|
||||
hostApplicationBuilder.Services.AddSingleton<IReactiveTelegramBot>(this);
|
||||
hostApplicationBuilder.Services.AddSingleton<IHandlersCollection>(handlers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Polling;
|
||||
using Telegrator.Hosting.Configuration;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.Hosting;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.Hosting.Providers;
|
||||
using Telegrator.MadiatorCore;
|
||||
|
||||
#pragma warning disable IDE0001
|
||||
namespace Telegrator.Hosting
|
||||
{
|
||||
public class TelegramBotHostBuilder : ITelegramBotHostBuilder
|
||||
{
|
||||
private readonly HostApplicationBuilder _innerBuilder;
|
||||
private readonly TelegramBotHostBuilderSettings _settings;
|
||||
private readonly HostHandlersCollection _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>
|
||||
internal TelegramBotHostBuilder(TelegramBotHostBuilderSettings? settings = null)
|
||||
{
|
||||
_settings = settings ?? new TelegramBotHostBuilderSettings();
|
||||
_innerBuilder = new HostApplicationBuilder(settings?.ToApplicationBuilderSettings());
|
||||
_handlers = new HostHandlersCollection(Services, _settings);
|
||||
|
||||
Services.Configure<TelegramBotOptions>(Configuration.GetSection(nameof(TelegramBotOptions)));
|
||||
Services.Configure<ReceiverOptions>(Configuration.GetSection(nameof(ReceiverOptions)));
|
||||
Services.Configure<TelegramBotClientOptions>(Configuration.GetSection(nameof(TelegramBotClientOptions)), new TelegramBotClientOptionsProxy());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the host.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public TelegramBotHost Build()
|
||||
{
|
||||
foreach (var preBuildRoutine in _handlers.PreBuilderRoutines)
|
||||
{
|
||||
try
|
||||
{
|
||||
preBuildRoutine.Invoke(this);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
_ = 0xBAD + 0xC0DE;
|
||||
}
|
||||
}
|
||||
|
||||
return new TelegramBotHost(_innerBuilder, _handlers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Telegrator.Configuration;
|
||||
|
||||
namespace Telegrator.Hosting
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class TelegramBotHostBuilderSettings() : IHandlersCollectingOptions
|
||||
{
|
||||
/// <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; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool DescendDescriptorIndex { get; set; } = true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool ExceptIntersectingCommandAliases { get; set; } = true;
|
||||
|
||||
internal HostApplicationBuilderSettings ToApplicationBuilderSettings() => new HostApplicationBuilderSettings()
|
||||
{
|
||||
DisableDefaults = DisableDefaults,
|
||||
Args = Args,
|
||||
Configuration = Configuration,
|
||||
EnvironmentName = EnvironmentName,
|
||||
ApplicationName = ApplicationName,
|
||||
ContentRootPath = ContentRootPath
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Telegrator\Telegrator.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,58 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
using Telegrator;
|
||||
using Telegrator.Configuration;
|
||||
using Telegrator.Hosting.Components;
|
||||
using Telegrator.Hosting.Configuration;
|
||||
using Telegrator.Hosting.Polling;
|
||||
using Telegrator.Hosting.Providers;
|
||||
using Telegrator.MadiatorCore;
|
||||
|
||||
namespace Telegrator.Hosting
|
||||
{
|
||||
public static class ServicesCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection Configure<TOptions>(this IServiceCollection services, IConfiguration configuration, ConfigureOptionsProxy<TOptions> optionsProxy) where TOptions : class
|
||||
{
|
||||
optionsProxy.Configure(services, configuration);
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddTelegramBotHostDefaults(this IServiceCollection services)
|
||||
{
|
||||
services.AddLogging(builder => builder.AddConsole());
|
||||
services.AddSingleton<IUpdateHandlersPool, HostUpdateHandlersPool>();
|
||||
services.AddSingleton<IAwaitingProvider, HostAwaitingProvider>();
|
||||
services.AddSingleton<IHandlersProvider, HostHandlersProvider>();
|
||||
services.AddSingleton<IUpdateRouter, HostUpdateRouter>();
|
||||
services.AddSingleton<ITelegramBotInfo, TelegramBotInfo>(services => new TelegramBotInfo(services.GetRequiredService<ITelegramBotClient>().GetMe().Result));
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
public static IServiceCollection AddTelegramReceiver(this IServiceCollection services)
|
||||
{
|
||||
services.AddHttpClient<ITelegramBotClient>("tgreceiver").RemoveAllLoggers().AddTypedClient(TypedTelegramBotClientFactory);
|
||||
services.AddHostedService<HostedUpdateReceiver>();
|
||||
return services;
|
||||
}
|
||||
|
||||
private static ITelegramBotClient TypedTelegramBotClientFactory(HttpClient httpClient, IServiceProvider provider)
|
||||
=> new TelegramBotClient(provider.GetRequiredService<IOptions<TelegramBotClientOptions>>().Value, httpClient);
|
||||
}
|
||||
|
||||
public static class TelegramBotHostExtensions
|
||||
{
|
||||
public static ITelegramBotHost SetBotCommands(this ITelegramBotHost botHost)
|
||||
{
|
||||
ITelegramBotClient client = botHost.Services.GetRequiredService<ITelegramBotClient>();
|
||||
IEnumerable<BotCommand> aliases = botHost.UpdateRouter.HandlersProvider.GetBotCommands();
|
||||
client.SetMyCommands(aliases).Wait();
|
||||
return botHost;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user