From ef5c1d482627b610d6ef02aacae9131d5fbac68d Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Thu, 19 Oct 2023 14:40:12 -0700 Subject: [PATCH] Make ping true ping --- docs/configs/services.md | 34 +++++++++++++++++++++------ docs/configs/settings.md | 8 +++---- package-lock.json | 9 +++++++ package.json | 1 + pnpm-lock.yaml | 8 +++++++ src/components/services/ping.jsx | 19 ++++++--------- src/pages/api/ping.js | 40 +++++++++++++------------------- src/pages/api/siteMonitor.js | 2 +- 8 files changed, 73 insertions(+), 48 deletions(-) diff --git a/docs/configs/services.md b/docs/configs/services.md index 3a099e63..89b9cdbd 100644 --- a/docs/configs/services.md +++ b/docs/configs/services.md @@ -101,30 +101,50 @@ To use a local icon, first create a Docker mount to `/app/public/icons` and then ## Ping -Services may have an optional `ping` property that allows you to monitor the availability of an endpoint you chose and have the response time displayed. You do not need to set your ping URL equal to your href URL. - -!!! note - - The ping feature works by making an http `HEAD` request to the URL, and falls back to `GET` in case that fails. It will not, for example, login if the URL requires auth or is behind e.g. Authelia. In the case of a reverse proxy and/or auth this usually requires the use of an 'internal' URL to make the ping feature correctly display status. +Services may have an optional `ping` property that allows you to monitor the availability of an external host. As of v0.7.5, the ping feature uses the true ping command on the underlying host. ```yaml - Group A: - Sonarr: icon: sonarr.png href: http://sonarr.host/ - ping: http://sonarr.host/ + ping: sonarr.host - Group B: - Radarr: icon: radarr.png href: http://radarr.host/ - ping: http://some.other.host/ + ping: some.other.host ``` Ping You can also apply different styles to the ping indicator by using the `statusStyle` property, see [settings](settings.md#status-style). +## Site Monitor + +Services may have an optional `siteMonitor` property (formerly `ping`) that allows you to monitor the availability of a URL you chose and have the response time displayed. You do not need to set your monitor URL equal to your href or ping URL. + +!!! note + + The site monitor feature works by making an http `HEAD` request to the URL, and falls back to `GET` in case that fails. It will not, for example, login if the URL requires auth or is behind e.g. Authelia. In the case of a reverse proxy and/or auth this usually requires the use of an 'internal' URL to make the site monitor feature correctly display status. + +```yaml +- Group A: + - Sonarr: + icon: sonarr.png + href: http://sonarr.host/ + siteMonitor: http://sonarr.host/ + +- Group B: + - Radarr: + icon: radarr.png + href: http://radarr.host/ + siteMonitor: http://some.other.host/ +``` + +You can also apply different styles to the site monitor indicator by using the `statusStyle` property, see [settings](settings.md#status-style). + ## Docker Integration Services may be connected to a Docker container, either running on the local machine, or a remote machine. diff --git a/docs/configs/settings.md b/docs/configs/settings.md index f2c17934..f366b204 100644 --- a/docs/configs/settings.md +++ b/docs/configs/settings.md @@ -382,11 +382,11 @@ If you have both set the per-service settings take precedence. ## Status Style -You can choose from the following styles for docker or k8s status and ping: `dot` or `basic` +You can choose from the following styles for docker or k8s status, site monitor and ping: `dot` or `basic` -- The default is no value, and displays the ping response time in ms and the docker / k8s container status -- `dot` shows a green dot for a successful ping or healthy status. -- `basic` shows either UP or DOWN for ping +- The default is no value, and displays the montior and ping response time in ms and the docker / k8s container status +- `dot` shows a green dot for a successful monitor ping or healthy status. +- `basic` shows either UP or DOWN for monitor & ping For example: diff --git a/package-lock.json b/package-lock.json index 904d337c..16e2ed68 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "minecraft-ping-js": "^1.0.2", "next": "^12.3.1", "next-i18next": "^12.0.1", + "ping": "^0.4.4", "pretty-bytes": "^6.0.0", "raw-body": "^2.5.1", "react": "^18.2.0", @@ -4861,6 +4862,14 @@ "node": ">=0.10.0" } }, + "node_modules/ping": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/ping/-/ping-0.4.4.tgz", + "integrity": "sha512-56ZMC0j7SCsMMLdOoUg12VZCfj/+ZO+yfOSjaNCRrmZZr6GLbN2X/Ui56T15dI8NhiHckaw5X2pvyfAomanwqQ==", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/pirates": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", diff --git a/package.json b/package.json index cc4805a5..0b10fedf 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "minecraft-ping-js": "^1.0.2", "next": "^12.3.1", "next-i18next": "^12.0.1", + "ping": "^0.4.4", "pretty-bytes": "^6.0.0", "raw-body": "^2.5.1", "react": "^18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 197c559c..335da832 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ dependencies: next-i18next: specifier: ^12.0.1 version: 12.1.0(next@12.3.4)(react-dom@18.2.0)(react@18.2.0) + ping: + specifier: ^0.4.4 + version: 0.4.4 pretty-bytes: specifier: ^6.0.0 version: 6.1.0 @@ -3103,6 +3106,11 @@ packages: engines: {node: '>=0.10.0'} dev: true + /ping@0.4.4: + resolution: {integrity: sha512-56ZMC0j7SCsMMLdOoUg12VZCfj/+ZO+yfOSjaNCRrmZZr6GLbN2X/Ui56T15dI8NhiHckaw5X2pvyfAomanwqQ==} + engines: {node: '>=4.0.0'} + dev: false + /pirates@4.0.5: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} diff --git a/src/components/services/ping.jsx b/src/components/services/ping.jsx index cdaec08d..f72d40b3 100644 --- a/src/components/services/ping.jsx +++ b/src/components/services/ping.jsx @@ -9,7 +9,7 @@ export default function Ping({ group, service, style }) { let colorClass = "text-black/20 dark:text-white/40 opacity-20"; let backgroundClass = "bg-theme-500/10 dark:bg-theme-900/50 px-1.5 py-0.5"; - let statusTitle = t("ping.http_status"); + let statusTitle = t("ping.ping"); let statusText = ""; if (error) { @@ -19,18 +19,13 @@ export default function Ping({ group, service, style }) { } else if (!data) { statusText = t("ping.ping"); statusTitle += ` ${t("ping.not_available")}`; - } else if (data.status > 403) { + } else if (!data.alive) { colorClass = "text-rose-500/80"; - statusTitle += ` ${data.status}`; - - if (style === "basic") { - statusText = t("ping.down"); - } else { - statusText = data.status; - } - } else if (data) { - const ping = t("common.ms", { value: data.latency, style: "unit", unit: "millisecond", maximumFractionDigits: 0 }); - statusTitle += ` ${data.status} (${ping})`; + statusTitle += ` ${t("ping.down")}`; + statusText = t("ping.down"); + } else if (data.alive) { + const ping = t("common.ms", { value: data.time, style: "unit", unit: "millisecond", maximumFractionDigits: 0 }); + statusTitle += ` ${t("ping.up")} (${ping})`; colorClass = "text-emerald-500/80"; if (style === "basic") { diff --git a/src/pages/api/ping.js b/src/pages/api/ping.js index 6843ce49..e540fa68 100644 --- a/src/pages/api/ping.js +++ b/src/pages/api/ping.js @@ -1,8 +1,7 @@ -import { performance } from "perf_hooks"; +import { promise as ping } from "ping"; import { getServiceItem } from "utils/config/service-helpers"; import createLogger from "utils/logger"; -import { httpProxy } from "utils/proxy/http"; const logger = createLogger("ping"); @@ -16,35 +15,28 @@ export default async function handler(req, res) { }); } - const { ping: pingURL } = serviceItem; + const { ping: pingHostOrURL } = serviceItem; - if (!pingURL) { - logger.debug("No ping URL specified"); + if (!pingHostOrURL) { + logger.debug("No ping host specified"); return res.status(400).send({ - error: "No ping URL given", + error: "No ping host given", }); } + let hostname = pingHostOrURL; try { - let startTime = performance.now(); - let [status] = await httpProxy(pingURL, { - method: "HEAD", - }); - let endTime = performance.now(); - - if (status > 403) { - // try one more time as a GET in case HEAD is rejected for whatever reason - startTime = performance.now(); - [status] = await httpProxy(pingURL); - endTime = performance.now(); - } - - return res.status(200).json({ - status, - latency: endTime - startTime, - }); + // maintain backwards compatibility with old ping where may be http://... + hostname = new URL(pingHostOrURL).hostname; } catch (e) { - logger.debug("Error attempting ping: %s", JSON.stringify(e)); + // eslint-disable-line no-empty + } + + try { + const response = await ping.probe(hostname); + return res.status(200).json(response); + } catch (e) { + logger.debug("Error attempting ping: %s", e); return res.status(400).send({ error: "Error attempting ping, see logs.", }); diff --git a/src/pages/api/siteMonitor.js b/src/pages/api/siteMonitor.js index 2c7fa445..9e030d74 100644 --- a/src/pages/api/siteMonitor.js +++ b/src/pages/api/siteMonitor.js @@ -44,7 +44,7 @@ export default async function handler(req, res) { latency: endTime - startTime, }); } catch (e) { - logger.debug("Error attempting http monitor: %s", JSON.stringify(e)); + logger.debug("Error attempting http monitor: %s", e); return res.status(400).send({ error: "Error attempting http monitor, see logs.", });