Update .gitignore to include log files and database journal files. Modify go.mod to update dependencies for go-sqlite3 and cloud.google.com/go/compute/metadata. Enhance Makefile to include logging options for manager and runner commands. Introduce new job token handling in auth package and implement database migration scripts. Refactor manager and runner components to improve job processing and metadata extraction. Add support for video preview in frontend components and enhance WebSocket management for channel subscriptions.

This commit is contained in:
2026-01-02 13:55:19 -06:00
parent edc8ea160c
commit 94490237fe
44 changed files with 9463 additions and 7875 deletions

View File

@@ -376,6 +376,10 @@ export const jobs = {
return `${API_BASE}/jobs/${jobId}/files/${fileId}/download`;
},
previewEXR(jobId, fileId) {
return `${API_BASE}/jobs/${jobId}/files/${fileId}/preview-exr`;
},
getVideoUrl(jobId) {
return `${API_BASE}/jobs/${jobId}/video`;
},

View File

@@ -10,6 +10,11 @@ class WebSocketManager {
this.isConnecting = false;
this.listenerIdCounter = 0;
this.verboseLogging = false; // Set to true to enable verbose WebSocket logging
// Track server-side channel subscriptions for re-subscription on reconnect
this.serverSubscriptions = new Set(); // Channels we want to be subscribed to
this.confirmedSubscriptions = new Set(); // Channels confirmed by server
this.pendingSubscriptions = new Set(); // Channels waiting for confirmation
}
connect() {
@@ -37,6 +42,10 @@ class WebSocketManager {
console.log('Shared WebSocket connected');
}
this.isConnecting = false;
// Re-subscribe to all channels that were previously subscribed
this.resubscribeToChannels();
this.notifyListeners('open', {});
};
@@ -68,17 +77,24 @@ class WebSocketManager {
}
this.ws = null;
this.isConnecting = false;
// Clear confirmed/pending but keep serverSubscriptions for re-subscription
this.confirmedSubscriptions.clear();
this.pendingSubscriptions.clear();
this.notifyListeners('close', event);
// Always retry connection
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
}
this.reconnectTimeout = setTimeout(() => {
if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
this.connect();
// Always retry connection if we have listeners
if (this.listeners.size > 0) {
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
}
}, this.reconnectDelay);
this.reconnectTimeout = setTimeout(() => {
if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
this.connect();
}
}, this.reconnectDelay);
}
};
} catch (error) {
console.error('Failed to create WebSocket:', error);
@@ -159,6 +175,81 @@ class WebSocketManager {
return this.ws ? this.ws.readyState : WebSocket.CLOSED;
}
// Subscribe to a server-side channel (will be re-subscribed on reconnect)
subscribeToChannel(channel) {
if (this.serverSubscriptions.has(channel)) {
// Already subscribed or pending
return;
}
this.serverSubscriptions.add(channel);
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
if (!this.confirmedSubscriptions.has(channel) && !this.pendingSubscriptions.has(channel)) {
this.pendingSubscriptions.add(channel);
this.send({ type: 'subscribe', channel });
if (this.verboseLogging) {
console.log('WebSocketManager: Subscribing to channel:', channel);
}
}
}
}
// Unsubscribe from a server-side channel (won't be re-subscribed on reconnect)
unsubscribeFromChannel(channel) {
this.serverSubscriptions.delete(channel);
this.confirmedSubscriptions.delete(channel);
this.pendingSubscriptions.delete(channel);
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
this.send({ type: 'unsubscribe', channel });
if (this.verboseLogging) {
console.log('WebSocketManager: Unsubscribing from channel:', channel);
}
}
}
// Mark a channel subscription as confirmed (call this when server confirms)
confirmSubscription(channel) {
this.pendingSubscriptions.delete(channel);
this.confirmedSubscriptions.add(channel);
if (this.verboseLogging) {
console.log('WebSocketManager: Subscription confirmed for channel:', channel);
}
}
// Mark a channel subscription as failed (call this when server rejects)
failSubscription(channel) {
this.pendingSubscriptions.delete(channel);
this.serverSubscriptions.delete(channel);
if (this.verboseLogging) {
console.log('WebSocketManager: Subscription failed for channel:', channel);
}
}
// Check if subscribed to a channel
isSubscribedToChannel(channel) {
return this.confirmedSubscriptions.has(channel);
}
// Re-subscribe to all channels after reconnect
resubscribeToChannels() {
if (this.serverSubscriptions.size === 0) {
return;
}
if (this.verboseLogging) {
console.log('WebSocketManager: Re-subscribing to channels:', Array.from(this.serverSubscriptions));
}
for (const channel of this.serverSubscriptions) {
if (!this.pendingSubscriptions.has(channel)) {
this.pendingSubscriptions.add(channel);
this.send({ type: 'subscribe', channel });
}
}
}
disconnect() {
if (this.reconnectTimeout) {
clearTimeout(this.reconnectTimeout);
@@ -169,6 +260,9 @@ class WebSocketManager {
this.ws = null;
}
this.listeners.clear();
this.serverSubscriptions.clear();
this.confirmedSubscriptions.clear();
this.pendingSubscriptions.clear();
}
}