|
|
package job
|
|
|
|
|
|
import (
|
|
|
"encoding/json"
|
|
|
"io/ioutil"
|
|
|
"log"
|
|
|
"os"
|
|
|
"sync"
|
|
|
"time"
|
|
|
|
|
|
"pplx2api/config"
|
|
|
"pplx2api/core"
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
|
|
|
ConfigFileName = "sessions.json"
|
|
|
)
|
|
|
|
|
|
var (
|
|
|
sessionUpdaterInstance *SessionUpdater
|
|
|
sessionUpdaterOnce sync.Once
|
|
|
)
|
|
|
|
|
|
|
|
|
type SessionConfig struct {
|
|
|
Sessions []config.SessionInfo `json:"sessions"`
|
|
|
}
|
|
|
|
|
|
|
|
|
type SessionUpdater struct {
|
|
|
interval time.Duration
|
|
|
stopChan chan struct{}
|
|
|
isRunning bool
|
|
|
runningLock sync.Mutex
|
|
|
configPath string
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
func (su *SessionUpdater) loadSessionsFromFile() {
|
|
|
|
|
|
if _, err := os.Stat(su.configPath); os.IsNotExist(err) {
|
|
|
log.Println("No sessions config file found, will create on first update")
|
|
|
return
|
|
|
}
|
|
|
|
|
|
|
|
|
data, err := ioutil.ReadFile(su.configPath)
|
|
|
if err != nil {
|
|
|
log.Printf("Failed to read sessions config file: %v", err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
|
|
|
var sessionConfig SessionConfig
|
|
|
if err := json.Unmarshal(data, &sessionConfig); err != nil {
|
|
|
log.Printf("Failed to parse sessions config file: %v", err)
|
|
|
return
|
|
|
}
|
|
|
|
|
|
|
|
|
config.ConfigInstance.RwMutex.Lock()
|
|
|
config.ConfigInstance.Sessions = sessionConfig.Sessions
|
|
|
config.ConfigInstance.RwMutex.Unlock()
|
|
|
|
|
|
log.Printf("Loaded %d sessions from config file", len(sessionConfig.Sessions))
|
|
|
}
|
|
|
|
|
|
|
|
|
func (su *SessionUpdater) saveSessionsToFile() error {
|
|
|
|
|
|
config.ConfigInstance.RwMutex.RLock()
|
|
|
sessionsCopy := make([]config.SessionInfo, len(config.ConfigInstance.Sessions))
|
|
|
copy(sessionsCopy, config.ConfigInstance.Sessions)
|
|
|
config.ConfigInstance.RwMutex.RUnlock()
|
|
|
|
|
|
|
|
|
sessionConfig := SessionConfig{
|
|
|
Sessions: sessionsCopy,
|
|
|
}
|
|
|
|
|
|
|
|
|
data, err := json.MarshalIndent(sessionConfig, "", " ")
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
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)
|
|
|
}
|
|
|
|
|
|
|
|
|
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")
|
|
|
}
|
|
|
|
|
|
|
|
|
func (su *SessionUpdater) runUpdateLoop() {
|
|
|
ticker := time.NewTicker(su.interval)
|
|
|
defer ticker.Stop()
|
|
|
|
|
|
|
|
|
for {
|
|
|
select {
|
|
|
case <-ticker.C:
|
|
|
su.updateAllSessions()
|
|
|
case <-su.stopChan:
|
|
|
log.Println("Update loop terminated")
|
|
|
return
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
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)
|
|
|
}
|
|
|
}
|
|
|
|