index.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import fastifyStatic from '@fastify/static';
  2. import * as fastlogger from './controllers/fastlogger.js'
  3. import path from 'path';
  4. import os from 'os';
  5. import qs from 'qs';
  6. import {fileURLToPath} from 'url';
  7. import formBody from '@fastify/formbody';
  8. import {validateBasicAuth, validatePwd} from "./utils/api_validate.js";
  9. const {fastify} = fastlogger;
  10. // 获取当前路径
  11. const __dirname = path.dirname(fileURLToPath(import.meta.url));
  12. const PORT = 5757;
  13. const MAX_TEXT_SIZE = 0.1 * 1024 * 1024; // 设置最大文本大小为 0.1 MB
  14. // 静态资源
  15. fastify.register(fastifyStatic, {
  16. root: path.join(__dirname, 'public'),
  17. prefix: '/public/',
  18. });
  19. fastify.register(fastifyStatic, {
  20. root: path.join(__dirname, 'apps'),
  21. prefix: '/apps/', // 新的访问路径前缀
  22. decorateReply: false, // 禁用 sendFile
  23. });
  24. fastify.register(fastifyStatic, {
  25. root: path.join(__dirname, 'json'),
  26. prefix: '/json/', // 新的访问路径前缀
  27. decorateReply: false, // 禁用 sendFile
  28. });
  29. fastify.register(fastifyStatic, {
  30. root: path.join(__dirname, 'js_dr2'),
  31. prefix: '/js/', // 新的访问路径前缀
  32. decorateReply: false, // 禁用 sendFile
  33. });
  34. // 注册插件以支持 application/x-www-form-urlencoded
  35. fastify.register(formBody);
  36. // 给静态目录插件中心挂载basic验证
  37. fastify.addHook('preHandler', (req, reply, done) => {
  38. if (req.raw.url.startsWith('/apps/')) {
  39. validateBasicAuth(req, reply, done);
  40. } else if (req.raw.url.startsWith('/js/')) {
  41. validatePwd(req, reply, done).then(r => done());
  42. } else {
  43. done();
  44. }
  45. });
  46. // 自定义插件替换 querystring 解析行为.避免出现两个相同参数被解析成列表
  47. fastify.addHook('onRequest', async (request, reply) => {
  48. // 获取原始 URL 中的 query 部分
  49. const rawUrl = request.raw.url;
  50. const urlParts = rawUrl.split('?');
  51. const path = urlParts[0];
  52. let rawQuery = urlParts.slice(1).join('?'); // 处理可能存在的多个 '?' 情况
  53. // log('rawQuery:', rawQuery);
  54. // 使用 qs 库解析 query 参数,确保兼容参数值中包含 '?' 的情况
  55. request.query = qs.parse(rawQuery, {
  56. strictNullHandling: true, // 确保 `=` 被解析为空字符串
  57. arrayLimit: 100, // 自定义数组限制
  58. allowDots: false, // 禁止点号表示嵌套对象
  59. });
  60. // 如果需要,可以在这里对 request.query 进行进一步处理
  61. });
  62. // 注册控制器
  63. import {registerRoutes} from './controllers/index.js';
  64. registerRoutes(fastify, {
  65. rootDir: __dirname,
  66. docsDir: path.join(__dirname, 'docs'),
  67. jsDir: path.join(__dirname, 'js'),
  68. dr2Dir: path.join(__dirname, 'js_dr2'),
  69. jxDir: path.join(__dirname, 'jx'),
  70. viewsDir: path.join(__dirname, 'views'),
  71. configDir: path.join(__dirname, 'config'),
  72. PORT,
  73. MAX_TEXT_SIZE,
  74. indexFilePath: path.join(__dirname, 'index.json'),
  75. customFilePath: path.join(__dirname, 'custom.json'),
  76. subFilePath: path.join(__dirname, 'public/sub/sub.json'),
  77. });
  78. // 启动服务
  79. const start = async () => {
  80. try {
  81. // 启动 Fastify 服务
  82. // await fastify.listen({port: PORT, host: '0.0.0.0'});
  83. await fastify.listen({port: PORT, host: '::'});
  84. // 获取本地和局域网地址
  85. const localAddress = `http://localhost:${PORT}`;
  86. const interfaces = os.networkInterfaces();
  87. let lanAddress = 'Not available';
  88. for (const iface of Object.values(interfaces)) {
  89. if (!iface) continue;
  90. for (const config of iface) {
  91. if (config.family === 'IPv4' && !config.internal) {
  92. lanAddress = `http://${config.address}:${PORT}`;
  93. break;
  94. }
  95. }
  96. }
  97. console.log(`Server listening at:`);
  98. console.log(`- Local: ${localAddress}`);
  99. console.log(`- LAN: ${lanAddress}`);
  100. console.log(`- PLATFORM: ${process.platform} ${process.arch}`);
  101. console.log(`- VERSION: ${process.version}`);
  102. if (process.env.VERCEL) {
  103. console.log('Running on Vercel!');
  104. console.log('Vercel Environment:', process.env.VERCEL_ENV); // development, preview, production
  105. console.log('Vercel URL:', process.env.VERCEL_URL);
  106. console.log('Vercel Region:', process.env.VERCEL_REGION);
  107. } else {
  108. console.log('Not running on Vercel!');
  109. }
  110. } catch (err) {
  111. fastify.log.error(err);
  112. process.exit(1);
  113. }
  114. };
  115. // 停止服务
  116. const stop = async () => {
  117. try {
  118. await fastify.close(); // 关闭服务器
  119. console.log('Server stopped gracefully');
  120. } catch (err) {
  121. fastify.log.error('Error while stopping the server:', err);
  122. }
  123. };
  124. // 导出 start 和 stop 方法
  125. export {start, stop};
  126. export default async function handler(req, res) {
  127. await fastify.ready()
  128. fastify.server.emit('request', req, res)
  129. }
  130. // 判断当前模块是否为主模块,如果是主模块,则启动服务
  131. const currentFile = path.normalize(fileURLToPath(import.meta.url)); // 使用 normalize 确保路径一致
  132. const indexFile = path.normalize(path.resolve(__dirname, 'index.js')); // 标准化路径
  133. if (currentFile === indexFile) {
  134. start();
  135. }