mirror of
https://github.com/tgdrive/teldrive.git
synced 2025-01-09 16:49:51 +08:00
240 lines
5.5 KiB
Go
240 lines
5.5 KiB
Go
package utils
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cenkalti/backoff/v4"
|
|
"github.com/divyam234/teldrive/types"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/gotd/contrib/bg"
|
|
"github.com/gotd/contrib/middleware/floodwait"
|
|
tdclock "github.com/gotd/td/clock"
|
|
"github.com/gotd/td/session"
|
|
"github.com/gotd/td/telegram"
|
|
"github.com/pkg/errors"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
var clients map[int64]*telegram.Client
|
|
|
|
var Workloads map[int]int
|
|
|
|
func getDeviceConfig() telegram.DeviceConfig {
|
|
appConfig := GetConfig()
|
|
config := telegram.DeviceConfig{
|
|
DeviceModel: appConfig.TgClientDeviceModel,
|
|
SystemVersion: appConfig.TgClientSystemVersion,
|
|
AppVersion: appConfig.TgClientAppVersion,
|
|
SystemLangCode: appConfig.TgClientSystemLangCode,
|
|
LangPack: appConfig.TgClientLangPack,
|
|
LangCode: appConfig.TgClientLangCode,
|
|
}
|
|
return config
|
|
}
|
|
|
|
func reconnectionBackoff() backoff.BackOff {
|
|
_clock := tdclock.System
|
|
b := backoff.NewExponentialBackOff()
|
|
b.Multiplier = 1.1
|
|
b.MaxElapsedTime = time.Duration(120) * time.Second
|
|
b.Clock = _clock
|
|
return b
|
|
}
|
|
|
|
func GetBotClient(clientName string) *telegram.Client {
|
|
|
|
config := GetConfig()
|
|
sessionStorage := &telegram.FileSessionStorage{
|
|
Path: filepath.Join("sessions", clientName+".json"),
|
|
}
|
|
middlewares := []telegram.Middleware{floodwait.NewSimpleWaiter()}
|
|
|
|
options := telegram.Options{
|
|
SessionStorage: sessionStorage,
|
|
Middlewares: middlewares,
|
|
ReconnectionBackoff: reconnectionBackoff,
|
|
RetryInterval: 5 * time.Second,
|
|
MaxRetries: 5,
|
|
Device: getDeviceConfig(),
|
|
Clock: tdclock.System,
|
|
}
|
|
|
|
client := telegram.NewClient(config.AppId, config.AppHash, options)
|
|
|
|
return client
|
|
|
|
}
|
|
|
|
func GetAuthClient(ctx context.Context, sessionStr string, userId int64) (*telegram.Client, error) {
|
|
|
|
data, err := session.TelethonSession(sessionStr)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var (
|
|
storage = new(session.StorageMemory)
|
|
loader = session.Loader{Storage: storage}
|
|
)
|
|
|
|
if err := loader.Save(ctx, data); err != nil {
|
|
return nil, err
|
|
}
|
|
middlewares := []telegram.Middleware{floodwait.NewSimpleWaiter()}
|
|
client := telegram.NewClient(config.AppId, config.AppHash, telegram.Options{
|
|
SessionStorage: storage,
|
|
Middlewares: middlewares,
|
|
ReconnectionBackoff: reconnectionBackoff,
|
|
RetryInterval: 5 * time.Second,
|
|
MaxRetries: 5,
|
|
Device: getDeviceConfig(),
|
|
Clock: tdclock.System,
|
|
})
|
|
|
|
return client, nil
|
|
}
|
|
|
|
func GetNonAuthClient(handler telegram.UpdateHandler, storage telegram.SessionStorage) *telegram.Client {
|
|
client := telegram.NewClient(config.AppId, config.AppHash, telegram.Options{
|
|
SessionStorage: storage,
|
|
Device: getDeviceConfig(),
|
|
UpdateHandler: handler,
|
|
ReconnectionBackoff: reconnectionBackoff,
|
|
RetryInterval: 5 * time.Second,
|
|
MaxRetries: 5,
|
|
})
|
|
|
|
return client
|
|
}
|
|
|
|
func startBotClient(ctx context.Context, client *telegram.Client, token string) (bg.StopFunc, error) {
|
|
|
|
stop, err := bg.Connect(client)
|
|
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "failed to start client")
|
|
}
|
|
|
|
tguser, err := client.Self(ctx)
|
|
|
|
if err != nil {
|
|
|
|
if _, err := client.Auth().Bot(ctx, token); err != nil {
|
|
return nil, err
|
|
}
|
|
tguser, _ = client.Self(ctx)
|
|
}
|
|
|
|
Logger.Info("started Client", zap.String("user", tguser.Username))
|
|
return stop, nil
|
|
}
|
|
|
|
func startAuthClient(c *gin.Context, client *telegram.Client) (bg.StopFunc, error) {
|
|
stop, err := bg.Connect(client)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
tguser, err := client.Self(c)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
Logger.Info("started Client", zap.String("user", tguser.Username))
|
|
|
|
clients[tguser.GetID()] = client
|
|
|
|
return stop, nil
|
|
}
|
|
|
|
func InitBotClients() {
|
|
|
|
ctx := context.Background()
|
|
|
|
clients = make(map[int64]*telegram.Client)
|
|
Workloads = make(map[int]int)
|
|
|
|
if config.MultiClient {
|
|
sessionDir := "sessions"
|
|
|
|
if err := os.MkdirAll(sessionDir, 0700); err != nil {
|
|
return
|
|
}
|
|
|
|
var keysToSort []string
|
|
|
|
for _, e := range os.Environ() {
|
|
if strings.HasPrefix(e, "MULTI_TOKEN") {
|
|
if i := strings.Index(e, "="); i >= 0 {
|
|
keysToSort = append(keysToSort, e[:i])
|
|
}
|
|
}
|
|
}
|
|
|
|
sort.Strings(keysToSort)
|
|
|
|
for idx, key := range keysToSort {
|
|
client := GetBotClient(fmt.Sprintf("client%d", idx))
|
|
Workloads[idx] = 0
|
|
clients[int64(idx)] = client
|
|
go func(k string) {
|
|
startBotClient(ctx, client, os.Getenv(k))
|
|
}(key)
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func getMinWorkloadIndex() int {
|
|
smallest := Workloads[0]
|
|
idx := 0
|
|
for i, workload := range Workloads {
|
|
if workload < smallest {
|
|
smallest = workload
|
|
idx = i
|
|
}
|
|
}
|
|
return idx
|
|
}
|
|
|
|
func GetUploadClient(c *gin.Context) (*telegram.Client, int) {
|
|
if config.MultiClient {
|
|
idx := getMinWorkloadIndex()
|
|
Workloads[idx]++
|
|
return GetBotClient(fmt.Sprintf("client%d", idx)), idx
|
|
} else {
|
|
val, _ := c.Get("jwtUser")
|
|
jwtUser := val.(*types.JWTClaims)
|
|
userId, _ := strconv.ParseInt(jwtUser.Subject, 10, 64)
|
|
client, _ := GetAuthClient(c, jwtUser.TgSession, userId)
|
|
return client, -1
|
|
}
|
|
}
|
|
|
|
func GetDownloadClient(c *gin.Context) (*telegram.Client, int) {
|
|
if config.MultiClient {
|
|
idx := getMinWorkloadIndex()
|
|
Workloads[idx]++
|
|
return clients[int64(idx)], idx
|
|
} else {
|
|
val, _ := c.Get("jwtUser")
|
|
jwtUser := val.(*types.JWTClaims)
|
|
userId, _ := strconv.ParseInt(jwtUser.Subject, 10, 64)
|
|
if client, ok := clients[userId]; ok {
|
|
return client, -1
|
|
}
|
|
client, _ := GetAuthClient(c, jwtUser.TgSession, userId)
|
|
startAuthClient(c, client)
|
|
return client, -1
|
|
}
|
|
}
|