@@ -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,147 +115,144 @@ 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 ( ) )
{
inlineMarkup = new InlineKeyboardMarkup (
req . Inline . Select ( row = > row . Select ( b = > new InlineKeyboardButton ( b . Label , b . Value ) ) . ToArray ( ) ) . ToArray ( )
) ;
}
else if ( req . Reply is not null )
{
if ( req . Reply . Any ( ) )
{
markup = new ReplyKeyboardMarkup ( req . Reply . Select ( row = > row . Select ( b = > new KeyboardButton ( b . Label ) ) . ToArray ( ) ) . ToArray ( ) )
{
ResizeKeyboard = true
} ;
}
else
{
markup = new ReplyKeyboardRemove ( ) ;
}
}
// Если есть файл - отправить файл
// Файлы: сейчас поддерживается один файл через SendRequest.File.
// При необходимости для нескольких файлов следует использовать альбомы (CreateAlbumBuilder)
if ( req . File is not null )
{
var file = req . File ;
// Получаем поток, если он задан
Stream ? stream = null ;
if ( file . GetStreamAsync is not null )
{
stream = await file . GetStreamAsync ( ct ) ;
if ( stream is not null ) stream . Position = 0 ;
}
InputFile inputFile ;
if ( stream is not null & & stream ! = Stream . Null )
{
inputFile = new InputFileStream ( stream , file . Name ) ;
}
else if ( file . Id . StartsWith ( "http://" ) | | file . Id . StartsWith ( "https://" ) )
{
inputFile = new InputFileUrl ( file . Id ) ;
}
else
{
inputFile = new InputFileId ( file . Id ) ;
}
var parseMode = ParseMode . None ;
switch ( req . CaptionFormat )
{
case MessageFormat . Html :
parseMode = ParseMode . Html ;
break ;
case MessageFormat . Markdown :
parseMode = ParseMode . MarkdownV2 ;
break ;
case MessageFormat . Plain :
case null :
parseMode = ParseMode . None ;
break ;
}
if ( inlineMarkup is not null ) markup = inlineMarkup ;
Message ? s entMessage = req . 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 ) ,
} ;
return sentMessage ? . MessageId . ToString ( ) ;
var sent = await S endFileAsync ( req . File , req . ChatId , markup , disableNotification , req . Caption , req . CaptionFormat , ct ) ;
return sent ? . MessageId . ToString ( ) ;
}
// Иначе - отправить т екст
// Т екст
if ( ! string . IsNullOrWhiteSpace ( req . Text ) )
{
var format = req . TextFormat ? ? MessageFormat . Plain ;
var parseMode = ParseMode . None ;
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 )
{
_logger . Log ( LogLevel . Warn , $"Message too long ({text.Length}). Truncated to {Capabilities.MaxMessageLength}." ) ;
text = text . Substring ( 0 , Capabilities . MaxMessageLength ) ;
}
if ( ! string . IsNullOrWhiteSpace ( req . MessageId ) )
{
await _client . EditMessageText (
messageId : int . Parse ( req . MessageId ) ,
chatId : long . Parse ( req . ChatId ) ,
text : text ,
parseMode : parseMode ,
replyMarkup : inlineMarkup ,
cancellationToken : ct
) ;
return req . MessageId ;
}
else
{
if ( inlineMarkup is not null ) markup = inlineMarkup ;
var message = await _client . SendMessage (
chatId : long . Parse ( req . ChatId ) ,
text : text ,
parseMode : parseMode ,
replyMarkup : markup ,
disableNotification : disableNotification ,
cancellationToken : ct
) ;
return message . MessageId . ToString ( ) ;
}
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 ( )
) ;
}
private ReplyMarkup ? BuildReplyMarkup ( IEnumerable < IEnumerable < ReplyButton > > ? reply )
{
if ( reply is null ) return null ;
if ( reply . Any ( ) )
{
return new ReplyKeyboardMarkup ( reply . Select ( row = > row . Select ( b = > new KeyboardButton ( b . Label ) ) . ToArray ( ) ) . ToArray ( ) )
{
ResizeKeyboard = true
} ;
}
else
{
return new ReplyKeyboardRemove ( ) ;
}
}
private static ParseMode GetParseMode ( MessageFormat ? format )
{
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 )
{
stream = await file . GetStreamAsync ( ct ) ;
if ( stream is not null ) stream . Position = 0 ;
}
if ( stream is not null & & stream ! = Stream . Null )
{
return new InputFileStream ( stream , file . Name ) ;
}
else if ( file . Id . StartsWith ( "http://" ) | | file . Id . StartsWith ( "https://" ) )
{
return new InputFileUrl ( file . Id ) ;
}
else
{
return new InputFileId ( file . Id ) ;
}
}
private async Task < Message ? > SendFileAsync ( FileDescriptor file , string chatId , ReplyMarkup ? markup , bool disableNotification , string? caption , MessageFormat ? captionFormat , CancellationToken ct )
{
var inputFile = await CreateInputFileAsync ( file , ct ) ;
var parseMode = GetParseMode ( captionFormat ) ;
return file . Kind switch
{
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 ) ,
} ;
}
private async Task < string? > SendTextAsync ( SendRequest req , InlineKeyboardMarkup ? inlineMarkup , ReplyMarkup ? markup , bool disableNotification , CancellationToken ct )
{
var format = req . TextFormat ? ? MessageFormat . Plain ;
var parseMode = GetParseMode ( format ) ;
var text = req . Text ! ;
if ( text . Length > Capabilities . MaxMessageLength )
{
_logger . Log ( LogLevel . Warn , $"Message too long ({text.Length}). Truncated to {Capabilities.MaxMessageLength}." ) ;
text = text . Substring ( 0 , Capabilities . MaxMessageLength ) ;
}
if ( ! string . IsNullOrWhiteSpace ( req . MessageId ) )
{
await _client . EditMessageText (
messageId : int . Parse ( req . MessageId ) ,
chatId : long . Parse ( req . ChatId ) ,
text : text ,
parseMode : parseMode ,
replyMarkup : inlineMarkup ,
cancellationToken : ct
) ;
return req . MessageId ;
}
else
{
if ( inlineMarkup is not null ) markup = inlineMarkup ;
var message = await _client . SendMessage (
chatId : long . Parse ( req . ChatId ) ,
text : text ,
parseMode : parseMode ,
replyMarkup : markup ,
disableNotification : disableNotification ,
cancellationToken : ct
) ;
return message . MessageId . ToString ( ) ;
}
}
/// <inheritdoc />
public IAlbumBuilder CreateAlbumBuilder ( PageContext ctx ) = > new TelegramAlbumBuilder ( this , ctx , _logger , _client ) ;