Files
trbot/plugins/teamspeak/connect.go
2026-03-09 16:14:43 +08:00

178 lines
4.4 KiB
Go

package teamspeak
import (
"context"
"fmt"
"time"
"github.com/go-telegram/bot"
ts3 "github.com/jkoenig134/go-ts3"
"github.com/rs/zerolog"
"trle5.xyz/trbot/utils"
"trle5.xyz/trbot/utils/flaterr"
)
// Connect 检查配置并尝试连接到 TeamSpeak 服务器
func (sc *ServerConfig) Connect(ctx context.Context) error {
logger := zerolog.Ctx(ctx).
With().
Str("pluginName", "teamspeak3").
Str(utils.GetCurrentFuncName()).
Int64("GroupID", sc.GroupID).
Logger()
var err error
sc.rw.Lock()
defer sc.rw.Unlock()
// 如果服务器地址为空不允许重新启动
if sc.URL == "" || sc.API == "" {
logger.Error().
Str("path", tsConfigPath).
Msg("No URL or API in config")
return fmt.Errorf("no URL API in config")
}
logger.Info().Msg("Starting client...")
sc.c = ts3.NewClient(ts3.NewConfig(sc.URL, sc.API))
info, err := sc.c.Whoami()
if err != nil {
logger.Error().
Err(err).
Str("path", tsConfigPath).
Msg("Failed to connect to server")
return fmt.Errorf("failed to connnect to server: %w", err)
}
botNickName = info.ClientUniqueIdentifier
logger.Info().Msg("Checking Group ID...")
// 检查要设定通知的群组 ID 是否存在
if sc.GroupID == 0 {
logger.Error().
Str("path", tsConfigPath).
Msg("No GroupID in config")
return fmt.Errorf("no GroupID in config")
}
logger.Info().Msg("Testing connection...")
// 显示服务端版本测试一下连接
v, err := sc.c.Version()
if err != nil {
logger.Error().
Err(err).
Str("path", tsConfigPath).
Msg("Failed to get server version")
return fmt.Errorf("failed to get server version: %w", err)
}
logger.Info().
Str("version", v.Version).
Str("platform", v.Platform).
Str("build", v.Build).
Msg("TeamSpeak server connected")
if !sc.s.IsCheckClientTaskScheduled {
err = sc.ScheduleCheckClientTask(ctx)
if err != nil {
logger.Error().
Err(err).
Msg("Failed to schedule check client task")
return fmt.Errorf("failed to schedule check client task: %w", err)
}
}
if !sc.s.IsDeleteMessageTaskScheduled {
err = sc.ScheduleDeleteMessageTask(ctx)
if err != nil {
logger.Error().
Err(err).
Msg("Failed to schedule delete message task")
return fmt.Errorf("failed to schedule delete message task: %w", err)
}
}
return nil
}
// RetryLoop 将循环尝试连接到服务器,直到成功为止
func (sc *ServerConfig) RetryLoop(ctx context.Context) {
logger := zerolog.Ctx(ctx).
With().
Str("pluginName", "teamspeak3").
Str(utils.GetCurrentFuncName()).
Logger()
sc.s.IsInRetryLoop = true
defer func() {
sc.s.IsInRetryLoop = false
logger.Info().Msg("reconnect loop exited")
}()
sc.s.RetryCount = 0
retryTicker := time.NewTicker(time.Second * 5)
defer retryTicker.Stop()
for {
select {
case <-ctx.Done():
return
case <-sc.s.ResetTicker:
sc.ResumeCheckClientTask(ctx)
logger.Info().Msg("reconnect by command success")
return
case <-retryTicker.C:
logger.Info().
Int("retryCount", sc.s.RetryCount).
Msg("try reconnect...")
// 实际上并不生效...
timeoutCtx, cancel := context.WithTimeout(ctx, time.Second * 30)
defer cancel()
err := sc.Connect(timeoutCtx)
if err != nil {
// 出现错误时,先降低 ticker 速度,然后尝试重新初始化
// 无法成功则等待下一个周期继续尝试
if sc.s.RetryCount < 15 {
sc.s.RetryCount++
retryTicker.Reset(time.Duration(sc.s.RetryCount * 20) * time.Second)
}
logger.Warn().
Int("retryCount", sc.s.RetryCount).
Time("nextRetry", time.Now().Add(time.Duration(sc.s.RetryCount * 20) * time.Second)).
Msg("reconnect failed")
} else {
// 重新初始化成功则恢复查询任务
sc.ResumeCheckClientTask(ctx)
logger.Info().Msg("reconnect success")
botMessage, err := botInstance.SendMessage(ctx, &bot.SendMessageParams{
ChatID: sc.GroupID,
Text: "已成功与服务器重新建立连接",
})
if err != nil {
logger.Error().
Err(err).
Int64("chatID", sc.GroupID).
Str("content", "success reconnect to server notice").
Msg(flaterr.SendMessage.Str())
} else {
sc.s.OldMessageID = append(tsConfig.s.OldMessageID,
OldMessageID{
Date: int(time.Now().Unix()),
ID: botMessage.ID,
},
OldMessageID{
Date: int(time.Now().Unix()),
ID: sc.s.RetryMsgID,
},
)
}
return
}
}
}
}