Aria2 Service Widget
This commit is contained in:
parent
9aa46e4fdd
commit
3b207f3250
18
docs/widgets/services/aria2.md
Normal file
18
docs/widgets/services/aria2.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
title: Aria2
|
||||||
|
description: Aria2 Widget Configuration
|
||||||
|
---
|
||||||
|
|
||||||
|
Learn more about [Aria2](https://github.com/aria2/aria2).
|
||||||
|
|
||||||
|
Find your API key in aria2c configuration file `aria2c.conf`: `rpc-secret`.
|
||||||
|
To make it work, JSON RPC in Aria2 should be enabled.
|
||||||
|
|
||||||
|
Optionally, `jsonrpc` endpoint path could be adjusted via `endpoint` widget config.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: aria2c
|
||||||
|
url: http://aria2c.host.or.ip
|
||||||
|
key: apikey
|
||||||
|
```
|
||||||
@ -1007,5 +1007,11 @@
|
|||||||
"issues": "Issues",
|
"issues": "Issues",
|
||||||
"merges": "Merge Requests",
|
"merges": "Merge Requests",
|
||||||
"projects": "Projects"
|
"projects": "Projects"
|
||||||
|
},
|
||||||
|
"aria2c": {
|
||||||
|
"active": "Active",
|
||||||
|
"waiting": "Waiting",
|
||||||
|
"download": "↓",
|
||||||
|
"upload": "↑"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/widgets/aria2c/component.jsx
Normal file
37
src/widgets/aria2c/component.jsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
|
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 { t } = useTranslation();
|
||||||
|
|
||||||
|
const { widget } = service;
|
||||||
|
|
||||||
|
const { data: aria2cData, error: aria2cError } = useWidgetAPI(widget);
|
||||||
|
|
||||||
|
if (aria2cError) {
|
||||||
|
return <Container service={service} error={aria2cError} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aria2cData) {
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="aria2c.active" />
|
||||||
|
<Block label="aria2c.waiting" />
|
||||||
|
<Block label="aria2c.download" />
|
||||||
|
<Block label="aria2c.upload" />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="aria2c.active" value={t("common.number", { value: aria2cData.numActive })} />
|
||||||
|
<Block label="aria2c.waiting" value={t("common.number", { value: aria2cData.numWaiting })} />
|
||||||
|
<Block label="aria2c.download" value={t("common.byterate", { value: parseInt(aria2cData.downloadSpeed, 10) })} />
|
||||||
|
<Block label="aria2c.upload" value={t("common.byterate", { value: parseInt(aria2cData.uploadSpeed, 10) })} />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
65
src/widgets/aria2c/proxy.js
Normal file
65
src/widgets/aria2c/proxy.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import getServiceWidget from "utils/config/service-helpers";
|
||||||
|
import { httpProxy } from "utils/proxy/http";
|
||||||
|
import widgets from "widgets/widgets";
|
||||||
|
import { formatApiCall } from "utils/proxy/api-helpers";
|
||||||
|
import createLogger from "utils/logger";
|
||||||
|
|
||||||
|
const logger = createLogger("ariaProxyHandler");
|
||||||
|
|
||||||
|
|
||||||
|
export default async function ariaProxyHandler(req, res) {
|
||||||
|
const { group, service, index } = req.query;
|
||||||
|
|
||||||
|
if (group && service) {
|
||||||
|
const widget = await getServiceWidget(group, service, index);
|
||||||
|
|
||||||
|
if (widget) {
|
||||||
|
if (widget.endpoint === undefined) {
|
||||||
|
widget.endpoint = 'jsonrpc'
|
||||||
|
}
|
||||||
|
|
||||||
|
const api = widgets?.[widget.type]?.api;
|
||||||
|
const url = new URL(formatApiCall(api, { ...widget }));
|
||||||
|
|
||||||
|
const headers = {
|
||||||
|
"content-type": "application/json",
|
||||||
|
accept: "application/json",
|
||||||
|
};
|
||||||
|
if (widget.username) {
|
||||||
|
headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rpcRequestBody = {
|
||||||
|
id: "homepage",
|
||||||
|
jsonrpc: "2.0",
|
||||||
|
method: "aria2.getGlobalStat",
|
||||||
|
params: []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (widget.token !== undefined) {
|
||||||
|
rpcRequestBody.params.push(`token:${widget.token}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const [status, , data] = await httpProxy(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify(rpcRequestBody),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (status !== 200) {
|
||||||
|
logger.error("HTTP Error %d calling %s", status, url.toString());
|
||||||
|
return res.status(status).json({ error: { message: "HTTP Error", url, data } });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const rawData = JSON.parse(data);
|
||||||
|
|
||||||
|
return res.status(200).send(rawData.result);
|
||||||
|
} catch (e) {
|
||||||
|
return res.status(500).json({ error: { message: e?.toString() ?? "Error parsing aria2c rpc data", url, data } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(500).json({ error: "Invalid proxy service type" });
|
||||||
|
}
|
||||||
8
src/widgets/aria2c/widget.js
Normal file
8
src/widgets/aria2c/widget.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import ariaProxyHandler from './proxy';
|
||||||
|
|
||||||
|
const widget = {
|
||||||
|
api: "{url}/{endpoint}",
|
||||||
|
proxyHandler: ariaProxyHandler,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default widget;
|
||||||
@ -3,6 +3,7 @@ import dynamic from "next/dynamic";
|
|||||||
const components = {
|
const components = {
|
||||||
adguard: dynamic(() => import("./adguard/component")),
|
adguard: dynamic(() => import("./adguard/component")),
|
||||||
argocd: dynamic(() => import("./argocd/component")),
|
argocd: dynamic(() => import("./argocd/component")),
|
||||||
|
aria2c: dynamic(() => import("./aria2c/component")),
|
||||||
atsumeru: dynamic(() => import("./atsumeru/component")),
|
atsumeru: dynamic(() => import("./atsumeru/component")),
|
||||||
audiobookshelf: dynamic(() => import("./audiobookshelf/component")),
|
audiobookshelf: dynamic(() => import("./audiobookshelf/component")),
|
||||||
authentik: dynamic(() => import("./authentik/component")),
|
authentik: dynamic(() => import("./authentik/component")),
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import adguard from "./adguard/widget";
|
import adguard from "./adguard/widget";
|
||||||
import argocd from "./argocd/widget";
|
import argocd from "./argocd/widget";
|
||||||
|
import aria2c from "./aria2c/widget";
|
||||||
import atsumeru from "./atsumeru/widget";
|
import atsumeru from "./atsumeru/widget";
|
||||||
import audiobookshelf from "./audiobookshelf/widget";
|
import audiobookshelf from "./audiobookshelf/widget";
|
||||||
import authentik from "./authentik/widget";
|
import authentik from "./authentik/widget";
|
||||||
@ -134,6 +135,7 @@ import zabbix from "./zabbix/widget";
|
|||||||
const widgets = {
|
const widgets = {
|
||||||
adguard,
|
adguard,
|
||||||
argocd,
|
argocd,
|
||||||
|
aria2c,
|
||||||
atsumeru,
|
atsumeru,
|
||||||
audiobookshelf,
|
audiobookshelf,
|
||||||
authentik,
|
authentik,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user