Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion cmd/tg/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@ func (h historyResult) MarshalText(w io.Writer) error {
// listHistory reads up to limit recent messages from peer (newest-first from the
// API), returning them oldest-first.
func listHistory(ctx context.Context, api *tg.Client, peer tg.InputPeerClass, limit int) (historyResult, error) {
iter := query.Messages(api).GetHistory(peer).Iter()
// Fetch in large batches to minimize round trips. The iterator's default
// batch size is 1, so it issues one messages.getHistory RPC per message,
// which makes larger --limit values extremely slow. Telegram does not
// reject a per-request limit above 100 but silently returns fewer/incorrect
// results, so cap at 100. Clamp to at least 1: a non-positive batch size
// would panic the iterator (it preallocates a slice with that capacity).
batch := max(1, min(limit, 100))
iter := query.Messages(api).GetHistory(peer).BatchSize(batch).Iter()

var res historyResult
for iter.Next(ctx) {
Expand Down
38 changes: 38 additions & 0 deletions cmd/tg/history_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,41 @@ func TestListHistoryLimit(t *testing.T) {
t.Fatalf("limit not respected: got %d", len(res.Messages))
}
}

// TestListHistoryBatchSize asserts the per-request limit is batched (capped at
// 100) instead of the iterator default of 1, and never goes below 1 (a
// non-positive batch size panics the iterator).
func TestListHistoryBatchSize(t *testing.T) {
for _, tt := range []struct {
limit int
wantBatch int
}{
{limit: 5, wantBatch: 5},
{limit: 100, wantBatch: 100},
{limit: 350, wantBatch: 100},
{limit: 0, wantBatch: 1},
{limit: -1, wantBatch: 1},
} {
var gotBatch int
api := newFuncAPI(t, func(req bin.Encoder) (bin.Encoder, error) {
r, ok := req.(*tg.MessagesGetHistoryRequest)
if !ok {
return nil, errors.Errorf("unexpected request %T", req)
}
gotBatch = r.Limit
return &tg.MessagesMessages{
Messages: []tg.MessageClass{
&tg.Message{ID: 1, PeerID: &tg.PeerUser{UserID: 5}, Date: 1},
},
Users: []tg.UserClass{&tg.User{ID: 5}},
}, nil
})

if _, err := listHistory(context.Background(), api, &tg.InputPeerSelf{}, tt.limit); err != nil {
t.Fatalf("limit %d: %v", tt.limit, err)
}
if gotBatch != tt.wantBatch {
t.Errorf("limit %d: request limit = %d, want %d", tt.limit, gotBatch, tt.wantBatch)
}
}
}