Убраны старые api
This commit is contained in:
@@ -14,66 +14,4 @@ public static class PageContextAdapterExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static Task<string?> SendAsync(this PageContext ctx, SendRequest request, CancellationToken ct = default)
|
public static Task<string?> SendAsync(this PageContext ctx, SendRequest request, CancellationToken ct = default)
|
||||||
=> ctx.Adapter.SendAsync(request, ct);
|
=> ctx.Adapter.SendAsync(request, ct);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Удобная оболочка: отправить текстовое сообщение.
|
|
||||||
/// </summary>
|
|
||||||
public static Task<string?> SendTextAsync(this PageContext ctx,
|
|
||||||
string text,
|
|
||||||
MessageFormat format = MessageFormat.Plain,
|
|
||||||
IEnumerable<IEnumerable<InlineButton>>? inline = null,
|
|
||||||
IEnumerable<IEnumerable<ReplyButton>>? reply = null,
|
|
||||||
string? messageId = null,
|
|
||||||
object? adapterOptions = null,
|
|
||||||
CancellationToken ct = default)
|
|
||||||
{
|
|
||||||
var bag = adapterOptions switch
|
|
||||||
{
|
|
||||||
null => null,
|
|
||||||
AdapterOptionsBag b => b,
|
|
||||||
_ => throw new ArgumentException("adapterOptions must be an AdapterOptionsBag or null. Use MessageBuilder extensions to set adapter options.", nameof(adapterOptions))
|
|
||||||
};
|
|
||||||
|
|
||||||
return ctx.SendAsync(new SendRequest
|
|
||||||
{
|
|
||||||
ChatId = ctx.Update.Chat.Id,
|
|
||||||
Text = text,
|
|
||||||
TextFormat = format,
|
|
||||||
Inline = inline,
|
|
||||||
Reply = reply,
|
|
||||||
MessageId = messageId,
|
|
||||||
AdapterOptions = bag
|
|
||||||
}, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Удобная оболочка: отправить файл.
|
|
||||||
/// </summary>
|
|
||||||
public static Task<string?> SendFileAsync(this PageContext ctx,
|
|
||||||
FileDescriptor file,
|
|
||||||
string? caption = null,
|
|
||||||
MessageFormat? captionFormat = null,
|
|
||||||
IEnumerable<IEnumerable<InlineButton>>? inline = null,
|
|
||||||
IEnumerable<IEnumerable<ReplyButton>>? reply = null,
|
|
||||||
object? adapterOptions = null,
|
|
||||||
CancellationToken ct = default)
|
|
||||||
{
|
|
||||||
var bag = adapterOptions switch
|
|
||||||
{
|
|
||||||
null => null,
|
|
||||||
AdapterOptionsBag b => b,
|
|
||||||
_ => throw new ArgumentException("adapterOptions must be an AdapterOptionsBag or null. Use MessageBuilder extensions to set adapter options.", nameof(adapterOptions))
|
|
||||||
};
|
|
||||||
|
|
||||||
return ctx.SendAsync(new SendRequest
|
|
||||||
{
|
|
||||||
ChatId = ctx.Update.Chat.Id,
|
|
||||||
File = file,
|
|
||||||
Caption = caption,
|
|
||||||
CaptionFormat = captionFormat,
|
|
||||||
Inline = inline,
|
|
||||||
Reply = reply,
|
|
||||||
AdapterOptions = bag
|
|
||||||
}, ct);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -25,10 +25,10 @@ public sealed class MessageBuilder
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Установить опции для конкретного адаптера. Ключ адаптера определяется адаптером (напр., "telegram").
|
/// Установить опции для конкретного адаптера. Ключ адаптера определяется адаптером (напр., "telegram").
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MessageBuilder WithAdapterOption<T>(string adapterKey, T options)
|
public MessageBuilder WithAdapterOption<T>(string adapterType, T options)
|
||||||
{
|
{
|
||||||
if (_adapterOptions is null) _adapterOptions = new AdapterOptionsBag();
|
if (_adapterOptions is null) _adapterOptions = new AdapterOptionsBag();
|
||||||
_adapterOptions.Set(adapterKey, options);
|
_adapterOptions.Set(adapterType, options);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,13 +141,35 @@ public sealed class MessageBuilder
|
|||||||
// Текст
|
// Текст
|
||||||
if (!string.IsNullOrWhiteSpace(_text))
|
if (!string.IsNullOrWhiteSpace(_text))
|
||||||
{
|
{
|
||||||
messageId = await _ctx.SendTextAsync(_text, _format, _inline, reply, _editMessageId, _adapterOptions, ct);
|
var req = new SendRequest
|
||||||
|
{
|
||||||
|
ChatId = _ctx.Update.Chat.Id,
|
||||||
|
Text = _text,
|
||||||
|
TextFormat = _format,
|
||||||
|
Inline = _inline,
|
||||||
|
Reply = reply,
|
||||||
|
MessageId = _editMessageId,
|
||||||
|
AdapterOptions = _adapterOptions
|
||||||
|
};
|
||||||
|
|
||||||
|
messageId = await _ctx.SendAsync(req, ct);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Файлы
|
// Файлы
|
||||||
foreach (var (file, caption, captionFormat) in _files)
|
foreach (var (file, caption, captionFormat) in _files)
|
||||||
{
|
{
|
||||||
var res = await _ctx.SendFileAsync(file, caption, captionFormat, _inline, reply, _adapterOptions, ct);
|
var req = new SendRequest
|
||||||
|
{
|
||||||
|
ChatId = _ctx.Update.Chat.Id,
|
||||||
|
File = file,
|
||||||
|
Caption = caption,
|
||||||
|
CaptionFormat = captionFormat,
|
||||||
|
Inline = _inline,
|
||||||
|
Reply = reply,
|
||||||
|
AdapterOptions = _adapterOptions
|
||||||
|
};
|
||||||
|
|
||||||
|
var res = await _ctx.SendAsync(req, ct);
|
||||||
// сохранить первый возвращённый id сообщения
|
// сохранить первый возвращённый id сообщения
|
||||||
if (messageId is null && res is not null) messageId = res;
|
if (messageId is null && res is not null) messageId = res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using BotPages.Core.Abstractions;
|
|
||||||
using BotPages.Core.Messaging;
|
using BotPages.Core.Messaging;
|
||||||
|
|
||||||
namespace BotPages.Telegram;
|
namespace BotPages.Telegram;
|
||||||
@@ -15,29 +14,6 @@ public static class MessageBuilderExtensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static MessageBuilder WithTelegramOptions(this MessageBuilder builder, TelegramOptions options)
|
public static MessageBuilder WithTelegramOptions(this MessageBuilder builder, TelegramOptions options)
|
||||||
{
|
{
|
||||||
// Ensure bag exists
|
return builder.WithAdapterOption(TelegramAdapter.AdapterType, options);
|
||||||
var bag = (builder as object) switch
|
|
||||||
{
|
|
||||||
MessageBuilder mb => GetAdapterBag(mb) ?? CreateAndSetAdapterBag(mb),
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
|
|
||||||
bag?.Set("telegram", options);
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reflection helpers to access private adapterOptions field on MessageBuilder
|
|
||||||
private static AdapterOptionsBag? GetAdapterBag(MessageBuilder builder)
|
|
||||||
{
|
|
||||||
var fi = typeof(MessageBuilder).GetField("_adapterOptions", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
|
||||||
return fi?.GetValue(builder) as AdapterOptionsBag;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static AdapterOptionsBag CreateAndSetAdapterBag(MessageBuilder builder)
|
|
||||||
{
|
|
||||||
var fi = typeof(MessageBuilder).GetField("_adapterOptions", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
|
||||||
var bag = new AdapterOptionsBag();
|
|
||||||
fi?.SetValue(builder, bag);
|
|
||||||
return bag;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using BotPages.Core.Abstractions;
|
using BotPages.Core.Abstractions;
|
||||||
using BotPages.Core.Context;
|
using BotPages.Core.Context;
|
||||||
using BotPages.Core.Logging;
|
using BotPages.Core.Logging;
|
||||||
using BotPages.Core.Messaging;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -23,6 +22,8 @@ namespace BotPages.Telegram;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class TelegramAdapter : IMessengerAdapterSetup
|
public sealed class TelegramAdapter : IMessengerAdapterSetup
|
||||||
{
|
{
|
||||||
|
internal static readonly string AdapterType = typeof(TelegramAdapter).FullName;
|
||||||
|
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private TelegramBotClient? _client;
|
private TelegramBotClient? _client;
|
||||||
private string _token;
|
private string _token;
|
||||||
@@ -104,9 +105,9 @@ public sealed class TelegramAdapter : IMessengerAdapterSetup
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine adapter-specific options (TelegramOptions) from bag or use adapter default
|
// Определите параметры адаптера (TelegramOptions) из папки или используйте параметры адаптера по умолчанию.
|
||||||
TelegramOptions telegramOptions = _options;
|
TelegramOptions telegramOptions = _options;
|
||||||
if (req.AdapterOptions is AdapterOptionsBag bag && bag.TryGet("telegram", out TelegramOptions? opt) && opt is not null)
|
if (req.AdapterOptions is AdapterOptionsBag bag && bag.TryGet(AdapterType, out TelegramOptions? opt) && opt is not null)
|
||||||
{
|
{
|
||||||
telegramOptions = opt;
|
telegramOptions = opt;
|
||||||
}
|
}
|
||||||
@@ -137,7 +138,7 @@ public sealed class TelegramAdapter : IMessengerAdapterSetup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a file — send file
|
// Если есть файл - отправить файл
|
||||||
if (req.File is not null)
|
if (req.File is not null)
|
||||||
{
|
{
|
||||||
var file = req.File;
|
var file = req.File;
|
||||||
@@ -193,7 +194,7 @@ public sealed class TelegramAdapter : IMessengerAdapterSetup
|
|||||||
return sentMessage?.MessageId.ToString();
|
return sentMessage?.MessageId.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise treat as text
|
// Иначе - отправить текст
|
||||||
if (!string.IsNullOrWhiteSpace(req.Text))
|
if (!string.IsNullOrWhiteSpace(req.Text))
|
||||||
{
|
{
|
||||||
var format = req.TextFormat ?? MessageFormat.Plain;
|
var format = req.TextFormat ?? MessageFormat.Plain;
|
||||||
@@ -254,54 +255,6 @@ public sealed class TelegramAdapter : IMessengerAdapterSetup
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task<string?> SendTextAsync(string chatId, string text,
|
|
||||||
MessageFormat format = MessageFormat.Plain,
|
|
||||||
IEnumerable<IEnumerable<InlineButton>>? inline = null,
|
|
||||||
IEnumerable<IEnumerable<ReplyButton>>? reply = null,
|
|
||||||
string? messageId = null,
|
|
||||||
object? adapterOptions = null,
|
|
||||||
CancellationToken ct = default)
|
|
||||||
{
|
|
||||||
var req = new SendRequest
|
|
||||||
{
|
|
||||||
ChatId = chatId,
|
|
||||||
Text = text,
|
|
||||||
TextFormat = format,
|
|
||||||
Inline = inline,
|
|
||||||
Reply = reply,
|
|
||||||
MessageId = messageId,
|
|
||||||
AdapterOptions = adapterOptions as AdapterOptionsBag
|
|
||||||
};
|
|
||||||
|
|
||||||
return SendAsync(req, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public Task SendFileAsync(string chatId,
|
|
||||||
FileDescriptor file,
|
|
||||||
string? caption = null,
|
|
||||||
MessageFormat? captionFormat = null,
|
|
||||||
IEnumerable<IEnumerable<InlineButton>>? inline = null,
|
|
||||||
IEnumerable<IEnumerable<ReplyButton>>? reply = null,
|
|
||||||
object? adapterOptions = null,
|
|
||||||
CancellationToken ct = default
|
|
||||||
)
|
|
||||||
{
|
|
||||||
var req = new SendRequest
|
|
||||||
{
|
|
||||||
ChatId = chatId,
|
|
||||||
File = file,
|
|
||||||
Caption = caption,
|
|
||||||
CaptionFormat = captionFormat,
|
|
||||||
Inline = inline,
|
|
||||||
Reply = reply,
|
|
||||||
AdapterOptions = adapterOptions as AdapterOptionsBag
|
|
||||||
};
|
|
||||||
|
|
||||||
return SendAsync(req, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IAlbumBuilder CreateAlbumBuilder(PageContext ctx) => new TelegramAlbumBuilder(this, ctx, _logger, _client);
|
public IAlbumBuilder CreateAlbumBuilder(PageContext ctx) => new TelegramAlbumBuilder(this, ctx, _logger, _client);
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,17 @@ public sealed class TelegramAlbumBuilder : IAlbumBuilder
|
|||||||
{
|
{
|
||||||
_logger.Log(LogLevel.Warn, "Albums not supported. Degraded to sequential sends.");
|
_logger.Log(LogLevel.Warn, "Albums not supported. Degraded to sequential sends.");
|
||||||
foreach (var (file, caption, captionFormat) in _items)
|
foreach (var (file, caption, captionFormat) in _items)
|
||||||
await _adapter.SendFileAsync(_ctx.Update.Chat.Id, file, caption, captionFormat, ct: ct);
|
{
|
||||||
|
var req = new SendRequest
|
||||||
|
{
|
||||||
|
ChatId = _ctx.Update.Chat.Id,
|
||||||
|
File = file,
|
||||||
|
Caption = caption,
|
||||||
|
CaptionFormat = captionFormat
|
||||||
|
};
|
||||||
|
|
||||||
|
await _ctx.SendAsync(req, ct);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +105,16 @@ public sealed class TelegramAlbumBuilder : IAlbumBuilder
|
|||||||
{
|
{
|
||||||
// Telegram не поддерживает document в альбомах — деградация
|
// Telegram не поддерживает document в альбомах — деградация
|
||||||
_logger.Log(LogLevel.Warn, $"Document '{file.Kind}' in album not supported. Sending document separately.");
|
_logger.Log(LogLevel.Warn, $"Document '{file.Kind}' in album not supported. Sending document separately.");
|
||||||
await _adapter.SendFileAsync(_ctx.Update.Chat.Id, file, caption, captionFormat, ct: ct);
|
|
||||||
|
var req = new SendRequest
|
||||||
|
{
|
||||||
|
ChatId = _ctx.Update.Chat.Id,
|
||||||
|
File = file,
|
||||||
|
Caption = caption,
|
||||||
|
CaptionFormat = captionFormat
|
||||||
|
};
|
||||||
|
|
||||||
|
await _ctx.SendAsync(req, ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Demo.Pages;
|
|||||||
[Route("FileSend")]
|
[Route("FileSend")]
|
||||||
public sealed class FileSendPage : SingletonPage
|
public sealed class FileSendPage : SingletonPage
|
||||||
{
|
{
|
||||||
public override Task OnEnter(PageContext ctx, CancellationToken ct)
|
public override async Task OnEnter(PageContext ctx, CancellationToken ct)
|
||||||
{
|
{
|
||||||
var content = "Hello from BotPages! This file is generated on the fly.";
|
var content = "Hello from BotPages! This file is generated on the fly.";
|
||||||
var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(content));
|
var stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(content));
|
||||||
@@ -23,9 +23,11 @@ public sealed class FileSendPage : SingletonPage
|
|||||||
GetStreamAsync = _ => Task.FromResult<Stream>(stream)
|
GetStreamAsync = _ => Task.FromResult<Stream>(stream)
|
||||||
};
|
};
|
||||||
|
|
||||||
return new MessageBuilder(ctx)
|
await new MessageBuilder(ctx)
|
||||||
.Text("Вот пример отправки нового файла 📎", MessageFormat.Markdown)
|
.Text("Вот пример отправки нового файла 📎", MessageFormat.Markdown)
|
||||||
.File(demoFile, "Демонстрационный файл")
|
.File(demoFile, "Демонстрационный файл")
|
||||||
.SendAsync(ct);
|
.SendAsync(ct);
|
||||||
|
|
||||||
|
await ctx.GoToHomeAsync(ct);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,13 @@ namespace Demo
|
|||||||
{
|
{
|
||||||
if (args is null || !args.TryGetValue("page", out var pageName))
|
if (args is null || !args.TryGetValue("page", out var pageName))
|
||||||
{
|
{
|
||||||
await ctx.SendTextAsync("Не указана страница для открытия.", ct: ct);
|
var req = new BotPages.Core.Abstractions.SendRequest
|
||||||
|
{
|
||||||
|
ChatId = ctx.Update.Chat.Id,
|
||||||
|
Text = "Не указана страница для открытия."
|
||||||
|
};
|
||||||
|
|
||||||
|
await ctx.SendAsync(req, ct: ct);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +43,7 @@ namespace Demo
|
|||||||
var app = new BotPagesApp(state, logger)
|
var app = new BotPagesApp(state, logger)
|
||||||
.AddDefaultPage<WelcomePage>()
|
.AddDefaultPage<WelcomePage>()
|
||||||
.MapCommand<WelcomePage>("/start", true, "Главная")
|
.MapCommand<WelcomePage>("/start", true, "Главная")
|
||||||
.MapCommand("/open {page}", openHandler, true, "открыть станицу /open {page}")
|
.MapCommand("/open {page}", openHandler, true, "открыть страницу /open {page}")
|
||||||
.MapCommand(DetailsPage.Command, DetailsPage.CommandHandler, true, DetailsPage.CommandDescription)
|
.MapCommand(DetailsPage.Command, DetailsPage.CommandHandler, true, DetailsPage.CommandDescription)
|
||||||
.AutoMapRoute()
|
.AutoMapRoute()
|
||||||
.AddMiddleware(new ErrorHandlingMiddleware(logger))
|
.AddMiddleware(new ErrorHandlingMiddleware(logger))
|
||||||
|
|||||||
Reference in New Issue
Block a user