teldrive/internal/tgc/workers.go

181 lines
3.7 KiB
Go
Raw Normal View History

2023-09-20 03:20:44 +08:00
package tgc
import (
2023-11-25 12:31:29 +08:00
"context"
2024-06-22 20:29:59 +08:00
"strings"
2023-09-20 03:20:44 +08:00
"sync"
"time"
2023-09-24 04:26:04 +08:00
"github.com/divyam234/teldrive/internal/config"
"github.com/divyam234/teldrive/internal/kv"
2023-09-24 04:26:04 +08:00
"github.com/gotd/td/telegram"
"go.uber.org/zap"
2023-09-20 03:20:44 +08:00
)
type BotWorker struct {
2024-08-04 19:43:40 +08:00
mu sync.RWMutex
2023-11-16 23:21:35 +08:00
bots map[int64][]string
currIdx map[int64]int
2023-09-20 03:20:44 +08:00
}
func NewBotWorker() *BotWorker {
return &BotWorker{
2024-08-04 19:43:40 +08:00
bots: make(map[int64][]string),
currIdx: make(map[int64]int),
2023-09-20 03:20:44 +08:00
}
}
func (w *BotWorker) Set(bots []string, channelID int64) {
2023-11-16 23:21:35 +08:00
w.mu.Lock()
defer w.mu.Unlock()
2024-08-04 19:43:40 +08:00
w.bots[channelID] = bots
w.currIdx[channelID] = 0
2023-09-20 03:20:44 +08:00
}
func (w *BotWorker) Next(channelID int64) (string, int) {
2024-08-04 19:43:40 +08:00
w.mu.RLock()
defer w.mu.RUnlock()
bots := w.bots[channelID]
index := w.currIdx[channelID]
w.currIdx[channelID] = (index + 1) % len(bots)
return bots[index], index
}
type ClientStatus int
const (
StatusIdle ClientStatus = iota
StatusBusy
)
2023-09-24 04:26:04 +08:00
type Client struct {
Tg *telegram.Client
Stop StopFunc
Status ClientStatus
UserID string
2023-09-24 04:26:04 +08:00
}
type StreamWorker struct {
mu sync.RWMutex
clients map[string]*Client
currIdx map[int64]int
channelBots map[int64][]string
cnf *config.TGConfig
kv kv.KV
ctx context.Context
logger *zap.SugaredLogger
activeStreams int
cancel context.CancelFunc
2023-09-24 04:26:04 +08:00
}
func NewStreamWorker(cnf *config.Config, kv kv.KV, logger *zap.SugaredLogger) *StreamWorker {
ctx, cancel := context.WithCancel(context.Background())
worker := &StreamWorker{
cnf: &cnf.TG,
kv: kv,
ctx: ctx,
clients: make(map[string]*Client),
currIdx: make(map[int64]int),
channelBots: make(map[int64][]string),
logger: logger,
cancel: cancel,
2024-08-04 19:43:40 +08:00
}
go worker.startIdleClientMonitor()
return worker
2024-08-04 19:43:40 +08:00
}
2024-08-04 19:43:40 +08:00
func (w *StreamWorker) Set(bots []string, channelID int64) {
2023-11-16 23:21:35 +08:00
w.mu.Lock()
defer w.mu.Unlock()
2024-08-04 19:43:40 +08:00
w.channelBots[channelID] = bots
w.currIdx[channelID] = 0
2023-09-24 04:26:04 +08:00
}
func (w *StreamWorker) Next(channelID int64) (*Client, error) {
2023-11-16 23:21:35 +08:00
w.mu.Lock()
defer w.mu.Unlock()
2024-08-04 19:43:40 +08:00
bots := w.channelBots[channelID]
index := w.currIdx[channelID]
token := bots[index]
userID := strings.Split(token, ":")[0]
client, err := w.getOrCreateClient(userID, token)
if err != nil {
return nil, err
2024-08-04 19:43:40 +08:00
}
w.currIdx[channelID] = (index + 1) % len(bots)
return client, nil
2023-11-16 23:21:35 +08:00
}
func (w *StreamWorker) IncActiveStream() error {
2023-11-16 23:21:35 +08:00
w.mu.Lock()
defer w.mu.Unlock()
w.activeStreams++
return nil
}
2023-11-16 23:21:35 +08:00
func (w *StreamWorker) DecActiveStreams() error {
w.mu.Lock()
defer w.mu.Unlock()
2023-11-16 23:21:35 +08:00
if w.activeStreams == 0 {
return nil
}
w.activeStreams--
return nil
}
2024-08-04 19:43:40 +08:00
func (w *StreamWorker) getOrCreateClient(userID, token string) (*Client, error) {
client, ok := w.clients[userID]
if !ok || (client.Status == StatusIdle && client.Stop == nil) {
middlewares := Middlewares(w.cnf, 5)
tgClient, _ := BotClient(w.ctx, w.kv, w.cnf, token, middlewares...)
client = &Client{Tg: tgClient, Status: StatusIdle, UserID: userID}
w.clients[userID] = client
stop, err := Connect(client.Tg, WithBotToken(token))
2023-11-16 23:21:35 +08:00
if err != nil {
return nil, err
}
client.Stop = stop
client.Status = StatusBusy
w.logger.Debug("started bg client: ", userID)
}
return client, nil
}
func (w *StreamWorker) startIdleClientMonitor() {
ticker := time.NewTicker(w.cnf.BgBotsCheckInterval)
defer ticker.Stop()
2024-08-04 19:43:40 +08:00
for {
select {
case <-ticker.C:
2024-08-04 19:43:40 +08:00
w.checkIdleClients()
case <-w.ctx.Done():
return
}
}
2023-09-24 04:26:04 +08:00
}
2024-08-04 19:43:40 +08:00
func (w *StreamWorker) checkIdleClients() {
w.mu.Lock()
defer w.mu.Unlock()
if w.activeStreams == 0 {
for _, client := range w.clients {
if client.Status == StatusBusy && client.Stop != nil {
2024-08-04 19:43:40 +08:00
client.Stop()
client.Stop = nil
client.Tg = nil
client.Status = StatusIdle
2024-08-04 19:43:40 +08:00
w.logger.Debug("stopped bg client: ", client.UserID)
}
}
2024-04-19 04:46:47 +08:00
}
}