package agent import ( "database/sql" "fmt" "os" "path/filepath" "strings" "gitea.hsrv.site/mrleo1nid/backup-master/internal/manifest" _ "modernc.org/sqlite" ) const xuiDB = "/etc/x-ui/x-ui.db" // snapshotXUI делает консистентную копию базы 3x-ui на горячую (VACUUM INTO), // без логина в панель и без остановки сервиса. func (c *collector) snapshotXUI(mc *manifest.Category) error { if _, err := os.Stat(xuiDB); err != nil { c.warn("xui: нет %s", xuiDB) return nil } dir, err := c.spoolDir(mc.Name) if err != nil { return err } out := filepath.Join(dir, "x-ui.db") if err := vacuumInto(xuiDB, out); err != nil { c.warn("xui: снимок базы не удался: %v", err) return nil } mc.Dumps = append(mc.Dumps, manifest.Dump{Name: "x-ui.db", Kind: "sqlite", Target: xuiDB}) c.add(manifest.MainPart, dumpItem(mc.Name, out, "x-ui.db")) return nil } func vacuumInto(src, dst string) error { _ = os.Remove(dst) db, err := sql.Open("sqlite", "file:"+src+"?_pragma=busy_timeout(10000)") if err != nil { return err } defer db.Close() _, err = db.Exec(fmt.Sprintf("VACUUM INTO '%s'", strings.ReplaceAll(dst, "'", "''"))) return err }