Files
mautrix-telegram/pkg/gotd/cmd/mtprint/printer.go
T
2025-06-27 20:03:37 -07:00

131 lines
2.7 KiB
Go

package main
import (
"encoding/json"
"fmt"
"io"
"github.com/go-faster/errors"
"github.com/k0kubun/pp/v3"
"go.mau.fi/mautrix-telegram/pkg/gotd/bin"
"go.mau.fi/mautrix-telegram/pkg/gotd/mt"
"go.mau.fi/mautrix-telegram/pkg/gotd/proto/codec"
"go.mau.fi/mautrix-telegram/pkg/gotd/tdp"
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
"go.mau.fi/mautrix-telegram/pkg/gotd/tmap"
"go.mau.fi/mautrix-telegram/pkg/gotd/transport"
)
// Object is abstraction for TL schema object.
type Object interface {
bin.Object
tdp.Object
}
// Formatter formats given bin.Object and prints it to io.Writer.
type Formatter interface {
Format(w io.Writer, i Object) error
}
// FormatterFunc is functional adapter for Formatter.
type FormatterFunc func(w io.Writer, i Object) error
// Format implements Formatter.
func (f FormatterFunc) Format(w io.Writer, i Object) error {
return f(w, i)
}
func formats(name string) Formatter {
switch name {
case "json":
return FormatterFunc(func(w io.Writer, i Object) error {
e := json.NewEncoder(w)
e.SetIndent("", "\t")
return e.Encode(i)
})
case "pp":
return FormatterFunc(func(w io.Writer, i Object) error {
_, err := pp.Fprintln(w, i)
return err
})
case "tdp":
return FormatterFunc(func(w io.Writer, i Object) error {
_, err := io.WriteString(w, tdp.Format(i))
return err
})
default: // "go" format
return FormatterFunc(func(w io.Writer, i Object) error {
_, err := fmt.Fprintln(w, i)
return err
})
}
}
// Printer decodes messages from given reader and prints is using Formatter.
type Printer struct {
src io.Reader
codec transport.Codec
format Formatter
}
// NewPrinter creates new Printer.
// If format is nil, "go" format will be used.
// If c is nil, codec.Intermediate will be use.
func NewPrinter(src io.Reader, format Formatter, c transport.Codec) Printer {
if c == nil {
c = codec.Intermediate{}
}
if format == nil {
format = formats("go")
}
return Printer{
src: src,
codec: c,
format: format,
}
}
// Print prints decoded messages to output.
func (p Printer) Print(output io.Writer) error {
b := &bin.Buffer{}
m := tmap.NewConstructor(
tg.TypesConstructorMap(),
mt.TypesConstructorMap(),
)
for {
b.Reset()
if err := p.codec.Read(p.src, b); err != nil {
if errors.Is(err, io.EOF) {
return nil
}
return err
}
id, err := b.PeekID()
if err != nil {
return err
}
obj := m.New(id)
if obj == nil {
return errors.Errorf("find type %#x", id)
}
v, ok := obj.(Object)
if !ok {
return errors.Errorf("unexpected type %T", obj)
}
if err := v.Decode(b); err != nil {
return err
}
if err := p.format.Format(output, v); err != nil {
return err
}
}
}