tgclient

package module
v0.167.2-0...-36fdf01 Latest Latest
Warning

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

Go to latest
Published: Jan 13, 2024 License: MIT Imports: 12 Imported by: 0

README

Attention! v0.166.2 has some important changes, check them out.

TG Client

It is a pure-Golang MTProto client for Telegram API.

Initially based on https://github.com/sdidyk/mtproto and https://github.com/ronaksoft/mtproto.

TL layer: 167

Consists of two parts:

  • mtproto — core part for API interaction;
  • tgclient — wrapper over mtproto with some useful logic like file download.

How to use it

You may use tg-history-dumper repo as an example, in particular this file: https://github.com/3bl3gamer/tg-history-dumper/blob/master/tg.go#L67

Create

First, TGClient object should be created with tgclient.NewTGClient or tgclient.NewTGClientExt for example:

tg := tgclient.NewTGClient(appID, appHash, &mtproto.SimpleLogHandler{})

And if you need more customization:

// Telegram client info
cfg := &mtproto.AppConfig{
    AppID:          appID,
    AppHash:        appHash,
    AppVersion:     "0.0.1",
    DeviceModel:    "Unknown",
    SystemVersion:  runtime.GOOS + "/" + runtime.GOARCH,
    SystemLangCode: "en",
    LangPack:       "",
    LangCode:       "en",
}

// store that will save/read session data
sessStore := &mtproto.SessFileStore{FPath: "tg_session.json"}

// optional dialer (may be nil) for proxying requests
dialer, err := proxy.SOCKS5("tcp", "127.0.0.1:9050", nil, proxy.Direct)

tg := tgclient.NewTGClientExt(cfg, sessStore, logHandler, dialer)
Connect

Then, the connection should be opened:

err := tg.InitAndConnect()
Auth

And client should authenticate with AuthAndInitEvents or AuthExt, for example:

// object that will... provide auth data:
// phone number, confirmation code and optionally password.
// ScanfAuthDataProvider will just prompt all this from terminal.
authDataProvider := mtproto.ScanfAuthDataProvider{}

err := tgclient.AuthAndInitEvents(authDataProvider)

While authing, AuthAndInitEvents sends mtproto.TL_updates_getState request. Same request will also be sent after each reconnection. It makes TG server send updates to client (like new incoming messages). If you do not need those (maybe you just want to dump your chats history), you may send something different:

authDataProvider := mtproto.ScanfAuthDataProvider{}
payload := mtproto.TL_users_getUsers{ID: []mtproto.TL{mtproto.TL_inputUserSelf{}}}

resp, err := tg.AuthExt(authDataProvider, payload)
// here resp should be a mtproto.VectorObject with one mtproto.TL_user item.
Communicate

With tg.SendSync or tg.SendSyncRetry. First one just sends request and returns response whatever it will be, so you generally should check if you got what you expected. For example:

res := c.tg.SendSync(mtproto.TL_contacts_resolveUsername{Username: "some chat name"})
peer, ok := res.(mtproto.TL_contacts_resolvedPeer)
if !ok {
  // res will likely be TL_rpc_error with message USERNAME_NOT_OCCUPIED or RPC_CALL_FAIL or other
  return mtproto.WrongRespError(res)
}
for _, chat := range peer.Chats {
    fmt.Printf("%#v\n", chat)
}

Often you will receive temporary errors like RPC_CALL_FAIL of FOOLD_WAIT_123 and want to re-send same request after little delay. This is done by

res := tg.SendSyncRetry(request, time.Second, 0, 30*time.Second)
Updates

Pass callback func:

tg.SetUpdateHandler(func(updateTL mtproto.TL) {
    switch update := updateTL.(type) {
        case mtproto.TL_updateUserStatus:
            fmt.Printf("U#%d %T\n", update.UserID, update.Status)
        case mtproto.TL_updateNewChannelMessage:
            ...
        case mtproto.TL_updateEditChannelMessage:
            ...
        ...
        default:
            return mtproto.WrongRespError(updateTL)
        }
    }
})

Updating API schema version (aka layer)

Get new schema from https://core.telegram.org/schema (remove definitions for int, long, double, string, vector, int128 and int256: they are hard-coded and must not be generated). If it is still outdated check other repos (like official ones), some useful links are at the top of generate_tl_schema.go.

Place new .tl file to mtproto/scheme folder.

Update //go:generate command in mtproto/mtproto.go. It should be

//go:generate go run scheme/generate_tl_schema.go <layer> scheme/<file>.tl tl_schema.go

Run go generate in mtproto folder.

Update this README.

TODO

  • if error occures while performing request to TL_invokeWithLayer in Connect(), two TL_invokeWithLayer may be sent. Nothing bad happens though.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Downloader

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

func (*Downloader) DownloadFileParts

func (d *Downloader) DownloadFileParts(
	file io.Writer, fileLocation mtproto.TL,
	dcID int32, size, partSize, offset int64,
	progressHnd FileProgressHandler,
) (*FilePartsResult, error)

func (*Downloader) DownloadFileToPath

func (d *Downloader) DownloadFileToPath(
	fpath string, fileLocation mtproto.TL, dcID int32, size int64, progressHnd FileProgressHandler,
) (*FilePartsResult, error)

func (*Downloader) ReqestFilePart

func (d *Downloader) ReqestFilePart(dcID int32, fileLocation mtproto.TL, offset, limit int64) chan *FileResponse

func (*Downloader) Start

func (d *Downloader) Start(tg *TGClient)

func (*Downloader) Stop

func (d *Downloader) Stop() error

type FilePartsResult

type FilePartsResult struct {
	Finished      bool
	ActualDcID    int32
	BytesRecieved int
	BytesWritten  int
}

type FileProgressHandler

type FileProgressHandler interface {
	OnProgress(fileLocation mtproto.TL, offset, size int64)
}

type FileResponse

type FileResponse struct {
	DcID int32
	Data []byte
	Err  error
}

type NoopFileProgressHandler

type NoopFileProgressHandler struct{}

func (NoopFileProgressHandler) OnProgress

func (h NoopFileProgressHandler) OnProgress(fileLocation mtproto.TL, offset, size int64)

type TGClient

type TGClient struct {
	Downloader
	// contains filtered or unexported fields
}

func NewTGClient

func NewTGClient(appID int32, appHash string, logHnd mtproto.LogHandler) *TGClient

func NewTGClientExt

func NewTGClientExt(cfg *mtproto.AppConfig, sessStore mtproto.SessionStore, logHnd mtproto.LogHandler, daler proxy.Dialer) *TGClient

func (*TGClient) AuthAndInitEvents

func (c *TGClient) AuthAndInitEvents(authData mtproto.AuthDataProvider) error

func (*TGClient) AuthExt

func (c *TGClient) AuthExt(authData mtproto.AuthDataProvider, message mtproto.TLReq) (mtproto.TL, error)

func (*TGClient) Disconnect

func (c *TGClient) Disconnect() error

func (*TGClient) FindExtraChannel

func (e *TGClient) FindExtraChannel(channelID int64) *mtproto.TL_channel

func (*TGClient) FindExtraChat

func (e *TGClient) FindExtraChat(chatID int64) *mtproto.TL_chat

func (*TGClient) FindExtraUser

func (e *TGClient) FindExtraUser(userID int64) *mtproto.TL_user

func (*TGClient) InitAndConnect

func (c *TGClient) InitAndConnect() error

func (*TGClient) SendSync

func (c *TGClient) SendSync(msg mtproto.TLReq) mtproto.TL

func (*TGClient) SendSyncRetry

func (c *TGClient) SendSyncRetry(
	msg mtproto.TLReq, failRetryInterval time.Duration,
	floodNumShortRetries int, floodMaxWait time.Duration,
) mtproto.TL

func (*TGClient) SetUpdateHandler

func (c *TGClient) SetUpdateHandler(handleUpdate UpdateHandler)

type UpdateHandler

type UpdateHandler func(mtproto.TL)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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