package handlers import ( "crypto/sha256" "fmt" "net/http" "github.com/flatrender/render-svc/internal/db" "github.com/flatrender/render-svc/internal/middleware" "github.com/flatrender/render-svc/internal/models" "github.com/gin-gonic/gin" "github.com/google/uuid" ) type SnapshotHandler struct { store *db.Store } func NewSnapshotHandler(store *db.Store) *SnapshotHandler { return &SnapshotHandler{store: store} } // POST /v1/snapshots func (h *SnapshotHandler) Create(c *gin.Context) { userID := middleware.GetUserID(c) tenantID := middleware.GetTenantID(c) var req models.SnapshotCreateRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, models.APIError{Code: "bad_request", Message: err.Error()}) return } // Deterministic cache key from inputs hash := fmt.Sprintf("%x", sha256.Sum256([]byte( fmt.Sprintf("%s:%s:%d", req.SavedProjectID, req.SceneKey, req.FrameNumber), ))) // Check cache first cached, err := h.store.GetCachedSnapshot(c.Request.Context(), req.SavedProjectID, req.SceneKey, req.FrameNumber, hash) if err == nil && cached != nil { c.JSON(http.StatusAccepted, gin.H{ "snapshot_id": cached.ID, "status": "Cached", "image_url": cached.ImageURL, "thumbnail_url": cached.ThumbnailURL, "expires_at": cached.ExpiresAt, }) return } snap, err := h.store.CreateSnapshot(c.Request.Context(), userID, tenantID, &req, hash) if err != nil { c.JSON(http.StatusInternalServerError, models.APIError{Code: "internal_error", Message: err.Error()}) return } c.JSON(http.StatusAccepted, gin.H{ "snapshot_id": snap.ID, "status": "Pending", "image_url": nil, "thumbnail_url": nil, "expires_at": snap.ExpiresAt, }) } // GET /v1/snapshots/:snapshot_id func (h *SnapshotHandler) Get(c *gin.Context) { snapID, err := uuid.Parse(c.Param("snapshot_id")) if err != nil { c.JSON(http.StatusBadRequest, models.APIError{Code: "bad_request", Message: "invalid snapshot_id"}) return } snap, err := h.store.GetSnapshotByID(c.Request.Context(), snapID) if err != nil { c.JSON(http.StatusNotFound, models.APIError{Code: "not_found", Message: err.Error()}) return } c.JSON(http.StatusOK, snap) }