(new): rich message support
Golang lint / lint (pull_request) Successful in 1m20s
Golang lint / lint (push) Successful in 4m8s

(fix): runtime reliability
(tests): regression coverage
(doc): v1.1 release notes
This commit is contained in:
2026-08-12 16:34:44 +03:00
parent 48ddf66540
commit f03a081ed6
83 changed files with 6122 additions and 1925 deletions
+22 -21
View File
@@ -8,10 +8,9 @@ import (
"reflect"
"strconv"
"strings"
"time"
"git.scuroneko.dev/scuroneko/laniakea/tgapi"
"git.scuroneko.dev/scuroneko/laniakea/tgfmt"
"git.scuroneko.dev/scuroneko/laniakea/tgrich"
"git.scuroneko.dev/scuroneko/sneklog/v2"
)
@@ -551,28 +550,19 @@ func (ctx *MessageContext) newDraft(parseMode tgapi.ParseMode) *Draft {
return nil
}
if ctx.API.Limiter != nil {
c, cancel := context.WithTimeout(ctx.Context(), 5*time.Second)
defer cancel()
if err := ctx.API.Limiter.Wait(c, ctx.Msg.Chat.ID); err != nil {
ctx.Logger.Errorln(err)
return nil
}
}
draft := ctx.draftProvider.NewDraft(parseMode).SetChat(ctx.Msg.Chat.ID, ctx.Msg.MessageThreadID)
return draft
}
// NewDraft creates a new message draft associated with the current chat.
// Uses the API limiter to avoid rate limiting.
// Draft sends are rate-limited by the API client.
func (ctx *MessageContext) NewDraft() *Draft {
return ctx.newDraft(tgapi.ParseNone)
}
// NewDraftMarkdown creates a new message draft associated with the current chat,
// with Markdown V2 parse mode enabled.
// Uses the API limiter to avoid rate limiting.
// Draft sends are rate-limited by the API client.
func (ctx *MessageContext) NewDraftMarkdown() *Draft {
return ctx.newDraft(tgapi.ParseMarkdownV2)
}
@@ -852,14 +842,25 @@ func (ctx *MessageContext) richAnswer(rich tgapi.InputRichMessage, keyboard *Inl
}
}
// RichAnswer sends a rich message (Bot API 10.1) built from tgfmt fragments.
// Both inline (tgfmt.Rich) and block (tgfmt.RichBlock) fragments are accepted
// at the top level: Telegram merges adjacent inline content into paragraphs.
func (ctx *MessageContext) RichAnswer(items ...tgfmt.RichItem) *AnswerMessage {
return ctx.richAnswer(tgfmt.RichMessage(items...), nil)
func (ctx *MessageContext) richBlocksAnswer(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage {
rich, err := tgrich.BuildHTML(blocks...)
if err != nil {
ctx.Logger.Errorln(err)
return nil
}
return ctx.richAnswer(rich, keyboard)
}
// RichAnswerKeyboard sends a rich message with an inline keyboard.
func (ctx *MessageContext) RichAnswerKeyboard(keyboard *InlineKeyboard, items ...tgfmt.RichItem) *AnswerMessage {
return ctx.richAnswer(tgfmt.RichMessage(items...), keyboard)
// RichAnswer builds and sends input rich-message blocks.
//
// Since: Bot API 10.2
func (ctx *MessageContext) RichAnswer(blocks ...tgapi.InputRichBlock) *AnswerMessage {
return ctx.richBlocksAnswer(nil, blocks...)
}
// RichAnswerKeyboard builds and sends input rich-message blocks with an inline keyboard.
//
// Since: Bot API 10.2
func (ctx *MessageContext) RichAnswerKeyboard(keyboard *InlineKeyboard, blocks ...tgapi.InputRichBlock) *AnswerMessage {
return ctx.richBlocksAnswer(keyboard, blocks...)
}