Adding support for RackNerd widget.
This commit is contained in:
parent
c58f59c105
commit
3cce7e4006
@ -108,6 +108,7 @@ You can also find a list of all available service widgets in the sidebar navigat
|
|||||||
- [PyLoad](pyload.md)
|
- [PyLoad](pyload.md)
|
||||||
- [qBittorrent](qbittorrent.md)
|
- [qBittorrent](qbittorrent.md)
|
||||||
- [QNAP](qnap.md)
|
- [QNAP](qnap.md)
|
||||||
|
- [RackNerd](racknerd.md)
|
||||||
- [Radarr](radarr.md)
|
- [Radarr](radarr.md)
|
||||||
- [Readarr](readarr.md)
|
- [Readarr](readarr.md)
|
||||||
- [ROMM](romm.md)
|
- [ROMM](romm.md)
|
||||||
|
|||||||
22
docs/widgets/services/racknerd.md
Normal file
22
docs/widgets/services/racknerd.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
title: RackNerd
|
||||||
|
description: RackNerd Widget Configuration
|
||||||
|
---
|
||||||
|
|
||||||
|
Learn more about [RackNerd](https://racknerd.com).
|
||||||
|
|
||||||
|
Use key & hash. Information about the key & hash can be found under the [VPS](https://nerdvm.racknerd.com) control panel in the API section.
|
||||||
|
|
||||||
|
Allowed fields: `["ipAddress", "hddtotal", "bandwidthfree", "bandwidthused"]`.
|
||||||
|
|
||||||
|
Note `"memoryusage"` is deprecated as v1 of their API result will be always be 0.
|
||||||
|
Note `"status"` is not fully implemented.
|
||||||
|
|
||||||
|
Note hard drive free/used/percentage isn't functioning in v1 of their API result.
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: racknerd
|
||||||
|
url: https://nerdvm.racknerd.com
|
||||||
|
key: token
|
||||||
|
hash: token
|
||||||
|
```
|
||||||
@ -131,6 +131,7 @@ nav:
|
|||||||
- widgets/services/pyload.md
|
- widgets/services/pyload.md
|
||||||
- widgets/services/qbittorrent.md
|
- widgets/services/qbittorrent.md
|
||||||
- widgets/services/qnap.md
|
- widgets/services/qnap.md
|
||||||
|
- widgets/services/racknerd.md
|
||||||
- widgets/services/radarr.md
|
- widgets/services/radarr.md
|
||||||
- widgets/services/readarr.md
|
- widgets/services/readarr.md
|
||||||
- widgets/services/romm.md
|
- widgets/services/romm.md
|
||||||
|
|||||||
@ -716,6 +716,14 @@
|
|||||||
"numfiles": "Files",
|
"numfiles": "Files",
|
||||||
"numshares": "Shared Items"
|
"numshares": "Shared Items"
|
||||||
},
|
},
|
||||||
|
"racknerd": {
|
||||||
|
"ipAddress": "IP Address",
|
||||||
|
"memoryusage": "Memory Usage",
|
||||||
|
"hddtotal": "Total Space",
|
||||||
|
"bandwidthtotal": "Bandwidth Total",
|
||||||
|
"bandwidthused": "Bandwidth Used",
|
||||||
|
"bandwidthfree": "Bandwidth Free"
|
||||||
|
},
|
||||||
"kopia": {
|
"kopia": {
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"size": "Size",
|
"size": "Size",
|
||||||
|
|||||||
@ -104,6 +104,7 @@ const components = {
|
|||||||
pyload: dynamic(() => import("./pyload/component")),
|
pyload: dynamic(() => import("./pyload/component")),
|
||||||
qbittorrent: dynamic(() => import("./qbittorrent/component")),
|
qbittorrent: dynamic(() => import("./qbittorrent/component")),
|
||||||
qnap: dynamic(() => import("./qnap/component")),
|
qnap: dynamic(() => import("./qnap/component")),
|
||||||
|
racknerd: dynamic(() => import("./racknerd/component")),
|
||||||
radarr: dynamic(() => import("./radarr/component")),
|
radarr: dynamic(() => import("./radarr/component")),
|
||||||
readarr: dynamic(() => import("./readarr/component")),
|
readarr: dynamic(() => import("./readarr/component")),
|
||||||
romm: dynamic(() => import("./romm/component")),
|
romm: dynamic(() => import("./romm/component")),
|
||||||
|
|||||||
71
src/widgets/racknerd/component.jsx
Normal file
71
src/widgets/racknerd/component.jsx
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
import Container from "components/services/widget/container";
|
||||||
|
import Block from "components/services/widget/block";
|
||||||
|
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||||
|
|
||||||
|
export const racknerdDefaultFields = ["ipAddress", "hddtotal", "bandwidthusage"];
|
||||||
|
|
||||||
|
export default function Component({ service }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { widget } = service;
|
||||||
|
const params = {
|
||||||
|
key: widget.key,
|
||||||
|
hash: widget.hash,
|
||||||
|
};
|
||||||
|
const { data: racknerdData, error: racknerdError } = useWidgetAPI(widget, "serverinfo", {...params, action: 'info'});
|
||||||
|
// Support for fields (harddriveusage, memoryusage, bandwidthusage)
|
||||||
|
const [showIpAddress, showMemoryUsage, showHardDriveUsage, showBandwidthUsed, showBandwidthFree] = useMemo(() => {
|
||||||
|
// Default values if fields is not set
|
||||||
|
if (!widget.fields) return [true, false, true, true, true];
|
||||||
|
|
||||||
|
const hasIpAddress = widget.fields?.includes("ipAddress") || false;
|
||||||
|
const hasMemoryUsage = widget.fields?.includes("memoryusage") || false;
|
||||||
|
const hasHardDriveUsage = widget.fields?.includes("hddtotal") || false;
|
||||||
|
const hasBandwidthUsed = widget.fields?.includes("bandwidthused") || false;
|
||||||
|
const hasBandwidthFree = widget.fields?.includes("bandwidthfree") || false;
|
||||||
|
return [hasIpAddress, hasMemoryUsage, hasHardDriveUsage, hasBandwidthUsed, hasBandwidthFree];
|
||||||
|
}, [widget.fields]);
|
||||||
|
if (racknerdError) {
|
||||||
|
return <Container service={service} error={racknerdError} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!racknerdData) {
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
{showIpAddress && <Block label="racknerd.ipAddress" />}
|
||||||
|
{showMemoryUsage && <Block label="racknerd.memoryusage" />}
|
||||||
|
{showHardDriveUsage && <Block label="racknerd.hddtotal" />}
|
||||||
|
{showBandwidthUsed && <Block label="racknerd.bandwidthused" />}
|
||||||
|
{showBandwidthFree && <Block label="racknerd.bandwidthfree" />}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const { racknerd: racknerdInfo } = racknerdData;
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
{showIpAddress && (<Block
|
||||||
|
label="racknerd.ipAddress"
|
||||||
|
value={racknerdInfo.ipAddress}
|
||||||
|
/>)}
|
||||||
|
{showMemoryUsage && (<Block
|
||||||
|
label="racknerd.memoryusage"
|
||||||
|
value={t("common.bbytes", { value: racknerdInfo.system.memoryused, maximumFractionDigits: 1 })}
|
||||||
|
/>)}
|
||||||
|
{showHardDriveUsage && (<Block
|
||||||
|
label="racknerd.hddtotal"
|
||||||
|
value={t("common.bbytes", { value: racknerdInfo.system.hdd_total, maximumFractionDigits: 1 })}
|
||||||
|
/>)}
|
||||||
|
{showBandwidthUsed && (<Block
|
||||||
|
label="racknerd.bandwidthused"
|
||||||
|
value={t("common.bbytes", { value: racknerdInfo.system.bandwidth_used, maximumFractionDigits: 1 })}
|
||||||
|
/>)}
|
||||||
|
{showBandwidthFree && (<Block
|
||||||
|
label="racknerd.bandwidthfree"
|
||||||
|
value={t("common.bbytes", { value: racknerdInfo.system.bandwidth_free, maximumFractionDigits: 1 })}
|
||||||
|
/>)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
100
src/widgets/racknerd/proxy.js
Normal file
100
src/widgets/racknerd/proxy.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import { xml2json } from "xml-js";
|
||||||
|
|
||||||
|
import { racknerdDefaultFields } from "./component";
|
||||||
|
|
||||||
|
import { httpProxy } from "utils/proxy/http";
|
||||||
|
import getServiceWidget from "utils/config/service-helpers";
|
||||||
|
import createLogger from "utils/logger";
|
||||||
|
|
||||||
|
const logger = createLogger("racknerdProxyHandler");
|
||||||
|
|
||||||
|
async function requestEndpoint(apiBaseUrl, action, params) {
|
||||||
|
const request = {
|
||||||
|
method: "POST"
|
||||||
|
};
|
||||||
|
let qs = "";
|
||||||
|
Object.entries(params).forEach(([key, value]) => {
|
||||||
|
qs += `&${key}=${value}`;
|
||||||
|
});
|
||||||
|
const apiUrl = `${apiBaseUrl}?action=${action}${qs}`;
|
||||||
|
const [status, , data] = await httpProxy(apiUrl, request);
|
||||||
|
if (status !== 200) {
|
||||||
|
logger.debug(`HTTP ${status} performing XMLRequest for ${action}`, data);
|
||||||
|
throw new Error(`Failed fetching '${action}'`);
|
||||||
|
}
|
||||||
|
const response = {};
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(xml2json(`<root>${data}</root>`, {compact: true}));
|
||||||
|
const responseElements = jsonData?.root || {};
|
||||||
|
Object.entries(responseElements).forEach(([responseKey, responseValue]) => {
|
||||||
|
/* eslint no-underscore-dangle: ["error", { "allow": ["_text"] }] */
|
||||||
|
response[responseKey] = responseValue?._text || "";
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug(`Failed parsing ${action} response:`, data);
|
||||||
|
throw new Error(`Failed parsing '${action}' response`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function racknerdProxyHandler(req, res) {
|
||||||
|
const { group, service, index } = req.query;
|
||||||
|
const serviceWidget = await getServiceWidget(group, service, index);
|
||||||
|
|
||||||
|
if (!serviceWidget) {
|
||||||
|
res.status(500).json({ error: { message: "Service widget not found" } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!serviceWidget.url) {
|
||||||
|
res.status(500).json({ error: { message: "Service widget url not configured" } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const serviceWidgetUrl = new URL(serviceWidget.url);
|
||||||
|
const apiBaseUrl = `${serviceWidgetUrl.protocol}//${serviceWidgetUrl.hostname}/api/client/command.php`;
|
||||||
|
|
||||||
|
if (!serviceWidget.fields?.length > 0) {
|
||||||
|
serviceWidget.fields = racknerdDefaultFields;
|
||||||
|
}
|
||||||
|
const requestStatus = ["status"].some((field) => serviceWidget.fields?.includes(field));
|
||||||
|
const requestInfo = ["bandwidthused", "memoryusage", "hddtotal", "ipAddress"].some((field) => serviceWidget.fields?.includes(field));
|
||||||
|
const params = {
|
||||||
|
bw: serviceWidget.fields?.includes('bandwidthused') || serviceWidget.fields?.includes('bandwidthfree'),
|
||||||
|
hdd: serviceWidget.fields?.includes('hddtotal'),
|
||||||
|
ipAddr: serviceWidget.fields?.includes('ipAddress'),
|
||||||
|
mem: serviceWidget.fields?.includes('memoryusage'),
|
||||||
|
key: serviceWidget.key,
|
||||||
|
hash: serviceWidget.hash,
|
||||||
|
};
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
requestStatus ? requestEndpoint(apiBaseUrl, "status", params) : null,
|
||||||
|
requestInfo ? requestEndpoint(apiBaseUrl, "info", params) : null,
|
||||||
|
])
|
||||||
|
.then(([statusResponse, infoResponse]) => {
|
||||||
|
const memoryItems = infoResponse.mem?.split(',');
|
||||||
|
const hddItems = infoResponse.hdd?.split(',');
|
||||||
|
const bandwidthItems = infoResponse.bw?.split(',');
|
||||||
|
res.status(200).json({
|
||||||
|
racknerd: {
|
||||||
|
ipAddress: infoResponse.ipaddress || undefined,
|
||||||
|
system: {
|
||||||
|
status: statusResponse ? statusResponse.statusmsg : undefined,
|
||||||
|
memoryused: memoryItems ? parseFloat(memoryItems[1], 10) : undefined,
|
||||||
|
hdd_total: hddItems ? parseFloat(hddItems[0], 10) : undefined,
|
||||||
|
bandwidth_total: bandwidthItems ? parseFloat(bandwidthItems[0], 10) : undefined,
|
||||||
|
bandwidth_used: bandwidthItems ? parseFloat(bandwidthItems[1], 10) : undefined,
|
||||||
|
bandwidth_free: bandwidthItems ? parseFloat(bandwidthItems[2], 10) : undefined,
|
||||||
|
mem_total: memoryItems ? parseFloat(memoryItems[0], 10) : undefined,
|
||||||
|
mem_free: memoryItems ? parseFloat(memoryItems[2], 10) : undefined,
|
||||||
|
mem_percent: memoryItems ? parseFloat(memoryItems[3], 10) : undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
res.status(500).json({ error: { message: error.message } });
|
||||||
|
});
|
||||||
|
}
|
||||||
16
src/widgets/racknerd/widget.js
Normal file
16
src/widgets/racknerd/widget.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import racknerdProxyHandler from "./proxy";
|
||||||
|
|
||||||
|
const widget = {
|
||||||
|
api: "{url}/{endpoint}",
|
||||||
|
proxyHandler: racknerdProxyHandler,
|
||||||
|
|
||||||
|
mappings: {
|
||||||
|
serverinfo: {
|
||||||
|
endpoint: "api/client/command.php",
|
||||||
|
params: ["key", "hash"],
|
||||||
|
optionalParams: ["bw", "mem", "hdd", "ipaddr"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default widget;
|
||||||
@ -96,6 +96,7 @@ import pterodactyl from "./pterodactyl/widget";
|
|||||||
import pyload from "./pyload/widget";
|
import pyload from "./pyload/widget";
|
||||||
import qbittorrent from "./qbittorrent/widget";
|
import qbittorrent from "./qbittorrent/widget";
|
||||||
import qnap from "./qnap/widget";
|
import qnap from "./qnap/widget";
|
||||||
|
import racknerd from "./racknerd/widget";
|
||||||
import radarr from "./radarr/widget";
|
import radarr from "./radarr/widget";
|
||||||
import readarr from "./readarr/widget";
|
import readarr from "./readarr/widget";
|
||||||
import rutorrent from "./rutorrent/widget";
|
import rutorrent from "./rutorrent/widget";
|
||||||
@ -232,6 +233,7 @@ const widgets = {
|
|||||||
pyload,
|
pyload,
|
||||||
qbittorrent,
|
qbittorrent,
|
||||||
qnap,
|
qnap,
|
||||||
|
racknerd,
|
||||||
radarr,
|
radarr,
|
||||||
readarr,
|
readarr,
|
||||||
romm,
|
romm,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user