diff --git a/BotPages.Core/Abstractions/CompositeSessionKey.cs b/BotPages.Core/Abstractions/CompositeSessionKey.cs
index 9809b31..69c4ca6 100644
--- a/BotPages.Core/Abstractions/CompositeSessionKey.cs
+++ b/BotPages.Core/Abstractions/CompositeSessionKey.cs
@@ -13,7 +13,7 @@ public readonly record struct CompositeSessionKey(string AdapterId, string ChatI
public static CompositeSessionKey FromUpdate(UpdateContext update)
{
return new CompositeSessionKey(
- update.AdapterId,
+ update.Adapter.Id,
update.Chat.Id,
update.User.Id);
}
diff --git a/BotPages.Core/Abstractions/IMessengerAdapter.cs b/BotPages.Core/Abstractions/IMessengerAdapter.cs
index e92f31b..3b46212 100644
--- a/BotPages.Core/Abstractions/IMessengerAdapter.cs
+++ b/BotPages.Core/Abstractions/IMessengerAdapter.cs
@@ -9,6 +9,16 @@ namespace BotPages.Core.Abstractions;
///
public interface IMessengerAdapter
{
+ ///
+ /// Уникальный идентификатор адаптера.
+ ///
+ string Id { get; }
+
+ ///
+ /// Тип адаптера (Telegram, VK, WhatsApp и т.д.).
+ ///
+ string Type { get; }
+
///
/// Доступные возможности мессенджера.
///
@@ -87,10 +97,16 @@ public interface IMessengerAdapter
///
public interface IMessengerAdapterSetup : IMessengerAdapter
{
+ ///
+ /// Внутренний метод для установки ID адаптера.
+ ///
+ void SetAdapterId(string adapterId);
+
///
/// Запуск работы адаптера
///
///
+ ///
///
///
Task StartAdapterAsync(Func onUpdate, List commands, CancellationToken ct);
diff --git a/BotPages.Core/Abstractions/MessengerAdapterBase.cs b/BotPages.Core/Abstractions/MessengerAdapterBase.cs
deleted file mode 100644
index 2240527..0000000
--- a/BotPages.Core/Abstractions/MessengerAdapterBase.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using BotPages.Core.Context;
-using BotPages.Core.Messaging;
-
-namespace BotPages.Core.Abstractions;
-
-///
-/// Базовый класс для адаптеров мессенджеров.
-///
-public abstract class MessengerAdapterBase : IMessengerAdapterSetup
-{
- ///
- /// Уникальный идентификатор адаптера.
- ///
- public string AdapterId { get; internal set; } = string.Empty;
-
- ///
- /// Тип адаптера (Telegram, VK, WhatsApp и т.д.).
- ///
- public abstract string AdapterType { get; }
-
- ///
- /// Название адаптера для отображения.
- ///
- public string DisplayName { get; set; } = string.Empty;
-
- ///
- /// Доступные возможности мессенджера.
- ///
- public abstract Capabilities Capabilities { get; }
-
- ///
- /// Универсальный метод отправки с использованием общего описания запроса.
- ///
- public abstract Task SendAsync(SendRequest request, CancellationToken ct = default);
-
- ///
- /// Универсальный метод удаления сообщения.
- ///
- public abstract Task DeleteAsync(string chatId, string messageId, CancellationToken ct = default);
-
- ///
- /// Удалить несколько сообщений за раз.
- ///
- public abstract Task DeleteMultipleAsync(string chatId, IEnumerable messageIds, CancellationToken ct = default);
-
- ///
- /// Редактировать только текст сообщения.
- ///
- public abstract Task EditTextAsync(string chatId, string messageId, string text,
- MessageFormat? format = null, CancellationToken ct = default);
-
- ///
- /// Редактировать только клавиатуру сообщения.
- ///
- public abstract Task EditButtonsAsync(string chatId, string messageId,
- IEnumerable>? inlineButtons = null,
- CancellationToken ct = default);
-
- ///
- /// Закрепить сообщение в чате.
- ///
- public abstract Task PinMessageAsync(string chatId, string messageId, bool disableNotification = false,
- CancellationToken ct = default);
-
- ///
- /// Открепить сообщение в чате.
- ///
- public abstract Task UnpinMessageAsync(string chatId, string messageId, CancellationToken ct = default);
-
- ///
- /// Получить информацию о сообщении.
- ///
- public abstract Task GetMessageInfoAsync(string chatId, string messageId, CancellationToken ct = default);
-
- ///
- /// Переслать сообщение.
- ///
- public abstract Task ForwardMessageAsync(string fromChatId, string messageId, string toChatId,
- bool disableNotification = false, CancellationToken ct = default);
-
- ///
- /// Копировать сообщение с возможностью редактирования.
- ///
- public abstract Task CopyMessageAsync(string fromChatId, string messageId, string toChatId,
- string? caption = null, MessageFormat? captionFormat = null,
- bool disableNotification = false, CancellationToken ct = default);
-
- ///
- /// Создать билдер альбома для отправки медиагруппы.
- ///
- public abstract IAlbumBuilder CreateAlbumBuilder(PageContext ctx);
-
- ///
- /// Вызывается при выходе со страницы.
- ///
- public abstract Task OnLeaveAsync(PageContext ctx, CancellationToken ct);
-
- ///
- /// Запуск работы адаптера.
- ///
- public abstract Task StartAdapterAsync(Func onUpdate, List commands, CancellationToken ct);
-}
\ No newline at end of file
diff --git a/BotPages.Core/Abstractions/MultiAdapterFactory.cs b/BotPages.Core/Abstractions/MultiAdapterFactory.cs
index ec3ac10..cd4cfca 100644
--- a/BotPages.Core/Abstractions/MultiAdapterFactory.cs
+++ b/BotPages.Core/Abstractions/MultiAdapterFactory.cs
@@ -26,16 +26,13 @@ public sealed class MultiAdapterFactory : IMessengerAdapterFactory
throw new ArgumentException($"Adapter with ID '{adapterId}' is already registered", nameof(adapterId));
// Устанавливаем идентификатор в адаптер
- if (adapter is MessengerAdapterBase adapterBase)
- {
- adapterBase.AdapterId = adapterId;
- }
+ adapter.SetAdapterId(adapterId);
_allAdapters.Add(adapter);
_adaptersById[adapterId] = adapter;
// Группируем по типу
- var adapterType = GetAdapterType(adapter);
+ var adapterType = adapter.Type;
if (!_adaptersByType.TryGetValue(adapterType, out var typeList))
{
typeList = new List();
@@ -106,7 +103,7 @@ public sealed class MultiAdapterFactory : IMessengerAdapterFactory
_allAdapters.Remove(adapter);
_adaptersById.Remove(adapterId);
- var adapterType = GetAdapterType(adapter);
+ var adapterType = adapter.Type;
if (_adaptersByType.TryGetValue(adapterType, out var typeList))
{
typeList.Remove(adapter);
@@ -122,20 +119,9 @@ public sealed class MultiAdapterFactory : IMessengerAdapterFactory
return false;
}
- private static string GetAdapterType(IMessengerAdapter adapter)
- {
- if (adapter is MessengerAdapterBase adapterBase)
- {
- return adapterBase.AdapterType;
- }
-
- // Для обратной совместимости
- return adapter.GetType().Name.Replace("Adapter", "");
- }
-
private static string GenerateAdapterId(IMessengerAdapter adapter)
{
- var adapterType = GetAdapterType(adapter);
+ var adapterType = adapter.Type;
var guid = Guid.NewGuid().ToString("N").Substring(0, 8);
return $"{adapterType}_{guid}".ToLowerInvariant();
}
diff --git a/BotPages.Core/BotPagesApp.cs b/BotPages.Core/BotPagesApp.cs
index 069bf3b..ce3bcc9 100644
--- a/BotPages.Core/BotPagesApp.cs
+++ b/BotPages.Core/BotPagesApp.cs
@@ -215,7 +215,7 @@ public sealed class BotPagesApp
SessionKey = sessionKey,
StateStorage = _state,
Navigation = _navigation,
- Adapter = _adapterFactory.Resolve(update.AdapterId),
+ Adapter = _adapterFactory.Resolve(update.Adapter.Id),
AdapterFactory = _adapterFactory,
};
diff --git a/BotPages.Core/Context/PageContext.cs b/BotPages.Core/Context/PageContext.cs
index f00ad13..0ccf417 100644
--- a/BotPages.Core/Context/PageContext.cs
+++ b/BotPages.Core/Context/PageContext.cs
@@ -52,12 +52,12 @@ public sealed class PageContext
///
/// Получить текущий тип адаптера.
///
- public string CurrentAdapterType => Update.AdapterType;
+ public string CurrentAdapterType => Update.Adapter.Type;
///
/// Получить текущий ID адаптера.
///
- public string CurrentAdapterId => Update.AdapterId;
+ public string CurrentAdapterId => Update.Adapter.Id;
///
/// Получить все адаптеры.
diff --git a/BotPages.Core/Context/UpdateContext.cs b/BotPages.Core/Context/UpdateContext.cs
index a8f9014..8da32bf 100644
--- a/BotPages.Core/Context/UpdateContext.cs
+++ b/BotPages.Core/Context/UpdateContext.cs
@@ -8,11 +8,8 @@ namespace BotPages.Core.Context;
///
public sealed class UpdateContext
{
- /// Идентификатор адаптера, от которого пришло обновление.
- public required string AdapterId { get; init; }
-
- /// Тип адаптера (определяется адаптером).
- public required string AdapterType { get; init; }
+ /// Адаптер, от которого пришло обновление.
+ public required IMessengerAdapter Adapter { get; init; }
///
/// Данные пользователя, от которого пришло обновление.
diff --git a/BotPages.Core/Middleware/LoggingMiddleware.cs b/BotPages.Core/Middleware/LoggingMiddleware.cs
index a01cb03..0722cf8 100644
--- a/BotPages.Core/Middleware/LoggingMiddleware.cs
+++ b/BotPages.Core/Middleware/LoggingMiddleware.cs
@@ -17,7 +17,7 @@ public sealed class LoggingMiddleware : IPageMiddleware
public async Task InvokeAsync(PageContext ctx, Func next, CancellationToken ct)
{
// Логируем базовую информацию
- _logger.Log(LogLevel.Info, $"Update from {ctx.Update.AdapterId} | Chat: {ctx.Update.Chat.Id} | User: {ctx.Update.User.Id}");
+ _logger.Log(LogLevel.Info, $"Update from {ctx.Update.Adapter.Id} | Chat: {ctx.Update.Chat.Id} | User: {ctx.Update.User.Id}");
// Логируем текст, кнопки, файлы
if (ctx.Update.Text is not null)
diff --git a/BotPages.Telegram/TelegramAdapter.cs b/BotPages.Telegram/TelegramAdapter.cs
index ea5ece3..833d7fa 100644
--- a/BotPages.Telegram/TelegramAdapter.cs
+++ b/BotPages.Telegram/TelegramAdapter.cs
@@ -20,7 +20,7 @@ namespace BotPages.Telegram;
/// Адаптер для Telegram на базе Telegram.Bot.
/// Реализует отправку текста, кнопок, файлов, альбомов и прогресса.
///
-public sealed class TelegramAdapter : MessengerAdapterBase
+public sealed class TelegramAdapter : IMessengerAdapterSetup
{
private readonly ILogger _logger;
private TelegramBotClient? _client;
@@ -43,27 +43,33 @@ public sealed class TelegramAdapter : MessengerAdapterBase
_token = token;
_options = options ?? new TelegramOptions();
- // Устанавливаем имя для отображения
- DisplayName = $"Telegram Bot";
+ Id = Guid.NewGuid().ToString();
+ DisplayName = $"Telegram {Id}";
}
- /// Тип адаптера.
- public override string AdapterType => "Telegram";
+ ///
+ public string Type => "Telegram";
+
+ ///
+ public string Id { get; set; }
///
- /// Идентификатор мессенджера / адаптера
+ /// Получение отображаемого имени бота (например, "Telegram: @mybot"). Доступно после запуска адаптера.
///
- public string MessengerType => "Telegram";
+ public string DisplayName { get; private set; }
+
+ ///
+ public void SetAdapterId(string adapterId) => Id = adapterId;
///
/// Доступные возможности адаптера.
///
- public override Capabilities Capabilities => _capabilities;
+ public Capabilities Capabilities => _capabilities;
///
/// Запустить polling для приема обновлений от Telegram.
///
- public override async Task StartAdapterAsync(Func onUpdate, List commands, CancellationToken ct)
+ public async Task StartAdapterAsync(Func onUpdate, List commands, CancellationToken ct)
{
_client = new TelegramBotClient(_token);
@@ -81,7 +87,7 @@ public sealed class TelegramAdapter : MessengerAdapterBase
errorHandler: async (_, ex, ct2) =>
{
- _logger.Log(LogLevel.Warn, $"{AdapterType} ({AdapterId}) error.", ex);
+ _logger.Log(LogLevel.Warn, $"{Type} ({Id}) error.", ex);
await Task.CompletedTask;
},
@@ -92,7 +98,7 @@ public sealed class TelegramAdapter : MessengerAdapterBase
var me = await _client.GetMe();
DisplayName = $"Telegram: @{me.Username}";
- _logger.Log(LogLevel.Info, $"{AdapterType} ({AdapterId}) started: {DisplayName}");
+ _logger.Log(LogLevel.Info, $"{Type} ({Id}) started: {DisplayName}");
return;
}
@@ -101,17 +107,17 @@ public sealed class TelegramAdapter : MessengerAdapterBase
/// Универсальный внутренний метод отправки — определяет, нужно ли отправлять текст или файл по параметрам.
/// Возвращает id сообщения (или null).
///
- public override async Task SendAsync(SendRequest req, CancellationToken ct)
+ public async Task SendAsync(SendRequest req, CancellationToken ct)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return null;
}
// Определите параметры адаптера (TelegramOptions) из папки или используйте параметры адаптера по умолчанию.
TelegramOptions telegramOptions = _options;
- if (req.AdapterOptions is AdapterOptionsBag bag && bag.TryGet(AdapterType, out TelegramOptions? opt) && opt is not null)
+ if (req.AdapterOptions is AdapterOptionsBag bag && bag.TryGet(Type, out TelegramOptions? opt) && opt is not null)
{
telegramOptions = opt;
}
@@ -150,11 +156,11 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override Task DeleteAsync(string chatId, string messageId, CancellationToken ct = default)
+ public Task DeleteAsync(string chatId, string messageId, CancellationToken ct = default)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return Task.CompletedTask;
}
@@ -162,11 +168,11 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override async Task DeleteMultipleAsync(string chatId, IEnumerable messageIds, CancellationToken ct = default)
+ public async Task DeleteMultipleAsync(string chatId, IEnumerable messageIds, CancellationToken ct = default)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return false;
}
@@ -187,12 +193,12 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override async Task EditTextAsync(string chatId, string messageId, string text,
+ public async Task EditTextAsync(string chatId, string messageId, string text,
MessageFormat? format = null, CancellationToken ct = default)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return null;
}
@@ -216,12 +222,12 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override async Task EditButtonsAsync(string chatId, string messageId,
+ public async Task EditButtonsAsync(string chatId, string messageId,
IEnumerable>? inlineButtons = null, CancellationToken ct = default)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return null;
}
@@ -244,12 +250,12 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override async Task PinMessageAsync(string chatId, string messageId, bool disableNotification = false,
+ public async Task PinMessageAsync(string chatId, string messageId, bool disableNotification = false,
CancellationToken ct = default)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return false;
}
@@ -271,11 +277,11 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override async Task UnpinMessageAsync(string chatId, string messageId, CancellationToken ct = default)
+ public async Task UnpinMessageAsync(string chatId, string messageId, CancellationToken ct = default)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return false;
}
@@ -296,18 +302,18 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override async Task GetMessageInfoAsync(string chatId, string messageId, CancellationToken ct = default)
+ public async Task GetMessageInfoAsync(string chatId, string messageId, CancellationToken ct = default)
{
throw new NotImplementedException();
}
///
- public override async Task ForwardMessageAsync(string fromChatId, string messageId, string toChatId,
+ public async Task ForwardMessageAsync(string fromChatId, string messageId, string toChatId,
bool disableNotification = false, CancellationToken ct = default)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return null;
}
@@ -331,13 +337,13 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override async Task CopyMessageAsync(string fromChatId, string messageId, string toChatId,
+ public async Task CopyMessageAsync(string fromChatId, string messageId, string toChatId,
string? caption = null, MessageFormat? captionFormat = null,
bool disableNotification = false, CancellationToken ct = default)
{
if (_client is null)
{
- _logger.Log(LogLevel.Critical, $"{MessengerType} client is not initialized.");
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
return null;
}
@@ -427,6 +433,12 @@ public sealed class TelegramAdapter : MessengerAdapterBase
bool disableNotification, string? caption, MessageFormat? captionFormat, int? replyToMessageId,
bool protectContent, CancellationToken ct)
{
+ if (_client is null)
+ {
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
+ return null;
+ }
+
var inputFile = await CreateInputFileAsync(file, ct);
var parseMode = GetParseMode(captionFormat);
@@ -482,6 +494,12 @@ public sealed class TelegramAdapter : MessengerAdapterBase
ReplyMarkup? markup, bool disableNotification, int? replyToMessageId,
bool disableWebPagePreview, bool protectContent, CancellationToken ct)
{
+ if (_client is null)
+ {
+ _logger.Log(LogLevel.Critical, $"{Type} client is not initialized.");
+ return null;
+ }
+
var format = req.TextFormat ?? MessageFormat.Plain;
var parseMode = GetParseMode(format);
@@ -533,8 +551,8 @@ public sealed class TelegramAdapter : MessengerAdapterBase
}
///
- public override IAlbumBuilder CreateAlbumBuilder(PageContext ctx) => new TelegramAlbumBuilder(this, ctx, _logger, _client);
+ public IAlbumBuilder CreateAlbumBuilder(PageContext ctx) => new TelegramAlbumBuilder(this, ctx, _logger, _client);
///
- public override Task OnLeaveAsync(PageContext ctx, CancellationToken ct) => Task.CompletedTask;
+ public Task OnLeaveAsync(PageContext ctx, CancellationToken ct) => Task.CompletedTask;
}
\ No newline at end of file
diff --git a/BotPages.Telegram/TelegramUpdateMapper.cs b/BotPages.Telegram/TelegramUpdateMapper.cs
index c17ae65..49bb787 100644
--- a/BotPages.Telegram/TelegramUpdateMapper.cs
+++ b/BotPages.Telegram/TelegramUpdateMapper.cs
@@ -182,8 +182,7 @@ public static class TelegramUpdateMapper
return new UpdateContext
{
- AdapterId = adapter.AdapterId,
- AdapterType = adapter.AdapterType,
+ Adapter = adapter,
User = userContext,
Chat = chatContext,
Text = text,