Skip to content

Commit 6ef01d8

Browse files
committed
fix: SendRichMessageDraft must send the input action
messages.setTyping for a rich draft carries inputSendMessageRichMessageDraftAction (InputRichMessageClass), not the resolved sendMessageRichMessageDraftAction (tg.RichMessage) which is the broadcast/output form — confirmed against telegram-bot-api 10.1 (DialogAction::get_input_send_message_action). Take a tg.InputRichMessageClass, mirroring SendRichMessage, so callers build content with the rich package (rich.New(...).Input(), rich.HTML, rich.Markdown). Drops the redundant botapi.RichMessage type.
1 parent 1ecd431 commit 6ef01d8

2 files changed

Lines changed: 22 additions & 61 deletions

File tree

send_draft.go

Lines changed: 13 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -68,50 +68,18 @@ func (b *Bot) SendMessageDraft(ctx context.Context, chat ChatID, draftID int64,
6868
return nil
6969
}
7070

71-
// RichMessage is the structured content of a rich message, expressed as native
72-
// MTProto page blocks.
71+
// SendRichMessageDraft streams a partial rich message (Bot API 10.1) to a chat
72+
// while the message is being generated, so its members see an ephemeral preview.
73+
// draftID is a unique client-side identifier for the draft; reuse it across the
74+
// stream and finalize with SendRichMessage once generation completes.
7375
//
74-
// The HTTP Bot API accepts a rich message only as an HTML or Markdown string and
75-
// parses it into this structure server-side. botapi is MTProto-native, so it
76-
// takes the page-block tree directly: no content parser is needed and the full
77-
// block vocabulary (paragraphs, headers, lists, embedded media, …) is available.
78-
// Build blocks with the tg.PageBlock* types; Bot.Raw exposes the same client.
79-
type RichMessage struct {
80-
// Blocks are the page blocks that make up the message body.
81-
Blocks []tg.PageBlockClass
82-
// Photos are photos referenced by the blocks.
83-
Photos []tg.PhotoClass
84-
// Documents are documents referenced by the blocks.
85-
Documents []tg.DocumentClass
86-
// RTL renders the message right-to-left.
87-
RTL bool
88-
// Part marks this as a partial segment of a longer streamed message.
89-
Part bool
90-
}
91-
92-
// toTg converts the rich message into its MTProto representation.
93-
func (r RichMessage) toTg() tg.RichMessage {
94-
out := tg.RichMessage{
95-
Blocks: r.Blocks,
96-
Photos: r.Photos,
97-
Documents: r.Documents,
98-
}
99-
if r.RTL {
100-
out.SetRtl(true)
101-
}
102-
103-
if r.Part {
104-
out.SetPart(true)
105-
}
106-
107-
return out
108-
}
109-
110-
// SendRichMessageDraft streams a partial rich message to a chat while the message
111-
// is being generated, so its members see an ephemeral preview. draftID is a
112-
// unique client-side identifier for the draft. Once generation finishes, persist
113-
// the result with a regular send.
114-
func (b *Bot) SendRichMessageDraft(ctx context.Context, chat ChatID, draftID int64, message RichMessage, opts ...DraftOption) error {
76+
// Build msg the same way as for SendRichMessage — from native page blocks with
77+
// github.com/gotd/td/telegram/message/rich (rich.New(...).Input()), or from a
78+
// whole HTML/Markdown document (rich.HTML / rich.Markdown), which Telegram's
79+
// servers parse.
80+
func (b *Bot) SendRichMessageDraft(
81+
ctx context.Context, chat ChatID, draftID int64, msg tg.InputRichMessageClass, opts ...DraftOption,
82+
) error {
11583
var cfg draftConfig
11684

11785
for _, o := range opts {
@@ -125,9 +93,9 @@ func (b *Bot) SendRichMessageDraft(ctx context.Context, chat ChatID, draftID int
12593

12694
req := &tg.MessagesSetTypingRequest{
12795
Peer: peer,
128-
Action: &tg.SendMessageRichMessageDraftAction{
96+
Action: &tg.InputSendMessageRichMessageDraftAction{
12997
RandomID: draftID,
130-
RichMessage: message.toTg(),
98+
RichMessage: msg,
13199
},
132100
}
133101
if cfg.messageThreadID != 0 {

send_draft_test.go

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"testing"
66

7+
"github.com/gotd/td/telegram/message/rich"
78
"github.com/gotd/td/tg"
89
)
910

@@ -38,34 +39,26 @@ func TestSendRichMessageDraft(t *testing.T) {
3839
inv := newMockInvoker()
3940
inv.reply(tg.MessagesSetTypingRequestTypeID, &tg.BoolTrue{})
4041

41-
message := RichMessage{
42-
Blocks: []tg.PageBlockClass{&tg.PageBlockParagraph{Text: &tg.TextPlain{Text: "partial"}}},
43-
RTL: true,
44-
Part: true,
45-
}
42+
msg := rich.New(&tg.PageBlockParagraph{Text: &tg.TextPlain{Text: "partial"}}).Input()
4643

47-
if err := newMockBot(inv).SendRichMessageDraft(context.Background(), userRef(10, 20), 1000, message); err != nil {
44+
if err := newMockBot(inv).SendRichMessageDraft(context.Background(), userRef(10, 20), 1000, msg); err != nil {
4845
t.Fatalf("SendRichMessageDraft: %v", err)
4946
}
5047

5148
var req tg.MessagesSetTypingRequest
5249

5350
inv.decode(t, tg.MessagesSetTypingRequestTypeID, &req)
5451

55-
action, ok := req.Action.(*tg.SendMessageRichMessageDraftAction)
52+
action, ok := req.Action.(*tg.InputSendMessageRichMessageDraftAction)
5653
if !ok {
57-
t.Fatalf("action = %#v, want rich draft", req.Action)
58-
}
59-
60-
if action.RandomID != 1000 || len(action.RichMessage.Blocks) != 1 {
61-
t.Fatalf("action = %#v", action)
54+
t.Fatalf("action = %#v, want input rich draft", req.Action)
6255
}
6356

64-
if !action.RichMessage.GetRtl() {
65-
t.Fatal("rtl flag should be set")
57+
if action.RandomID != 1000 {
58+
t.Fatalf("random id = %d", action.RandomID)
6659
}
6760

68-
if _, ok := action.RichMessage.Blocks[0].(*tg.PageBlockParagraph); !ok {
69-
t.Fatalf("block 0 = %#v, want paragraph", action.RichMessage.Blocks[0])
61+
if _, ok := action.RichMessage.(*tg.InputRichMessage); !ok {
62+
t.Fatalf("rich message = %#v, want input rich message", action.RichMessage)
7063
}
7164
}

0 commit comments

Comments
 (0)