This commit is contained in:
25
BotPages.Core/Abstractions/Capabilities.cs
Normal file
25
BotPages.Core/Abstractions/Capabilities.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Возможности мессенджера (inline кнопки, альбомы, форматирование и т.д.).
|
||||
/// </summary>
|
||||
public sealed class Capabilities
|
||||
{
|
||||
/// <summary>Поддержка inline-кнопок.</summary>
|
||||
public bool SupportsInlineButtons { get; init; }
|
||||
|
||||
/// <summary>Поддержка reply-кнопок.</summary>
|
||||
public bool SupportsReplyButtons { get; init; }
|
||||
|
||||
/// <summary>Поддержка альбомов (медиагрупп).</summary>
|
||||
public bool SupportsAlbums { get; init; }
|
||||
|
||||
/// <summary>Поддержка форматирования Markdown.</summary>
|
||||
public bool SupportsFormattingMarkdown { get; init; }
|
||||
|
||||
/// <summary>Поддержка форматирования HTML.</summary>
|
||||
public bool SupportsFormattingHtml { get; init; }
|
||||
|
||||
/// <summary>Максимальная длина сообщения.</summary>
|
||||
public int MaxMessageLength { get; init; } = 4096;
|
||||
}
|
||||
6
BotPages.Core/Abstractions/CompositeSessionKey.cs
Normal file
6
BotPages.Core/Abstractions/CompositeSessionKey.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Ключ для идентификации пользовательской сессии.
|
||||
/// </summary>
|
||||
public readonly record struct CompositeSessionKey(string MessengerType, string ChatId, string? UserId);
|
||||
22
BotPages.Core/Abstractions/FileDescriptor.cs
Normal file
22
BotPages.Core/Abstractions/FileDescriptor.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Описание файла, полученного или отправляемого через мессенджер.
|
||||
/// </summary>
|
||||
public sealed class FileDescriptor
|
||||
{
|
||||
/// <summary>Идентификатор файла в мессенджере.</summary>
|
||||
public required string Id { get; init; }
|
||||
/// <summary>Имя файла.</summary>
|
||||
public required string Name { get; init; }
|
||||
/// <summary>Расширение файла.</summary>
|
||||
public required string Extension { get; init; }
|
||||
/// <summary>Размер файла в байтах.</summary>
|
||||
public long Size { get; init; }
|
||||
/// <summary>MIME-тип файла.</summary>
|
||||
public string? Mime { get; init; }
|
||||
/// <summary>Тип файла.</summary>
|
||||
public FileKind Kind { get; init; } = FileKind.Document;
|
||||
/// <summary>Функция получения потока файла.</summary>
|
||||
public Func<CancellationToken, Task<Stream>> GetStreamAsync { get; init; } = _ => Task.FromResult<Stream>(Stream.Null);
|
||||
}
|
||||
20
BotPages.Core/Abstractions/FileKind.cs
Normal file
20
BotPages.Core/Abstractions/FileKind.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Тип файла.
|
||||
/// </summary>
|
||||
public enum FileKind
|
||||
{
|
||||
/// <summary> Фото </summary>
|
||||
Photo,
|
||||
/// <summary> Документ </summary>
|
||||
Document,
|
||||
/// <summary> Аудио </summary>
|
||||
Audio,
|
||||
/// <summary> Видео </summary>
|
||||
Video,
|
||||
/// <summary> Стикер </summary>
|
||||
Sticker,
|
||||
/// <summary> Остальное </summary>
|
||||
Other,
|
||||
}
|
||||
12
BotPages.Core/Abstractions/IAlbumBuilder.cs
Normal file
12
BotPages.Core/Abstractions/IAlbumBuilder.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Билдер отправки медиагруппы (альбома).
|
||||
/// </summary>
|
||||
public interface IAlbumBuilder
|
||||
{
|
||||
/// <summary>Добавить элемент в альбом.</summary>
|
||||
IAlbumBuilder Add(FileDescriptor file, string? caption = null);
|
||||
/// <summary>Отправить альбом.</summary>
|
||||
Task SendAsync(CancellationToken ct = default);
|
||||
}
|
||||
42
BotPages.Core/Abstractions/IMessengerAdapter.cs
Normal file
42
BotPages.Core/Abstractions/IMessengerAdapter.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using BotPages.Core.Messaging;
|
||||
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Контракт адаптера мессенджера.
|
||||
/// Определяет операции отправки сообщений, файлов и прогресса.
|
||||
/// </summary>
|
||||
public interface IMessengerAdapter
|
||||
{
|
||||
/// <summary>
|
||||
/// Отправить текстовое сообщение в чат.
|
||||
/// </summary>
|
||||
Task SendTextAsync(PageContext ctx, string text, MessageFormat format,
|
||||
IEnumerable<IEnumerable<InlineButton>>? inline,
|
||||
IEnumerable<IEnumerable<ReplyButton>>? reply, CancellationToken ct);
|
||||
|
||||
/// <summary>
|
||||
/// Отправить файл в чат.
|
||||
/// </summary>
|
||||
Task SendFileAsync(PageContext ctx, FileDescriptor file, string? caption, CancellationToken ct);
|
||||
|
||||
/// <summary>
|
||||
/// Создать билдер альбома для отправки медиагруппы.
|
||||
/// </summary>
|
||||
IAlbumBuilder CreateAlbumBuilder(PageContext ctx);
|
||||
|
||||
/// <summary>
|
||||
/// Начать отображение прогресса операции.
|
||||
/// </summary>
|
||||
Task<string?> StartProgressAsync(PageContext ctx, string title, CancellationToken ct);
|
||||
|
||||
/// <summary>
|
||||
/// Обновить прогресс операции.
|
||||
/// </summary>
|
||||
Task UpdateProgressAsync(PageContext ctx, string messageId, string title, int percent, CancellationToken ct);
|
||||
|
||||
/// <summary>
|
||||
/// Вызывается при выходе со страницы.
|
||||
/// </summary>
|
||||
Task OnLeaveAsync(PageContext ctx, CancellationToken ct);
|
||||
}
|
||||
25
BotPages.Core/Abstractions/IMessengerAdapterFactory.cs
Normal file
25
BotPages.Core/Abstractions/IMessengerAdapterFactory.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using BotPages.Core.Context;
|
||||
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Фабрика адаптеров мессенджеров.
|
||||
/// Используется для разрешения конкретного <see cref="IMessengerAdapter"/> по типу мессенджера.
|
||||
/// </summary>
|
||||
public interface IMessengerAdapterFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Получить адаптер для указанного мессенджера.
|
||||
/// </summary>
|
||||
/// <param name="messengerType">
|
||||
/// Тип мессенджера (например, "Telegram", "Slack", "VK").
|
||||
/// Значение должно совпадать с <see cref="UpdateContext.User"/>.<see cref="UserContext.MessengerType"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IMessengerAdapter"/>, зарегистрированный для данного типа мессенджера.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается, если адаптер для указанного типа не зарегистрирован.
|
||||
/// </exception>
|
||||
IMessengerAdapter Resolve(string messengerType);
|
||||
}
|
||||
11
BotPages.Core/Abstractions/IPageMiddleware.cs
Normal file
11
BotPages.Core/Abstractions/IPageMiddleware.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
/// <summary>
|
||||
/// Интерфейс middleware для обработки входящих обновлений.
|
||||
/// </summary>
|
||||
public interface IPageMiddleware
|
||||
{
|
||||
/// <summary>
|
||||
/// Выполнить промежуточную логику, затем вызвать следующий обработчик.
|
||||
/// </summary>
|
||||
Task InvokeAsync(PageContext ctx, Func<Task> next, CancellationToken ct);
|
||||
}
|
||||
20
BotPages.Core/Abstractions/IStateStorage.cs
Normal file
20
BotPages.Core/Abstractions/IStateStorage.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Интерфейс универсального хранилища состояния.
|
||||
/// Позволяет сохранять и восстанавливать данные между обновлениями.
|
||||
/// </summary>
|
||||
public interface IStateStorage
|
||||
{
|
||||
/// <summary>Получить состояние по ключу.</summary>
|
||||
Task<T?> GetAsync<T>(CompositeSessionKey session, string key, CancellationToken ct);
|
||||
|
||||
/// <summary>Сохранить состояние по ключу.</summary>
|
||||
Task SetAsync<T>(CompositeSessionKey session, string key, T state, CancellationToken ct);
|
||||
|
||||
/// <summary>Удалить состояние по ключу.</summary>
|
||||
Task<bool> RemoveAsync(CompositeSessionKey session, string key, CancellationToken ct);
|
||||
|
||||
/// <summary>Удалить все состояния по ключу.</summary>
|
||||
Task<bool> ClearAsync(CompositeSessionKey session, CancellationToken ct);
|
||||
}
|
||||
14
BotPages.Core/Abstractions/MessageFormat.cs
Normal file
14
BotPages.Core/Abstractions/MessageFormat.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
/// <summary>
|
||||
/// Форматирование текста сообщения.
|
||||
/// </summary>
|
||||
public enum MessageFormat
|
||||
{
|
||||
/// <summary>Обычный текст без форматирования.</summary>
|
||||
Plain,
|
||||
/// <summary>Markdown форматирование.</summary>
|
||||
Markdown,
|
||||
/// <summary>HTML форматирование.</summary>
|
||||
Html
|
||||
}
|
||||
45
BotPages.Core/Abstractions/MultiAdapterFactory.cs
Normal file
45
BotPages.Core/Abstractions/MultiAdapterFactory.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
namespace BotPages.Core.Abstractions;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Реализация <see cref="IMessengerAdapterFactory"/>, позволяющая регистрировать и разрешать несколько адаптеров мессенджеров.
|
||||
/// </summary>
|
||||
public sealed class MultiAdapterFactory : IMessengerAdapterFactory
|
||||
{
|
||||
private readonly Dictionary<string, IMessengerAdapter> _adapters = new(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
/// <summary>
|
||||
/// Зарегистрировать адаптер для указанного типа мессенджера.
|
||||
/// </summary>
|
||||
/// <param name="messengerType">
|
||||
/// Тип мессенджера (например, "Telegram", "Slack", "VK").
|
||||
/// </param>
|
||||
/// <param name="adapter">
|
||||
/// Экземпляр адаптера, реализующий <see cref="IMessengerAdapter"/>.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Текущий экземпляр <see cref="MultiAdapterFactory"/> для цепочки вызовов.
|
||||
/// </returns>
|
||||
public MultiAdapterFactory Register(string messengerType, IMessengerAdapter adapter)
|
||||
{
|
||||
_adapters[messengerType] = adapter;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получить адаптер для указанного мессенджера.
|
||||
/// </summary>
|
||||
/// <param name="messengerType">
|
||||
/// Тип мессенджера (например, "Telegram", "Slack", "VK").
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Экземпляр <see cref="IMessengerAdapter"/>, зарегистрированный для данного типа мессенджера.
|
||||
/// </returns>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Выбрасывается, если адаптер для указанного типа не зарегистрирован.
|
||||
/// </exception>
|
||||
public IMessengerAdapter Resolve(string messengerType)
|
||||
=> _adapters.TryGetValue(messengerType, out var adapter)
|
||||
? adapter
|
||||
: throw new InvalidOperationException($"No adapter registered for {messengerType}");
|
||||
}
|
||||
Reference in New Issue
Block a user