starting of widget refactoring

This commit is contained in:
Ben Phelps 2022-09-25 19:43:47 +03:00
parent d6f6ea9dba
commit 562235f828
42 changed files with 337 additions and 301 deletions

View file

@ -1,44 +1,44 @@
const formats = {
emby: `{url}/emby/{endpoint}?api_key={key}`,
jellyfin: `{url}/emby/{endpoint}?api_key={key}`,
pihole: `{url}/admin/{endpoint}`,
radarr: `{url}/api/v3/{endpoint}?apikey={key}`,
sonarr: `{url}/api/v3/{endpoint}?apikey={key}`,
speedtest: `{url}/api/{endpoint}`,
tautulli: `{url}/api/v2?apikey={key}&cmd={endpoint}`,
traefik: `{url}/api/{endpoint}`,
portainer: `{url}/api/endpoints/{env}/{endpoint}`,
rutorrent: `{url}/plugins/httprpc/action.php`,
transmission: `{url}/transmission/rpc`,
qbittorrent: `{url}/api/v2/{endpoint}`,
jellyseerr: `{url}/api/v1/{endpoint}`,
overseerr: `{url}/api/v1/{endpoint}`,
ombi: `{url}/api/v1/{endpoint}`,
npm: `{url}/api/{endpoint}`,
lidarr: `{url}/api/v1/{endpoint}?apikey={key}`,
readarr: `{url}/api/v1/{endpoint}?apikey={key}`,
bazarr: `{url}/api/{endpoint}/wanted?apikey={key}`,
sabnzbd: `{url}/api/?apikey={key}&output=json&mode={endpoint}`,
coinmarketcap: `https://pro-api.coinmarketcap.com/{endpoint}`,
gotify: `{url}/{endpoint}`,
prowlarr: `{url}/api/v1/{endpoint}`,
jackett: `{url}/api/v2.0/{endpoint}?apikey={key}&configured=true`,
adguard: `{url}/control/{endpoint}`,
strelaysrv: `{url}/{endpoint}`,
mastodon: `{url}/api/v1/{endpoint}`,
};
// const formats = {
// emby: `{url}/emby/{endpoint}?api_key={key}`,
// jellyfin: `{url}/emby/{endpoint}?api_key={key}`,
// pihole: `{url}/admin/{endpoint}`,
// radarr: `{url}/api/v3/{endpoint}?apikey={key}`,
// sonarr: `{url}/api/v3/{endpoint}?apikey={key}`,
// speedtest: `{url}/api/{endpoint}`,
// tautulli: `{url}/api/v2?apikey={key}&cmd={endpoint}`,
// traefik: `{url}/api/{endpoint}`,
// portainer: `{url}/api/endpoints/{env}/{endpoint}`,
// rutorrent: `{url}/plugins/httprpc/action.php`,
// transmission: `{url}/transmission/rpc`,
// qbittorrent: `{url}/api/v2/{endpoint}`,
// jellyseerr: `{url}/api/v1/{endpoint}`,
// overseerr: `{url}/api/v1/{endpoint}`,
// ombi: `{url}/api/v1/{endpoint}`,
// npm: `{url}/api/{endpoint}`,
// lidarr: `{url}/api/v1/{endpoint}?apikey={key}`,
// readarr: `{url}/api/v1/{endpoint}?apikey={key}`,
// bazarr: `{url}/api/{endpoint}/wanted?apikey={key}`,
// sabnzbd: `{url}/api/?apikey={key}&output=json&mode={endpoint}`,
// coinmarketcap: `https://pro-api.coinmarketcap.com/{endpoint}`,
// gotify: `{url}/{endpoint}`,
// prowlarr: `{url}/api/v1/{endpoint}`,
// jackett: `{url}/api/v2.0/{endpoint}?apikey={key}&configured=true`,
// adguard: `{url}/control/{endpoint}`,
// strelaysrv: `{url}/{endpoint}`,
// mastodon: `{url}/api/v1/{endpoint}`,
// };
export function formatApiCall(api, args) {
export function formatApiCall(url, args) {
const find = /\{.*?\}/g;
const replace = (match) => {
const key = match.replace(/\{|\}/g, "");
return args[key];
};
return formats[api].replace(find, replace);
return url.replace(find, replace);
}
export function formatApiUrl(widget, endpoint) {
export function formatProxyUrl(widget, endpoint) {
const params = new URLSearchParams({
type: widget.type,
group: widget.service_group,
@ -47,3 +47,23 @@ export function formatApiUrl(widget, endpoint) {
});
return `/api/services/proxy?${params.toString()}`;
}
export function asJson(data) {
if (data?.length > 0) {
const json = JSON.parse(data.toString());
return json;
}
return data;
}
export function jsonArrayTransform(data, transform) {
const json = asJson(data);
if (json instanceof Array) {
return transform(json);
}
return json;
}
export function jsonArrayFilter(data, filter) {
return jsonArrayTransform(data, (items) => items.filter(filter));
}

View file

@ -1,6 +1,7 @@
import getServiceWidget from "utils/service-helpers";
import { formatApiCall } from "utils/api-helpers";
import { httpProxy } from "utils/http";
import widgets from "widgets/widgets";
export default async function credentialedProxyHandler(req, res) {
const { group, service, endpoint } = req.query;
@ -8,8 +9,12 @@ export default async function credentialedProxyHandler(req, res) {
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(widget.type, { endpoint, ...widget }));
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const headers = {
"Content-Type": "application/json",

View file

@ -2,17 +2,22 @@ import getServiceWidget from "utils/service-helpers";
import { formatApiCall } from "utils/api-helpers";
import { httpProxy } from "utils/http";
import createLogger from "utils/logger";
import widgets from "widgets/widgets";
const logger = createLogger('genericProxyHandler');
const logger = createLogger("genericProxyHandler");
export default async function genericProxyHandler(req, res, maps) {
export default async function genericProxyHandler(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(widget.type, { endpoint, ...widget }));
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
let headers;
if (widget.username && widget.password) {
@ -27,8 +32,8 @@ export default async function genericProxyHandler(req, res, maps) {
});
let resultData = data;
if ((status === 200) && (maps?.[endpoint])) {
resultData = maps[endpoint](data);
if (status === 200 && map) {
resultData = map(data);
}
if (contentType) res.setHeader("Content-Type", contentType);

View file

@ -1,5 +1,6 @@
import getServiceWidget from "utils/service-helpers";
import { formatApiCall } from "utils/api-helpers";
import widgets from "widgets/widgets";
export default async function npmProxyHandler(req, res) {
const { group, service, endpoint } = req.query;
@ -7,8 +8,12 @@ export default async function npmProxyHandler(req, res) {
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(widget.type, { endpoint, ...widget }));
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const loginUrl = `${widget.url}/api/tokens`;
const body = { identity: widget.username, secret: widget.password };

View file

@ -12,15 +12,15 @@ async function login(widget, params) {
return fetch(loginUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: loginBody
body: loginBody,
})
.then(async response => {
addCookieToJar(loginUrl, response.headers);
setCookieHeader(loginUrl, params);
const data = await response.text();
return ([response.status, data]);
})
.catch(err => ([500, err]));
.then(async (response) => {
addCookieToJar(loginUrl, response.headers);
setCookieHeader(loginUrl, params);
const data = await response.text();
return [response.status, data];
})
.catch((err) => [500, err]);
}
export default async function qbittorrentProxyHandler(req, res) {
@ -46,7 +46,7 @@ export default async function qbittorrentProxyHandler(req, res) {
if (status !== 200) {
return res.status(status).end(data);
}
if (data.toString() !== 'Ok.') {
if (data.toString() !== "Ok.") {
return res.status(401).end(data);
}
}
@ -55,4 +55,4 @@ export default async function qbittorrentProxyHandler(req, res) {
if (contentType) res.setHeader("Content-Type", contentType);
return res.status(status).send(data);
}
}