tgclient

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: MIT Imports: 33 Imported by: 0

Documentation

Overview

Package tgclient wraps gotd: connection, locking, session storage, peer resolution and the JSON shapes. Commands talk to the Telegram interface so they can be tested against a fake (see tgfake).

Index

Constants

View Source
const DefaultMentionScan = 50

DefaultMentionScan is how many recent groups an account-wide mention search visits.

Variables

This section is empty.

Functions

func DisplayName

func DisplayName(first, last string) string

DisplayName follows Telethon's get_display_name.

func FloodWaitMiddleware

func FloodWaitMiddleware(max time.Duration, retries int) telegram.Middleware

FloodWaitMiddleware sleeps through short FLOOD_WAITs (≤ max) and retries, like Telethon's flood_sleep_threshold.

func ISO

func ISO(t time.Time) string

ISO formats a time as UTC "2006-01-02T15:04:05Z".

func MapError

func MapError(err error) error

MapError turns gotd/guard errors into the stable output errors.

func MarkedID

func MarkedID(k Kind, raw int64) int64

MarkedID turns a raw id into the marked form: users +id, basic groups -id, channels -100id.

func MediaFilename

func MediaFilename(info *Media, date time.Time) string

MediaFilename is the attachment's own (sanitised) name, else Telethon-style kind_date.ext.

func PeerMarkedID

func PeerMarkedID(p tg.PeerClass) int64

PeerMarkedID returns the marked id of a tg.PeerClass (0 if nil).

func Run

func Run(ctx context.Context, opts Options, fn func(ctx context.Context, c *Conn) error) error

Run takes the data dir lock, connects, calls fn, disconnects and saves the peer cache.

func RunSession

func RunSession(ctx context.Context, opts Options, fn func(ctx context.Context, t Telegram) error) error

RunSession is Run for the read/send commands: authorised, wrapped as Telegram.

func SanitizeFilename

func SanitizeFilename(name string) string

SanitizeFilename keeps only a safe base name: no directories, no leading dots, no control chars.

Types

type ChatInfo

type ChatInfo struct {
	ID            int64   `json:"id"`
	Name          string  `json:"name"`
	Type          string  `json:"type"`
	Username      *string `json:"username"`
	Phone         *string `json:"phone,omitempty"`
	Contact       *bool   `json:"contact,omitempty"`
	MutualContact *bool   `json:"mutual_contact,omitempty"`
	About         *string `json:"about,omitempty"`
	Members       *int    `json:"members,omitempty"`
}

ChatInfo is `chats show` output.

type ChatRef

type ChatRef struct {
	ID   int64  `json:"id"`
	Name string `json:"name"`
	Type string `json:"type"`
}

ChatRef is the short chat object in command output.

type Conn

type Conn struct {
	Client *telegram.Client
	API    *tg.Client
	Config config.Config
	Cache  *PeerCache
	Self   *tg.User // set when Options.NeedAuth
}

Conn is a locked, connected client handed to Run's callback.

func (*Conn) Session

func (c *Conn) Session() *Session

Session returns the Telegram implementation over this connection.

type ContactsResult

type ContactsResult struct {
	Mine   []User `json:"mine"`
	Public []User `json:"public"`
}

ContactsResult is `contacts search` output.

type Dialog

type Dialog struct {
	ID       int64        `json:"id"`
	Name     string       `json:"name"`
	Type     string       `json:"type"`
	Username *string      `json:"username"`
	Unread   int          `json:"unread"`
	Mentions int          `json:"mentions"`
	Pinned   bool         `json:"pinned"`
	Archived bool         `json:"archived"`
	Muted    bool         `json:"muted"`
	Last     *LastMessage `json:"last,omitempty"`

	Peer           Peer `json:"-"`
	TopMessage     int  `json:"-"`
	ReadInboxMaxID int  `json:"-"`
}

Dialog is one entry of the chat list.

func MatchDialogs

func MatchDialogs(name string, dialogs []Dialog) []Dialog

MatchDialogs picks dialogs by name: exact (case-insensitive) matches, else substring matches.

type Download

type Download struct {
	Path  string `json:"path"`
	Media *Media `json:"media"`
}

Download is `media download` output.

type FileStorage

type FileStorage struct {
	Path  string
	Write func(path string, data []byte) error
}

FileStorage is gotd session storage: an atomically written 0600 JSON file.

func (*FileStorage) LoadSession

func (f *FileStorage) LoadSession(context.Context) ([]byte, error)

func (*FileStorage) StoreSession

func (f *FileStorage) StoreSession(_ context.Context, data []byte) error

type Folder

type Folder int

Folder selects dialogs by folder.

const (
	FolderAll     Folder = iota // main list and archive
	FolderMain                  // main list only
	FolderArchive               // archive only
)

type HistoryQuery

type HistoryQuery struct {
	Limit      int
	OffsetID   int       // ids below this (or above it when Reverse)
	OffsetDate time.Time // messages before this (or after it when Reverse)
	MinID      int       // exclusive
	MaxID      int       // exclusive
	Reverse    bool      // oldest first
	Topic      int       // forum topic id (messages.getReplies)
}

HistoryQuery mirrors Telethon's iter_messages arguments.

type Kind

type Kind string

Kind is the MTProto peer kind.

const (
	KindUser    Kind = "user"
	KindChat    Kind = "chat"
	KindChannel Kind = "channel"
)

func SplitMarked

func SplitMarked(id int64) (Kind, int64)

SplitMarked is the inverse of MarkedID.

type LastMessage

type LastMessage struct {
	ID     int     `json:"id"`
	Date   string  `json:"date"`
	FromMe bool    `json:"from_me"`
	Text   string  `json:"text"`
	Media  *string `json:"media"`
}

LastMessage is the dialog's top message preview.

type Media

type Media struct {
	Type     string `json:"type"`
	Name     string `json:"name,omitempty"`
	Mime     string `json:"mime,omitempty"`
	Size     int64  `json:"size,omitempty"`
	URL      string `json:"url,omitempty"`
	Title    string `json:"title,omitempty"`
	Question string `json:"question,omitempty"`
}

Media describes an attachment.

func MediaInfo

func MediaInfo(mc tg.MessageMediaClass) *Media

MediaInfo is the prototype's media_info.

type MentionsQuery

type MentionsQuery struct {
	Unread bool // messages.getUnreadMentions (does not mark them read)
	Limit  int
	Scan   int // without a chat and Unread: how many recent groups to search (0 = default)
}

MentionsQuery lists mentions/replies to the user.

type Message

type Message struct {
	ID            int     `json:"id"`
	ChatID        int64   `json:"chat_id"`
	ChatName      *string `json:"chat_name"`
	Date          string  `json:"date"`
	FromMe        bool    `json:"from_me"`
	SenderID      *int64  `json:"sender_id"`
	SenderName    *string `json:"sender_name"`
	Text          string  `json:"text"`
	Edited        string  `json:"edited,omitempty"`
	ReplyTo       int     `json:"reply_to,omitempty"`
	ForwardedFrom any     `json:"forwarded_from,omitempty"`
	Media         *Media  `json:"media,omitempty"`
	Album         int64   `json:"album,omitempty"`
	Service       string  `json:"service,omitempty"`
	Views         *int    `json:"views,omitempty"`
	Mentioned     bool    `json:"mentioned,omitempty"`

	Time time.Time `json:"-"`
}

Message is the JSON shape of a message (field names from the prototype).

type Options

type Options struct {
	Paths      config.Paths
	AppVersion string
	AuthMode   bool // allow auth.* methods through the read-only guard
	NeedAuth   bool // fail with an auth error unless the session is logged in
	// UpdateHandler enables updates (needed for QR login); nil means no updates.
	UpdateHandler telegram.UpdateHandler
	// Middlewares run after the read-only guard, i.e. they see only what goes to the network.
	Middlewares []telegram.Middleware
}

Options configures one connection.

type Peer

type Peer struct {
	ID         int64  `json:"id"`
	Name       string `json:"name"`
	Type       string `json:"type"`
	Username   string `json:"username,omitempty"`
	Kind       Kind   `json:"-"`
	RawID      int64  `json:"-"`
	AccessHash int64  `json:"-"`
}

Peer is a resolved chat or user. AccessHash never leaves the process.

func PickByName

func PickByName(name string, dialogs []Dialog) (*Peer, error)

PickByName resolves a name among dialogs: one hit, not found, or ambiguous (up to 10 candidates).

func (*Peer) InputPeer

func (p *Peer) InputPeer() tg.InputPeerClass

InputPeer builds the MTProto input peer.

func (*Peer) IsGroup

func (p *Peer) IsGroup() bool

IsGroup is true for basic groups, supergroups and forums.

func (*Peer) Ref

func (p *Peer) Ref() ChatRef

Ref returns the short output form.

type PeerCache

type PeerCache struct {
	// contains filtered or unexported fields
}

PeerCache remembers access hashes so numeric ids resolve without walking every dialog. It is a cache: a missing or corrupt file just starts empty.

func LoadPeerCache

func LoadPeerCache(path string) *PeerCache

LoadPeerCache reads path; errors yield an empty cache.

func (*PeerCache) FindPhone

func (c *PeerCache) FindPhone(digits string) (Peer, bool)

FindPhone looks a user up by phone digits.

func (*PeerCache) Get

func (c *PeerCache) Get(id int64) (Peer, bool)

Get returns a cached peer by marked id.

func (*PeerCache) Len

func (c *PeerCache) Len() int

Len is the number of cached peers.

func (*PeerCache) Put

func (c *PeerCache) Put(p Peer, phone string, min bool)

Put stores p. A min access hash never replaces a known full one.

func (*PeerCache) Save

func (c *PeerCache) Save(write func(path string, data []byte) error) error

Save writes the cache with write (an atomic 0600 writer) if it changed.

type Ref

type Ref struct {
	Kind  RefKind
	ID    int64
	Value string // username, invite hash, phone digits, or name
}

Ref is a parsed --chat value.

func ParseRef

func ParseRef(s string) (Ref, error)

ParseRef classifies a --chat value.

type RefKind

type RefKind int

RefKind says how a --chat value should be resolved.

const (
	RefID       RefKind = iota // marked id (also t.me/c/<id> links)
	RefUsername                // @name, t.me/name, tg://resolve
	RefInvite                  // t.me/+hash, t.me/joinchat/hash
	RefPhone                   // +digits
	RefName                    // dialog name
)

type SearchQuery

type SearchQuery struct {
	Query  string
	From   *Peer // sender filter; needs a chat
	Limit  int
	After  time.Time
	Before time.Time
}

SearchQuery is a text search in one chat or account-wide.

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session implements Telegram over a connected gotd client.

func NewSession

func NewSession(api *tg.Client, cache *PeerCache, self *tg.User) *Session

NewSession wraps an authorised client. self is the logged-in user.

func (*Session) DownloadMedia

func (s *Session) DownloadMedia(ctx context.Context, p *Peer, msgID int, dir string) (*Download, error)

func (*Session) History

func (s *Session) History(ctx context.Context, p *Peer, q HistoryQuery) ([]Message, error)

func (*Session) IterDialogs

func (s *Session) IterDialogs(ctx context.Context, folder Folder, fn func(Dialog) bool) error

func (*Session) Mentions

func (s *Session) Mentions(ctx context.Context, p *Peer, q MentionsQuery) ([]Message, error)

Mentions never marks anything read. Without a chat it visits dialogs one by one: messages.searchGlobal rejects the my-mentions filter (INPUT_FILTER_INVALID).

func (*Session) MessagesByID

func (s *Session) MessagesByID(ctx context.Context, p *Peer, ids []int) ([]Message, error)

func (*Session) PeerInfo

func (s *Session) PeerInfo(ctx context.Context, p *Peer) (*ChatInfo, error)

func (*Session) Resolve

func (s *Session) Resolve(ctx context.Context, ref string) (*Peer, error)

Resolve finds a peer: marked id (cache, then dialogs), @username / t.me link, +phone (cache, contacts, then contacts.resolvePhone), or dialog name.

func (*Session) Search

func (s *Session) Search(ctx context.Context, p *Peer, q SearchQuery) ([]Message, error)

func (*Session) SearchContacts

func (s *Session) SearchContacts(ctx context.Context, query string, limit int) (*ContactsResult, error)

func (*Session) Self

func (s *Session) Self(context.Context) (*User, error)

func (*Session) SendFile

func (s *Session) SendFile(ctx context.Context, p *Peer, path, caption string, reply int) (*Message, error)

func (*Session) SendText

func (s *Session) SendText(ctx context.Context, p *Peer, text string, reply int) (*Message, error)

type Telegram

type Telegram interface {
	Self(ctx context.Context) (*User, error)

	// IterDialogs calls fn for each dialog (pinned first, then by recency) until fn returns false.
	IterDialogs(ctx context.Context, folder Folder, fn func(Dialog) bool) error
	// Resolve accepts a marked id, @username, t.me link, +phone, or a dialog name.
	Resolve(ctx context.Context, ref string) (*Peer, error)
	PeerInfo(ctx context.Context, p *Peer) (*ChatInfo, error)

	History(ctx context.Context, p *Peer, q HistoryQuery) ([]Message, error)
	// Search searches one chat, or the whole account when p is nil.
	Search(ctx context.Context, p *Peer, q SearchQuery) ([]Message, error)
	MessagesByID(ctx context.Context, p *Peer, ids []int) ([]Message, error)
	// Mentions lists messages that mention or reply to the user, in one chat or all (p nil).
	Mentions(ctx context.Context, p *Peer, q MentionsQuery) ([]Message, error)

	SearchContacts(ctx context.Context, query string, limit int) (*ContactsResult, error)
	DownloadMedia(ctx context.Context, p *Peer, msgID int, dir string) (*Download, error)

	SendText(ctx context.Context, p *Peer, text string, replyTo int) (*Message, error)
	SendFile(ctx context.Context, p *Peer, path, caption string, replyTo int) (*Message, error)
}

Telegram is everything the read/send commands need from an authorised session.

type TelethonImport

type TelethonImport struct {
	Data  *session.Data
	Peers []TelethonPeer
}

TelethonImport is what a Telethon SQLite session yields.

func ReadTelethonSession

func ReadTelethonSession(path string) (*TelethonImport, error)

ReadTelethonSession reads the `sessions` row (dc_id, server_address, port, auth_key) and the `entities` table of a Telethon .session file, read-only.

type TelethonPeer

type TelethonPeer struct {
	Peer  Peer
	Phone string
}

TelethonPeer is one row of Telethon's entities table (marked id + access hash).

type User

type User struct {
	ID            int64   `json:"id"`
	Name          string  `json:"name"`
	Type          string  `json:"type"`
	Username      *string `json:"username"`
	Phone         *string `json:"phone"`
	Contact       bool    `json:"contact"`
	MutualContact bool    `json:"-"`
}

User is the JSON shape of a user (or a chat in contact search).

func PeerUserJSON

func PeerUserJSON(p Peer) User

PeerUserJSON is user_json for a non-user peer (contact search results).

func UserJSON

func UserJSON(u *tg.User) User

UserJSON is the prototype's user_json.

Directories

Path Synopsis
Package tgfake is an in-memory tgclient.Telegram for tests: no network.
Package tgfake is an in-memory tgclient.Telegram for tests: no network.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL