mirror of
https://wget.la/https://github.com/leookun/cursor-byok
synced 2026-08-19 12:37:55 +08:00
v0.3.8
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
package forwarder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const historyMaintenanceLockStaleAfter = 30 * time.Minute
|
||||
const historyMaintenanceTempStaleAfter = 5 * time.Minute
|
||||
|
||||
func (service *Service) startHistoryMaintenance() {
|
||||
if service == nil || service.store == nil {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
if err := service.runHistoryMaintenance(); err != nil {
|
||||
log.Printf("forwarder history maintenance failed: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (service *Service) runHistoryMaintenance() error {
|
||||
historyRoot := strings.TrimSpace(service.store.HistoryDir())
|
||||
if historyRoot == "" {
|
||||
return nil
|
||||
}
|
||||
release, ok, err := acquireHistoryMaintenanceLock(historyRoot)
|
||||
if err != nil || !ok {
|
||||
return err
|
||||
}
|
||||
defer release()
|
||||
|
||||
entries, err := os.ReadDir(historyRoot)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
cleanupRootLegacyHistoryArtifact(historyRoot, entry.Name())
|
||||
continue
|
||||
}
|
||||
service.cleanupConversationLegacyArtifacts(filepath.Join(historyRoot, entry.Name()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func cleanupRootLegacyHistoryArtifact(historyRoot string, name string) {
|
||||
trimmedName := strings.TrimSpace(name)
|
||||
if trimmedName == "" || trimmedName == ".history-maintenance.lock" {
|
||||
return
|
||||
}
|
||||
if !isRootLegacyHistoryArtifact(trimmedName) {
|
||||
return
|
||||
}
|
||||
path := filepath.Join(historyRoot, trimmedName)
|
||||
if strings.Contains(trimmedName, ".tmp-") {
|
||||
cleanupStaleHistoryTempArtifact(path)
|
||||
return
|
||||
}
|
||||
if err := os.RemoveAll(path); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("forwarder root legacy cleanup failed path=%s err=%v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
func isRootLegacyHistoryArtifact(name string) bool {
|
||||
if strings.TrimSpace(name) == usageFileName || strings.TrimSpace(name) == usageFileName+".lock" {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(name, ".json") || strings.HasSuffix(name, ".jsonl") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(name, ".tmp-") {
|
||||
return true
|
||||
}
|
||||
if strings.HasSuffix(name, ".lock") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (service *Service) cleanupConversationLegacyArtifacts(conversationDir string) {
|
||||
for _, name := range []string{
|
||||
"turns",
|
||||
"active",
|
||||
"latest.json",
|
||||
"summary.json",
|
||||
"replay.json",
|
||||
"runtime.json",
|
||||
"request.json",
|
||||
"recovery.json",
|
||||
"conversation.json",
|
||||
"entries.jsonl",
|
||||
} {
|
||||
path := filepath.Join(conversationDir, name)
|
||||
if err := os.RemoveAll(path); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("forwarder legacy cleanup failed path=%s err=%v", path, err)
|
||||
}
|
||||
}
|
||||
entries, err := os.ReadDir(conversationDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
if strings.Contains(entry.Name(), ".tmp-") {
|
||||
cleanupStaleHistoryTempArtifact(filepath.Join(conversationDir, entry.Name()))
|
||||
}
|
||||
continue
|
||||
}
|
||||
if _, err := strconv.Atoi(strings.TrimSpace(entry.Name())); err != nil {
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(conversationDir, entry.Name())
|
||||
if err := os.RemoveAll(path); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("forwarder numeric legacy cleanup failed path=%s err=%v", path, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cleanupStaleHistoryTempArtifact(path string) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if time.Since(info.ModTime()) < historyMaintenanceTempStaleAfter {
|
||||
return
|
||||
}
|
||||
if err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("forwarder temp cleanup failed path=%s err=%v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
func acquireHistoryMaintenanceLock(historyRoot string) (func(), bool, error) {
|
||||
if err := os.MkdirAll(historyRoot, 0o755); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
lockPath := filepath.Join(historyRoot, ".history-maintenance.lock")
|
||||
for attempt := 0; attempt < 2; attempt++ {
|
||||
file, err := os.OpenFile(lockPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o600)
|
||||
if err == nil {
|
||||
_, _ = file.WriteString(time.Now().UTC().Format(time.RFC3339Nano))
|
||||
_ = file.Close()
|
||||
return func() {
|
||||
_ = os.Remove(lockPath)
|
||||
}, true, nil
|
||||
}
|
||||
if !errors.Is(err, os.ErrExist) {
|
||||
return nil, false, err
|
||||
}
|
||||
info, statErr := os.Stat(lockPath)
|
||||
if statErr != nil {
|
||||
if errors.Is(statErr, os.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
return nil, false, statErr
|
||||
}
|
||||
if time.Since(info.ModTime()) > historyMaintenanceLockStaleAfter {
|
||||
_ = os.Remove(lockPath)
|
||||
continue
|
||||
}
|
||||
return nil, false, nil
|
||||
}
|
||||
return nil, false, nil
|
||||
}
|
||||
Reference in New Issue
Block a user