mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-06-02 22:20:41 +08:00
feat: add user client
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/dao"
|
"github.com/krau/SaveAny-Bot/dao"
|
||||||
"github.com/krau/SaveAny-Bot/queue"
|
"github.com/krau/SaveAny-Bot/queue"
|
||||||
"github.com/krau/SaveAny-Bot/types"
|
"github.com/krau/SaveAny-Bot/types"
|
||||||
|
"github.com/krau/SaveAny-Bot/userclient"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -153,7 +154,14 @@ func AddToQueue(ctx *ext.Context, update *ext.Update) error {
|
|||||||
task.StoragePath = path.Join(dir.Path, record.FileName)
|
task.StoragePath = path.Join(dir.Path, record.FileName)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
file, err := FileFromMessage(ctx, record.ChatID, record.MessageID, record.FileName)
|
var file *types.File
|
||||||
|
var err error
|
||||||
|
if record.UseUserClient && userclient.UC != nil {
|
||||||
|
uctx := userclient.UC.CreateContext()
|
||||||
|
file, err = FileFromMessage(uctx, record.ChatID, record.MessageID, record.FileName)
|
||||||
|
} else {
|
||||||
|
file, err = FileFromMessage(ctx, record.ChatID, record.MessageID, record.FileName)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Errorf("获取消息中的文件失败: %s", err)
|
common.Log.Errorf("获取消息中的文件失败: %s", err)
|
||||||
ctx.AnswerCallback(&tg.MessagesSetBotCallbackAnswerRequest{
|
ctx.AnswerCallback(&tg.MessagesSetBotCallbackAnswerRequest{
|
||||||
@@ -168,6 +176,7 @@ func AddToQueue(ctx *ext.Context, update *ext.Update) error {
|
|||||||
task = types.Task{
|
task = types.Task{
|
||||||
Ctx: ctx,
|
Ctx: ctx,
|
||||||
Status: types.Pending,
|
Status: types.Pending,
|
||||||
|
UseUserClient: record.UseUserClient,
|
||||||
FileDBID: record.ID,
|
FileDBID: record.ID,
|
||||||
File: file,
|
File: file,
|
||||||
StorageName: storageName,
|
StorageName: storageName,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/common"
|
"github.com/krau/SaveAny-Bot/common"
|
||||||
"github.com/krau/SaveAny-Bot/dao"
|
"github.com/krau/SaveAny-Bot/dao"
|
||||||
"github.com/krau/SaveAny-Bot/types"
|
"github.com/krau/SaveAny-Bot/types"
|
||||||
|
"github.com/krau/SaveAny-Bot/userclient"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -50,6 +51,31 @@ func parseLink(ctx *ext.Context, link string) (chatID int64, messageID int, err
|
|||||||
return chatID, messageID, nil
|
return chatID, messageID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use passed ctx client to fetch file from message,
|
||||||
|
//
|
||||||
|
// if failed try using userclient
|
||||||
|
func tryFetchFileFromMessage(ctx *ext.Context, chatID int64, messageID int, fileName string) (*types.File, bool, error) {
|
||||||
|
file, err := FileFromMessage(ctx, chatID, messageID, fileName)
|
||||||
|
if err == nil {
|
||||||
|
return file, false, nil
|
||||||
|
}
|
||||||
|
if (strings.Contains(err.Error(), "peer not found") || strings.Contains(err.Error(), "unexpected message type")) && userclient.UC != nil {
|
||||||
|
common.Log.Warnf("无法获取文件 %d:%d, 尝试使用 userbot: %s", chatID, messageID, err)
|
||||||
|
uctx := userclient.GetCtx()
|
||||||
|
// TODO: 群组支持
|
||||||
|
file, err = FileFromMessage(uctx, chatID, messageID, fileName)
|
||||||
|
if err == nil {
|
||||||
|
return file, true, nil
|
||||||
|
}
|
||||||
|
return nil, true, err
|
||||||
|
}
|
||||||
|
return nil, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func tryFetchMessage(ctx *ext.Context, chatID int64, messageID int) (*tg.Message, error) {
|
||||||
|
return GetTGMessage(ctx, chatID, messageID)
|
||||||
|
}
|
||||||
|
|
||||||
func handleLinkMessage(ctx *ext.Context, update *ext.Update) error {
|
func handleLinkMessage(ctx *ext.Context, update *ext.Update) error {
|
||||||
common.Log.Trace("Got link message")
|
common.Log.Trace("Got link message")
|
||||||
link := linkRegex.FindString(update.EffectiveMessage.Text)
|
link := linkRegex.FindString(update.EffectiveMessage.Text)
|
||||||
@@ -70,26 +96,25 @@ func handleLinkMessage(ctx *ext.Context, update *ext.Update) error {
|
|||||||
return dispatcher.EndGroups
|
return dispatcher.EndGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
// storages := storage.GetUserStorages(user.ChatID)
|
|
||||||
// if len(storages) == 0 {
|
|
||||||
// ctx.Reply(update, ext.ReplyTextString("无可用的存储"), nil)
|
|
||||||
// return dispatcher.EndGroups
|
|
||||||
// }
|
|
||||||
|
|
||||||
replied, err := ctx.Reply(update, ext.ReplyTextString("正在获取文件..."), nil)
|
replied, err := ctx.Reply(update, ext.ReplyTextString("正在获取文件..."), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Errorf("回复失败: %s", err)
|
common.Log.Errorf("回复失败: %s", err)
|
||||||
return dispatcher.EndGroups
|
return dispatcher.EndGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := FileFromMessage(ctx, linkChatID, messageID, "")
|
file, useUserClient, err := tryFetchFileFromMessage(ctx, linkChatID, messageID, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Errorf("获取文件失败: %s", err)
|
common.Log.Errorf("获取文件失败: %s", err)
|
||||||
ctx.Reply(update, ext.ReplyTextString("获取文件失败: "+err.Error()), nil)
|
ctx.Reply(update, ext.ReplyTextString("获取文件失败: "+err.Error()), nil)
|
||||||
return dispatcher.EndGroups
|
return dispatcher.EndGroups
|
||||||
}
|
}
|
||||||
if file.FileName == "" {
|
if file.FileName == "" {
|
||||||
file.FileName = GenFileNameFromMessage(*update.EffectiveMessage.Message, file)
|
msg, err := tryFetchMessage(ctx, linkChatID, messageID)
|
||||||
|
if err != nil {
|
||||||
|
file.FileName = fmt.Sprintf("%d_%d", linkChatID, messageID)
|
||||||
|
} else {
|
||||||
|
file.FileName = GenFileNameFromMessage(*msg, file)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
receivedFile := &dao.ReceivedFile{
|
receivedFile := &dao.ReceivedFile{
|
||||||
@@ -99,6 +124,7 @@ func handleLinkMessage(ctx *ext.Context, update *ext.Update) error {
|
|||||||
MessageID: messageID,
|
MessageID: messageID,
|
||||||
ReplyMessageID: replied.ID,
|
ReplyMessageID: replied.ID,
|
||||||
ReplyChatID: update.GetUserChat().GetID(),
|
ReplyChatID: update.GetUserChat().GetID(),
|
||||||
|
UseUserClient: useUserClient,
|
||||||
}
|
}
|
||||||
record, err := dao.SaveReceivedFile(receivedFile)
|
record, err := dao.SaveReceivedFile(receivedFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -116,6 +142,7 @@ func handleLinkMessage(ctx *ext.Context, update *ext.Update) error {
|
|||||||
Ctx: ctx,
|
Ctx: ctx,
|
||||||
Status: types.Pending,
|
Status: types.Pending,
|
||||||
FileDBID: record.ID,
|
FileDBID: record.ID,
|
||||||
|
UseUserClient: useUserClient,
|
||||||
File: file,
|
File: file,
|
||||||
StorageName: user.DefaultStorage,
|
StorageName: user.DefaultStorage,
|
||||||
UserID: user.ChatID,
|
UserID: user.ChatID,
|
||||||
|
|||||||
@@ -4,31 +4,38 @@ import (
|
|||||||
"github.com/celestix/gotgproto/dispatcher"
|
"github.com/celestix/gotgproto/dispatcher"
|
||||||
"github.com/celestix/gotgproto/dispatcher/handlers"
|
"github.com/celestix/gotgproto/dispatcher/handlers"
|
||||||
"github.com/celestix/gotgproto/dispatcher/handlers/filters"
|
"github.com/celestix/gotgproto/dispatcher/handlers/filters"
|
||||||
|
"github.com/celestix/gotgproto/ext"
|
||||||
"github.com/krau/SaveAny-Bot/common"
|
"github.com/krau/SaveAny-Bot/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RegisterHandlers(dispatcher dispatcher.Dispatcher) {
|
func RegisterHandlers(disp dispatcher.Dispatcher) {
|
||||||
dispatcher.AddHandler(handlers.NewMessage(filters.Message.All, checkPermission))
|
disp.AddHandler(handlers.NewMessage(filters.Message.ChatType(filters.ChatTypeChannel), func(ctx *ext.Context, u *ext.Update) error {
|
||||||
dispatcher.AddHandler(handlers.NewCommand("start", start))
|
return dispatcher.EndGroups
|
||||||
dispatcher.AddHandler(handlers.NewCommand("help", help))
|
}))
|
||||||
dispatcher.AddHandler(handlers.NewCommand("silent", silent))
|
disp.AddHandler(handlers.NewMessage(filters.Message.ChatType(filters.ChatTypeChat), func(ctx *ext.Context, u *ext.Update) error {
|
||||||
dispatcher.AddHandler(handlers.NewCommand("storage", storageCmd))
|
return dispatcher.EndGroups
|
||||||
dispatcher.AddHandler(handlers.NewCommand("save", saveCmd))
|
}))
|
||||||
dispatcher.AddHandler(handlers.NewCommand("dir", dirCmd))
|
disp.AddHandler(handlers.NewMessage(filters.Message.All, checkPermission))
|
||||||
dispatcher.AddHandler(handlers.NewCommand("rule", ruleCmd))
|
disp.AddHandler(handlers.NewCommand("start", start))
|
||||||
|
disp.AddHandler(handlers.NewCommand("help", help))
|
||||||
|
disp.AddHandler(handlers.NewCommand("silent", silent))
|
||||||
|
disp.AddHandler(handlers.NewCommand("storage", storageCmd))
|
||||||
|
disp.AddHandler(handlers.NewCommand("save", saveCmd))
|
||||||
|
disp.AddHandler(handlers.NewCommand("dir", dirCmd))
|
||||||
|
disp.AddHandler(handlers.NewCommand("rule", ruleCmd))
|
||||||
linkRegexFilter, err := filters.Message.Regex(linkRegexString)
|
linkRegexFilter, err := filters.Message.Regex(linkRegexString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Panicf("创建正则表达式过滤器失败: %s", err)
|
common.Log.Panicf("创建正则表达式过滤器失败: %s", err)
|
||||||
}
|
}
|
||||||
dispatcher.AddHandler(handlers.NewMessage(linkRegexFilter, handleLinkMessage))
|
disp.AddHandler(handlers.NewMessage(linkRegexFilter, handleLinkMessage))
|
||||||
telegraphUrlRegexFilter, err := filters.Message.Regex(TelegraphUrlRegexString)
|
telegraphUrlRegexFilter, err := filters.Message.Regex(TelegraphUrlRegexString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Panicf("创建 Telegraph URL 正则表达式过滤器失败: %s", err)
|
common.Log.Panicf("创建 Telegraph URL 正则表达式过滤器失败: %s", err)
|
||||||
}
|
}
|
||||||
dispatcher.AddHandler(handlers.NewMessage(telegraphUrlRegexFilter, handleTelegraph))
|
disp.AddHandler(handlers.NewMessage(telegraphUrlRegexFilter, handleTelegraph))
|
||||||
dispatcher.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("add"), AddToQueue))
|
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("add"), AddToQueue))
|
||||||
dispatcher.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("set_default"), setDefaultStorage))
|
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("set_default"), setDefaultStorage))
|
||||||
dispatcher.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("cancel"), cancelTask))
|
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("cancel"), cancelTask))
|
||||||
dispatcher.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("send_here"), sendFileToTelegram))
|
disp.AddHandler(handlers.NewCallbackQuery(filters.CallbackQuery.Prefix("send_here"), sendFileToTelegram))
|
||||||
dispatcher.AddHandler(handlers.NewMessage(filters.Message.Media, handleFileMessage))
|
disp.AddHandler(handlers.NewMessage(filters.Message.Media, handleFileMessage))
|
||||||
}
|
}
|
||||||
|
|||||||
12
cmd/run.go
12
cmd/run.go
@@ -1,6 +1,7 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
@@ -17,6 +18,7 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/i18n"
|
"github.com/krau/SaveAny-Bot/i18n"
|
||||||
"github.com/krau/SaveAny-Bot/i18n/i18nk"
|
"github.com/krau/SaveAny-Bot/i18n/i18nk"
|
||||||
"github.com/krau/SaveAny-Bot/storage"
|
"github.com/krau/SaveAny-Bot/storage"
|
||||||
|
"github.com/krau/SaveAny-Bot/userclient"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -76,5 +78,15 @@ func InitAll() {
|
|||||||
dao.Init()
|
dao.Init()
|
||||||
storage.LoadStorages()
|
storage.LoadStorages()
|
||||||
common.Init()
|
common.Init()
|
||||||
|
if config.Cfg.Telegram.Userbot.Enable {
|
||||||
|
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer cancel()
|
||||||
|
uc, err := userclient.Login(ctx)
|
||||||
|
if err != nil {
|
||||||
|
common.Log.Errorf("User client login failed: %s", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
common.Log.Infof("User client logged in as %s", uc.Self.FirstName)
|
||||||
|
}
|
||||||
bot.Init()
|
bot.Init()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,13 +51,19 @@ type dbConfig struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type telegramConfig struct {
|
type telegramConfig struct {
|
||||||
Token string `toml:"token" mapstructure:"token"`
|
Token string `toml:"token" mapstructure:"token"`
|
||||||
AppID int `toml:"app_id" mapstructure:"app_id" json:"app_id"`
|
AppID int `toml:"app_id" mapstructure:"app_id" json:"app_id"`
|
||||||
AppHash string `toml:"app_hash" mapstructure:"app_hash" json:"app_hash"`
|
AppHash string `toml:"app_hash" mapstructure:"app_hash" json:"app_hash"`
|
||||||
Timeout int `toml:"timeout" mapstructure:"timeout" json:"timeout"`
|
Timeout int `toml:"timeout" mapstructure:"timeout" json:"timeout"`
|
||||||
Proxy proxyConfig `toml:"proxy" mapstructure:"proxy"`
|
Proxy proxyConfig `toml:"proxy" mapstructure:"proxy"`
|
||||||
FloodRetry int `toml:"flood_retry" mapstructure:"flood_retry" json:"flood_retry"`
|
FloodRetry int `toml:"flood_retry" mapstructure:"flood_retry" json:"flood_retry"`
|
||||||
RpcRetry int `toml:"rpc_retry" mapstructure:"rpc_retry" json:"rpc_retry"`
|
RpcRetry int `toml:"rpc_retry" mapstructure:"rpc_retry" json:"rpc_retry"`
|
||||||
|
Userbot userbotConfig `toml:"userbot" mapstructure:"userbot" json:"userbot"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type userbotConfig struct {
|
||||||
|
Enable bool `toml:"enable" mapstructure:"enable"`
|
||||||
|
Session string `toml:"session" mapstructure:"session"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type proxyConfig struct {
|
type proxyConfig struct {
|
||||||
@@ -97,6 +103,8 @@ func Init() error {
|
|||||||
viper.SetDefault("telegram.timeout", 60)
|
viper.SetDefault("telegram.timeout", 60)
|
||||||
viper.SetDefault("telegram.flood_retry", 5)
|
viper.SetDefault("telegram.flood_retry", 5)
|
||||||
viper.SetDefault("telegram.rpc_retry", 5)
|
viper.SetDefault("telegram.rpc_retry", 5)
|
||||||
|
viper.SetDefault("telegram.userbot.enable", false)
|
||||||
|
viper.SetDefault("telegram.userbot.session", "data/usersession.db")
|
||||||
|
|
||||||
viper.SetDefault("temp.base_path", "cache/")
|
viper.SetDefault("temp.base_path", "cache/")
|
||||||
viper.SetDefault("temp.cache_ttl", 30)
|
viper.SetDefault("temp.cache_ttl", 30)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/krau/SaveAny-Bot/config"
|
"github.com/krau/SaveAny-Bot/config"
|
||||||
"github.com/krau/SaveAny-Bot/storage"
|
"github.com/krau/SaveAny-Bot/storage"
|
||||||
"github.com/krau/SaveAny-Bot/types"
|
"github.com/krau/SaveAny-Bot/types"
|
||||||
|
"github.com/krau/SaveAny-Bot/userclient"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -62,8 +63,11 @@ func processPendingTask(task *types.Task) error {
|
|||||||
if task.File.FileSize == 0 {
|
if task.File.FileSize == 0 {
|
||||||
return processPhoto(task, taskStorage)
|
return processPhoto(task, taskStorage)
|
||||||
}
|
}
|
||||||
|
api := bot.Client.API()
|
||||||
downloadBuilder := Downloader.Download(bot.Client.API(), task.File.Location).WithThreads(getTaskThreads(task.File.FileSize))
|
if task.UseUserClient && userclient.UC != nil {
|
||||||
|
api = userclient.UC.API()
|
||||||
|
}
|
||||||
|
downloadBuilder := Downloader.Download(api, task.File.Location).WithThreads(getTaskThreads(task.File.FileSize))
|
||||||
|
|
||||||
notsupportStreamStorage, notsupportStream := taskStorage.(storage.StorageNotSupportStream)
|
notsupportStreamStorage, notsupportStream := taskStorage.(storage.StorageNotSupportStream)
|
||||||
cancelMarkUp := getCancelTaskMarkup(task)
|
cancelMarkUp := getCancelTaskMarkup(task)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ type ReceivedFile struct {
|
|||||||
FileName string
|
FileName string
|
||||||
IsTelegraph bool
|
IsTelegraph bool
|
||||||
TelegraphURL string
|
TelegraphURL string
|
||||||
|
UseUserClient bool // Whether to use userbot client to fetch the file
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
|||||||
29
go.mod
29
go.mod
@@ -6,9 +6,14 @@ require (
|
|||||||
github.com/blang/semver v3.5.1+incompatible
|
github.com/blang/semver v3.5.1+incompatible
|
||||||
github.com/celestix/gotgproto v1.0.0-beta21
|
github.com/celestix/gotgproto v1.0.0-beta21
|
||||||
github.com/celestix/telegraph-go/v2 v2.0.4
|
github.com/celestix/telegraph-go/v2 v2.0.4
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0
|
||||||
|
github.com/charmbracelet/huh v0.7.0
|
||||||
|
github.com/charmbracelet/log v0.4.2
|
||||||
github.com/eko/gocache/lib/v4 v4.2.0
|
github.com/eko/gocache/lib/v4 v4.2.0
|
||||||
github.com/eko/gocache/store/go_cache/v4 v4.2.2
|
github.com/eko/gocache/store/go_cache/v4 v4.2.2
|
||||||
|
github.com/fatih/color v1.18.0
|
||||||
github.com/gabriel-vasile/mimetype v1.4.9
|
github.com/gabriel-vasile/mimetype v1.4.9
|
||||||
|
github.com/go-faster/errors v0.7.1
|
||||||
github.com/gookit/slog v0.5.8
|
github.com/gookit/slog v0.5.8
|
||||||
github.com/gotd/contrib v0.21.0
|
github.com/gotd/contrib v0.21.0
|
||||||
github.com/gotd/td v0.125.0
|
github.com/gotd/td v0.125.0
|
||||||
@@ -22,20 +27,30 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AnimeKaizoku/cacher v1.0.2 // indirect
|
github.com/AnimeKaizoku/cacher v1.0.2 // indirect
|
||||||
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
github.com/catppuccin/go v0.3.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/charmbracelet/bubbles v0.21.0 // indirect
|
||||||
|
github.com/charmbracelet/bubbletea v1.3.4 // indirect
|
||||||
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0 // indirect
|
||||||
|
github.com/charmbracelet/x/ansi v0.8.0 // indirect
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 // indirect
|
||||||
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
github.com/coder/websocket v1.8.13 // indirect
|
github.com/coder/websocket v1.8.13 // indirect
|
||||||
github.com/dlclark/regexp2 v1.11.5 // indirect
|
github.com/dlclark/regexp2 v1.11.5 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
github.com/ghodss/yaml v1.0.0 // indirect
|
||||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||||
github.com/go-faster/errors v0.7.1 // indirect
|
|
||||||
github.com/go-faster/jx v1.1.0 // indirect
|
github.com/go-faster/jx v1.1.0 // indirect
|
||||||
github.com/go-faster/xor v1.0.0 // indirect
|
github.com/go-faster/xor v1.0.0 // indirect
|
||||||
github.com/go-faster/yaml v0.4.6 // indirect
|
github.com/go-faster/yaml v0.4.6 // indirect
|
||||||
github.com/go-ini/ini v1.67.0 // indirect
|
github.com/go-ini/ini v1.67.0 // indirect
|
||||||
|
github.com/go-logfmt/logfmt v0.6.0 // indirect
|
||||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||||
github.com/goccy/go-json v0.10.5 // indirect
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
@@ -48,10 +63,17 @@ require (
|
|||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
github.com/minio/crc64nvme v1.0.2 // indirect
|
github.com/minio/crc64nvme v1.0.2 // indirect
|
||||||
github.com/minio/md5-simd v1.1.2 // indirect
|
github.com/minio/md5-simd v1.1.2 // indirect
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
|
github.com/muesli/termenv v0.16.0 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/ogen-go/ogen v1.14.0 // indirect
|
github.com/ogen-go/ogen v1.14.0 // indirect
|
||||||
@@ -63,6 +85,7 @@ require (
|
|||||||
github.com/prometheus/common v0.64.0 // indirect
|
github.com/prometheus/common v0.64.0 // indirect
|
||||||
github.com/prometheus/procfs v0.16.1 // indirect
|
github.com/prometheus/procfs v0.16.1 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/rs/xid v1.6.0 // indirect
|
github.com/rs/xid v1.6.0 // indirect
|
||||||
github.com/segmentio/asm v1.2.0 // indirect
|
github.com/segmentio/asm v1.2.0 // indirect
|
||||||
github.com/tcnksm/go-gitconfig v0.1.2 // indirect
|
github.com/tcnksm/go-gitconfig v0.1.2 // indirect
|
||||||
|
|||||||
64
go.sum
64
go.sum
@@ -2,10 +2,20 @@ github.com/AnimeKaizoku/cacher v1.0.2 h1:7Bf5qRylWb7q2Evib0OXlhG37/t7BP2HK/7IyPv
|
|||||||
github.com/AnimeKaizoku/cacher v1.0.2/go.mod h1:jw0de/b0K6W7Y3T9rHCMGVKUf6oG7hENNcssxYcZTCc=
|
github.com/AnimeKaizoku/cacher v1.0.2/go.mod h1:jw0de/b0K6W7Y3T9rHCMGVKUf6oG7hENNcssxYcZTCc=
|
||||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
|
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||||
|
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||||
|
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||||
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
|
github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8=
|
||||||
|
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
|
||||||
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||||
|
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
|
||||||
|
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
||||||
github.com/celestix/gotgproto v1.0.0-beta21 h1:VUuAC/Kj5Sdu/WZan3ZUb0GFNAavFxMYxmHAhCBX0J8=
|
github.com/celestix/gotgproto v1.0.0-beta21 h1:VUuAC/Kj5Sdu/WZan3ZUb0GFNAavFxMYxmHAhCBX0J8=
|
||||||
github.com/celestix/gotgproto v1.0.0-beta21/go.mod h1:viDkHe9rBegJoEE/jNuFfbBM0XZ3pSx/ugjaNaVnbvU=
|
github.com/celestix/gotgproto v1.0.0-beta21/go.mod h1:viDkHe9rBegJoEE/jNuFfbBM0XZ3pSx/ugjaNaVnbvU=
|
||||||
github.com/celestix/telegraph-go/v2 v2.0.4 h1:w8HWymJFhMSMPjdGoyTh3/NqE3eXAT1njTvelh0338k=
|
github.com/celestix/telegraph-go/v2 v2.0.4 h1:w8HWymJFhMSMPjdGoyTh3/NqE3eXAT1njTvelh0338k=
|
||||||
@@ -14,9 +24,41 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
|
|||||||
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs=
|
||||||
|
github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg=
|
||||||
|
github.com/charmbracelet/bubbletea v1.3.4 h1:kCg7B+jSCFPLYRA52SDZjr51kG/fMUEoPoZrkaDHyoI=
|
||||||
|
github.com/charmbracelet/bubbletea v1.3.4/go.mod h1:dtcUCyCGEX3g9tosuYiut3MXgY/Jsv9nKVdibKKRRXo=
|
||||||
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
|
||||||
|
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
|
||||||
|
github.com/charmbracelet/huh v0.7.0 h1:W8S1uyGETgj9Tuda3/JdVkc3x7DBLZYPZc4c+/rnRdc=
|
||||||
|
github.com/charmbracelet/huh v0.7.0/go.mod h1:UGC3DZHlgOKHvHC07a5vHag41zzhpPFj34U92sOmyuk=
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
|
||||||
|
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
|
||||||
|
github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig=
|
||||||
|
github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw=
|
||||||
|
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
|
||||||
|
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
|
||||||
|
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
|
||||||
|
github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U=
|
||||||
|
github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ=
|
||||||
|
github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86 h1:JSt3B+U9iqk37QUU2Rvb6DSBYRLtWqFqfxf8l5hOZUA=
|
||||||
|
github.com/charmbracelet/x/errors v0.0.0-20240508181413-e8d8b6e2de86/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0=
|
||||||
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ=
|
||||||
|
github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U=
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0 h1:qko3AQ4gK1MTS/de7F5hPGx6/k1u0w4TeYmBFwzYVP4=
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20240722160745-212f7b056ed0/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
||||||
|
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||||
|
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||||
|
github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY=
|
||||||
|
github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo=
|
||||||
|
github.com/charmbracelet/x/xpty v0.1.2 h1:Pqmu4TEJ8KeA9uSkISKMU3f+C1F6OGBn8ABuGlqCbtI=
|
||||||
|
github.com/charmbracelet/x/xpty v0.1.2/go.mod h1:XK2Z0id5rtLWcpeNiMYBccNNBrP2IJnzHI0Lq13Xzq4=
|
||||||
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
|
github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
|
||||||
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||||
|
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
|
||||||
|
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||||
@@ -29,6 +71,8 @@ github.com/eko/gocache/lib/v4 v4.2.0 h1:MNykyi5Xw+5Wu3+PUrvtOCaKSZM1nUSVftbzmeC7
|
|||||||
github.com/eko/gocache/lib/v4 v4.2.0/go.mod h1:7ViVmbU+CzDHzRpmB4SXKyyzyuJ8A3UW3/cszpcqB4M=
|
github.com/eko/gocache/lib/v4 v4.2.0/go.mod h1:7ViVmbU+CzDHzRpmB4SXKyyzyuJ8A3UW3/cszpcqB4M=
|
||||||
github.com/eko/gocache/store/go_cache/v4 v4.2.2 h1:tAI9nl6TLoJyKG1ujF0CS0n/IgTEMl+NivxtR5R3/hw=
|
github.com/eko/gocache/store/go_cache/v4 v4.2.2 h1:tAI9nl6TLoJyKG1ujF0CS0n/IgTEMl+NivxtR5R3/hw=
|
||||||
github.com/eko/gocache/store/go_cache/v4 v4.2.2/go.mod h1:T9zkHokzr8K9EiC7RfMbDg6HSwaV6rv3UdcNu13SGcA=
|
github.com/eko/gocache/store/go_cache/v4 v4.2.2/go.mod h1:T9zkHokzr8K9EiC7RfMbDg6HSwaV6rv3UdcNu13SGcA=
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
@@ -55,6 +99,8 @@ github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I=
|
|||||||
github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk=
|
github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk=
|
||||||
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
|
||||||
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||||
|
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
|
||||||
|
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
@@ -118,18 +164,32 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||||
|
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/minio/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg=
|
github.com/minio/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg=
|
||||||
github.com/minio/crc64nvme v1.0.2/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
github.com/minio/crc64nvme v1.0.2/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
|
||||||
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
|
||||||
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
|
||||||
github.com/minio/minio-go/v7 v7.0.92 h1:jpBFWyRS3p8P/9tsRc+NuvqoFi7qAmTCFPoRFmobbVw=
|
github.com/minio/minio-go/v7 v7.0.92 h1:jpBFWyRS3p8P/9tsRc+NuvqoFi7qAmTCFPoRFmobbVw=
|
||||||
github.com/minio/minio-go/v7 v7.0.92/go.mod h1:vTIc8DNcnAZIhyFsk8EB90AbPjj3j68aWIEQCiPj7d0=
|
github.com/minio/minio-go/v7 v7.0.92/go.mod h1:vTIc8DNcnAZIhyFsk8EB90AbPjj3j68aWIEQCiPj7d0=
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
|
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
|
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||||
|
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
|
||||||
@@ -164,6 +224,9 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
|
|||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag=
|
github.com/rhysd/go-github-selfupdate v1.2.3 h1:iaa+J202f+Nc+A8zi75uccC8Wg3omaM7HDeimXA22Ag=
|
||||||
github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg=
|
github.com/rhysd/go-github-selfupdate v1.2.3/go.mod h1:mp/N8zj6jFfBQy/XMYoWsmfzxazpPAODuqarmPDe2Rg=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||||
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
|
||||||
@@ -254,6 +317,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
|||||||
@@ -13,15 +13,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Task struct {
|
type Task struct {
|
||||||
Ctx context.Context
|
Ctx context.Context
|
||||||
Cancel context.CancelFunc
|
Cancel context.CancelFunc
|
||||||
Error error
|
Error error
|
||||||
Status TaskStatus
|
UseUserClient bool
|
||||||
StorageName string
|
Status TaskStatus
|
||||||
StoragePath string
|
StorageName string
|
||||||
StartTime time.Time
|
StoragePath string
|
||||||
FileDBID uint
|
StartTime time.Time
|
||||||
|
|
||||||
|
FileDBID uint
|
||||||
File *File
|
File *File
|
||||||
FileMessageID int
|
FileMessageID int
|
||||||
FileChatID int64
|
FileChatID int64
|
||||||
|
|||||||
80
userclient/auth.go
Normal file
80
userclient/auth.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package userclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/celestix/gotgproto"
|
||||||
|
"github.com/charmbracelet/huh"
|
||||||
|
"github.com/charmbracelet/log"
|
||||||
|
"github.com/fatih/color"
|
||||||
|
)
|
||||||
|
|
||||||
|
type termialAuthConversator struct{}
|
||||||
|
|
||||||
|
func (t *termialAuthConversator) AskPhoneNumber() (string, error) {
|
||||||
|
phone := ""
|
||||||
|
err := huh.NewInput().Title("Your Phone Number").
|
||||||
|
Placeholder("+44 123456").
|
||||||
|
Prompt("> ").
|
||||||
|
Value(&phone).
|
||||||
|
WithTheme(huh.ThemeCatppuccin()).
|
||||||
|
Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Sending code to your phone number...")
|
||||||
|
|
||||||
|
return strings.TrimSpace(phone), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *termialAuthConversator) AskCode() (string, error) {
|
||||||
|
code := ""
|
||||||
|
err := huh.NewInput().Title("Your Code").
|
||||||
|
Placeholder("123456").
|
||||||
|
Value(&code).
|
||||||
|
Prompt("> ").
|
||||||
|
WithTheme(huh.ThemeCatppuccin()).
|
||||||
|
Run()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(code), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *termialAuthConversator) AskPassword() (string, error) {
|
||||||
|
pwd := ""
|
||||||
|
|
||||||
|
err := huh.NewInput().Title("Your 2FA Password").
|
||||||
|
EchoMode(huh.EchoModePassword).
|
||||||
|
Value(&pwd).
|
||||||
|
Prompt("> ").
|
||||||
|
WithTheme(huh.ThemeCatppuccin()).
|
||||||
|
Run()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(pwd), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *termialAuthConversator) AuthStatus(authStatus gotgproto.AuthStatus) {
|
||||||
|
switch authStatus.Event {
|
||||||
|
case gotgproto.AuthStatusPhoneRetrial:
|
||||||
|
color.Red("The phone number you just entered seems to be incorrect,")
|
||||||
|
color.Red("Attempts Left: %d", authStatus.AttemptsLeft)
|
||||||
|
color.Red("Please try again....")
|
||||||
|
case gotgproto.AuthStatusPasswordRetrial:
|
||||||
|
color.Red("The 2FA password you just entered seems to be incorrect,")
|
||||||
|
color.Red("Attempts Left: %d", authStatus.AttemptsLeft)
|
||||||
|
color.Red("Please try again....")
|
||||||
|
case gotgproto.AuthStatusPhoneCodeRetrial:
|
||||||
|
color.Red("The OTP you just entered seems to be incorrect,")
|
||||||
|
color.Red("Attempts Left: %d", authStatus.AttemptsLeft)
|
||||||
|
color.Red("Please try again....")
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
29
userclient/middlewares/middlewares.go
Normal file
29
userclient/middlewares/middlewares.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cenkalti/backoff/v4"
|
||||||
|
"github.com/gotd/contrib/middleware/floodwait"
|
||||||
|
"github.com/gotd/td/telegram"
|
||||||
|
"github.com/krau/SaveAny-Bot/userclient/middlewares/recovery"
|
||||||
|
"github.com/krau/SaveAny-Bot/userclient/middlewares/retry"
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
61
userclient/middlewares/recovery/recovery.go
Normal file
61
userclient/middlewares/recovery/recovery.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
package recovery
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cenkalti/backoff/v4"
|
||||||
|
"github.com/go-faster/errors"
|
||||||
|
"github.com/gotd/td/bin"
|
||||||
|
"github.com/gotd/td/telegram"
|
||||||
|
"github.com/gotd/td/tg"
|
||||||
|
"github.com/gotd/td/tgerr"
|
||||||
|
"github.com/krau/SaveAny-Bot/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type recovery struct {
|
||||||
|
ctx context.Context
|
||||||
|
backoff backoff.BackOff
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(ctx context.Context, backoff backoff.BackOff) telegram.Middleware {
|
||||||
|
return &recovery{
|
||||||
|
ctx: ctx,
|
||||||
|
backoff: backoff,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *recovery) Handle(next tg.Invoker) telegram.InvokeFunc {
|
||||||
|
return func(ctx context.Context, input bin.Encoder, output bin.Decoder) error {
|
||||||
|
|
||||||
|
return backoff.RetryNotify(func() error {
|
||||||
|
if err := next.Invoke(ctx, input, output); err != nil {
|
||||||
|
if r.shouldRecover(ctx, err) {
|
||||||
|
return errors.Wrap(err, "recover")
|
||||||
|
}
|
||||||
|
|
||||||
|
return backoff.Permanent(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, r.backoff, func(err error, duration time.Duration) {
|
||||||
|
common.Log.Debug("Wait for connection recovery", "error", err, "duration", duration)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *recovery) shouldRecover(ctx context.Context, err error) bool {
|
||||||
|
// context in recovery is used to stop recovery process by external os signal, otherwise we will wait till max retries when user press ctrl+c
|
||||||
|
select {
|
||||||
|
case <-r.ctx.Done():
|
||||||
|
return false
|
||||||
|
case <-ctx.Done():
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
// we try recover when encountered any error that is not telegram business error
|
||||||
|
_, ok := tgerr.As(err)
|
||||||
|
|
||||||
|
return !ok
|
||||||
|
}
|
||||||
56
userclient/middlewares/retry/retry.go
Normal file
56
userclient/middlewares/retry/retry.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package retry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/go-faster/errors"
|
||||||
|
"github.com/gotd/td/bin"
|
||||||
|
"github.com/gotd/td/telegram"
|
||||||
|
"github.com/gotd/td/tg"
|
||||||
|
"github.com/gotd/td/tgerr"
|
||||||
|
"github.com/krau/SaveAny-Bot/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
var internalErrors = []string{
|
||||||
|
"Timedout", // #373
|
||||||
|
"No workers running",
|
||||||
|
"RPC_CALL_FAIL",
|
||||||
|
"RPC_MCGET_FAIL",
|
||||||
|
"WORKER_BUSY_TOO_LONG_RETRY", // #462
|
||||||
|
"memory limit exit", // #504
|
||||||
|
}
|
||||||
|
|
||||||
|
type retry struct {
|
||||||
|
max int
|
||||||
|
errors []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r retry) Handle(next tg.Invoker) telegram.InvokeFunc {
|
||||||
|
return func(ctx context.Context, input bin.Encoder, output bin.Decoder) error {
|
||||||
|
retries := 0
|
||||||
|
|
||||||
|
for retries < r.max {
|
||||||
|
if err := next.Invoke(ctx, input, output); err != nil {
|
||||||
|
if tgerr.Is(err, r.errors...) {
|
||||||
|
common.Log.Debug("retry middleware", "retries", retries, "error", err)
|
||||||
|
retries++
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return errors.Wrap(err, "retry middleware skip")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("retry limit reached after %d attempts", r.max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// New returns middleware that retries request if it fails with one of provided errors.
|
||||||
|
func New(max int, errors ...string) telegram.Middleware {
|
||||||
|
return retry{
|
||||||
|
max: max,
|
||||||
|
errors: append(errors, internalErrors...), // #373
|
||||||
|
}
|
||||||
|
}
|
||||||
74
userclient/userclient.go
Normal file
74
userclient/userclient.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
package userclient
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/celestix/gotgproto"
|
||||||
|
"github.com/celestix/gotgproto/ext"
|
||||||
|
"github.com/celestix/gotgproto/sessionMaker"
|
||||||
|
"github.com/glebarez/sqlite"
|
||||||
|
"github.com/krau/SaveAny-Bot/common"
|
||||||
|
"github.com/krau/SaveAny-Bot/config"
|
||||||
|
"github.com/krau/SaveAny-Bot/userclient/middlewares"
|
||||||
|
)
|
||||||
|
|
||||||
|
var UC *gotgproto.Client
|
||||||
|
var ectx *ext.Context
|
||||||
|
|
||||||
|
func GetCtx() *ext.Context {
|
||||||
|
if ectx != nil {
|
||||||
|
return ectx
|
||||||
|
}
|
||||||
|
ectx = UC.CreateContext()
|
||||||
|
return ectx
|
||||||
|
}
|
||||||
|
|
||||||
|
func Login(ctx context.Context) (*gotgproto.Client, error) {
|
||||||
|
common.Log.Debug("Logging in as user client")
|
||||||
|
if UC != nil {
|
||||||
|
return UC, nil
|
||||||
|
}
|
||||||
|
res := make(chan struct {
|
||||||
|
client *gotgproto.Client
|
||||||
|
err error
|
||||||
|
})
|
||||||
|
go func() {
|
||||||
|
tclient, err := gotgproto.NewClient(
|
||||||
|
config.Cfg.Telegram.AppID,
|
||||||
|
config.Cfg.Telegram.AppHash,
|
||||||
|
gotgproto.ClientTypePhone(""),
|
||||||
|
&gotgproto.ClientOpts{
|
||||||
|
Session: sessionMaker.SqlSession(sqlite.Open(config.Cfg.Telegram.Userbot.Session)),
|
||||||
|
AuthConversator: &termialAuthConversator{},
|
||||||
|
// Context: ctx,
|
||||||
|
DisableCopyright: true,
|
||||||
|
Middlewares: middlewares.NewDefaultMiddlewares(ctx, 5*time.Minute),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
res <- struct {
|
||||||
|
client *gotgproto.Client
|
||||||
|
err error
|
||||||
|
}{nil, err}
|
||||||
|
}
|
||||||
|
res <- struct {
|
||||||
|
client *gotgproto.Client
|
||||||
|
err error
|
||||||
|
}(struct {
|
||||||
|
client *gotgproto.Client
|
||||||
|
err error
|
||||||
|
}{tclient, nil})
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case r := <-res:
|
||||||
|
if r.err != nil {
|
||||||
|
return nil, r.err
|
||||||
|
}
|
||||||
|
UC = r.client
|
||||||
|
return UC, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user