diff --git a/client/bot/bot.go b/client/bot/bot.go index d442f7b..fda570d 100644 --- a/client/bot/bot.go +++ b/client/bot/bot.go @@ -2,7 +2,6 @@ package bot import ( "context" - "net/url" "time" "github.com/celestix/gotgproto" @@ -14,21 +13,12 @@ import ( "github.com/gotd/td/tg" "github.com/krau/SaveAny-Bot/client/bot/handlers" "github.com/krau/SaveAny-Bot/client/middleware" + "github.com/krau/SaveAny-Bot/common/utils/netutil" "github.com/krau/SaveAny-Bot/config" "github.com/ncruces/go-sqlite3/gormlite" "golang.org/x/net/proxy" ) -var Client *gotgproto.Client - -func newProxyDialer(proxyUrl string) (proxy.Dialer, error) { - url, err := url.Parse(proxyUrl) - if err != nil { - return nil, err - } - return proxy.FromURL(url, proxy.Direct) -} - func Init(ctx context.Context) { log.FromContext(ctx).Info("初始化 Bot...") resultChan := make(chan struct { @@ -38,7 +28,7 @@ func Init(ctx context.Context) { go func() { var resolver dcs.Resolver if config.Cfg.Telegram.Proxy.Enable && config.Cfg.Telegram.Proxy.URL != "" { - dialer, err := newProxyDialer(config.Cfg.Telegram.Proxy.URL) + dialer, err := netutil.NewProxyDialer(config.Cfg.Telegram.Proxy.URL) if err != nil { resultChan <- struct { client *gotgproto.Client @@ -52,7 +42,8 @@ func Init(ctx context.Context) { } else { resolver = dcs.DefaultResolver() } - client, err := gotgproto.NewClient(config.Cfg.Telegram.AppID, + client, err := gotgproto.NewClient( + config.Cfg.Telegram.AppID, config.Cfg.Telegram.AppHash, gotgproto.ClientTypeBot(config.Cfg.Telegram.Token), &gotgproto.ClientOpts{ @@ -104,8 +95,7 @@ func Init(ctx context.Context) { if result.err != nil { log.FromContext(ctx).Fatalf("初始化 Bot 失败: %s", result.err) } - Client = result.client - handlers.Register(Client.Dispatcher) + handlers.Register(result.client.Dispatcher) log.FromContext(ctx).Info("Bot 初始化完成") } } diff --git a/client/bot/handlers/link.go b/client/bot/handlers/link.go index 54606f8..4ac0e54 100644 --- a/client/bot/handlers/link.go +++ b/client/bot/handlers/link.go @@ -38,8 +38,7 @@ func handleMessageLink(ctx *ext.Context, update *ext.Update) error { editReplied("构建存储选择键盘失败: "+err.Error(), nil) return dispatcher.EndGroups } - editReplied(fmt.Sprintf("找到 %d 个文件, 请选择存储位置", len(files)), - markup) + editReplied(fmt.Sprintf("找到 %d 个文件, 请选择存储位置", len(files)), markup) return dispatcher.EndGroups } diff --git a/client/user/auth.go b/client/user/auth_terminal.go similarity index 83% rename from client/user/auth.go rename to client/user/auth_terminal.go index 048a5e4..3f53eb4 100644 --- a/client/user/auth.go +++ b/client/user/auth_terminal.go @@ -9,9 +9,9 @@ import ( "github.com/fatih/color" ) -type termialAuthConversator struct{} +type terminalAuthConversator struct{} -func (t *termialAuthConversator) AskPhoneNumber() (string, error) { +func (t *terminalAuthConversator) AskPhoneNumber() (string, error) { phone := "" err := huh.NewInput().Title("Your Phone Number"). Placeholder("+44 123456"). @@ -29,7 +29,7 @@ func (t *termialAuthConversator) AskPhoneNumber() (string, error) { return strings.TrimSpace(phone), nil } -func (t *termialAuthConversator) AskCode() (string, error) { +func (t *terminalAuthConversator) AskCode() (string, error) { code := "" err := huh.NewInput().Title("Your Code"). Placeholder("123456"). @@ -45,7 +45,7 @@ func (t *termialAuthConversator) AskCode() (string, error) { return strings.TrimSpace(code), nil } -func (t *termialAuthConversator) AskPassword() (string, error) { +func (t *terminalAuthConversator) AskPassword() (string, error) { pwd := "" err := huh.NewInput().Title("Your 2FA Password"). @@ -61,7 +61,7 @@ func (t *termialAuthConversator) AskPassword() (string, error) { return strings.TrimSpace(pwd), nil } -func (t *termialAuthConversator) AuthStatus(authStatus gotgproto.AuthStatus) { +func (t *terminalAuthConversator) AuthStatus(authStatus gotgproto.AuthStatus) { switch authStatus.Event { case gotgproto.AuthStatusPhoneRetrial: color.Red("The phone number you just entered seems to be incorrect,") diff --git a/client/user/userclient.go b/client/user/userclient.go index 004e4e5..32b50b7 100644 --- a/client/user/userclient.go +++ b/client/user/userclient.go @@ -5,46 +5,82 @@ import ( "time" "github.com/celestix/gotgproto" + "github.com/celestix/gotgproto/dispatcher" "github.com/celestix/gotgproto/ext" "github.com/celestix/gotgproto/sessionMaker" "github.com/charmbracelet/log" + "github.com/gotd/td/telegram/dcs" "github.com/krau/SaveAny-Bot/client/middleware" + "github.com/krau/SaveAny-Bot/common/utils/netutil" "github.com/krau/SaveAny-Bot/config" "github.com/ncruces/go-sqlite3/gormlite" + "golang.org/x/net/proxy" ) -var UC *gotgproto.Client +var uc *gotgproto.Client var ectx *ext.Context func GetCtx() *ext.Context { + if uc == nil { + panic("User client is not initialized, please call Login first") + } if ectx != nil { - // UC.RefreshContext(ectx) return ectx } - ectx = UC.CreateContext() + ectx = uc.CreateContext() return ectx } +func GetClient() *gotgproto.Client { + if uc == nil { + panic("User client is not initialized, please call Login first") + } + return uc +} + func Login(ctx context.Context) (*gotgproto.Client, error) { - log.FromContext(ctx).Debug("Logging in as user client") - if UC != nil { - return UC, nil + log.FromContext(ctx).Debug("Logging in user client") + if uc != nil { + return uc, nil } res := make(chan struct { client *gotgproto.Client err error }) go func() { + var resolver dcs.Resolver + if config.Cfg.Telegram.Proxy.Enable && config.Cfg.Telegram.Proxy.URL != "" { + dialer, err := netutil.NewProxyDialer(config.Cfg.Telegram.Proxy.URL) + if err != nil { + res <- struct { + client *gotgproto.Client + err error + }{nil, err} + return + } + resolver = dcs.Plain(dcs.PlainOptions{ + Dial: dialer.(proxy.ContextDialer).DialContext, + }) + } else { + resolver = dcs.DefaultResolver() + } tclient, err := gotgproto.NewClient( config.Cfg.Telegram.AppID, config.Cfg.Telegram.AppHash, gotgproto.ClientTypePhone(""), &gotgproto.ClientOpts{ Session: sessionMaker.SqlSession(gormlite.Open(config.Cfg.Telegram.Userbot.Session)), - AuthConversator: &termialAuthConversator{}, + AuthConversator: &terminalAuthConversator{}, Context: ctx, DisableCopyright: true, + Resolver: resolver, + MaxRetries: config.Cfg.Telegram.RpcRetry, + AutoFetchReply: true, Middlewares: middleware.NewDefaultMiddlewares(ctx, 5*time.Minute), + ErrorHandler: func(ctx *ext.Context, u *ext.Update, s string) error { + log.FromContext(ctx).Errorf("Unhandled error: %s", s) + return dispatcher.EndGroups + }, }, ) if err != nil { @@ -69,7 +105,8 @@ func Login(ctx context.Context) (*gotgproto.Client, error) { if r.err != nil { return nil, r.err } - UC = r.client - return UC, nil + uc = r.client + log.FromContext(ctx).Infof("User client logged in successfully: %s", uc.Self.FirstName+" "+uc.Self.LastName) + return uc, nil } } diff --git a/cmd/run.go b/cmd/run.go index 3498026..9976896 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -51,16 +51,14 @@ func initAll(ctx context.Context) { logger := log.FromContext(ctx) i18n.Init(config.Cfg.Lang) logger.Info(i18n.T(i18nk.Initing)) + database.Init(ctx) + storage.LoadStorages(ctx) if config.Cfg.Telegram.Userbot.Enable { - uc, err := userclient.Login(ctx) + _, err := userclient.Login(ctx) if err != nil { logger.Fatalf("User client login failed: %s", err) } - logger.Infof("User client logged in as %s", uc.Self.FirstName) } - database.Init(ctx) - storage.LoadStorages(ctx) - bot.Init(ctx) } diff --git a/common/utils/netutil/proxy.go b/common/utils/netutil/proxy.go new file mode 100644 index 0000000..6833fe4 --- /dev/null +++ b/common/utils/netutil/proxy.go @@ -0,0 +1,15 @@ +package netutil + +import ( + "net/url" + + "golang.org/x/net/proxy" +) + +func NewProxyDialer(proxyUrl string) (proxy.Dialer, error) { + url, err := url.Parse(proxyUrl) + if err != nil { + return nil, err + } + return proxy.FromURL(url, proxy.Direct) +}