diff --git a/dashcaddy-api/pylon/start-pylon.vbs b/dashcaddy-api/pylon/start-pylon.vbs new file mode 100644 index 0000000..26d096b --- /dev/null +++ b/dashcaddy-api/pylon/start-pylon.vbs @@ -0,0 +1,2 @@ +Set WshShell = CreateObject("WScript.Shell") +WshShell.Run """C:\Program Files\nodejs\node.exe"" ""E:\CaddyCerts\sites\dashcaddy-api\pylon\dashcaddy-pylon.js""", 0, False diff --git a/dashcaddy-api/routes/services.js b/dashcaddy-api/routes/services.js index 06fcac8..fcb9569 100644 --- a/dashcaddy-api/routes/services.js +++ b/dashcaddy-api/routes/services.js @@ -65,6 +65,25 @@ module.exports = function(ctx) { }); } + async function probeViaPylon(targetUrl) { + const pylonConfig = ctx.siteConfig?.pylon; + if (!pylonConfig?.url) return null; + try { + const probeUrl = `${pylonConfig.url}/probe?url=${encodeURIComponent(targetUrl)}`; + const headers = {}; + if (pylonConfig.key) headers['x-pylon-key'] = pylonConfig.key; + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), 12000); + const response = await ctx.fetchT(probeUrl, { method: 'GET', signal: controller.signal, headers }); + clearTimeout(timeout); + if (!response.ok) return null; + const data = await response.json(); + return data; + } catch (_) { + return null; + } + } + async function probeServiceStatus(id, service) { const startedAt = process.hrtime.bigint(); let url = resolveProbeUrl(id, service); @@ -92,6 +111,22 @@ module.exports = function(ctx) { } } + // Pylon relay fallback — if direct probes failed, try through the pylon + if (error && ctx.siteConfig?.pylon) { + const pylonResult = await probeViaPylon(url); + if (pylonResult && pylonResult.status) { + const responseTime = Number((process.hrtime.bigint() - startedAt) / 1000000n); + return { + id, + isUp: pylonResult.status === 'healthy', + statusCode: pylonResult.statusCode || 0, + responseTime, + url, + via: 'pylon' + }; + } + } + const responseTime = Number((process.hrtime.bigint() - startedAt) / 1000000n); if (error) { return {