mirror of
https://github.com/arkorty/DownLink.git
synced 2026-03-18 00:57:15 +00:00
feat: caching & logging
This commit is contained in:
109
backend/handlers/video.go
Normal file
109
backend/handlers/video.go
Normal file
@@ -0,0 +1,109 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"DownLink/models"
|
||||
"DownLink/services"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type VideoHandler struct {
|
||||
videoService *services.VideoService
|
||||
}
|
||||
|
||||
func NewVideoHandler(videoService *services.VideoService) *VideoHandler {
|
||||
return &VideoHandler{
|
||||
videoService: videoService,
|
||||
}
|
||||
}
|
||||
|
||||
func (vh *VideoHandler) DownloadVideo(w http.ResponseWriter, r *http.Request) {
|
||||
var req models.VideoDownloadRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
slog.Error("Failed to decode request body", "error", err)
|
||||
vh.writeError(w, http.StatusBadRequest, "Invalid JSON")
|
||||
return
|
||||
}
|
||||
|
||||
if req.URL == "" || req.Quality == "" {
|
||||
slog.Warn("Invalid request parameters", "url", req.URL, "quality", req.Quality)
|
||||
vh.writeError(w, http.StatusBadRequest, "URL and Quality are required")
|
||||
return
|
||||
}
|
||||
|
||||
slog.Info("Starting video download", "url", req.URL, "quality", req.Quality)
|
||||
|
||||
outputPath, err := vh.videoService.DownloadVideo(req.URL, req.Quality)
|
||||
if err != nil {
|
||||
slog.Error("Video download failed", "url", req.URL, "quality", req.Quality, "error", err)
|
||||
vh.writeError(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Determine if this was a cached response
|
||||
isCached := !strings.Contains(outputPath, "dl_") && strings.Contains(outputPath, "cache")
|
||||
|
||||
// Only cleanup if it's a fresh download (not cached)
|
||||
if strings.Contains(outputPath, "dl_") {
|
||||
defer vh.videoService.CleanupTempDir(outputPath)
|
||||
}
|
||||
|
||||
uid := uuid.New().String()
|
||||
filename := fmt.Sprintf("video_%s.mp4", uid)
|
||||
|
||||
// Add cache status header
|
||||
if isCached {
|
||||
w.Header().Set("X-Cache-Status", "HIT")
|
||||
slog.Info("Serving cached video", "url", req.URL, "quality", req.Quality, "file", outputPath)
|
||||
} else {
|
||||
w.Header().Set("X-Cache-Status", "MISS")
|
||||
slog.Info("Serving fresh download", "url", req.URL, "quality", req.Quality, "file", outputPath)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
|
||||
w.Header().Set("Content-Type", "video/mp4")
|
||||
|
||||
http.ServeFile(w, r, outputPath)
|
||||
}
|
||||
|
||||
func (vh *VideoHandler) HealthCheck(w http.ResponseWriter, r *http.Request) {
|
||||
slog.Debug("Health check requested", "remote_addr", r.RemoteAddr)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("Backend for DownLink is running.\n"))
|
||||
}
|
||||
|
||||
func (vh *VideoHandler) ClearCache(w http.ResponseWriter, r *http.Request) {
|
||||
slog.Info("Cache clear requested")
|
||||
if err := vh.videoService.CleanupExpiredCache(0); err != nil {
|
||||
slog.Error("Failed to clear cache", "error", err)
|
||||
vh.writeError(w, http.StatusInternalServerError, fmt.Sprintf("Failed to clear cache: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
slog.Info("Cache cleared successfully")
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]string{"message": "Cache cleared successfully"})
|
||||
}
|
||||
|
||||
func (vh *VideoHandler) GetCacheStatus(w http.ResponseWriter, r *http.Request) {
|
||||
slog.Debug("Cache status requested")
|
||||
status := vh.videoService.GetCacheStats()
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(status)
|
||||
}
|
||||
|
||||
func (vh *VideoHandler) writeError(w http.ResponseWriter, status int, message string) {
|
||||
slog.Error("HTTP error response", "status", status, "message", message)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
json.NewEncoder(w).Encode(models.ErrorResponse{Error: message})
|
||||
}
|
||||
Reference in New Issue
Block a user