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 } } }