fallback to copying while rename failed; keep file if moving failed

This commit is contained in:
Dmitrii Andreev
2025-04-13 07:46:29 +03:00
parent 23f6f258d5
commit c63a640eb0
2 changed files with 42 additions and 6 deletions

View File

@@ -27,7 +27,7 @@ func LoadConfig() (*Config, error) {
"STREAM_URL": "",
"CHECK_INTERVAL": "1m",
"RECORDINGS_PATH": "./recordings",
"TEMP_PATH": "./temp",
"TEMP_PATH": "/tmp",
"SERVER_ADDRESS": ":8080",
"RSS_FEED_URL": "http://localhost:8080/rss",
"LOG_LEVEL": "info",

View File

@@ -81,6 +81,7 @@ func (r *Recorder) StopRecording() {
func (r *Recorder) recordStream(ctx context.Context, streamURL string) {
startTime := time.Now()
var tempFilePath string
var moveSuccessful bool
defer func() {
r.mu.Lock()
@@ -89,13 +90,16 @@ func (r *Recorder) recordStream(ctx context.Context, streamURL string) {
r.mu.Unlock()
slog.Info("Recording process finished")
if tempFilePath != "" {
// Only clean up temp file if it was successfully moved to final location
if tempFilePath != "" && moveSuccessful {
if _, err := os.Stat(tempFilePath); err == nil {
slog.Warn("Cleaning up temporary file", "path", tempFilePath)
slog.Debug("Cleaning up temporary file", "path", tempFilePath)
if err := os.Remove(tempFilePath); err != nil {
slog.Error("Failed to remove temporary file", "error", err)
}
}
} else if tempFilePath != "" && !moveSuccessful {
slog.Warn("Temporary file preserved for manual inspection", "path", tempFilePath)
}
}()
@@ -139,15 +143,47 @@ func (r *Recorder) recordStream(ctx context.Context, streamURL string) {
finalFilename = sanitizeFilename(finalFilename)
finalPath := filepath.Join(r.recordingsPath, finalFilename)
// Try rename first (fastest)
if err := os.Rename(tempFilePath, finalPath); err != nil {
slog.Error("Failed to move recording to final location", "error", err)
return
slog.Warn("Failed to move recording with rename, trying copy fallback", "error", err)
// Fallback to manual copy
if err := copyFile(tempFilePath, finalPath); err != nil {
slog.Error("Failed to move recording to final location", "error", err)
return
}
// Copy successful, mark for cleanup
moveSuccessful = true
slog.Info("Recording copied successfully using fallback method", "path", finalPath)
} else {
moveSuccessful = true
}
tempFilePath = "" // Prevent cleanup in defer
slog.Info("Recording saved", "path", finalPath, "size", bytesWritten, "duration", duration)
}
// copyFile copies a file from src to dst
func copyFile(src, dst string) error {
sourceFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("failed to open source file: %w", err)
}
defer sourceFile.Close()
destFile, err := os.Create(dst)
if err != nil {
return fmt.Errorf("failed to create destination file: %w", err)
}
defer destFile.Close()
if _, err := io.Copy(destFile, sourceFile); err != nil {
return fmt.Errorf("failed to copy file contents: %w", err)
}
return nil
}
func (r *Recorder) downloadStream(ctx context.Context, streamURL string, writer io.Writer) (int64, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, streamURL, nil)
if err != nil {