Expose a monitor endpoint for MyMonitor status and job progress.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -9,6 +9,9 @@ COMFY_LAUNCH_CMD=
|
|||||||
# Windows host agent (scripts/comfy-host-agent.mjs) so Coolify can start Comfy remotely
|
# Windows host agent (scripts/comfy-host-agent.mjs) so Coolify can start Comfy remotely
|
||||||
COMFY_CONTROL_URL=http://192.168.77.7:8199
|
COMFY_CONTROL_URL=http://192.168.77.7:8199
|
||||||
COMFY_CONTROL_TOKEN=
|
COMFY_CONTROL_TOKEN=
|
||||||
|
# Optional. If set, MyMonitor must send it as X-Monitor-Token (or ?token=).
|
||||||
|
# MONITOR_TOKEN=
|
||||||
|
|
||||||
# Idle-stop lives on the Beast host agent only (default 30 min). Set on the desktop, not here.
|
# Idle-stop lives on the Beast host agent only (default 30 min). Set on the desktop, not here.
|
||||||
# COMFY_IDLE_MS=1800000
|
# COMFY_IDLE_MS=1800000
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export default defineNuxtConfig({
|
|||||||
comfyLaunchCmd: process.env.COMFY_LAUNCH_CMD || '',
|
comfyLaunchCmd: process.env.COMFY_LAUNCH_CMD || '',
|
||||||
comfyControlUrl: process.env.COMFY_CONTROL_URL || '',
|
comfyControlUrl: process.env.COMFY_CONTROL_URL || '',
|
||||||
comfyControlToken: process.env.COMFY_CONTROL_TOKEN || '',
|
comfyControlToken: process.env.COMFY_CONTROL_TOKEN || '',
|
||||||
|
monitorToken: process.env.MONITOR_TOKEN || '',
|
||||||
imageComfyHost: process.env.IMAGE_COMFY_HOST || '',
|
imageComfyHost: process.env.IMAGE_COMFY_HOST || '',
|
||||||
imageComfyPort: process.env.IMAGE_COMFY_PORT || '',
|
imageComfyPort: process.env.IMAGE_COMFY_PORT || '',
|
||||||
imageComfyPrimaryHost: process.env.IMAGE_COMFY_PRIMARY_HOST || '',
|
imageComfyPrimaryHost: process.env.IMAGE_COMFY_PRIMARY_HOST || '',
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
import { checkComfyHttp, fetchQueue, fetchComfyControlStatus } from '~/server/utils/comfyLifecycle'
|
||||||
|
import { comfyConfigured } from '~/server/utils/comfy'
|
||||||
|
import { listJobs, type Job } from '~/server/utils/jobs'
|
||||||
|
|
||||||
|
const ACTIVE: Job['status'][] = ['queued', 'uploading', 'running']
|
||||||
|
|
||||||
|
function monitorToken() {
|
||||||
|
return String(useRuntimeConfig().monitorToken || process.env.MONITOR_TOKEN || '').trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function activeProgress(jobs: Job[]) {
|
||||||
|
const active = jobs.filter(job => ACTIVE.includes(job.status))
|
||||||
|
if (!active.length) {
|
||||||
|
return { running: false, percent: 0 }
|
||||||
|
}
|
||||||
|
const percent = Math.max(0, Math.min(100, Math.round(Math.max(...active.map(job => Number(job.progress) || 0)))))
|
||||||
|
return { running: true, percent }
|
||||||
|
}
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const expected = monitorToken()
|
||||||
|
if (expected) {
|
||||||
|
const given = String(getHeader(event, 'x-monitor-token') || getQuery(event).token || '').trim()
|
||||||
|
if (given !== expected) {
|
||||||
|
throw createError({ statusCode: 401, statusMessage: 'Monitor token required' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setHeader(event, 'Cache-Control', 'no-store')
|
||||||
|
|
||||||
|
const videoConfigured = comfyConfigured()
|
||||||
|
const [comfy, queue, control] = await Promise.all([
|
||||||
|
videoConfigured
|
||||||
|
? checkComfyHttp().catch(() => ({ ok: false }))
|
||||||
|
: Promise.resolve({ ok: false }),
|
||||||
|
videoConfigured ? fetchQueue() : Promise.resolve({ running: 0, pending: 0, ok: false }),
|
||||||
|
fetchComfyControlStatus().catch(() => null)
|
||||||
|
])
|
||||||
|
const comfyReachable = Boolean(comfy.ok || queue.ok)
|
||||||
|
const hostAgentOk = Boolean(control && control.ok !== false)
|
||||||
|
const busy = Boolean(comfyReachable && queue.running > 0)
|
||||||
|
const progress = activeProgress(listJobs())
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
instance: String(useRuntimeConfig().public.instanceName || 'aigen'),
|
||||||
|
comfy: {
|
||||||
|
ok: comfyReachable,
|
||||||
|
busy,
|
||||||
|
asleep: Boolean(control?.asleep) && !comfyReachable,
|
||||||
|
processUp: Boolean(control?.process ?? control?.processUp)
|
||||||
|
},
|
||||||
|
hostAgent: {
|
||||||
|
ok: hostAgentOk
|
||||||
|
},
|
||||||
|
progress
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -7,6 +7,7 @@ export default defineEventHandler((event) => {
|
|||||||
path.startsWith('/api/auth/logout') ||
|
path.startsWith('/api/auth/logout') ||
|
||||||
path.startsWith('/api/auth/me') ||
|
path.startsWith('/api/auth/me') ||
|
||||||
path.startsWith('/api/health') ||
|
path.startsWith('/api/health') ||
|
||||||
|
path.startsWith('/api/monitor') ||
|
||||||
path.startsWith('/_nuxt') ||
|
path.startsWith('/_nuxt') ||
|
||||||
path.startsWith('/favicon') ||
|
path.startsWith('/favicon') ||
|
||||||
path === '/login'
|
path === '/login'
|
||||||
|
|||||||
Reference in New Issue
Block a user