From b45d6240ae25727af68422ad3814b3d04d7fc7c8 Mon Sep 17 00:00:00 2001 From: Jeff Rescignano Date: Thu, 12 Jan 2023 02:07:53 -0500 Subject: [PATCH 1/2] Add Unmanic service widget --- public/locales/en/common.json | 5 +++ src/widgets/components.js | 1 + src/widgets/unmanic/component.jsx | 33 +++++++++++++++++++ src/widgets/unmanic/proxy.js | 55 +++++++++++++++++++++++++++++++ src/widgets/unmanic/widget.js | 27 +++++++++++++++ src/widgets/widgets.js | 2 ++ 6 files changed, 123 insertions(+) create mode 100644 src/widgets/unmanic/component.jsx create mode 100644 src/widgets/unmanic/proxy.js create mode 100644 src/widgets/unmanic/widget.js diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 0bf28285e..150afbd90 100755 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -502,5 +502,10 @@ "lastrun": "Last Run", "nextrun": "Next Run", "failed": "Failed" + }, + "unmanic": { + "active_workers": "Active Workers", + "total_workers": "Total Workers", + "records_total": "Queue Length" } } \ No newline at end of file diff --git a/src/widgets/components.js b/src/widgets/components.js index e4ecb9479..fb64e2b02 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -68,6 +68,7 @@ const components = { tubearchivist: dynamic(() => import("./tubearchivist/component")), truenas: dynamic(() => import("./truenas/component")), unifi: dynamic(() => import("./unifi/component")), + unmanic: dynamic(() => import("./unmanic/component")), watchtower: dynamic(() => import("./watchtower/component")), xteve: dynamic(() => import("./xteve/component")), immich: dynamic(() => import("./immich/component")), diff --git a/src/widgets/unmanic/component.jsx b/src/widgets/unmanic/component.jsx new file mode 100644 index 000000000..1d68e7650 --- /dev/null +++ b/src/widgets/unmanic/component.jsx @@ -0,0 +1,33 @@ +import Container from "components/services/widget/container"; +import Block from "components/services/widget/block"; +import useWidgetAPI from "utils/proxy/use-widget-api"; + +export default function Component({ service }) { + const { widget } = service; + + const { data: workersData, error: workersError } = useWidgetAPI(widget, "workers"); + const { data: pendingData, error: pendingError } = useWidgetAPI(widget, "pending"); + + if (workersError || pendingError) { + const finalError = workersError ?? pendingError; + return ; + } + + if (!workersData || !pendingData) { + return ( + + + + + + ); + } + + return ( + + + + + + ); +} diff --git a/src/widgets/unmanic/proxy.js b/src/widgets/unmanic/proxy.js new file mode 100644 index 000000000..7a8337659 --- /dev/null +++ b/src/widgets/unmanic/proxy.js @@ -0,0 +1,55 @@ +import getServiceWidget from "utils/config/service-helpers"; +import { formatApiCall } from "utils/proxy/api-helpers"; +import validateWidgetData from "utils/proxy/validate-widget-data"; +import { httpProxy } from "utils/proxy/http"; +import createLogger from "utils/logger"; +import widgets from "widgets/widgets"; + +const logger = createLogger("unmanicProxyHandler"); + +export default async function unmanicProxyHandler(req, res, map) { + const { group, service, endpoint } = req.query; + + if (group && service) { + const widget = await getServiceWidget(group, service); + + if (!widgets?.[widget.type]?.api) { + return res.status(403).json({ error: "Service does not support API calls" }); + } + + if (widget) { + const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); + + const [status, contentType, data] = await httpProxy(url, { + method: req.method, + body: (endpoint === "pending/tasks") ? "{}" : "", + }); + + let resultData = data; + + if (!validateWidgetData(widget, endpoint, resultData)) { + return res.status(status).json({error: {message: "Invalid data", url, data: resultData}}); + } + + if (status === 200 && map) { + resultData = map(data); + } + + if (contentType) res.setHeader("Content-Type", contentType); + + if (status === 204 || status === 304) { + return res.status(status).end(); + } + + if (status >= 400) { + logger.debug("HTTP Error %d calling %s//%s%s...", status, url.protocol, url.hostname, url.pathname); + return res.status(status).json({error: {message: "HTTP Error", url, data}}); + } + + return res.status(status).send(resultData); + } + } + + logger.debug("Invalid or missing proxy service type '%s' in group '%s'", service, group); + return res.status(400).json({ error: "Invalid proxy service type" }); +} diff --git a/src/widgets/unmanic/widget.js b/src/widgets/unmanic/widget.js new file mode 100644 index 000000000..69bc63808 --- /dev/null +++ b/src/widgets/unmanic/widget.js @@ -0,0 +1,27 @@ +import unmanicProxyHandler from "./proxy"; + +import { asJson } from "utils/proxy/api-helpers"; + +const widget = { + api: "{url}/unmanic/api/v2/{endpoint}", + proxyHandler: unmanicProxyHandler, + + mappings: { + workers: { + endpoint: "workers/status", + map: (data) => ({ + total_workers: (asJson(data).workers_status).length, + active_workers: (asJson(data).workers_status).filter(worker => !worker.idle).length, + }) + }, + pending: { + method: "POST", + endpoint: "pending/tasks", + validate: [ + "recordsTotal" + ] + }, + }, +}; + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index bf9457c66..c9f299cba 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -66,6 +66,7 @@ import watchtower from "./watchtower/widget"; import xteve from "./xteve/widget"; import immich from "./immich/widget"; import uptimekuma from "./uptimekuma/widget"; +import unmanic from "./unmanic/widget"; const widgets = { adguard, @@ -134,6 +135,7 @@ const widgets = { truenas, unifi, unifi_console: unifi, + unmanic, watchtower, xteve, immich, From 0666268d9158e218ecffe40700b0084d23ce16ca Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sat, 18 Feb 2023 22:19:01 -0800 Subject: [PATCH 2/2] unmanic use generic proxy --- src/widgets/unmanic/proxy.js | 55 ----------------------------------- src/widgets/unmanic/widget.js | 6 ++-- 2 files changed, 3 insertions(+), 58 deletions(-) delete mode 100644 src/widgets/unmanic/proxy.js diff --git a/src/widgets/unmanic/proxy.js b/src/widgets/unmanic/proxy.js deleted file mode 100644 index 7a8337659..000000000 --- a/src/widgets/unmanic/proxy.js +++ /dev/null @@ -1,55 +0,0 @@ -import getServiceWidget from "utils/config/service-helpers"; -import { formatApiCall } from "utils/proxy/api-helpers"; -import validateWidgetData from "utils/proxy/validate-widget-data"; -import { httpProxy } from "utils/proxy/http"; -import createLogger from "utils/logger"; -import widgets from "widgets/widgets"; - -const logger = createLogger("unmanicProxyHandler"); - -export default async function unmanicProxyHandler(req, res, map) { - const { group, service, endpoint } = req.query; - - if (group && service) { - const widget = await getServiceWidget(group, service); - - if (!widgets?.[widget.type]?.api) { - return res.status(403).json({ error: "Service does not support API calls" }); - } - - if (widget) { - const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); - - const [status, contentType, data] = await httpProxy(url, { - method: req.method, - body: (endpoint === "pending/tasks") ? "{}" : "", - }); - - let resultData = data; - - if (!validateWidgetData(widget, endpoint, resultData)) { - return res.status(status).json({error: {message: "Invalid data", url, data: resultData}}); - } - - if (status === 200 && map) { - resultData = map(data); - } - - if (contentType) res.setHeader("Content-Type", contentType); - - if (status === 204 || status === 304) { - return res.status(status).end(); - } - - if (status >= 400) { - logger.debug("HTTP Error %d calling %s//%s%s...", status, url.protocol, url.hostname, url.pathname); - return res.status(status).json({error: {message: "HTTP Error", url, data}}); - } - - return res.status(status).send(resultData); - } - } - - logger.debug("Invalid or missing proxy service type '%s' in group '%s'", service, group); - return res.status(400).json({ error: "Invalid proxy service type" }); -} diff --git a/src/widgets/unmanic/widget.js b/src/widgets/unmanic/widget.js index 69bc63808..5de0626d3 100644 --- a/src/widgets/unmanic/widget.js +++ b/src/widgets/unmanic/widget.js @@ -1,10 +1,9 @@ -import unmanicProxyHandler from "./proxy"; - +import genericProxyHandler from "utils/proxy/handlers/generic"; import { asJson } from "utils/proxy/api-helpers"; const widget = { api: "{url}/unmanic/api/v2/{endpoint}", - proxyHandler: unmanicProxyHandler, + proxyHandler: genericProxyHandler, mappings: { workers: { @@ -16,6 +15,7 @@ const widget = { }, pending: { method: "POST", + body: "{}", endpoint: "pending/tasks", validate: [ "recordsTotal"