Add clean command
This commit is contained in:
@@ -91,9 +91,14 @@ func SessionSpoolAudioDir(spoolRoot, campaign, sessionID, runID string) string {
|
||||
return filepath.Join(spoolRoot, campaign, sessionID, runID, config.PathAudioDirSegment)
|
||||
}
|
||||
|
||||
// SessionSpoolDir returns the campaign/session scoped local spool root.
|
||||
func SessionSpoolDir(spoolRoot, campaign, sessionID string) string {
|
||||
return filepath.Join(spoolRoot, campaign, sessionID)
|
||||
}
|
||||
|
||||
// SessionSpoolRestoreAudioDir returns the local spool audio path for restore downloads.
|
||||
func SessionSpoolRestoreAudioDir(spoolRoot, campaign, sessionID string) string {
|
||||
return filepath.Join(spoolRoot, campaign, sessionID, "restore", config.PathAudioDirSegment)
|
||||
return filepath.Join(SessionSpoolDir(spoolRoot, campaign, sessionID), "restore", config.PathAudioDirSegment)
|
||||
}
|
||||
|
||||
// S3AudioCachePath returns the durable local cache path for one S3 audio object.
|
||||
@@ -120,6 +125,17 @@ func S3AudioCachePath(cacheRoot, bucket, key string) (string, error) {
|
||||
return filepath.Join(root, "s3", bucket, filepath.FromSlash(cleanKey)), nil
|
||||
}
|
||||
|
||||
// S3AudioCacheNamespaceDir returns the durable local cache namespace for all
|
||||
// Narratio S3 audio objects under one bucket/root prefix.
|
||||
func S3AudioCacheNamespaceDir(cacheRoot, bucket, rootPrefix string) (string, error) {
|
||||
sentinelKey := path.Join(cleanS3PathPart(rootPrefix), config.S3CampaignsSegment, ".narratio-cache-sentinel")
|
||||
sentinelPath, err := S3AudioCachePath(cacheRoot, bucket, sentinelKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Dir(sentinelPath), nil
|
||||
}
|
||||
|
||||
func cleanCacheS3Key(key string) string {
|
||||
normalized := strings.ReplaceAll(strings.TrimSpace(key), `\`, "/")
|
||||
normalized = strings.Trim(normalized, "/")
|
||||
|
||||
@@ -115,6 +115,15 @@ func TestSessionSpoolAudioDir(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionSpoolDir(t *testing.T) {
|
||||
root := "/var/spool/narratio"
|
||||
got := SessionSpoolDir(root, "forsaken", "2026-04-19")
|
||||
want := filepath.Join(root, "forsaken", "2026-04-19")
|
||||
if got != want {
|
||||
t.Fatalf("SessionSpoolDir() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionSpoolRestoreAudioDir(t *testing.T) {
|
||||
root := "/var/spool/narratio"
|
||||
got := SessionSpoolRestoreAudioDir(root, "forsaken", "2026-04-19")
|
||||
@@ -135,6 +144,17 @@ func TestS3AudioCachePath(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3AudioCacheNamespaceDir(t *testing.T) {
|
||||
got, err := S3AudioCacheNamespaceDir("/var/cache/narratio", "my-dnd-archive", "dnd")
|
||||
if err != nil {
|
||||
t.Fatalf("S3AudioCacheNamespaceDir() error = %v", err)
|
||||
}
|
||||
want := filepath.Join("/var/cache/narratio", "s3", "my-dnd-archive", "dnd", "campaigns")
|
||||
if got != want {
|
||||
t.Fatalf("S3AudioCacheNamespaceDir() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestS3AudioCachePathRejectsUnsafeInputs(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
||||
Reference in New Issue
Block a user