-
+
diff --git a/lib/errors/index.ts b/lib/errors/index.ts
index 97027ed4db..a400516a11 100644
--- a/lib/errors/index.ts
+++ b/lib/errors/index.ts
@@ -1,3 +1,65 @@
+import { type ErrorHandler } from 'hono';
import _RequestInProgressError from './RequestInProgress';
+import { getDebugInfo, setDebugInfo } from '@/utils/debug-info';
+import { config } from '@/config';
+import Sentry from '@sentry/node';
+import logger from '@/utils/logger';
+import art from 'art-template';
+import * as path from 'node:path';
+import gitHash from '@/utils/git-hash';
export const RequestInProgressError = _RequestInProgressError;
+
+export const errorHandler: ErrorHandler = (error, ctx) => {
+ let message = '';
+ if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError')) {
+ message = `${error.message}: target website might be blocking our access, you can host your own RSSHub instance for a better usability.`;
+ } else if (error instanceof Error) {
+ message = process.env.NODE_ENV === 'production' ? error.message : (error.stack || error.message);
+ }
+
+ const debug = getDebugInfo();
+ if (ctx.res.headers.get('X-Koa-Redis-Cache') || ctx.res.headers.get('X-Koa-Memory-Cache')) {
+ debug.hitCache++;
+ setDebugInfo(debug);
+ }
+
+ if (config.sentry.dsn) {
+ Sentry.withScope((scope) => {
+ scope.setTag('name', ctx.req.path.split('/')[1]);
+ Sentry.captureException(error);
+ });
+ }
+
+ logger.error(`Error in ${ctx.req.path}: ${message}`);
+
+ if (config.isPackage) {
+ return ctx.json({
+ error: {
+ message: error.message ?? error,
+ },
+ });
+ } else {
+ ctx.header('Content-Type', 'text/html; charset=UTF-8');
+
+ if (error instanceof RequestInProgressError) {
+ ctx.status(503);
+ message = error.message;
+ ctx.set('Cache-Control', `public, max-age=${config.cache.requestTimeout}`);
+ } else if (ctx.res.status === 403) {
+ message = error.message;
+ } else {
+ ctx.status(404);
+ }
+
+ const requestPath = ctx.req.path;
+
+ return ctx.body(art(path.resolve(__dirname, '../views/error.art'), {
+ requestPath,
+ message,
+ errorPath: ctx.req.path,
+ nodeVersion: process.version,
+ gitHash,
+ }));
+ }
+}
diff --git a/lib/index.ts b/lib/index.ts
index 1abea49b7e..3691ec74a0 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -14,6 +14,7 @@ import logger from '@/utils/logger'
import routes from '@/routes'
import index from '@/v3/index'
import { config } from '@/config'
+import { errorHandler } from '@/errors'
process.on('uncaughtException', (e) => {
logger.error('uncaughtException: ' + e);
@@ -46,7 +47,7 @@ for (const name in routes) {
app.get('/', index)
-console.log(app)
+app.onError(errorHandler)
const port = config.connect.port
diff --git a/lib/middleware/debug.ts b/lib/middleware/debug.ts
index 71e9149870..ef6188e29e 100644
--- a/lib/middleware/debug.ts
+++ b/lib/middleware/debug.ts
@@ -1,43 +1,26 @@
import { MiddlewareHandler } from "hono";
-import { getRouteNameFromPath } from '@/utils/helpers';
-
-const debug = {
- hitCache: 0,
- request: 0,
- etag: 0,
- paths: [],
- routes: [],
- errorPaths: [],
- errorRoutes: [],
-}
+import { getDebugInfo, setDebugInfo } from "@/utils/debug-info";
const middleware: MiddlewareHandler = async (ctx, next) => {
- if (!debug.paths[ctx.req.path]) {
- debug.paths[ctx.req.path] = 0;
+ {
+ const debug = getDebugInfo();
+ debug.request++;
+ setDebugInfo(debug);
}
- debug.paths[ctx.req.path]++;
-
- debug.request++;
await next();
- const routeName = getRouteNameFromPath(ctx.req.path);
- if (routeName) {
- if (!debug.routes[routeName]) {
- debug.routes[routeName] = 0;
+ {
+ const debug = getDebugInfo();
+ if (ctx.res.headers.get('X-Koa-Redis-Cache') || ctx.res.headers.get('X-Koa-Memory-Cache')) {
+ debug.hitCache++;
}
- debug.routes[routeName]++;
- }
- if (ctx.res.headers.get('X-Koa-Redis-Cache') || ctx.res.headers.get('X-Koa-Memory-Cache')) {
- debug.hitCache++;
- }
-
- if (ctx.res.status === 304) {
- debug.etag++;
+ if (ctx.res.status === 304) {
+ debug.etag++;
+ }
+ setDebugInfo(debug);
}
};
export default middleware;
-
-export const getDebugInfo = () => debug
diff --git a/lib/middleware/onerror.ts b/lib/middleware/onerror.ts
index a332f1ea3f..6aa6a3def9 100644
--- a/lib/middleware/onerror.ts
+++ b/lib/middleware/onerror.ts
@@ -1,14 +1,8 @@
import { MiddlewareHandler } from "hono";
import logger from "@/utils/logger";
import { config } from "@/config";
-import art from 'art-template';
-import * as path from 'node:path';
-import { RequestInProgressError } from '@/errors';
import Sentry from '@sentry/node';
import { getRouteNameFromPath } from "@/utils/helpers";
-import gitRevSync from 'git-rev-sync';
-
-let gitHash;
if (config.sentry.dsn) {
Sentry.init({
@@ -19,74 +13,15 @@ if (config.sentry.dsn) {
logger.info('Sentry inited.');
}
-try {
- gitHash = gitRevSync.short();
-} catch {
- gitHash = (process.env.HEROKU_SLUG_COMMIT && process.env.HEROKU_SLUG_COMMIT.slice(0, 7)) || (process.env.VERCEL_GIT_COMMIT_SHA && process.env.VERCEL_GIT_COMMIT_SHA.slice(0, 7)) || 'unknown';
-}
-
const middleware: MiddlewareHandler = async (ctx, next) => {
- try {
- const time = Date.now();
- await next();
- if (config.sentry.dsn && Date.now() - time >= config.sentry.routeTimeout) {
- Sentry.withScope((scope) => {
- scope.setTag('name', getRouteNameFromPath(ctx.req.path));
- Sentry.captureException(new Error('Route Timeout'));
- });
- }
- } catch (error: any) {
- let message = error;
- if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError')) {
- message = `${error.message}: target website might be blocking our access, you can host your own RSSHub instance for a better usability.`;
- } else if (error instanceof Error) {
- message = process.env.NODE_ENV === 'production' ? error.message : error.stack;
- }
-
- logger.error(`Error in ${ctx.req.path}: ${message}`);
-
- if (config.isPackage) {
- ctx.json({
- error: {
- message: error.message ?? error,
- },
- });
- } else {
- ctx.header('Content-Type', 'text/html; charset=UTF-8');
-
- if (error instanceof RequestInProgressError) {
- ctx.status(503);
- message = error.message;
- ctx.set('Cache-Control', `public, max-age=${config.cache.requestTimeout}`);
- } else if (ctx.res.status === 403) {
- message = error.message;
- } else {
- ctx.status(404);
- }
-
- const requestPath = ctx.req.path;
-
- ctx.body = art(path.resolve(__dirname, '../views/error.art'), {
- requestPath,
- message,
- errorPath: ctx.req.path,
- nodeVersion: process.version,
- gitHash,
- });
- }
-
- const debug = ctx.get('debug');
- if (ctx.res.headers.get('X-Koa-Redis-Cache') || ctx.res.headers.get('X-Koa-Memory-Cache')) {
- debug.hitCache++;
- }
-
- if (config.sentry.dsn) {
- Sentry.withScope((scope) => {
- scope.setTag('name', ctx.req.path.split('/')[1]);
- Sentry.captureException(error);
- });
- }
+ const time = Date.now();
+ await next();
+ if (config.sentry.dsn && Date.now() - time >= config.sentry.routeTimeout) {
+ Sentry.withScope((scope) => {
+ scope.setTag('name', getRouteNameFromPath(ctx.req.path));
+ Sentry.captureException(new Error('Route Timeout'));
+ });
}
};
-export default middleware;
\ No newline at end of file
+export default middleware;
diff --git a/lib/routes.ts b/lib/routes.ts
index 3a8388bb6c..ade7d80f30 100644
--- a/lib/routes.ts
+++ b/lib/routes.ts
@@ -1,5 +1,5 @@
import { directoryImport } from '@/utils/directory-import';
-import type { Context, Handler, Hono } from 'hono'
+import type { Handler } from 'hono'
type Root = {
get: (path: string, handler: Handler) => void;
diff --git a/lib/utils/debug-info.ts b/lib/utils/debug-info.ts
new file mode 100644
index 0000000000..d54e5e70ca
--- /dev/null
+++ b/lib/utils/debug-info.ts
@@ -0,0 +1,8 @@
+const debug = {
+ hitCache: 0,
+ request: 0,
+ etag: 0,
+}
+
+export const getDebugInfo = () => debug
+export const setDebugInfo = (info: typeof debug) => Object.assign(debug, info)
diff --git a/lib/utils/git-hash.ts b/lib/utils/git-hash.ts
new file mode 100644
index 0000000000..2eafc589dd
--- /dev/null
+++ b/lib/utils/git-hash.ts
@@ -0,0 +1,12 @@
+import gitRevSync from 'git-rev-sync';
+
+let gitHash = process.env.HEROKU_SLUG_COMMIT?.slice(0, 7) || process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 7)
+if (!gitHash) {
+ try {
+ gitHash = gitRevSync.short();
+ } catch {
+ gitHash = 'unknown';
+ }
+}
+
+export default gitHash;
diff --git a/lib/v3/index.ts b/lib/v3/index.ts
index e606d7dd03..6c39813104 100644
--- a/lib/v3/index.ts
+++ b/lib/v3/index.ts
@@ -2,17 +2,8 @@ import type { Handler } from 'hono';
import { config } from '@/config';
import art from 'art-template';
import * as path from 'node:path';
-import gitRevSync from 'git-rev-sync';
-import { getDebugInfo } from '@/middleware/debug';
-
-let gitHash = process.env.HEROKU_SLUG_COMMIT?.slice(0, 7) || process.env.VERCEL_GIT_COMMIT_SHA?.slice(0, 7)
-if (!gitHash) {
- try {
- gitHash = gitRevSync.short();
- } catch {
- gitHash = 'unknown';
- }
-}
+import gitHash from '@/utils/git-hash';
+import { getDebugInfo } from '@/utils/debug-info';
const startTime = Date.now();
@@ -21,28 +12,6 @@ const handler: Handler = (ctx) => {
ctx.header('Cache-Control', 'no-cache')
const debug = getDebugInfo();
- const routes = Object.keys(debug.routes).sort((a, b) => debug.routes[b] - debug.routes[a]);
- const hotRoutes = routes.slice(0, 30);
- const hotRoutesValue = hotRoutes.map((item) => `${debug.routes[item]} ${item}
`).join('');
-
- const paths = Object.keys(debug.paths).sort((a, b) => debug.paths[b] - debug.paths[a]);
- const hotPaths = paths.slice(0, 30);
-
- const hotPathsValue = hotPaths.map((item) => `${debug.paths[item]} ${item}
`).join('');
-
- let hotErrorRoutesValue = '';
- if (debug.errorRoutes) {
- const errorRoutes = Object.keys(debug.errorRoutes).sort((a, b) => debug.errorRoutes[b] - debug.errorRoutes[a]);
- const hotErrorRoutes = errorRoutes.slice(0, 30);
- hotErrorRoutesValue = hotErrorRoutes.map((item) => `${debug.errorRoutes[item]} ${item}
`).join('');
- }
-
- let hotErrorPathsValue = '';
- if (debug.errorPaths) {
- const errorPaths = Object.keys(debug.errorPaths).sort((a, b) => debug.errorPaths[b] - debug.errorPaths[a]);
- const hotErrorPaths = errorPaths.slice(0, 30);
- hotErrorPathsValue = hotErrorPaths.map((item) => `${debug.errorPaths[item]} ${item}
`).join('');
- }
const showDebug = !config.debugInfo || config.debugInfo === 'false' ? false : config.debugInfo === 'true' || config.debugInfo === ctx.req.query('debug');
const { disallowRobot, nodeName } = config;
@@ -83,22 +52,6 @@ const handler: Handler = (ctx) => {
name: 'Run Time',
value: (duration / 3_600_000).toFixed(2) + ' hour(s)',
},
- {
- name: 'Hot Routes',
- value: hotRoutesValue,
- },
- {
- name: 'Hot Paths',
- value: hotPathsValue,
- },
- {
- name: 'Hot Error Routes',
- value: hotErrorRoutesValue,
- },
- {
- name: 'Hot Error Paths',
- value: hotErrorPathsValue,
- },
],
}));
};
diff --git a/lib/views/error.art b/lib/views/error.art
index e128d63fcd..8c83de4013 100644
--- a/lib/views/error.art
+++ b/lib/views/error.art
@@ -36,7 +36,7 @@
-
+