mirror of
https://github.com/mmahdium/TGSS.git
synced 2026-08-12 08:32:48 +03:30
feat: update Telegram client to support proxy configuration and enhance error handling
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
.env
|
||||
.vscode/launch.json
|
||||
@@ -28,4 +28,6 @@ func main() {
|
||||
if err := app.Start(startCtx); err != nil {
|
||||
log.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
||||
app.Wait()
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ type Config struct {
|
||||
TgAppHash string
|
||||
|
||||
SessionPath string
|
||||
ProxyURL string
|
||||
}
|
||||
|
||||
func Load(logger *zap.Logger) *Config {
|
||||
@@ -27,7 +28,7 @@ func Load(logger *zap.Logger) *Config {
|
||||
|
||||
phoneNumber := os.Getenv("TG_PHONE_NUMBER")
|
||||
if phoneNumber == "" {
|
||||
logger.Fatal("No phone number provided")
|
||||
logger.Warn("No phone number provided")
|
||||
}
|
||||
|
||||
botToken := os.Getenv("TG_BOT_TOKEN")
|
||||
@@ -60,6 +61,8 @@ func Load(logger *zap.Logger) *Config {
|
||||
|
||||
sessionFile := filepath.Join(sessionPath, "session.json")
|
||||
|
||||
proxyURL := os.Getenv("TG_PROXY_URL")
|
||||
|
||||
return &Config{
|
||||
TgPhoneNumber: strings.TrimSpace(phoneNumber),
|
||||
TgBotToken: strings.TrimSpace(botToken),
|
||||
@@ -67,5 +70,6 @@ func Load(logger *zap.Logger) *Config {
|
||||
TgAppHash: strings.TrimSpace(appHash),
|
||||
|
||||
SessionPath: sessionFile,
|
||||
ProxyURL: strings.TrimSpace(proxyURL),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package telegram
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"net/url"
|
||||
"tgss/internal/config"
|
||||
|
||||
"github.com/gotd/td/session"
|
||||
@@ -8,24 +11,84 @@ import (
|
||||
"github.com/gotd/td/telegram/dcs"
|
||||
"go.uber.org/fx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func NewTelegramClient(cfg *config.Config, logger *zap.Logger) *telegram.Client {
|
||||
return telegram.NewClient(cfg.TgAppId, cfg.TgAppHash, telegram.Options{
|
||||
DC: 2,
|
||||
DCList: dcs.Prod(),
|
||||
Logger: logger,
|
||||
SessionStorage: &session.FileStorage{
|
||||
Path: cfg.SessionPath,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func NewService(client *telegram.Client, logger *zap.Logger) *Service {
|
||||
return &Service{client: client, log: logger}
|
||||
}
|
||||
|
||||
var Module = fx.Provide(
|
||||
NewTelegramClient,
|
||||
NewService,
|
||||
)
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
func NewTelegramClient(cfg *config.Config, logger *zap.Logger) *telegram.Client {
|
||||
opts := telegram.Options{
|
||||
DC: 2,
|
||||
DCList: dcs.Prod(),
|
||||
Logger: logger,
|
||||
SessionStorage: &session.FileStorage{Path: cfg.SessionPath},
|
||||
}
|
||||
|
||||
if cfg.ProxyURL != "" {
|
||||
proxyURL, err := url.Parse(cfg.ProxyURL)
|
||||
if err != nil {
|
||||
logger.Warn("Failed to parse proxy URL, ignoring proxy", zap.String("url", cfg.ProxyURL), zap.Error(err))
|
||||
} else {
|
||||
dialer, err := proxy.FromURL(proxyURL, proxy.Direct)
|
||||
if err != nil {
|
||||
logger.Warn("Failed to create proxy dialer, ignoring proxy", zap.String("url", cfg.ProxyURL), zap.Error(err))
|
||||
} else {
|
||||
opts.Resolver = dcs.Plain(dcs.PlainOptions{
|
||||
Dial: func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return dialer.Dial(network, addr)
|
||||
},
|
||||
})
|
||||
logger.Info("Using proxy", zap.String("url", cfg.ProxyURL))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return telegram.NewClient(cfg.TgAppId, cfg.TgAppHash, opts)
|
||||
}
|
||||
|
||||
func NewService(client *telegram.Client, logger *zap.Logger) *Service {
|
||||
return &Service{client: client, log: logger}
|
||||
}
|
||||
|
||||
func RunClient(lc fx.Lifecycle, client *telegram.Client, cfg *config.Config, logger *zap.Logger) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
lc.Append(fx.Hook{
|
||||
OnStart: func(context.Context) error {
|
||||
errCh := make(chan error, 1)
|
||||
readyCh := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
if err := client.Run(ctx, func(ctx context.Context) error {
|
||||
if _, err := client.Auth().Bot(ctx, cfg.TgBotToken); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("Telegram bot authenticated and running")
|
||||
close(readyCh)
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
}); err != nil {
|
||||
errCh <- err
|
||||
}
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-readyCh:
|
||||
return nil
|
||||
case err := <-errCh:
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
},
|
||||
OnStop: func(context.Context) error {
|
||||
cancel()
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
var Module = fx.Options(
|
||||
fx.Provide(
|
||||
NewTelegramClient,
|
||||
NewService,
|
||||
),
|
||||
fx.Invoke(RunClient),
|
||||
)
|
||||
|
||||
@@ -22,27 +22,25 @@ func (s *Service) LastMessages(ctx context.Context, username string, limit int)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var peer tg.InputPeerClass
|
||||
for _, chat := range resolved.Chats {
|
||||
if ch, ok := chat.(*tg.Channel); ok {
|
||||
peer = &tg.InputPeerChannel{
|
||||
ChannelID: ch.ID,
|
||||
AccessHash: ch.AccessHash,
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if peer == nil {
|
||||
if len(resolved.Chats) == 0 {
|
||||
return nil, errors.New("channel not found")
|
||||
}
|
||||
// Fetch history
|
||||
history, err := api.MessagesGetHistory(ctx, &tg.MessagesGetHistoryRequest{
|
||||
Peer: peer,
|
||||
Limit: limit,
|
||||
channel, ok := resolved.Chats[0].(*tg.Channel)
|
||||
if !ok {
|
||||
return nil, errors.New("resolved peer is not a channel")
|
||||
}
|
||||
|
||||
history, err := s.client.API().MessagesGetHistory(ctx, &tg.MessagesGetHistoryRequest{
|
||||
Peer: &tg.InputPeerChannel{
|
||||
ChannelID: channel.ID,
|
||||
AccessHash: channel.AccessHash,
|
||||
},
|
||||
Limit: 100,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Extract messages
|
||||
var msgs []tg.MessageClass
|
||||
switch h := history.(type) {
|
||||
|
||||
Reference in New Issue
Block a user