diff --git a/src/widgets/pyload/component.jsx b/src/widgets/pyload/component.jsx index e35bb3b56..958733c31 100644 --- a/src/widgets/pyload/component.jsx +++ b/src/widgets/pyload/component.jsx @@ -7,15 +7,23 @@ import useWidgetAPI from "utils/proxy/use-widget-api"; export default function Component({ service }) { const { t } = useTranslation(); const { widget } = service; - const { data: pyloadData, error: pyloadError } = useWidgetAPI( - widget, - "statusServer", - ); + const { data: pyloadData, error: pyloadError } = useWidgetAPI(widget, "status"); - if (pyloadError || !pyloadData) { + if (pyloadError || pyloadData?.error) { return ; } + if (!pyloadData) { + return ( + + + + + + + ); + } + return ( diff --git a/src/widgets/pyload/proxy.js b/src/widgets/pyload/proxy.js index 35fb7becc..d96b859c1 100644 --- a/src/widgets/pyload/proxy.js +++ b/src/widgets/pyload/proxy.js @@ -1,6 +1,36 @@ +import cache from "memory-cache"; + import getServiceWidget from "utils/config/service-helpers"; import { formatApiCall } from "utils/proxy/api-helpers"; import widgets from "widgets/widgets"; +import createLogger from "utils/logger"; + +const proxyName = 'pyloadProxyHandler'; +const logger = createLogger(proxyName); +const sessionCacheKey = `${proxyName}__sessionId`; + +async function fetchFromPyloadAPI(url, sessionId, params) { + const options = { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + }, + }; + + if (params) { + options.body = Object.keys(params).map(k => `${k}=${params[k]}`).join('&'); + } else { + options.body = `session=${sessionId}` + } + + return fetch(url, options).then((response) => response.json()); +} + +async function login(loginUrl, username, password) { + const sessionId = await fetchFromPyloadAPI(loginUrl, null, { username, password }) + cache.put(sessionCacheKey, sessionId); + return sessionId; +} export default async function pyloadProxyHandler(req, res) { const { group, service, endpoint } = req.query; @@ -12,27 +42,29 @@ export default async function pyloadProxyHandler(req, res) { const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); const loginUrl = `${widget.url}/api/login`; - // Pyload api does not support argument passing as JSON. - const sessionId = await fetch(loginUrl, { - method: "POST", - // Empty passwords are supported. - body: `username=${widget.username}&password=${widget.password ?? ''}`, - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - }).then((response) => response.json()); - - const apiResponse = await fetch(url, { - method: "POST", - body: `session=${sessionId}`, - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - }).then((response) => response.json()); + let sessionId = cache.get(sessionCacheKey); + + if (!sessionId) { + sessionId = await login(loginUrl, widget.username, widget.password); + } + let apiResponse = await fetchFromPyloadAPI(url, sessionId); + + if (apiResponse?.error === 'Forbidden') { + logger.debug("Failed to retrieve data from Pyload API, login and re-try"); + cache.del(sessionCacheKey); + sessionId = await login(loginUrl, widget.username, widget.password); + apiResponse = await fetchFromPyloadAPI(url, sessionId); + } + + if (apiResponse?.error) { + return res.status(500).send(apiResponse); + } + cache.del(sessionCacheKey); + return res.send(apiResponse); } } return res.status(400).json({ error: "Invalid proxy service type" }); -} +} \ No newline at end of file diff --git a/src/widgets/pyload/widget.js b/src/widgets/pyload/widget.js index 3d2f2958f..71073c0f1 100644 --- a/src/widgets/pyload/widget.js +++ b/src/widgets/pyload/widget.js @@ -3,6 +3,12 @@ import pyloadProxyHandler from "./proxy"; const widget = { api: "{url}/api/{endpoint}", proxyHandler: pyloadProxyHandler, -}; + + mappings: { + "status": { + endpoint: "statusServer", + } + } +} export default widget;