diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 8784443a4..24177db67 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -52,7 +52,13 @@ "tx": "TX", "mem": "MEM", "cpu": "CPU", - "offline": "Offline" + "offline": "Offline", + "error": "Error", + "unknown": "Unknown" + }, + "ping": { + "error": "Error", + "ping": "Ping" }, "emby": { "playing": "Playing", diff --git a/src/components/services/item.jsx b/src/components/services/item.jsx index 56ed2b4b1..3f9df9307 100644 --- a/src/components/services/item.jsx +++ b/src/components/services/item.jsx @@ -3,6 +3,7 @@ import { useContext, useState } from "react"; import Status from "./status"; import Widget from "./widget"; +import Ping from "./ping"; import Docker from "widgets/docker/component"; import { SettingsContext } from "utils/contexts/settings"; @@ -30,7 +31,7 @@ export default function Item({ service }) {
{service.icon && @@ -70,16 +71,25 @@ export default function Item({ service }) {
)} - {service.container && ( - - )} +
+ {service.ping && ( +
+ + Ping status +
+ )} + + {service.container && ( + + )} +
{service.container && service.server && ( diff --git a/src/components/services/ping.jsx b/src/components/services/ping.jsx new file mode 100644 index 000000000..e30562323 --- /dev/null +++ b/src/components/services/ping.jsx @@ -0,0 +1,44 @@ +import { useTranslation } from "react-i18next"; +import useSWR from "swr"; + +export default function Ping({ service }) { + const { t } = useTranslation(); + const { data, error } = useSWR(`/api/ping?${new URLSearchParams({ping: service.ping}).toString()}`, { + refreshInterval: 30000 + }); + + if (error) { + return ( +
+
{t("ping.error")}
+
+ ); + } + + if (!data) { + return ( +
+
{t("ping.ping")}
+
+ ); + } + + const statusText = `${service.ping}: HTTP status ${data.status}`; + + if (data && data.status !== 200) { + return ( +
+
{data.status}
+
+ ); + } + + if (data && data.status === 200) { + return ( +
+
{t("common.ms", { value: data.latency, style: "unit", unit: "millisecond", unitDisplay: "narrow", maximumFractionDigits: 0 })}
+
+ ); + } + +} diff --git a/src/components/services/status.jsx b/src/components/services/status.jsx index dc9034081..2d07e49e8 100644 --- a/src/components/services/status.jsx +++ b/src/components/services/status.jsx @@ -1,19 +1,36 @@ +import { useTranslation } from "react-i18next"; import useSWR from "swr"; export default function Status({ service }) { + const { t } = useTranslation(); + const { data, error } = useSWR(`/api/docker/status/${service.container}/${service.server || ""}`); if (error) { - return
; +
+
{t("docker.error")}
+
} if (data && data.status === "running") { - return
; + return ( +
+
{data.status}
+
+ ); } - if (data && data.status === "not found") { - return
; + if (data && (data.status === "not found" || data.status === "exited")) { + return ( +
+
{data.status}
+
+ ); } - return
; + return ( +
+
{t("docker.unknown")}
+
+ ); } diff --git a/src/pages/api/ping.js b/src/pages/api/ping.js new file mode 100644 index 000000000..79c7da0c9 --- /dev/null +++ b/src/pages/api/ping.js @@ -0,0 +1,28 @@ +import { performance } from "perf_hooks"; + +import createLogger from "utils/logger"; +import { httpProxy } from "utils/proxy/http"; + +const logger = createLogger("ping"); + +export default async function handler(req, res) { + const { ping: pingURL } = req.query; + + if (!pingURL) { + logger.debug("No ping URL specified"); + return res.status(400).send({ + error: "No ping URL given", + }); + } + + const startTime = performance.now(); + const [status] = await httpProxy(pingURL, { + method: "HEAD" + }); + const endTime = performance.now(); + + return res.status(200).json({ + status, + latency: endTime - startTime + }); +} diff --git a/src/utils/proxy/http.js b/src/utils/proxy/http.js index 4eba83f32..8f180a7fe 100644 --- a/src/utils/proxy/http.js +++ b/src/utils/proxy/http.js @@ -96,7 +96,7 @@ export async function httpProxy(url, params = {}) { return [status, contentType, data, responseHeaders]; } catch (err) { - logger.error("Error calling %s//%s%s...", url.protocol, url.hostname, url.pathname); + logger.error("Error calling %s//%s%s...", constructedUrl.protocol, constructedUrl.hostname, constructedUrl.pathname); logger.error(err); return [500, "application/json", { error: "Unexpected error" }, null]; }