-
-
Notifications
You must be signed in to change notification settings - Fork 393
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package tclient | ||
|
||
import "github.com/gotd/td/telegram" | ||
|
||
const ( | ||
AppBuiltin = "builtin" | ||
AppDesktop = "desktop" | ||
) | ||
|
||
var Apps = map[string]struct { | ||
AppID int | ||
AppHash string | ||
}{ | ||
// application created by iyear | ||
AppBuiltin: {AppID: 15055931, AppHash: "021d433426cbb920eeb95164498fe3d3"}, | ||
// application created by tdesktop. | ||
// https://opentele.readthedocs.io/en/latest/documentation/authorization/api/#class-telegramdesktop | ||
AppDesktop: {AppID: 2040, AppHash: "b18441a1ff607e10a989891a5462e627"}, | ||
} | ||
|
||
var Device = telegram.DeviceConfig{ | ||
DeviceModel: "Desktop", | ||
SystemVersion: "Windows 10", | ||
AppVersion: "4.2.4 x64", | ||
LangCode: "en", | ||
SystemLangCode: "en-US", | ||
LangPack: "tdesktop", | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package tclient | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/cenkalti/backoff/v4" | ||
"github.com/go-faster/errors" | ||
"github.com/gotd/contrib/middleware/floodwait" | ||
"github.com/gotd/contrib/middleware/ratelimit" | ||
tdclock "github.com/gotd/td/clock" | ||
"github.com/gotd/td/telegram" | ||
"github.com/gotd/td/telegram/dcs" | ||
"golang.org/x/net/proxy" | ||
"golang.org/x/time/rate" | ||
|
||
"github.com/iyear/tdl/pkg/clock" | ||
"github.com/iyear/tdl/pkg/key" | ||
"github.com/iyear/tdl/pkg/kv" | ||
"github.com/iyear/tdl/pkg/logger" | ||
"github.com/iyear/tdl/pkg/recovery" | ||
"github.com/iyear/tdl/pkg/retry" | ||
"github.com/iyear/tdl/pkg/storage" | ||
"github.com/iyear/tdl/pkg/utils" | ||
) | ||
|
||
type Options struct { | ||
KV kv.KV | ||
Proxy string | ||
NTP string | ||
ReconnectTimeout time.Duration | ||
Test bool | ||
} | ||
|
||
func New(ctx context.Context, o Options, login bool, middlewares ...telegram.Middleware) (*telegram.Client, error) { | ||
_clock := tdclock.System | ||
if ntp := o.NTP; ntp != "" { | ||
var err error | ||
_clock, err = clock.New() | ||
if err != nil { | ||
return nil, errors.Wrap(err, "create network clock") | ||
} | ||
} | ||
|
||
mode, err := o.KV.Get(key.App()) | ||
if err != nil { | ||
mode = []byte(AppBuiltin) | ||
} | ||
app, ok := Apps[string(mode)] | ||
if !ok { | ||
return nil, fmt.Errorf("can't find app: %s, please try re-login", mode) | ||
} | ||
appId, appHash := app.AppID, app.AppHash | ||
|
||
// process proxy | ||
var dialer dcs.DialFunc = proxy.Direct.DialContext | ||
if p := o.Proxy; p != "" { | ||
d, err := utils.Proxy.GetDial(p) | ||
if err != nil { | ||
return nil, errors.Wrap(err, "get dialer") | ||
} | ||
dialer = d.DialContext | ||
} | ||
|
||
opts := telegram.Options{ | ||
Resolver: dcs.Plain(dcs.PlainOptions{ | ||
Dial: dialer, | ||
}), | ||
ReconnectionBackoff: func() backoff.BackOff { | ||
return newBackoff(o.ReconnectTimeout) | ||
}, | ||
Device: Device, | ||
SessionStorage: storage.NewSession(o.KV, login), | ||
RetryInterval: 5 * time.Second, | ||
MaxRetries: -1, // infinite retries | ||
DialTimeout: 10 * time.Second, | ||
Middlewares: append(NewDefaultMiddlewares(ctx, o.ReconnectTimeout), middlewares...), | ||
Clock: _clock, | ||
Logger: logger.From(ctx).Named("td"), | ||
} | ||
|
||
// test mode, hook options | ||
if o.Test { | ||
appId, appHash = telegram.TestAppID, telegram.TestAppHash | ||
opts.DC = 2 | ||
opts.DCList = dcs.Test() | ||
// add rate limit to avoid frequent flood wait | ||
opts.Middlewares = append(opts.Middlewares, ratelimit.New(rate.Every(100*time.Millisecond), 5)) | ||
} | ||
|
||
return telegram.NewClient(appId, appHash, opts), nil | ||
} | ||
|
||
func NewDefaultMiddlewares(ctx context.Context, timeout time.Duration) []telegram.Middleware { | ||
return []telegram.Middleware{ | ||
recovery.New(ctx, newBackoff(timeout)), | ||
retry.New(5), | ||
floodwait.NewSimpleWaiter(), | ||
} | ||
} | ||
|
||
func newBackoff(timeout time.Duration) backoff.BackOff { | ||
b := backoff.NewExponentialBackOff() | ||
|
||
b.Multiplier = 1.1 | ||
b.MaxElapsedTime = timeout | ||
b.MaxInterval = 10 * time.Second | ||
return b | ||
} | ||
|
||
func Run(ctx context.Context, client *telegram.Client, f func(ctx context.Context) error) error { | ||
return client.Run(ctx, func(ctx context.Context) error { | ||
status, err := client.Auth().Status(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
if !status.Authorized { | ||
return fmt.Errorf("not authorized. please login first") | ||
} | ||
|
||
return f(ctx) | ||
}) | ||
} |