LLM / job /cookie.go
ASI233's picture
Upload folder using huggingface_hub
c4baeb2 verified
package job
import (
"encoding/json"
"io/ioutil"
"log"
"os"
"sync"
"time"
"pplx2api/config"
"pplx2api/core"
)
const (
// ConfigFileName is the name of the file to store sessions
ConfigFileName = "sessions.json"
)
var (
sessionUpdaterInstance *SessionUpdater
sessionUpdaterOnce sync.Once
)
// SessionConfig represents the structure to be saved to file
type SessionConfig struct {
Sessions []config.SessionInfo `json:"sessions"`
}
// SessionUpdater 管理 Perplexity 会话的定时更新
type SessionUpdater struct {
interval time.Duration
stopChan chan struct{}
isRunning bool
runningLock sync.Mutex
configPath string
}
// NewSessionUpdater 创建一个新的会话更新器
// interval: 更新间隔时间
func GetSessionUpdater(interval time.Duration) *SessionUpdater {
sessionUpdaterOnce.Do(func() {
// 使用当前文件夹下的配置文件
configPath := ConfigFileName
sessionUpdaterInstance = &SessionUpdater{
interval: interval,
stopChan: make(chan struct{}),
isRunning: false,
configPath: configPath,
}
// 初始化时从文件加载会话
sessionUpdaterInstance.loadSessionsFromFile()
})
return sessionUpdaterInstance
}
// loadSessionsFromFile loads sessions from the config file if it exists
func (su *SessionUpdater) loadSessionsFromFile() {
// Check if file exists
if _, err := os.Stat(su.configPath); os.IsNotExist(err) {
log.Println("No sessions config file found, will create on first update")
return
}
// Read the file
data, err := ioutil.ReadFile(su.configPath)
if err != nil {
log.Printf("Failed to read sessions config file: %v", err)
return
}
// Parse the JSON
var sessionConfig SessionConfig
if err := json.Unmarshal(data, &sessionConfig); err != nil {
log.Printf("Failed to parse sessions config file: %v", err)
return
}
// Update the config with loaded sessions
config.ConfigInstance.RwMutex.Lock()
config.ConfigInstance.Sessions = sessionConfig.Sessions
config.ConfigInstance.RwMutex.Unlock()
log.Printf("Loaded %d sessions from config file", len(sessionConfig.Sessions))
}
// saveSessionsToFile saves the current sessions to the config file
func (su *SessionUpdater) saveSessionsToFile() error {
// Get current sessions
config.ConfigInstance.RwMutex.RLock()
sessionsCopy := make([]config.SessionInfo, len(config.ConfigInstance.Sessions))
copy(sessionsCopy, config.ConfigInstance.Sessions)
config.ConfigInstance.RwMutex.RUnlock()
// Create config structure
sessionConfig := SessionConfig{
Sessions: sessionsCopy,
}
// Convert to JSON
data, err := json.MarshalIndent(sessionConfig, "", " ")
if err != nil {
return err
}
// Write to file
err = ioutil.WriteFile(su.configPath, data, 0644)
if err != nil {
return err
}
log.Printf("Saved %d sessions to sessions.json file", len(sessionsCopy))
return nil
}
// Start 启动定时更新任务
func (su *SessionUpdater) Start() {
su.runningLock.Lock()
defer su.runningLock.Unlock()
if su.isRunning {
log.Println("Session updater is already running")
return
}
su.isRunning = true
su.stopChan = make(chan struct{})
go su.runUpdateLoop()
log.Println("Session updater started with interval:", su.interval)
}
// Stop 停止定时更新任务
func (su *SessionUpdater) Stop() {
su.runningLock.Lock()
defer su.runningLock.Unlock()
if !su.isRunning {
log.Println("Session updater is not running")
return
}
close(su.stopChan)
su.isRunning = false
log.Println("Session updater stopped")
}
// runUpdateLoop 运行更新循环
func (su *SessionUpdater) runUpdateLoop() {
ticker := time.NewTicker(su.interval)
defer ticker.Stop()
// 立即执行一次更新
// su.updateAllSessions()
for {
select {
case <-ticker.C:
su.updateAllSessions()
case <-su.stopChan:
log.Println("Update loop terminated")
return
}
}
}
// updateAllSessions 更新所有会话
func (su *SessionUpdater) updateAllSessions() {
log.Println("Starting session update for all sessions...")
// 复制当前会话列表,避免长时间持有锁
config.ConfigInstance.RwMutex.RLock()
sessionsCopy := make([]config.SessionInfo, len(config.ConfigInstance.Sessions))
copy(sessionsCopy, config.ConfigInstance.Sessions)
proxy := config.ConfigInstance.Proxy
config.ConfigInstance.RwMutex.RUnlock()
// 如果没有会话需要更新,直接返回
if len(sessionsCopy) == 0 {
log.Println("No sessions to update")
return
}
// 创建更新后的会话切片
updatedSessions := make([]config.SessionInfo, len(sessionsCopy))
var wg sync.WaitGroup
// 对每个会话执行更新
for i, session := range sessionsCopy {
wg.Add(1)
go func(index int, origSession config.SessionInfo) {
defer wg.Done()
// 创建客户端并更新 cookie
// 写死 model 和 openSearch 参数
client := core.NewClient(origSession.SessionKey, proxy, "claude-3-opus-20240229", false)
newCookie, err := client.GetNewCookie()
if err != nil {
log.Printf("Failed to update session %d: %v", index, err)
// 如果更新失败,保留原始会话
updatedSessions[index] = origSession
return
}
// 创建更新后的会话对象
updatedSessions[index] = config.SessionInfo{
SessionKey: newCookie,
}
}(i, session)
}
// 等待所有更新完成
wg.Wait()
// 一次性替换所有会话
config.ConfigInstance.RwMutex.Lock()
config.ConfigInstance.Sessions = updatedSessions
config.ConfigInstance.RwMutex.Unlock()
log.Printf("All %d sessions have been updated", len(updatedSessions))
// 保存更新后的配置到文件
if err := su.saveSessionsToFile(); err != nil {
log.Printf("Failed to save updated config: %v", err)
}
}