Update dependencies and clean up project structure. Add cloud.google.com/go/compute/metadata as an indirect requirement in go.mod. Remove unused files and update package.json for Vite and React plugins. Refactor Makefile for improved build process.
This commit is contained in:
@@ -18,6 +18,10 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const runnerIDContextKey contextKey = "runner_id"
|
||||
|
||||
// handleListRunners lists all runners
|
||||
func (s *Server) handleListRunners(w http.ResponseWriter, r *http.Request) {
|
||||
_, err := getUserID(r)
|
||||
@@ -86,7 +90,7 @@ func (s *Server) runnerAuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
|
||||
// Add runner ID to context
|
||||
ctx := r.Context()
|
||||
ctx = context.WithValue(ctx, "runner_id", runnerID)
|
||||
ctx = context.WithValue(ctx, runnerIDContextKey, runnerID)
|
||||
next(w, r.WithContext(ctx))
|
||||
}
|
||||
}
|
||||
@@ -188,7 +192,7 @@ func (s *Server) handleUpdateTaskProgress(w http.ResponseWriter, r *http.Request
|
||||
// handleUpdateTaskStep handles step start/complete events from runners
|
||||
func (s *Server) handleUpdateTaskStep(w http.ResponseWriter, r *http.Request) {
|
||||
// Get runner ID from context (set by runnerAuthMiddleware)
|
||||
runnerID, ok := r.Context().Value("runner_id").(int64)
|
||||
runnerID, ok := r.Context().Value(runnerIDContextKey).(int64)
|
||||
if !ok {
|
||||
s.respondError(w, http.StatusUnauthorized, "runner_id not found in context")
|
||||
return
|
||||
@@ -379,43 +383,6 @@ func (s *Server) handleUploadFileFromRunner(w http.ResponseWriter, r *http.Reque
|
||||
})
|
||||
}
|
||||
|
||||
// generateMP4Video generates MP4 video from PNG frames for a completed job
|
||||
func (s *Server) generateMP4Video(jobID int64) {
|
||||
// This would be called by a runner or external process
|
||||
// For now, we'll create a special task that runners can pick up
|
||||
// In a production system, you might want to use a job queue or have a dedicated video processor
|
||||
|
||||
// Get all PNG output files for this job
|
||||
rows, err := s.db.Query(
|
||||
`SELECT file_path, file_name FROM job_files
|
||||
WHERE job_id = ? AND file_type = ? AND file_name LIKE '%.png'
|
||||
ORDER BY file_name`,
|
||||
jobID, types.JobFileTypeOutput,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to query PNG files for job %d: %v", jobID, err)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var pngFiles []string
|
||||
for rows.Next() {
|
||||
var filePath, fileName string
|
||||
if err := rows.Scan(&filePath, &fileName); err == nil {
|
||||
pngFiles = append(pngFiles, filePath)
|
||||
}
|
||||
}
|
||||
|
||||
if len(pngFiles) == 0 {
|
||||
log.Printf("No PNG files found for job %d", jobID)
|
||||
return
|
||||
}
|
||||
|
||||
// Note: Video generation will be handled by runners when they complete tasks
|
||||
// Runners can check job status and generate MP4 when all frames are complete
|
||||
log.Printf("Job %d completed with %d PNG frames - ready for MP4 generation", jobID, len(pngFiles))
|
||||
}
|
||||
|
||||
// handleGetJobStatusForRunner allows runners to check job status
|
||||
func (s *Server) handleGetJobStatusForRunner(w http.ResponseWriter, r *http.Request) {
|
||||
jobID, err := parseID(r, "jobId")
|
||||
@@ -632,18 +599,15 @@ func (s *Server) handleRunnerWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
go func() {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
s.runnerConnsMu.RLock()
|
||||
conn, exists := s.runnerConns[runnerID]
|
||||
s.runnerConnsMu.RUnlock()
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
if err := conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(10*time.Second)); err != nil {
|
||||
return
|
||||
}
|
||||
for range ticker.C {
|
||||
s.runnerConnsMu.RLock()
|
||||
conn, exists := s.runnerConns[runnerID]
|
||||
s.runnerConnsMu.RUnlock()
|
||||
if !exists {
|
||||
return
|
||||
}
|
||||
if err := conn.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(10*time.Second)); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -496,6 +496,9 @@ func (s *Server) recoverTaskTimeouts() {
|
||||
WHERE id = ?`,
|
||||
types.TaskStatusFailed, "Task timeout exceeded, max retries reached", taskID,
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("Failed to mark task %d as failed: %v", taskID, err)
|
||||
}
|
||||
} else {
|
||||
// Reset to pending
|
||||
_, err = s.db.Exec(
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -496,10 +497,10 @@ func (c *Client) processTask(task map[string]interface{}, jobName, outputFormat
|
||||
cmd.Dir = workDir
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("blender failed: %w\nOutput: %s", err, string(output))
|
||||
errMsg := fmt.Sprintf("blender failed: %v\nOutput: %s", err, string(output))
|
||||
c.sendLog(taskID, types.LogLevelError, errMsg, "render_blender")
|
||||
c.sendStepUpdate(taskID, "render_blender", types.StepStatusFailed, errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
// Find rendered output file
|
||||
@@ -508,7 +509,7 @@ func (c *Client) processTask(task map[string]interface{}, jobName, outputFormat
|
||||
errMsg := fmt.Sprintf("output file not found: %s", outputFile)
|
||||
c.sendLog(taskID, types.LogLevelError, errMsg, "render_blender")
|
||||
c.sendStepUpdate(taskID, "render_blender", types.StepStatusFailed, errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
c.sendLog(taskID, types.LogLevelInfo, fmt.Sprintf("Blender render completed for frame %d", frameStart), "render_blender")
|
||||
c.sendStepUpdate(taskID, "render_blender", types.StepStatusCompleted, "")
|
||||
@@ -523,10 +524,10 @@ func (c *Client) processTask(task map[string]interface{}, jobName, outputFormat
|
||||
|
||||
outputPath, err := c.uploadFile(jobID, outputFile)
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("failed to upload output: %w", err)
|
||||
errMsg := fmt.Sprintf("failed to upload output: %v", err)
|
||||
c.sendLog(taskID, types.LogLevelError, errMsg, uploadStepName)
|
||||
c.sendStepUpdate(taskID, uploadStepName, types.StepStatusFailed, errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
c.sendLog(taskID, types.LogLevelInfo, "Output file uploaded successfully", uploadStepName)
|
||||
c.sendStepUpdate(taskID, uploadStepName, types.StepStatusCompleted, "")
|
||||
@@ -1001,10 +1002,10 @@ sys.stdout.flush()
|
||||
cmd.Dir = workDir
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
errMsg := fmt.Sprintf("blender metadata extraction failed: %w\nOutput: %s", err, string(output))
|
||||
errMsg := fmt.Sprintf("blender metadata extraction failed: %v\nOutput: %s", err, string(output))
|
||||
c.sendLog(taskID, types.LogLevelError, errMsg, "extract_metadata")
|
||||
c.sendStepUpdate(taskID, "extract_metadata", types.StepStatusFailed, errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
// Parse output (metadata is printed to stdout)
|
||||
@@ -1016,16 +1017,16 @@ sys.stdout.flush()
|
||||
errMsg := "Failed to extract JSON from Blender output"
|
||||
c.sendLog(taskID, types.LogLevelError, errMsg, "extract_metadata")
|
||||
c.sendStepUpdate(taskID, "extract_metadata", types.StepStatusFailed, errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
metadataJSON = metadataJSON[jsonStart : jsonEnd+1]
|
||||
|
||||
var metadata types.BlendMetadata
|
||||
if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
|
||||
errMsg := fmt.Sprintf("Failed to parse metadata JSON: %w", err)
|
||||
errMsg := fmt.Sprintf("Failed to parse metadata JSON: %v", err)
|
||||
c.sendLog(taskID, types.LogLevelError, errMsg, "extract_metadata")
|
||||
c.sendStepUpdate(taskID, "extract_metadata", types.StepStatusFailed, errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
c.sendLog(taskID, types.LogLevelInfo, fmt.Sprintf("Metadata extracted: frames %d-%d, resolution %dx%d",
|
||||
@@ -1038,10 +1039,10 @@ sys.stdout.flush()
|
||||
|
||||
// Submit metadata to manager
|
||||
if err := c.submitMetadata(jobID, metadata); err != nil {
|
||||
errMsg := fmt.Sprintf("Failed to submit metadata: %w", err)
|
||||
errMsg := fmt.Sprintf("Failed to submit metadata: %v", err)
|
||||
c.sendLog(taskID, types.LogLevelError, errMsg, "submit_metadata")
|
||||
c.sendStepUpdate(taskID, "submit_metadata", types.StepStatusFailed, errMsg)
|
||||
return fmt.Errorf(errMsg)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
|
||||
c.sendStepUpdate(taskID, "submit_metadata", types.StepStatusCompleted, "")
|
||||
|
||||
Reference in New Issue
Block a user