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)
|
||||
- [qBittorrent](qbittorrent.md)
|
||||
- [QNAP](qnap.md)
|
||||
- [RackNerd](racknerd.md)
|
||||
- [Radarr](radarr.md)
|
||||
- [Readarr](readarr.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/qbittorrent.md
|
||||
- widgets/services/qnap.md
|
||||
- widgets/services/racknerd.md
|
||||
- widgets/services/radarr.md
|
||||
- widgets/services/readarr.md
|
||||
- widgets/services/romm.md
|
||||
|
||||
@ -716,6 +716,14 @@
|
||||
"numfiles": "Files",
|
||||
"numshares": "Shared Items"
|
||||
},
|
||||
"racknerd": {
|
||||
"ipAddress": "IP Address",
|
||||
"memoryusage": "Memory Usage",
|
||||
"hddtotal": "Total Space",
|
||||
"bandwidthtotal": "Bandwidth Total",
|
||||
"bandwidthused": "Bandwidth Used",
|
||||
"bandwidthfree": "Bandwidth Free"
|
||||
},
|
||||
"kopia": {
|
||||
"status": "Status",
|
||||
"size": "Size",
|
||||
|
||||
@ -104,6 +104,7 @@ const components = {
|
||||
pyload: dynamic(() => import("./pyload/component")),
|
||||
qbittorrent: dynamic(() => import("./qbittorrent/component")),
|
||||
qnap: dynamic(() => import("./qnap/component")),
|
||||
racknerd: dynamic(() => import("./racknerd/component")),
|
||||
radarr: dynamic(() => import("./radarr/component")),
|
||||
readarr: dynamic(() => import("./readarr/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 qbittorrent from "./qbittorrent/widget";
|
||||
import qnap from "./qnap/widget";
|
||||
import racknerd from "./racknerd/widget";
|
||||
import radarr from "./radarr/widget";
|
||||
import readarr from "./readarr/widget";
|
||||
import rutorrent from "./rutorrent/widget";
|
||||
@ -232,6 +233,7 @@ const widgets = {
|
||||
pyload,
|
||||
qbittorrent,
|
||||
qnap,
|
||||
racknerd,
|
||||
radarr,
|
||||
readarr,
|
||||
romm,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user