append service name to cache keys
This commit is contained in:
parent
702dbd8a82
commit
91d8e56471
6 changed files with 46 additions and 41 deletions
|
@ -10,7 +10,7 @@ const proxyName = "homebridgeProxyHandler";
|
|||
const sessionTokenCacheKey = `${proxyName}__sessionToken`;
|
||||
const logger = createLogger(proxyName);
|
||||
|
||||
async function login(widget) {
|
||||
async function login(widget, service) {
|
||||
const endpoint = "auth/login";
|
||||
const api = widgets?.[widget.type]?.api
|
||||
const loginUrl = new URL(formatApiCall(api, { endpoint, ...widget }));
|
||||
|
@ -26,7 +26,7 @@ async function login(widget) {
|
|||
try {
|
||||
const { access_token: accessToken, expires_in: expiresIn } = JSON.parse(data.toString());
|
||||
|
||||
cache.put(sessionTokenCacheKey, accessToken, (expiresIn * 1000) - 5 * 60 * 1000); // expiresIn (s) - 5m
|
||||
cache.put(`${sessionTokenCacheKey}.${service}`, accessToken, (expiresIn * 1000) - 5 * 60 * 1000); // expiresIn (s) - 5m
|
||||
return { accessToken };
|
||||
} catch (e) {
|
||||
logger.error("Unable to login to Homebridge API: %s", e);
|
||||
|
@ -35,10 +35,11 @@ async function login(widget) {
|
|||
return { accessToken: false };
|
||||
}
|
||||
|
||||
async function apiCall(widget, endpoint) {
|
||||
async function apiCall(widget, endpoint, service) {
|
||||
const key = `${sessionTokenCacheKey}.${service}`;
|
||||
const headers = {
|
||||
"content-type": "application/json",
|
||||
"Authorization": `Bearer ${cache.get(sessionTokenCacheKey)}`,
|
||||
"Authorization": `Bearer ${cache.get(key)}`,
|
||||
}
|
||||
|
||||
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
|
||||
|
@ -51,7 +52,7 @@ async function apiCall(widget, endpoint) {
|
|||
|
||||
if (status === 401) {
|
||||
logger.debug("Homebridge API rejected the request, attempting to obtain new session token");
|
||||
const { accessToken } = login(widget);
|
||||
const { accessToken } = login(widget, service);
|
||||
headers.Authorization = `Bearer ${accessToken}`;
|
||||
|
||||
// retry the request, now with the new session token
|
||||
|
@ -83,14 +84,14 @@ export default async function homebridgeProxyHandler(req, res) {
|
|||
return res.status(400).json({ error: "Invalid proxy service type" });
|
||||
}
|
||||
|
||||
if (!cache.get(sessionTokenCacheKey)) {
|
||||
await login(widget);
|
||||
if (!cache.get(`${sessionTokenCacheKey}.${service}`)) {
|
||||
await login(widget, service);
|
||||
}
|
||||
|
||||
const { data: statusData } = await apiCall(widget, "status/homebridge");
|
||||
const { data: versionData } = await apiCall(widget, "status/homebridge-version");
|
||||
const { data: childBridgeData } = await apiCall(widget, "status/homebridge/child-bridges");
|
||||
const { data: pluginsData } = await apiCall(widget, "plugins");
|
||||
const { data: statusData } = await apiCall(widget, "status/homebridge", service);
|
||||
const { data: versionData } = await apiCall(widget, "status/homebridge-version", service);
|
||||
const { data: childBridgeData } = await apiCall(widget, "status/homebridge/child-bridges", service);
|
||||
const { data: pluginsData } = await apiCall(widget, "plugins", service);
|
||||
|
||||
return res.status(200).send({
|
||||
status: statusData?.status,
|
||||
|
|
|
@ -10,7 +10,7 @@ const proxyName = "npmProxyHandler";
|
|||
const tokenCacheKey = `${proxyName}__token`;
|
||||
const logger = createLogger(proxyName);
|
||||
|
||||
async function login(loginUrl, username, password) {
|
||||
async function login(loginUrl, username, password, service) {
|
||||
const authResponse = await httpProxy(loginUrl, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ identity: username, secret: password }),
|
||||
|
@ -27,7 +27,7 @@ async function login(loginUrl, username, password) {
|
|||
|
||||
if (status === 200) {
|
||||
const expiration = new Date(data.expires) - Date.now();
|
||||
cache.put(tokenCacheKey, data.token, expiration - (5 * 60 * 1000)); // expiration -5 minutes
|
||||
cache.put(`${tokenCacheKey}.${service}`, data.token, expiration - (5 * 60 * 1000)); // expiration -5 minutes
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(`Error ${status} logging into npm`, authResponse[2]);
|
||||
|
@ -53,9 +53,9 @@ export default async function npmProxyHandler(req, res) {
|
|||
let contentType;
|
||||
let data;
|
||||
|
||||
let token = cache.get(tokenCacheKey);
|
||||
let token = cache.get(`${tokenCacheKey}.${service}`);
|
||||
if (!token) {
|
||||
[status, token] = await login(loginUrl, widget.username, widget.password);
|
||||
[status, token] = await login(loginUrl, widget.username, widget.password, service);
|
||||
if (status !== 200) {
|
||||
logger.debug(`HTTTP ${status} logging into npm api: ${token}`);
|
||||
return res.status(status).send(token);
|
||||
|
@ -72,8 +72,8 @@ export default async function npmProxyHandler(req, res) {
|
|||
|
||||
if (status === 403) {
|
||||
logger.debug(`HTTTP ${status} retrieving data from npm api, logging in and trying again.`);
|
||||
cache.del(tokenCacheKey);
|
||||
[status, token] = await login(loginUrl, widget.username, widget.password);
|
||||
cache.del(`${tokenCacheKey}.${service}`);
|
||||
[status, token] = await login(loginUrl, widget.username, widget.password, service);
|
||||
|
||||
if (status !== 200) {
|
||||
logger.debug(`HTTTP ${status} logging into npm api: ${data}`);
|
||||
|
|
|
@ -58,6 +58,9 @@ async function fetchFromPlexAPI(endpoint, widget) {
|
|||
|
||||
export default async function plexProxyHandler(req, res) {
|
||||
const widget = await getWidget(req);
|
||||
|
||||
const { service } = req.query;
|
||||
|
||||
if (!widget) {
|
||||
return res.status(400).json({ error: "Invalid proxy service type" });
|
||||
}
|
||||
|
@ -74,18 +77,18 @@ export default async function plexProxyHandler(req, res) {
|
|||
streams = apiData.MediaContainer._attributes.size;
|
||||
}
|
||||
|
||||
let libraries = cache.get(librariesCacheKey);
|
||||
let libraries = cache.get(`${librariesCacheKey}.${service}`);
|
||||
if (libraries === null) {
|
||||
logger.debug("Getting libraries from Plex API");
|
||||
[status, apiData] = await fetchFromPlexAPI("/library/sections", widget);
|
||||
if (apiData && apiData.MediaContainer) {
|
||||
libraries = [].concat(apiData.MediaContainer.Directory);
|
||||
cache.put(librariesCacheKey, libraries, 1000 * 60 * 60 * 6);
|
||||
cache.put(`${librariesCacheKey}.${service}`, libraries, 1000 * 60 * 60 * 6);
|
||||
}
|
||||
}
|
||||
|
||||
let movies = cache.get(moviesCacheKey);
|
||||
let tv = cache.get(tvCacheKey);
|
||||
let movies = cache.get(`${moviesCacheKey}.${service}`);
|
||||
let tv = cache.get(`${tvCacheKey}.${service}`);
|
||||
if (movies === null || tv === null) {
|
||||
movies = 0;
|
||||
tv = 0;
|
||||
|
@ -100,8 +103,8 @@ export default async function plexProxyHandler(req, res) {
|
|||
tv += size;
|
||||
}
|
||||
}
|
||||
cache.put(tvCacheKey, tv, 1000 * 60 * 10);
|
||||
cache.put(moviesCacheKey, movies, 1000 * 60 * 10);
|
||||
cache.put(`${tvCacheKey}.${service}`, tv, 1000 * 60 * 10);
|
||||
cache.put(`${moviesCacheKey}.${service}`, movies, 1000 * 60 * 10);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ const logger = createLogger(proxyName);
|
|||
const sessionCacheKey = `${proxyName}__sessionId`;
|
||||
const isNgCacheKey = `${proxyName}__isNg`;
|
||||
|
||||
async function fetchFromPyloadAPI(url, sessionId, params) {
|
||||
async function fetchFromPyloadAPI(url, sessionId, params, service) {
|
||||
const options = {
|
||||
body: params
|
||||
? Object.keys(params)
|
||||
|
@ -25,10 +25,10 @@ async function fetchFromPyloadAPI(url, sessionId, params) {
|
|||
};
|
||||
|
||||
// see https://github.com/benphelps/homepage/issues/517
|
||||
const isNg = cache.get(isNgCacheKey);
|
||||
const isNg = cache.get(`${isNgCacheKey}.${service}`);
|
||||
if (isNg && !params) {
|
||||
delete options.body;
|
||||
options.headers.Cookie = cache.get(sessionCacheKey);
|
||||
options.headers.Cookie = cache.get(`${sessionCacheKey}.${service}`);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
|
@ -43,19 +43,19 @@ async function fetchFromPyloadAPI(url, sessionId, params) {
|
|||
return [status, returnData, responseHeaders];
|
||||
}
|
||||
|
||||
async function login(loginUrl, username, password = '') {
|
||||
const [status, sessionId, responseHeaders] = await fetchFromPyloadAPI(loginUrl, null, { username, password });
|
||||
async function login(loginUrl, service, username, password = '') {
|
||||
const [status, sessionId, responseHeaders] = await fetchFromPyloadAPI(loginUrl, null, { username, password }, service);
|
||||
|
||||
// this API actually returns status 200 even on login failure
|
||||
if (status !== 200 || sessionId === false) {
|
||||
logger.error(`HTTP ${status} logging into Pyload API, returned: ${JSON.stringify(sessionId)}`);
|
||||
} else if (responseHeaders['set-cookie']?.join().includes('pyload_session')) {
|
||||
// Support pyload-ng, see https://github.com/benphelps/homepage/issues/517
|
||||
cache.put(isNgCacheKey, true);
|
||||
cache.put(`${isNgCacheKey}.${service}`, true);
|
||||
const sessionCookie = responseHeaders['set-cookie'][0];
|
||||
cache.put(sessionCacheKey, sessionCookie, 60 * 60 * 23 * 1000); // cache for 23h
|
||||
cache.put(`${sessionCacheKey}.${service}`, sessionCookie, 60 * 60 * 23 * 1000); // cache for 23h
|
||||
} else {
|
||||
cache.put(sessionCacheKey, sessionId);
|
||||
cache.put(`${sessionCacheKey}.${service}`, sessionId);
|
||||
}
|
||||
|
||||
return sessionId;
|
||||
|
@ -72,14 +72,14 @@ export default async function pyloadProxyHandler(req, res) {
|
|||
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
|
||||
const loginUrl = `${widget.url}/api/login`;
|
||||
|
||||
let sessionId = cache.get(sessionCacheKey) ?? await login(loginUrl, widget.username, widget.password);
|
||||
let [status, data] = await fetchFromPyloadAPI(url, sessionId);
|
||||
let sessionId = cache.get(`${sessionCacheKey}.${service}`) ?? await login(loginUrl, service, widget.username, widget.password);
|
||||
let [status, data] = await fetchFromPyloadAPI(url, sessionId, null, service);
|
||||
|
||||
if (status === 403 || status === 401) {
|
||||
logger.info('Failed to retrieve data from Pyload API, trying to login again...');
|
||||
cache.del(sessionCacheKey);
|
||||
sessionId = await login(loginUrl, widget.username, widget.password);
|
||||
[status, data] = await fetchFromPyloadAPI(url, sessionId);
|
||||
cache.del(`${sessionCacheKey}.${service}`);
|
||||
sessionId = await login(loginUrl, service, widget.username, widget.password);
|
||||
[status, data] = await fetchFromPyloadAPI(url, sessionId, null, service);
|
||||
}
|
||||
|
||||
if (data?.error || status !== 200) {
|
||||
|
|
|
@ -25,12 +25,12 @@ export default async function transmissionProxyHandler(req, res) {
|
|||
return res.status(400).json({ error: "Invalid proxy service type" });
|
||||
}
|
||||
|
||||
let headers = cache.get(headerCacheKey);
|
||||
let headers = cache.get(`${headerCacheKey}.${service}`);
|
||||
if (!headers) {
|
||||
headers = {
|
||||
"content-type": "application/json",
|
||||
}
|
||||
cache.put(headerCacheKey, headers);
|
||||
cache.put(`${headerCacheKey}.${service}`, headers);
|
||||
}
|
||||
|
||||
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
|
||||
|
@ -55,7 +55,7 @@ export default async function transmissionProxyHandler(req, res) {
|
|||
if (status === 409) {
|
||||
logger.debug("Transmission is rejecting the request, but returning a CSRF token");
|
||||
headers[csrfHeaderName] = responseHeaders[csrfHeaderName];
|
||||
cache.put(headerCacheKey, headers);
|
||||
cache.put(`${headerCacheKey}.${service}`, headers);
|
||||
|
||||
// retry the request, now with the CSRF token
|
||||
[status, contentType, data, responseHeaders] = await httpProxy(url, {
|
||||
|
|
|
@ -58,6 +58,7 @@ async function login(widget) {
|
|||
|
||||
export default async function unifiProxyHandler(req, res) {
|
||||
const widget = await getWidget(req);
|
||||
const { service } = req.query;
|
||||
if (!widget) {
|
||||
return res.status(400).json({ error: "Invalid proxy service type" });
|
||||
}
|
||||
|
@ -68,7 +69,7 @@ export default async function unifiProxyHandler(req, res) {
|
|||
}
|
||||
|
||||
let [status, contentType, data, responseHeaders] = [];
|
||||
let prefix = cache.get(prefixCacheKey);
|
||||
let prefix = cache.get(`${prefixCacheKey}.${service}`);
|
||||
if (prefix === null) {
|
||||
// auto detect if we're talking to a UDM Pro, and cache the result so that we
|
||||
// don't make two requests each time data from Unifi is required
|
||||
|
@ -77,7 +78,7 @@ export default async function unifiProxyHandler(req, res) {
|
|||
if (responseHeaders?.["x-csrf-token"]) {
|
||||
prefix = udmpPrefix;
|
||||
}
|
||||
cache.put(prefixCacheKey, prefix);
|
||||
cache.put(`${prefixCacheKey}.${service}`, prefix);
|
||||
}
|
||||
|
||||
widget.prefix = prefix;
|
||||
|
|
Loading…
Add table
Reference in a new issue