From a91c4ba137b3435e27b60da65db0a0ceb1ba5e01 Mon Sep 17 00:00:00 2001 From: Vadim Sobinin Date: Sun, 15 Mar 2026 01:09:14 +0300 Subject: [PATCH] =?UTF-8?q?fix(proxy):=20fix=20UpSnap=20wake=20=E2=80=94?= =?UTF-8?q?=20use=20/api/upsnap/wake=20endpoint?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PATCH { status: "on" } no longer works in current UpSnap version. Switch to GET /api/upsnap/wake/{id} with 10s timeout (WoL packet is sent immediately, endpoint blocks until device responds). Co-Authored-By: Claude --- packages/proxy/src/services/upsnap.ts | 59 ++++++++++++++++++++------- 1 file changed, 44 insertions(+), 15 deletions(-) diff --git a/packages/proxy/src/services/upsnap.ts b/packages/proxy/src/services/upsnap.ts index 7d825c6..6e0202a 100644 --- a/packages/proxy/src/services/upsnap.ts +++ b/packages/proxy/src/services/upsnap.ts @@ -63,31 +63,60 @@ async function upSnapFetch(path: string, options: RequestInit = {}): Promise { - const res = await upSnapFetch( - `/api/collections/devices/records/${config.upsnap.deviceId}`, - { method: 'PATCH', body: JSON.stringify({ status: 'on' }) } - ); + // Use the dedicated wake endpoint — it sends a WoL packet. + // This endpoint may block until the device responds or its internal timeout expires, + // so we abort after 10s — the WoL packet is already sent by then. + const authToken = await getToken(); - if (res.ok) return; + try { + const res = await fetch( + `${config.upsnap.url}/api/upsnap/wake/${config.upsnap.deviceId}`, + { + method: 'GET', + headers: { Authorization: authToken }, + signal: AbortSignal.timeout(10_000), + }, + ); - const body1 = await res.text().catch(() => ''); - console.error(`[UpSnap] PATCH wake failed (${res.status}): ${body1}`); + if (res.status === 401 || res.status === 403) { + const newToken = await authenticate(); + await fetch( + `${config.upsnap.url}/api/upsnap/wake/${config.upsnap.deviceId}`, + { + method: 'GET', + headers: { Authorization: newToken }, + signal: AbortSignal.timeout(10_000), + }, + ).catch(() => {}); + // WoL packet sent regardless of response + return; + } - // Fallback: GET wake endpoint - const res2 = await upSnapFetch(`/api/upsnap/wake/${config.upsnap.deviceId}`, { - method: 'GET', - }); - if (!res2.ok) { - const body2 = await res2.text().catch(() => ''); - throw new Error(`UpSnap wake failed: ${res2.status} — ${body2}`); + if (!res.ok) { + const body = await res.text().catch(() => ''); + throw new Error(`UpSnap wake failed: ${res.status} — ${body}`); + } + } catch (err) { + // AbortError / TimeoutError is expected — the WoL packet was already sent + if (err instanceof DOMException && err.name === 'TimeoutError') { + console.log('[UpSnap] Wake request timed out (expected — WoL packet was sent)'); + return; + } + if (err instanceof DOMException && err.name === 'AbortError') { + console.log('[UpSnap] Wake request aborted (expected — WoL packet was sent)'); + return; + } + throw err; } } export async function shutdownDevice(): Promise { const res = await upSnapFetch(`/api/upsnap/shutdown/${config.upsnap.deviceId}`, { method: 'GET', + signal: AbortSignal.timeout(10_000), }); if (!res.ok) { - throw new Error(`UpSnap shutdown failed: ${res.status}`); + const body = await res.text().catch(() => ''); + throw new Error(`UpSnap shutdown failed: ${res.status} — ${body}`); } }