|
|
|
|
@@ -2,6 +2,7 @@
|
|
|
|
|
using BotPages.Core.Abstractions;
|
|
|
|
|
using BotPages.Core.Context;
|
|
|
|
|
using BotPages.Core.Logging;
|
|
|
|
|
using BotPages.Core.Messaging;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
@@ -114,36 +115,67 @@ public sealed class TelegramAdapter : IMessengerAdapterSetup
|
|
|
|
|
var disableNotification = !telegramOptions.NotifyOnSend;
|
|
|
|
|
|
|
|
|
|
// Build markup
|
|
|
|
|
InlineKeyboardMarkup? inlineMarkup = null;
|
|
|
|
|
ReplyMarkup? markup = null;
|
|
|
|
|
var inlineMarkup = BuildInlineMarkup(req.Inline);
|
|
|
|
|
ReplyMarkup? markup = BuildReplyMarkup(req.Reply);
|
|
|
|
|
|
|
|
|
|
if (req.Inline is not null && req.Inline.Any())
|
|
|
|
|
// Файлы: сейчас поддерживается один файл через SendRequest.File.
|
|
|
|
|
// При необходимости для нескольких файлов следует использовать альбомы (CreateAlbumBuilder)
|
|
|
|
|
if (req.File is not null)
|
|
|
|
|
{
|
|
|
|
|
inlineMarkup = new InlineKeyboardMarkup(
|
|
|
|
|
req.Inline.Select(row => row.Select(b => new InlineKeyboardButton(b.Label, b.Value)).ToArray()).ToArray()
|
|
|
|
|
if (inlineMarkup is not null) markup = inlineMarkup;
|
|
|
|
|
|
|
|
|
|
var sent = await SendFileAsync(req.File, req.ChatId, markup, disableNotification, req.Caption, req.CaptionFormat, ct);
|
|
|
|
|
return sent?.MessageId.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Текст
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(req.Text))
|
|
|
|
|
{
|
|
|
|
|
return await SendTextAsync(req, inlineMarkup, markup, disableNotification, ct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Helpers ---
|
|
|
|
|
|
|
|
|
|
private InlineKeyboardMarkup? BuildInlineMarkup(IEnumerable<IEnumerable<InlineButton>>? inline)
|
|
|
|
|
{
|
|
|
|
|
if (inline is null || !inline.Any()) return null;
|
|
|
|
|
return new InlineKeyboardMarkup(
|
|
|
|
|
inline.Select(row => row.Select(b => new InlineKeyboardButton(b.Label, b.Value)).ToArray()).ToArray()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else if (req.Reply is not null)
|
|
|
|
|
|
|
|
|
|
private ReplyMarkup? BuildReplyMarkup(IEnumerable<IEnumerable<ReplyButton>>? reply)
|
|
|
|
|
{
|
|
|
|
|
if (req.Reply.Any())
|
|
|
|
|
if (reply is null) return null;
|
|
|
|
|
|
|
|
|
|
if (reply.Any())
|
|
|
|
|
{
|
|
|
|
|
markup = new ReplyKeyboardMarkup(req.Reply.Select(row => row.Select(b => new KeyboardButton(b.Label)).ToArray()).ToArray())
|
|
|
|
|
return new ReplyKeyboardMarkup(reply.Select(row => row.Select(b => new KeyboardButton(b.Label)).ToArray()).ToArray())
|
|
|
|
|
{
|
|
|
|
|
ResizeKeyboard = true
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
markup = new ReplyKeyboardRemove();
|
|
|
|
|
return new ReplyKeyboardRemove();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Если есть файл - отправить файл
|
|
|
|
|
if (req.File is not null)
|
|
|
|
|
private static ParseMode GetParseMode(MessageFormat? format)
|
|
|
|
|
{
|
|
|
|
|
var file = req.File;
|
|
|
|
|
return format switch
|
|
|
|
|
{
|
|
|
|
|
MessageFormat.Html => ParseMode.Html,
|
|
|
|
|
MessageFormat.Markdown => ParseMode.MarkdownV2,
|
|
|
|
|
_ => ParseMode.None,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Получаем поток, если он задан
|
|
|
|
|
private async Task<InputFile> CreateInputFileAsync(FileDescriptor file, CancellationToken ct)
|
|
|
|
|
{
|
|
|
|
|
Stream? stream = null;
|
|
|
|
|
if (file.GetStreamAsync is not null)
|
|
|
|
|
{
|
|
|
|
|
@@ -151,70 +183,39 @@ public sealed class TelegramAdapter : IMessengerAdapterSetup
|
|
|
|
|
if (stream is not null) stream.Position = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
InputFile inputFile;
|
|
|
|
|
|
|
|
|
|
if (stream is not null && stream != Stream.Null)
|
|
|
|
|
{
|
|
|
|
|
inputFile = new InputFileStream(stream, file.Name);
|
|
|
|
|
return new InputFileStream(stream, file.Name);
|
|
|
|
|
}
|
|
|
|
|
else if (file.Id.StartsWith("http://") || file.Id.StartsWith("https://"))
|
|
|
|
|
{
|
|
|
|
|
inputFile = new InputFileUrl(file.Id);
|
|
|
|
|
return new InputFileUrl(file.Id);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
inputFile = new InputFileId(file.Id);
|
|
|
|
|
return new InputFileId(file.Id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var parseMode = ParseMode.None;
|
|
|
|
|
switch (req.CaptionFormat)
|
|
|
|
|
private async Task<Message?> SendFileAsync(FileDescriptor file, string chatId, ReplyMarkup? markup, bool disableNotification, string? caption, MessageFormat? captionFormat, CancellationToken ct)
|
|
|
|
|
{
|
|
|
|
|
case MessageFormat.Html:
|
|
|
|
|
parseMode = ParseMode.Html;
|
|
|
|
|
break;
|
|
|
|
|
case MessageFormat.Markdown:
|
|
|
|
|
parseMode = ParseMode.MarkdownV2;
|
|
|
|
|
break;
|
|
|
|
|
case MessageFormat.Plain:
|
|
|
|
|
case null:
|
|
|
|
|
parseMode = ParseMode.None;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
var inputFile = await CreateInputFileAsync(file, ct);
|
|
|
|
|
var parseMode = GetParseMode(captionFormat);
|
|
|
|
|
|
|
|
|
|
if (inlineMarkup is not null) markup = inlineMarkup;
|
|
|
|
|
|
|
|
|
|
Message? sentMessage = req.File.Kind switch
|
|
|
|
|
return file.Kind switch
|
|
|
|
|
{
|
|
|
|
|
FileKind.Photo => await _client.SendPhoto(long.Parse(req.ChatId), inputFile, req.Caption ?? "", parseMode, replyMarkup: markup, disableNotification: disableNotification, cancellationToken: ct),
|
|
|
|
|
FileKind.Video => await _client.SendVideo(long.Parse(req.ChatId), inputFile, caption: req.Caption ?? "", parseMode, replyMarkup: markup, disableNotification: disableNotification, cancellationToken: ct),
|
|
|
|
|
FileKind.Audio => await _client.SendAudio(long.Parse(req.ChatId), inputFile, req.Caption ?? "", parseMode, replyMarkup: markup, disableNotification: disableNotification, cancellationToken: ct),
|
|
|
|
|
_ => await _client.SendDocument(long.Parse(req.ChatId), inputFile, req.Caption ?? "", parseMode, replyMarkup: markup, disableNotification: disableNotification, cancellationToken: ct),
|
|
|
|
|
FileKind.Photo => await _client.SendPhoto(long.Parse(chatId), inputFile, caption ?? "", parseMode, replyMarkup: markup, disableNotification: disableNotification, cancellationToken: ct),
|
|
|
|
|
FileKind.Video => await _client.SendVideo(long.Parse(chatId), inputFile, caption: caption ?? "", parseMode, replyMarkup: markup, disableNotification: disableNotification, cancellationToken: ct),
|
|
|
|
|
FileKind.Audio => await _client.SendAudio(long.Parse(chatId), inputFile, caption ?? "", parseMode, replyMarkup: markup, disableNotification: disableNotification, cancellationToken: ct),
|
|
|
|
|
_ => await _client.SendDocument(long.Parse(chatId), inputFile, caption ?? "", parseMode, replyMarkup: markup, disableNotification: disableNotification, cancellationToken: ct),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return sentMessage?.MessageId.ToString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Иначе - отправить текст
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(req.Text))
|
|
|
|
|
private async Task<string?> SendTextAsync(SendRequest req, InlineKeyboardMarkup? inlineMarkup, ReplyMarkup? markup, bool disableNotification, CancellationToken ct)
|
|
|
|
|
{
|
|
|
|
|
var format = req.TextFormat ?? MessageFormat.Plain;
|
|
|
|
|
var parseMode = ParseMode.None;
|
|
|
|
|
var parseMode = GetParseMode(format);
|
|
|
|
|
|
|
|
|
|
switch (format)
|
|
|
|
|
{
|
|
|
|
|
case MessageFormat.Html:
|
|
|
|
|
parseMode = ParseMode.Html;
|
|
|
|
|
break;
|
|
|
|
|
case MessageFormat.Markdown:
|
|
|
|
|
parseMode = ParseMode.MarkdownV2;
|
|
|
|
|
break;
|
|
|
|
|
case MessageFormat.Plain:
|
|
|
|
|
default:
|
|
|
|
|
parseMode = ParseMode.None;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Длина сообщения
|
|
|
|
|
var text = req.Text!;
|
|
|
|
|
if (text.Length > Capabilities.MaxMessageLength)
|
|
|
|
|
{
|
|
|
|
|
@@ -252,9 +253,6 @@ public sealed class TelegramAdapter : IMessengerAdapterSetup
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
|
public IAlbumBuilder CreateAlbumBuilder(PageContext ctx) => new TelegramAlbumBuilder(this, ctx, _logger, _client);
|
|
|
|
|
|
|
|
|
|
|