move gotd fork into repo. (#111)

- update to latest telegram layer
- remove some references to fields in tg.Entities that don't exist in
the schema
- originally added here:
https://github.com/beeper/td/commit/820929062a2ba0104397bc01235ab58a9cff780e
  - referenced here
-
https://github.com/mautrix/telegramgo/commit/124f0967ed195b5a380c9bd02e170ada9710dde3
-
https://github.com/mautrix/telegramgo/commit/4205047aab2e0639217148b5d125bfaab668bd8e
This commit is contained in:
Adam Van Ymeren
2025-06-27 20:03:37 -07:00
committed by GitHub
parent 0952df0244
commit 7a04f298d2
19264 changed files with 1539697 additions and 84 deletions
@@ -0,0 +1,174 @@
// Package blocked contains blocked contacts iteration helper.
package blocked
import (
"context"
"github.com/go-faster/errors"
"go.mau.fi/mautrix-telegram/pkg/gotd/telegram/message/peer"
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
)
// Elem is a contact iterator element.
type Elem struct {
Contact tg.PeerBlocked
Entities peer.Entities
}
// Iterator is a blocked contacts stream iterator.
type Iterator struct {
// Current state.
lastErr error
// Buffer state.
buf []Elem
bufCur int
// Request state.
limit int
lastBatch bool
// Offset parameters state.
offset int
// Remote state.
count int
totalGot bool
// Query builder.
query Query
}
// NewIterator creates new iterator.
func NewIterator(query Query, limit int) *Iterator {
return &Iterator{
buf: make([]Elem, 0, limit),
bufCur: -1,
limit: limit,
query: query,
}
}
// Offset sets Offset request parameter.
func (m *Iterator) Offset(offset int) *Iterator {
m.offset = offset
return m
}
func (m *Iterator) apply(r tg.ContactsBlockedClass) error {
if m.lastBatch {
return nil
}
var (
blocked []tg.PeerBlocked
entities peer.Entities
)
switch ctcs := r.(type) {
case *tg.ContactsBlocked: // contacts.blocked#ade1591
blocked = ctcs.Blocked
entities = peer.EntitiesFromResult(ctcs)
m.count = len(ctcs.Blocked)
m.lastBatch = true
case *tg.ContactsBlockedSlice: // contacts.blockedSlice#e1664194
blocked = ctcs.Blocked
entities = peer.EntitiesFromResult(ctcs)
m.count = ctcs.Count
m.lastBatch = len(ctcs.Blocked) < m.limit
default:
return errors.Errorf("unexpected type %T", r)
}
m.totalGot = true
m.offset += len(blocked)
m.bufCur = -1
m.buf = m.buf[:0]
for i := range blocked {
m.buf = append(m.buf, Elem{Contact: blocked[i], Entities: entities})
}
return nil
}
func (m *Iterator) requestNext(ctx context.Context) error {
r, err := m.query.Query(ctx, Request{
Offset: m.offset,
Limit: m.limit,
})
if err != nil {
return err
}
return m.apply(r)
}
func (m *Iterator) bufNext() bool {
if len(m.buf)-1 <= m.bufCur {
return false
}
m.bufCur++
return true
}
// Total returns last fetched count of elements.
// If count was not fetched before, it requests server using FetchTotal.
func (m *Iterator) Total(ctx context.Context) (int, error) {
if m.totalGot {
return m.count, nil
}
return m.FetchTotal(ctx)
}
// FetchTotal fetches and returns count of elements.
func (m *Iterator) FetchTotal(ctx context.Context) (int, error) {
r, err := m.query.Query(ctx, Request{
Limit: 1,
})
if err != nil {
return 0, errors.Wrap(err, "fetch total")
}
switch ctcs := r.(type) {
case *tg.ContactsBlocked: // contacts.blocked#ade1591
m.count = len(ctcs.Blocked)
case *tg.ContactsBlockedSlice: // contacts.blockedSlice#e1664194
m.count = ctcs.Count
default:
return 0, errors.Errorf("unexpected type %T", r)
}
m.totalGot = true
return m.count, nil
}
// Next prepares the next message for reading with the Value method.
// It returns true on success, or false if there is no next message or an error happened while preparing it.
// Err should be consulted to distinguish between the two cases.
func (m *Iterator) Next(ctx context.Context) bool {
if m.lastErr != nil {
return false
}
if !m.bufNext() {
// If buffer is empty, we should fetch next batch.
if err := m.requestNext(ctx); err != nil {
m.lastErr = err
return false
}
// Try again with new buffer.
return m.bufNext()
}
return true
}
// Value returns current message.
func (m *Iterator) Value() Elem {
return m.buf[m.bufCur]
}
// Err returns the error, if any, that was encountered during iteration.
func (m *Iterator) Err() error {
return m.lastErr
}
@@ -0,0 +1,80 @@
package blocked
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
"go.mau.fi/mautrix-telegram/pkg/gotd/tgmock"
)
func generateBlocked(count int) []tg.PeerBlocked {
r := make([]tg.PeerBlocked, 0, count)
for i := 0; i < count; i++ {
r = append(r, tg.PeerBlocked{
PeerID: &tg.PeerUser{
UserID: int64(i + 1),
},
Date: i,
})
}
return r
}
func result(r []tg.PeerBlocked, count int) tg.ContactsBlockedClass {
return &tg.ContactsBlockedSlice{
Blocked: r,
Count: count,
}
}
func TestIterator(t *testing.T) {
ctx := context.Background()
mock := tgmock.NewRequire(t)
limit := 10
totalRecords := 3 * limit
expected := generateBlocked(totalRecords)
raw := tg.NewClient(mock)
mock.ExpectCall(&tg.ContactsGetBlockedRequest{
Offset: 0,
Limit: limit,
}).ThenResult(result(expected[0:limit], totalRecords))
mock.ExpectCall(&tg.ContactsGetBlockedRequest{
Offset: limit,
Limit: limit,
}).ThenResult(result(expected[limit:2*limit], totalRecords))
mock.ExpectCall(&tg.ContactsGetBlockedRequest{
Offset: 2 * limit,
Limit: limit,
}).ThenResult(result(expected[2*limit:3*limit], totalRecords))
mock.ExpectCall(&tg.ContactsGetBlockedRequest{
Offset: 3 * limit,
Limit: limit,
}).ThenResult(result(expected[3*limit:], totalRecords))
iter := NewQueryBuilder(raw).GetBlocked().BatchSize(10).Iter()
i := 0
for iter.Next(ctx) {
require.Equal(t, expected[i], iter.Value().Contact)
i++
}
require.NoError(t, iter.Err())
require.Equal(t, totalRecords, i)
total, err := iter.Total(ctx)
require.NoError(t, err)
require.Equal(t, totalRecords, total)
mock.ExpectCall(&tg.ContactsGetBlockedRequest{
Offset: 0,
Limit: 1,
}).ThenResult(result(expected[:0], totalRecords))
total, err = iter.FetchTotal(ctx)
require.NoError(t, err)
require.Equal(t, totalRecords, total)
}
@@ -0,0 +1,132 @@
// Code generated by itergen, DO NOT EDIT.
package blocked
import (
"context"
"github.com/go-faster/errors"
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
)
// No-op definition for keeping imports.
var _ = context.Background()
// Request is a parameter for Query.
type Request struct {
Offset int
Limit int
}
// Query is an abstraction for blocked request.
// NB: iterator mutates returned data (sorts, at least).
type Query interface {
Query(ctx context.Context, req Request) (tg.ContactsBlockedClass, error)
}
// QueryFunc is a function adapter for Query.
type QueryFunc func(ctx context.Context, req Request) (tg.ContactsBlockedClass, error)
// Query implements Query interface.
func (q QueryFunc) Query(ctx context.Context, req Request) (tg.ContactsBlockedClass, error) {
return q(ctx, req)
}
// QueryBuilder is a helper to create message queries.
type QueryBuilder struct {
raw *tg.Client
}
// NewQueryBuilder creates new QueryBuilder.
func NewQueryBuilder(raw *tg.Client) *QueryBuilder {
return &QueryBuilder{raw: raw}
}
// GetBlockedQueryBuilder is query builder of ContactsGetBlocked.
type GetBlockedQueryBuilder struct {
raw *tg.Client
req tg.ContactsGetBlockedRequest
batchSize int
offset int
}
// GetBlocked creates query builder of ContactsGetBlocked.
func (q *QueryBuilder) GetBlocked() *GetBlockedQueryBuilder {
b := &GetBlockedQueryBuilder{
raw: q.raw,
batchSize: 1,
req: tg.ContactsGetBlockedRequest{},
}
return b
}
// BatchSize sets buffer of message loaded from one request.
// Be carefully, when set this limit, because Telegram does not return error if limit is too big,
// so results can be incorrect.
func (b *GetBlockedQueryBuilder) BatchSize(batchSize int) *GetBlockedQueryBuilder {
b.batchSize = batchSize
return b
}
// MyStoriesFrom sets MyStoriesFrom field of GetBlocked query.
func (b *GetBlockedQueryBuilder) MyStoriesFrom(paramMyStoriesFrom bool) *GetBlockedQueryBuilder {
b.req.MyStoriesFrom = paramMyStoriesFrom
return b
}
// Query implements Query interface.
func (b *GetBlockedQueryBuilder) Query(ctx context.Context, req Request) (tg.ContactsBlockedClass, error) {
r := &tg.ContactsGetBlockedRequest{
Limit: req.Limit,
}
r.MyStoriesFrom = b.req.MyStoriesFrom
r.Offset = req.Offset
return b.raw.ContactsGetBlocked(ctx, r)
}
// Iter returns iterator using built query.
func (b *GetBlockedQueryBuilder) Iter() *Iterator {
iter := NewIterator(b, b.batchSize)
iter = iter.Offset(b.offset)
return iter
}
// ForEach calls given callback on each iterator element.
func (b *GetBlockedQueryBuilder) ForEach(ctx context.Context, cb func(context.Context, Elem) error) error {
iter := b.Iter()
for iter.Next(ctx) {
if err := cb(ctx, iter.Value()); err != nil {
return err
}
}
return iter.Err()
}
// Count fetches remote state to get number of elements.
func (b *GetBlockedQueryBuilder) Count(ctx context.Context) (int, error) {
iter := b.Iter()
c, err := iter.Total(ctx)
if err != nil {
return 0, errors.Wrap(err, "get total")
}
return c, nil
}
// Collect creates iterator and collects all elements to slice.
func (b *GetBlockedQueryBuilder) Collect(ctx context.Context) ([]Elem, error) {
iter := b.Iter()
c, err := iter.Total(ctx)
if err != nil {
return nil, errors.Wrap(err, "get total")
}
r := make([]Elem, 0, c)
for iter.Next(ctx) {
r = append(r, iter.Value())
}
return r, iter.Err()
}
@@ -0,0 +1,3 @@
package blocked
//go:generate go run go.mau.fi/mautrix-telegram/pkg/gotd/telegram/query/internal/itergen -result=ContactsBlockedClass -package=blocked -prefix=Contacts -out=queries.gen.go