mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-10 07:12:51 +08:00
feat(core): first attempt to init script standard (#8224)
- lazy load - rate limit per path - init .debug.json support - docs - maintainer - radar
This commit is contained in:
129
lib/middleware/cache/index.js
vendored
Normal file
129
lib/middleware/cache/index.js
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
const md5 = require('@/utils/md5');
|
||||
const config = require('@/config').value;
|
||||
const logger = require('@/utils/logger');
|
||||
const { RequestInProgressError } = require('@/errors');
|
||||
|
||||
const globalCache = {
|
||||
get: () => null,
|
||||
set: () => null,
|
||||
};
|
||||
|
||||
let cacheModule = {
|
||||
get: () => null,
|
||||
set: () => null,
|
||||
status: { available: false },
|
||||
clients: {},
|
||||
};
|
||||
|
||||
if (config.cache.type === 'redis') {
|
||||
cacheModule = require('./redis');
|
||||
const { redisClient } = cacheModule.clients;
|
||||
globalCache.get = async (key) => {
|
||||
if (key && cacheModule.status.available) {
|
||||
const value = await redisClient.get(key);
|
||||
return value;
|
||||
}
|
||||
};
|
||||
globalCache.set = cacheModule.set;
|
||||
} else if (config.cache.type === 'memory') {
|
||||
cacheModule = require('./memory');
|
||||
const { pageCache } = cacheModule.clients;
|
||||
globalCache.get = (key) => {
|
||||
if (key && cacheModule.status.available) {
|
||||
return pageCache.get(key);
|
||||
}
|
||||
};
|
||||
globalCache.set = (key, value, maxAge) => {
|
||||
if (!value || value === 'undefined') {
|
||||
value = '';
|
||||
}
|
||||
if (typeof value === 'object') {
|
||||
value = JSON.stringify(value);
|
||||
}
|
||||
if (key) {
|
||||
return pageCache.set(key, value, maxAge * 1000);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
logger.error('Cache not available, concurrent requests are not limited. This could lead to bad behavior.');
|
||||
}
|
||||
|
||||
// only give cache string, as the `!` condition tricky
|
||||
// md5 is used to shrink key size
|
||||
// plz, write these tips in comments!
|
||||
module.exports = function (app) {
|
||||
const { get, set, status } = cacheModule;
|
||||
app.context.cache = {
|
||||
...cacheModule,
|
||||
tryGet: async (key, getValueFunc, maxAge = config.cache.contentExpire) => {
|
||||
let v = await get(key);
|
||||
if (!v) {
|
||||
v = await getValueFunc();
|
||||
set(key, v, maxAge);
|
||||
} else {
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(v);
|
||||
} catch (e) {
|
||||
parsed = null;
|
||||
}
|
||||
if (parsed) {
|
||||
v = parsed;
|
||||
}
|
||||
}
|
||||
|
||||
return v;
|
||||
},
|
||||
globalCache,
|
||||
};
|
||||
|
||||
return async (ctx, next) => {
|
||||
const key = 'koa-redis-cache:' + md5(ctx.request.path);
|
||||
const controlKey = 'path-requested:' + md5(ctx.request.path);
|
||||
|
||||
if (!status.available) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const isRequesting = await globalCache.get(controlKey);
|
||||
|
||||
if (isRequesting === '1') {
|
||||
throw new RequestInProgressError('This path is currently fetching, please come back later!');
|
||||
}
|
||||
|
||||
try {
|
||||
const value = await globalCache.get(key);
|
||||
|
||||
if (value) {
|
||||
ctx.response.status = 200;
|
||||
if (config.cache.type === 'redis') {
|
||||
ctx.response.set({
|
||||
'X-Koa-Redis-Cache': 'true',
|
||||
});
|
||||
} else if (config.cache.type === 'memory') {
|
||||
ctx.response.set({
|
||||
'X-Koa-Memory-Cache': 'true',
|
||||
});
|
||||
}
|
||||
ctx.state.data = JSON.parse(value);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
|
||||
// Doesn't hit the cache? We need to let others know!
|
||||
await globalCache.set(controlKey, '1', config.cache.requestTimeout);
|
||||
await next();
|
||||
|
||||
if (ctx.response.get('Cache-Control') !== 'no-cache' && ctx.state && ctx.state.data) {
|
||||
ctx.state.data.lastBuildDate = new Date().toUTCString();
|
||||
const body = JSON.stringify(ctx.state.data);
|
||||
await globalCache.set(key, body, config.cache.routeExpire);
|
||||
}
|
||||
|
||||
// We need to let it go, even no cache set.
|
||||
// Wait to set cache so the next request could be handled correctly
|
||||
await globalCache.set(controlKey, '0', config.cache.requestTimeout);
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user