owpengram-server/internal/rpc/convert_rich_message.go

134 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/tg"
"telesrv/internal/domain"
)
// 本文件集中 Layer 227 富文本消息richMessage的 tg.* ↔ domain 转换。
// Phase 1仅支持 inputRichMessageblocks 形态HTML/Markdown 变体(需服务端解析为
// PageBlock尚未实现直接拒绝。blocks 以 TL 向量序列化为不透明字节存 domain详见
// domain.MessageRichMessage
// encodeRichBlocks 把 []tg.PageBlockClass 序列化为 TL 向量字节(含 vector 头)。
func encodeRichBlocks(blocks []tg.PageBlockClass) ([]byte, error) {
var b bin.Buffer
b.PutVectorHeader(len(blocks))
for _, blk := range blocks {
if blk == nil {
return nil, mediaInvalidErr()
}
if err := blk.Encode(&b); err != nil {
return nil, err
}
}
return b.Buf, nil
}
// decodeRichBlocks 把 encodeRichBlocks 产生的字节还原为 []tg.PageBlockClass。
func decodeRichBlocks(data []byte) ([]tg.PageBlockClass, error) {
if len(data) == 0 {
return nil, nil
}
b := &bin.Buffer{Buf: append([]byte(nil), data...)}
n, err := b.VectorHeader()
if err != nil {
return nil, err
}
out := make([]tg.PageBlockClass, 0, n)
for i := 0; i < n; i++ {
blk, err := tg.DecodePageBlock(b)
if err != nil {
return nil, err
}
out = append(out, blk)
}
return out, nil
}
// domainRichMessageFromInput 把入站 tg.InputRichMessageClass 解析为 domain 快照:
// 序列化 blocks + 按 id 解析内嵌 photos/documents复用 sendMedia 同款媒体解析)。
// 返回 nil 表示无富文本载荷。Phase 1 仅认 *tg.InputRichMessage。
func (r *Router) domainRichMessageFromInput(ctx context.Context, input tg.InputRichMessageClass) (*domain.MessageRichMessage, error) {
if input == nil {
return nil, nil
}
in, ok := input.(*tg.InputRichMessage)
if !ok {
// Phase 1HTML/Markdown 变体需服务端解析为 PageBlock尚未支持。
return nil, mediaInvalidErr()
}
if r.deps.Files == nil {
return nil, notImplementedErr()
}
blocks, err := encodeRichBlocks(in.Blocks)
if err != nil {
return nil, err
}
rich := &domain.MessageRichMessage{
Rtl: in.Rtl,
Blocks: blocks,
}
for _, p := range in.Photos {
id, ok := inputPhotoID(p)
if !ok {
return nil, photoInvalidErr()
}
photo, found, err := r.deps.Files.GetPhoto(ctx, id)
if err != nil {
return nil, internalErr()
}
if !found {
return nil, photoInvalidErr()
}
rich.Photos = append(rich.Photos, photo)
}
for _, d := range in.Documents {
id, ok := inputDocumentID(d)
if !ok {
return nil, mediaInvalidErr()
}
doc, found, err := r.deps.Files.GetDocument(ctx, id)
if err != nil {
return nil, internalErr()
}
if !found {
return nil, mediaInvalidErr()
}
rich.Documents = append(rich.Documents, doc)
}
if rich.IsZero() {
return nil, nil
}
return rich, nil
}
// tgRichMessage 把 domain 富文本快照投影为 tg.RichMessage反序列化 blocks + 复用
// tgPhoto/tgDocument 投影内嵌媒体)。空载荷或 blocks 解码失败返回 (nil, err)。
func tgRichMessage(m *domain.MessageRichMessage) (*tg.RichMessage, error) {
if m.IsZero() {
return nil, nil
}
blocks, err := decodeRichBlocks(m.Blocks)
if err != nil {
return nil, err
}
out := &tg.RichMessage{
Rtl: m.Rtl,
Part: m.Part,
Blocks: blocks,
Photos: make([]tg.PhotoClass, 0, len(m.Photos)),
Documents: make([]tg.DocumentClass, 0, len(m.Documents)),
}
for _, p := range m.Photos {
out.Photos = append(out.Photos, tgPhoto(p))
}
for _, d := range m.Documents {
out.Documents = append(out.Documents, tgDocument(d))
}
return out, nil
}