Refactor runner and installation scripts for improved functionality

- Removed the `--disable-hiprt` flag from the runner command, simplifying the rendering options for users.
- Updated the `jiggablend-runner` script and README to reflect the removal of the HIPRT control flag, enhancing clarity in usage instructions.
- Enhanced the installation script to provide clearer examples for running the jiggablend manager and runner, improving user experience during setup.
- Implemented a more robust GPU backend detection mechanism, allowing for better compatibility with various hardware configurations.
This commit is contained in:
2026-03-14 21:08:06 -05:00
parent 28cb50492c
commit 16d6a95058
30 changed files with 1041 additions and 782 deletions

View File

@@ -30,27 +30,22 @@ import (
"github.com/gorilla/websocket"
)
// Configuration constants
// Configuration constants (non-configurable infrastructure values)
const (
// WebSocket timeouts
WSReadDeadline = 90 * time.Second
WSPingInterval = 30 * time.Second
WSWriteDeadline = 10 * time.Second
// Task timeouts
RenderTimeout = 60 * 60 // 1 hour for frame rendering
VideoEncodeTimeout = 60 * 60 * 24 // 24 hours for encoding
// Limits
MaxUploadSize = 50 << 30 // 50 GB
// Infrastructure timers
RunnerHeartbeatTimeout = 90 * time.Second
TaskDistributionInterval = 10 * time.Second
ProgressUpdateThrottle = 2 * time.Second
// Cookie settings
SessionCookieMaxAge = 86400 // 24 hours
)
// Operational limits are loaded from database config at Manager initialization.
// Defaults are defined in internal/config/config.go convenience methods.
// Manager represents the manager server
type Manager struct {
db *database.DB
@@ -109,6 +104,12 @@ type Manager struct {
// Server start time for health checks
startTime time.Time
// Configurable operational values loaded from config
renderTimeout int // seconds
videoEncodeTimeout int // seconds
maxUploadSize int64 // bytes
sessionCookieMaxAge int // seconds
}
// ClientConnection represents a client WebSocket connection with subscriptions
@@ -166,6 +167,11 @@ func NewManager(db *database.DB, cfg *config.Config, auth *authpkg.Auth, storage
router: chi.NewRouter(),
ui: ui,
startTime: time.Now(),
renderTimeout: cfg.RenderTimeoutSeconds(),
videoEncodeTimeout: cfg.EncodeTimeoutSeconds(),
maxUploadSize: cfg.MaxUploadBytes(),
sessionCookieMaxAge: cfg.SessionCookieMaxAgeSec(),
wsUpgrader: websocket.Upgrader{
CheckOrigin: checkWebSocketOrigin,
ReadBufferSize: 1024,
@@ -189,6 +195,10 @@ func NewManager(db *database.DB, cfg *config.Config, auth *authpkg.Auth, storage
jobStatusUpdateMu: make(map[int64]*sync.Mutex),
}
// Initialize rate limiters from config
apiRateLimiter = NewRateLimiter(cfg.APIRateLimitPerMinute(), time.Minute)
authRateLimiter = NewRateLimiter(cfg.AuthRateLimitPerMinute(), time.Minute)
// Check for required external tools
if err := s.checkRequiredTools(); err != nil {
return nil, err
@@ -267,6 +277,7 @@ type RateLimiter struct {
mu sync.RWMutex
limit int // max requests
window time.Duration // time window
stopChan chan struct{}
}
// NewRateLimiter creates a new rate limiter
@@ -275,12 +286,17 @@ func NewRateLimiter(limit int, window time.Duration) *RateLimiter {
requests: make(map[string][]time.Time),
limit: limit,
window: window,
stopChan: make(chan struct{}),
}
// Start cleanup goroutine
go rl.cleanup()
return rl
}
// Stop shuts down the cleanup goroutine.
func (rl *RateLimiter) Stop() {
close(rl.stopChan)
}
// Allow checks if a request from the given IP is allowed
func (rl *RateLimiter) Allow(ip string) bool {
rl.mu.Lock()
@@ -313,32 +329,37 @@ func (rl *RateLimiter) Allow(ip string) bool {
// cleanup periodically removes old entries
func (rl *RateLimiter) cleanup() {
ticker := time.NewTicker(5 * time.Minute)
for range ticker.C {
rl.mu.Lock()
cutoff := time.Now().Add(-rl.window)
for ip, reqs := range rl.requests {
validReqs := make([]time.Time, 0, len(reqs))
for _, t := range reqs {
if t.After(cutoff) {
validReqs = append(validReqs, t)
defer ticker.Stop()
for {
select {
case <-ticker.C:
rl.mu.Lock()
cutoff := time.Now().Add(-rl.window)
for ip, reqs := range rl.requests {
validReqs := make([]time.Time, 0, len(reqs))
for _, t := range reqs {
if t.After(cutoff) {
validReqs = append(validReqs, t)
}
}
if len(validReqs) == 0 {
delete(rl.requests, ip)
} else {
rl.requests[ip] = validReqs
}
}
if len(validReqs) == 0 {
delete(rl.requests, ip)
} else {
rl.requests[ip] = validReqs
}
rl.mu.Unlock()
case <-rl.stopChan:
return
}
rl.mu.Unlock()
}
}
// Global rate limiters for different endpoint types
// Rate limiters — initialized per Manager instance in NewManager.
var (
// General API rate limiter: 100 requests per minute per IP
apiRateLimiter = NewRateLimiter(100, time.Minute)
// Auth rate limiter: 10 requests per minute per IP (stricter for login attempts)
authRateLimiter = NewRateLimiter(10, time.Minute)
apiRateLimiter *RateLimiter
authRateLimiter *RateLimiter
)
// rateLimitMiddleware applies rate limiting based on client IP
@@ -610,17 +631,16 @@ func (s *Manager) respondError(w http.ResponseWriter, status int, message string
}
// createSessionCookie creates a secure session cookie with appropriate flags for the environment
func createSessionCookie(sessionID string) *http.Cookie {
func (s *Manager) createSessionCookie(sessionID string) *http.Cookie {
cookie := &http.Cookie{
Name: "session_id",
Value: sessionID,
Path: "/",
MaxAge: SessionCookieMaxAge,
MaxAge: s.sessionCookieMaxAge,
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
}
// In production mode, set Secure flag to require HTTPS
if authpkg.IsProductionMode() {
cookie.Secure = true
}
@@ -712,7 +732,7 @@ func (s *Manager) handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
}
sessionID := s.auth.CreateSession(session)
http.SetCookie(w, createSessionCookie(sessionID))
http.SetCookie(w, s.createSessionCookie(sessionID))
http.Redirect(w, r, "/", http.StatusFound)
}
@@ -745,7 +765,7 @@ func (s *Manager) handleDiscordCallback(w http.ResponseWriter, r *http.Request)
}
sessionID := s.auth.CreateSession(session)
http.SetCookie(w, createSessionCookie(sessionID))
http.SetCookie(w, s.createSessionCookie(sessionID))
http.Redirect(w, r, "/", http.StatusFound)
}
@@ -838,7 +858,7 @@ func (s *Manager) handleLocalRegister(w http.ResponseWriter, r *http.Request) {
}
sessionID := s.auth.CreateSession(session)
http.SetCookie(w, createSessionCookie(sessionID))
http.SetCookie(w, s.createSessionCookie(sessionID))
s.respondJSON(w, http.StatusCreated, map[string]interface{}{
"message": "Registration successful",
@@ -875,7 +895,7 @@ func (s *Manager) handleLocalLogin(w http.ResponseWriter, r *http.Request) {
}
sessionID := s.auth.CreateSession(session)
http.SetCookie(w, createSessionCookie(sessionID))
http.SetCookie(w, s.createSessionCookie(sessionID))
s.respondJSON(w, http.StatusOK, map[string]interface{}{
"message": "Login successful",