mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-09-05 15:46:37 +08:00
feat: add global proxy config
This commit is contained in:
+9
-18
@@ -9,14 +9,12 @@ import (
|
|||||||
"github.com/celestix/gotgproto/ext"
|
"github.com/celestix/gotgproto/ext"
|
||||||
"github.com/celestix/gotgproto/sessionMaker"
|
"github.com/celestix/gotgproto/sessionMaker"
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
"github.com/gotd/td/telegram/dcs"
|
|
||||||
"github.com/gotd/td/tg"
|
"github.com/gotd/td/tg"
|
||||||
"github.com/krau/SaveAny-Bot/client/bot/handlers"
|
"github.com/krau/SaveAny-Bot/client/bot/handlers"
|
||||||
"github.com/krau/SaveAny-Bot/client/middleware"
|
"github.com/krau/SaveAny-Bot/client/middleware"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/netutil"
|
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
||||||
"github.com/krau/SaveAny-Bot/config"
|
"github.com/krau/SaveAny-Bot/config"
|
||||||
"github.com/ncruces/go-sqlite3/gormlite"
|
"github.com/ncruces/go-sqlite3/gormlite"
|
||||||
"golang.org/x/net/proxy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func Init(ctx context.Context) <-chan struct{} {
|
func Init(ctx context.Context) <-chan struct{} {
|
||||||
@@ -26,22 +24,15 @@ func Init(ctx context.Context) <-chan struct{} {
|
|||||||
err error
|
err error
|
||||||
})
|
})
|
||||||
shouldRestart := make(chan struct{})
|
shouldRestart := make(chan struct{})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
var resolver dcs.Resolver
|
resolver, err := tgutil.NewConfigProxyResolver()
|
||||||
if config.C().Telegram.Proxy.Enable && config.C().Telegram.Proxy.URL != "" {
|
if err != nil {
|
||||||
dialer, err := netutil.NewProxyDialer(config.C().Telegram.Proxy.URL)
|
resultChan <- struct {
|
||||||
if err != nil {
|
client *gotgproto.Client
|
||||||
resultChan <- struct {
|
err error
|
||||||
client *gotgproto.Client
|
}{nil, err}
|
||||||
err error
|
return
|
||||||
}{nil, err}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resolver = dcs.Plain(dcs.PlainOptions{
|
|
||||||
Dial: dialer.(proxy.ContextDialer).DialContext,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
resolver = dcs.DefaultResolver()
|
|
||||||
}
|
}
|
||||||
client, err := gotgproto.NewClient(
|
client, err := gotgproto.NewClient(
|
||||||
config.C().Telegram.AppID,
|
config.C().Telegram.AppID,
|
||||||
|
|||||||
@@ -44,13 +44,7 @@ func handleMessageLink(ctx *ext.Context, update *ext.Update) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleSilentSaveLink(ctx *ext.Context, update *ext.Update) error {
|
func handleSilentSaveLink(ctx *ext.Context, update *ext.Update) error {
|
||||||
logger := log.FromContext(ctx)
|
|
||||||
stor := storage.FromContext(ctx)
|
stor := storage.FromContext(ctx)
|
||||||
if stor == nil {
|
|
||||||
logger.Warn("Context storage is nil")
|
|
||||||
ctx.Reply(update, ext.ReplyTextString("未找到存储"), nil)
|
|
||||||
return dispatcher.EndGroups
|
|
||||||
}
|
|
||||||
replied, files, _, err := shortcut.GetFilesFromUpdateLinkMessageWithReplyEdit(ctx, update)
|
replied, files, _, err := shortcut.GetFilesFromUpdateLinkMessageWithReplyEdit(ctx, update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -45,11 +45,6 @@ func handleMediaMessage(ctx *ext.Context, update *ext.Update) error {
|
|||||||
func handleSilentSaveMedia(ctx *ext.Context, update *ext.Update) error {
|
func handleSilentSaveMedia(ctx *ext.Context, update *ext.Update) error {
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
stor := storage.FromContext(ctx)
|
stor := storage.FromContext(ctx)
|
||||||
if stor == nil {
|
|
||||||
logger.Warn("Context storage is nil")
|
|
||||||
ctx.Reply(update, ext.ReplyTextString("未找到存储"), nil)
|
|
||||||
return dispatcher.EndGroups
|
|
||||||
}
|
|
||||||
message := update.EffectiveMessage.Message
|
message := update.EffectiveMessage.Message
|
||||||
groupID, isGroup := message.GetGroupedID()
|
groupID, isGroup := message.GetGroupedID()
|
||||||
if isGroup && groupID != 0 {
|
if isGroup && groupID != 0 {
|
||||||
|
|||||||
@@ -77,11 +77,6 @@ func handleTextMessage(ctx *ext.Context, u *ext.Update) error {
|
|||||||
func handleSilentSaveText(ctx *ext.Context, u *ext.Update) error {
|
func handleSilentSaveText(ctx *ext.Context, u *ext.Update) error {
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
stor := storage.FromContext(ctx)
|
stor := storage.FromContext(ctx)
|
||||||
if stor == nil {
|
|
||||||
logger.Warn("Context storage is nil")
|
|
||||||
ctx.Reply(u, ext.ReplyTextString("未找到存储"), nil)
|
|
||||||
return dispatcher.EndGroups
|
|
||||||
}
|
|
||||||
text := u.EffectiveMessage.Text
|
text := u.EffectiveMessage.Text
|
||||||
if text == "" {
|
if text == "" {
|
||||||
return dispatcher.EndGroups
|
return dispatcher.EndGroups
|
||||||
|
|||||||
@@ -76,13 +76,7 @@ func handleSilentSaveReplied(ctx *ext.Context, update *ext.Update) error {
|
|||||||
if len(args) >= 3 {
|
if len(args) >= 3 {
|
||||||
return handleBatchSave(ctx, update, args[1:])
|
return handleBatchSave(ctx, update, args[1:])
|
||||||
}
|
}
|
||||||
logger := log.FromContext(ctx)
|
|
||||||
stor := storage.FromContext(ctx)
|
stor := storage.FromContext(ctx)
|
||||||
if stor == nil {
|
|
||||||
logger.Warn("Context storage is nil")
|
|
||||||
ctx.Reply(update, ext.ReplyTextString("未找到存储"), nil)
|
|
||||||
return dispatcher.EndGroups
|
|
||||||
}
|
|
||||||
replyTo := update.EffectiveMessage.ReplyToMessage
|
replyTo := update.EffectiveMessage.ReplyToMessage
|
||||||
if replyTo == nil || replyTo.Message == nil {
|
if replyTo == nil || replyTo.Message == nil {
|
||||||
ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgSaveHelpText)), nil)
|
ctx.Reply(update, ext.ReplyTextString(i18n.T(i18nk.BotMsgSaveHelpText)), nil)
|
||||||
|
|||||||
@@ -61,13 +61,7 @@ func handleTelegraphUrlMessage(ctx *ext.Context, update *ext.Update) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func handleSilentSaveTelegraph(ctx *ext.Context, update *ext.Update) error {
|
func handleSilentSaveTelegraph(ctx *ext.Context, update *ext.Update) error {
|
||||||
logger := log.FromContext(ctx)
|
|
||||||
stor := storage.FromContext(ctx)
|
stor := storage.FromContext(ctx)
|
||||||
if stor == nil {
|
|
||||||
logger.Warn("Context storage is nil")
|
|
||||||
ctx.Reply(update, ext.ReplyTextString("未找到存储"), nil)
|
|
||||||
return dispatcher.EndGroups
|
|
||||||
}
|
|
||||||
msg, result, err := shortcut.GetTphPicsFromMessageWithReply(ctx, update)
|
msg, result, err := shortcut.GetTphPicsFromMessageWithReply(ctx, update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -12,14 +12,12 @@ import (
|
|||||||
"github.com/celestix/gotgproto/sessionMaker"
|
"github.com/celestix/gotgproto/sessionMaker"
|
||||||
|
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
"github.com/gotd/td/telegram/dcs"
|
|
||||||
"github.com/gotd/td/tg"
|
"github.com/gotd/td/tg"
|
||||||
"github.com/krau/SaveAny-Bot/client/middleware"
|
"github.com/krau/SaveAny-Bot/client/middleware"
|
||||||
"github.com/krau/SaveAny-Bot/common/utils/netutil"
|
"github.com/krau/SaveAny-Bot/common/utils/tgutil"
|
||||||
"github.com/krau/SaveAny-Bot/config"
|
"github.com/krau/SaveAny-Bot/config"
|
||||||
"github.com/krau/SaveAny-Bot/database"
|
"github.com/krau/SaveAny-Bot/database"
|
||||||
"github.com/ncruces/go-sqlite3/gormlite"
|
"github.com/ncruces/go-sqlite3/gormlite"
|
||||||
"golang.org/x/net/proxy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var uc *gotgproto.Client
|
var uc *gotgproto.Client
|
||||||
@@ -53,21 +51,13 @@ func Login(ctx context.Context) (*gotgproto.Client, error) {
|
|||||||
err error
|
err error
|
||||||
})
|
})
|
||||||
go func() {
|
go func() {
|
||||||
var resolver dcs.Resolver
|
resolver, err := tgutil.NewConfigProxyResolver()
|
||||||
if config.C().Telegram.Proxy.Enable && config.C().Telegram.Proxy.URL != "" {
|
if err != nil {
|
||||||
dialer, err := netutil.NewProxyDialer(config.C().Telegram.Proxy.URL)
|
res <- struct {
|
||||||
if err != nil {
|
client *gotgproto.Client
|
||||||
res <- struct {
|
err error
|
||||||
client *gotgproto.Client
|
}{nil, err}
|
||||||
err error
|
return
|
||||||
}{nil, err}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resolver = dcs.Plain(dcs.PlainOptions{
|
|
||||||
Dial: dialer.(proxy.ContextDialer).DialContext,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
resolver = dcs.DefaultResolver()
|
|
||||||
}
|
}
|
||||||
tclient, err := gotgproto.NewClient(
|
tclient, err := gotgproto.NewClient(
|
||||||
config.C().Telegram.AppID,
|
config.C().Telegram.AppID,
|
||||||
|
|||||||
@@ -7,56 +7,24 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/charmbracelet/log"
|
"github.com/charmbracelet/log"
|
||||||
"github.com/krau/SaveAny-Bot/config"
|
"github.com/krau/SaveAny-Bot/config"
|
||||||
"golang.org/x/net/proxy"
|
"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)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewProxyHTTPClient(proxyUrl string) (*http.Client, error) {
|
func NewProxyHTTPClient(proxyUrl string) (*http.Client, error) {
|
||||||
if proxyUrl == "" {
|
if proxyUrl == "" {
|
||||||
return &http.Client{
|
return http.DefaultClient, nil
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyFromEnvironment,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
transport, err := NewProxyTransport(proxyUrl)
|
||||||
u, err := url.Parse(proxyUrl)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
return &http.Client{
|
||||||
switch u.Scheme {
|
Transport: transport,
|
||||||
case "http", "https":
|
}, nil
|
||||||
return &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
Proxy: http.ProxyURL(u),
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
case "socks5":
|
|
||||||
dialer, err := proxy.FromURL(u, proxy.Direct)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &http.Client{
|
|
||||||
Transport: &http.Transport{
|
|
||||||
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
|
||||||
return dialer.Dial(network, addr)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("unsupported proxy scheme: %s", u.Scheme)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -76,3 +44,35 @@ func DefaultParserHTTPClient() *http.Client {
|
|||||||
})
|
})
|
||||||
return defaultProxyHttpClient
|
return defaultProxyHttpClient
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewProxyTransport(proxyStr string) (*http.Transport, error) {
|
||||||
|
proxyURL, err := url.Parse(proxyStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
transport := &http.Transport{
|
||||||
|
ForceAttemptHTTP2: true,
|
||||||
|
MaxIdleConns: 100,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
|
}
|
||||||
|
switch proxyURL.Scheme {
|
||||||
|
case "http", "https":
|
||||||
|
transport.Proxy = http.ProxyURL(proxyURL)
|
||||||
|
|
||||||
|
case "socks5", "socks5h":
|
||||||
|
dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return dialer.(proxy.ContextDialer).DialContext(ctx, network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported proxy type: %s", proxyURL.Scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
return transport, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package tgutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"github.com/gotd/td/telegram/dcs"
|
||||||
|
"github.com/krau/SaveAny-Bot/config"
|
||||||
|
"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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConfigProxyResolver() (dcs.Resolver, error) {
|
||||||
|
resolver := dcs.DefaultResolver()
|
||||||
|
if config.C().Proxy != "" {
|
||||||
|
// gloabl proxy, which has lower priority
|
||||||
|
dialer, err := newProxyDialer(config.C().Proxy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resolver = dcs.Plain(dcs.PlainOptions{
|
||||||
|
Dial: dialer.(proxy.ContextDialer).DialContext,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if config.C().Telegram.Proxy.Enable && config.C().Telegram.Proxy.URL != "" {
|
||||||
|
dialer, err := newProxyDialer(config.C().Telegram.Proxy.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
resolver = dcs.Plain(dcs.PlainOptions{
|
||||||
|
Dial: dialer.(proxy.ContextDialer).DialContext,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return resolver, nil
|
||||||
|
}
|
||||||
@@ -4,13 +4,18 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/duke-git/lancet/v2/slice"
|
"github.com/duke-git/lancet/v2/slice"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n"
|
"github.com/krau/SaveAny-Bot/common/i18n"
|
||||||
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
"github.com/krau/SaveAny-Bot/common/i18n/i18nk"
|
||||||
"github.com/krau/SaveAny-Bot/config/storage"
|
"github.com/krau/SaveAny-Bot/config/storage"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
@@ -20,6 +25,7 @@ type Config struct {
|
|||||||
NoCleanCache bool `toml:"no_clean_cache" mapstructure:"no_clean_cache" json:"no_clean_cache"`
|
NoCleanCache bool `toml:"no_clean_cache" mapstructure:"no_clean_cache" json:"no_clean_cache"`
|
||||||
Threads int `toml:"threads" mapstructure:"threads" json:"threads"`
|
Threads int `toml:"threads" mapstructure:"threads" json:"threads"`
|
||||||
Stream bool `toml:"stream" mapstructure:"stream" json:"stream"`
|
Stream bool `toml:"stream" mapstructure:"stream" json:"stream"`
|
||||||
|
Proxy string `toml:"proxy" mapstructure:"proxy" json:"proxy"`
|
||||||
|
|
||||||
Cache cacheConfig `toml:"cache" mapstructure:"cache" json:"cache"`
|
Cache cacheConfig `toml:"cache" mapstructure:"cache" json:"cache"`
|
||||||
Users []userConfig `toml:"users" mapstructure:"users" json:"users"`
|
Users []userConfig `toml:"users" mapstructure:"users" json:"users"`
|
||||||
@@ -147,5 +153,43 @@ func Init(ctx context.Context) error {
|
|||||||
userStorages[user.ID] = user.Storages
|
userStorages[user.ID] = user.Storages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if cfg.Proxy != "" {
|
||||||
|
http.DefaultTransport, err = newProxyTransport(cfg.Proxy)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create proxy transport: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newProxyTransport(proxyStr string) (*http.Transport, error) {
|
||||||
|
proxyURL, err := url.Parse(proxyStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
transport := &http.Transport{
|
||||||
|
ForceAttemptHTTP2: true,
|
||||||
|
MaxIdleConns: 100,
|
||||||
|
IdleConnTimeout: 90 * time.Second,
|
||||||
|
TLSHandshakeTimeout: 10 * time.Second,
|
||||||
|
ExpectContinueTimeout: 1 * time.Second,
|
||||||
|
}
|
||||||
|
switch proxyURL.Scheme {
|
||||||
|
case "http", "https":
|
||||||
|
transport.Proxy = http.ProxyURL(proxyURL)
|
||||||
|
|
||||||
|
case "socks5", "socks5h":
|
||||||
|
dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
transport.DialContext = func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return dialer.(proxy.ContextDialer).DialContext(ctx, network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported proxy type: %s", proxyURL.Scheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
return transport, nil
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ func GetStorageByUserIDAndName(ctx context.Context, chatID int64, name string) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !config.C().HasStorage(chatID, name) {
|
if !config.C().HasStorage(chatID, name) {
|
||||||
return nil, fmt.Errorf("没有找到用户 %d 的存储 %s", chatID, name)
|
return nil, fmt.Errorf("no storage %s for user %d", name, chatID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return getStorageByName(ctx, name)
|
return getStorageByName(ctx, name)
|
||||||
|
|||||||
Reference in New Issue
Block a user