diff --git a/client/shared/model/plugin.ts b/client/shared/model/plugin.ts index da71c1e1..019105f4 100644 --- a/client/shared/model/plugin.ts +++ b/client/shared/model/plugin.ts @@ -72,7 +72,7 @@ export async function fetchRegistryPlugins(): Promise { * 后端固定 */ export async function fetchServiceRegistryPlugins(): Promise { - const { data } = await request.get('/registry.json'); + const { data } = await request.get('/registry-be.json'); return data; } diff --git a/docker-compose.yml b/docker-compose.yml index 34cf7d60..2a7d5e15 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,21 +1,6 @@ version: "3.3" services: - # 应用网关 - web: - build: - context: . - image: tailchat - restart: unless-stopped - env_file: docker-compose.env - labels: - - "traefik.enable=true" - - "traefik.http.routers.web.rule=Method(`GET`) || (Path(`/`) || PathPrefix(`/main`) || PathPrefix(`/entry`))" - - "traefik.http.services.web.loadbalancer.server.port=11011" - command: npx http-server-spa ./client/web/dist index.html 11011 - networks: - - internal - # 应用网关 service-gateway: build: diff --git a/package.json b/package.json index 158de34e..d64d5933 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "dev:web": "cd client/web && pnpm run dev", "dev:server": "cd server && pnpm run dev", "start:service": "cd server && pnpm run start:service", - "build": "concurrently npm:build:web npm:build:server && cp -r client/web/dist/* server/dist/public", + "build": "concurrently npm:build:web npm:build:server && cp -r client/web/dist/* server/dist/public && cp -r client/web/dist/* server/dist/public", "build:web": "cd client/web && pnpm run build", "build:server": "cd server && pnpm run build && echo \"Install server side plugin:\" && pnpm run plugin:install com.msgbyte.tasks com.msgbyte.linkmeta com.msgbyte.github com.msgbyte.simplenotify && mkdir -p ./dist/public && cp -r ./public/plugins ./dist/public && cp ./public/registry.json ./dist/public", "check:type": "concurrently npm:check:type:client npm:check:type:server", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 46e5e06e..555d2fcb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -479,6 +479,7 @@ importers: '@moonrailgun/socket.io-admin-ui': ^0.2.1 '@socket.io/redis-adapter': ^7.0.0 '@typegoose/typegoose': 9.3.1 + '@types/accepts': ^1.3.5 '@types/bcryptjs': ^2.4.2 '@types/blessed': ^0.1.19 '@types/bluebird': ^3.5.36 @@ -498,6 +499,9 @@ importers: '@types/node': 16.11.7 '@types/nodemailer': ^6.4.4 '@types/oidc-provider': ^7.8.1 + '@types/send': ^0.17.1 + '@types/serve-static': ^1.15.0 + accepts: ^1.3.8 bcryptjs: ^2.4.3 bluebird: ^3.7.2 crc: ^3.8.0 @@ -535,6 +539,8 @@ importers: prettier: ^2.3.2 qs: ^6.10.3 redlock: ^4.2.0 + send: ^0.18.0 + serve-static: ^1.15.0 socket.io: ^4.2.0 socket.io-client: ^4.1.3 tailchat-server-sdk: workspace:* @@ -548,6 +554,7 @@ importers: '@typegoose/typegoose': 9.3.1_mongoose@6.1.1 '@types/blessed': 0.1.19 '@types/bluebird': 3.5.36 + accepts: 1.3.8 bcryptjs: 2.4.3 bluebird: 3.7.2 crc: 3.8.0 @@ -574,12 +581,15 @@ importers: oidc-provider: 7.11.5 qs: 6.11.0 redlock: 4.2.0 + send: 0.18.0 + serve-static: 1.15.0 socket.io: 4.5.1 tailchat-server-sdk: link:packages/sdk ts-node: 10.9.1_t4lrjbt3sxauai4t5o275zsepa typescript: 4.7.4 devDependencies: '@babel/helper-compilation-targets': 7.18.9 + '@types/accepts': 1.3.5 '@types/bcryptjs': 2.4.2 '@types/crc': 3.8.0 '@types/ejs': 3.1.1 @@ -597,6 +607,8 @@ importers: '@types/node': 16.11.7 '@types/nodemailer': 6.4.5 '@types/oidc-provider': 7.11.1 + '@types/send': 0.17.1 + '@types/serve-static': 1.15.0 fs-extra: 10.1.0 gulp-sort: 2.0.0 i18next-scanner: 3.3.0 @@ -6238,6 +6250,10 @@ packages: dependencies: '@types/unist': 2.0.6 + /@types/mime/1.3.2: + resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==} + dev: true + /@types/mime/2.0.3: resolution: {integrity: sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==} dev: true @@ -6476,6 +6492,13 @@ packages: /@types/scheduler/0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} + /@types/send/0.17.1: + resolution: {integrity: sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==} + dependencies: + '@types/mime': 1.3.2 + '@types/node': 18.7.11 + dev: true + /@types/serve-index/1.9.1: resolution: {integrity: sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==} dependencies: @@ -14694,7 +14717,7 @@ packages: pretty-format: 27.5.1 slash: 3.0.0 strip-json-comments: 3.1.1 - ts-node: 10.9.1_bqee57coj3oib6dw4m24wknwqe + ts-node: 10.9.1_t4lrjbt3sxauai4t5o275zsepa transitivePeerDependencies: - bufferutil - canvas @@ -22838,7 +22861,6 @@ packages: typescript: 4.7.4 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - dev: false /ts-pnp/1.2.0_typescript@4.7.4: resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==} diff --git a/server/package.json b/server/package.json index ea275246..acc285a4 100644 --- a/server/package.json +++ b/server/package.json @@ -37,6 +37,7 @@ "@typegoose/typegoose": "9.3.1", "@types/blessed": "^0.1.19", "@types/bluebird": "^3.5.36", + "accepts": "^1.3.8", "bcryptjs": "^2.4.3", "bluebird": "^3.7.2", "crc": "^3.8.0", @@ -63,6 +64,8 @@ "oidc-provider": "^7.10.6", "qs": "^6.10.3", "redlock": "^4.2.0", + "send": "^0.18.0", + "serve-static": "^1.15.0", "socket.io": "^4.2.0", "tailchat-server-sdk": "workspace:*", "ts-node": "^10.0.0", @@ -70,6 +73,7 @@ }, "devDependencies": { "@babel/helper-compilation-targets": "^7.18.2", + "@types/accepts": "^1.3.5", "@types/bcryptjs": "^2.4.2", "@types/crc": "^3.4.0", "@types/ejs": "^3.1.0", @@ -87,6 +91,8 @@ "@types/node": "16.11.7", "@types/nodemailer": "^6.4.4", "@types/oidc-provider": "^7.8.1", + "@types/send": "^0.17.1", + "@types/serve-static": "^1.15.0", "fs-extra": "^10.0.0", "gulp-sort": "^2.0.0", "i18next-scanner": "^3.0.0", diff --git a/server/scripts/installPlugin.js b/server/scripts/installPlugin.js index a0fb1ae1..dd467c2d 100644 --- a/server/scripts/installPlugin.js +++ b/server/scripts/installPlugin.js @@ -11,6 +11,7 @@ const _ = require('lodash'); const containerPath = path.resolve(__dirname, '../plugins'); const publicPath = path.resolve(__dirname, '../public'); +const registryPath = path.resolve(publicPath, './registry-be.json'); const list = fs.readdirSync(containerPath); const dirs = list.filter((item) => @@ -57,14 +58,9 @@ async function start() { // 追加前端配置到registry const originRegistry = - (await fs - .readJSON(path.resolve(publicPath, './registry.json')) - .catch(() => [])) ?? []; + (await fs.readJSON(registryPath).catch(() => [])) ?? []; const newRegistry = _.uniqBy([manifest, ...originRegistry], (m) => m.name); - await fs.writeJSON( - path.resolve(publicPath, './registry.json'), - newRegistry - ); + await fs.writeJSON(registryPath, newRegistry); console.log('└ 安装完毕:', p); } diff --git a/server/services/core/gateway.service.ts b/server/services/core/gateway.service.ts index 66ff3d33..687c40ce 100644 --- a/server/services/core/gateway.service.ts +++ b/server/services/core/gateway.service.ts @@ -14,6 +14,9 @@ import { import { TcHealth } from '../../mixins/health.mixin'; import type { Readable } from 'stream'; import { checkPathMatch } from '../../lib/utils'; +import serve from 'serve-static'; +import accepts from 'accepts'; +import send from 'send'; export default class ApiService extends TcService { authWhitelist = []; @@ -50,11 +53,11 @@ export default class ApiService extends TcService { // Logging the response data. Set to any log level to enable it. E.g. "info" this.registerSetting('logResponseData', null); // Serve assets from "public" folder - this.registerSetting('assets', { - folder: 'public', - // Options to `server-static` module - options: {}, - }); + // this.registerSetting('assets', { + // folder: 'public', + // // Options to `server-static` module + // options: {}, + // }); this.registerSetting('cors', { // Configures the Access-Control-Allow-Origin CORS header. origin: '*', @@ -69,6 +72,27 @@ export default class ApiService extends TcService { // Configures the Access-Control-Max-Age CORS header. maxAge: 3600, }); + // this.registerSetting('rateLimit', { + // // How long to keep record of requests in memory (in milliseconds). + // // Defaults to 60000 (1 min) + // window: 60 * 1000, + + // // Max number of requests during window. Defaults to 30 + // limit: 30, + + // // Set rate limit headers to response. Defaults to false + // headers: true, + + // // Function used to generate keys. Defaults to: + // key: (req) => { + // return ( + // req.headers['x-forwarded-for'] || + // req.connection.remoteAddress || + // req.socket.remoteAddress || + // req.connection.socket.remoteAddress + // ); + // }, + // }); this.registerMethod('authorize', this.authorize); @@ -83,6 +107,7 @@ export default class ApiService extends TcService { getRoutes() { return [ + // /api { path: '/api', whitelist: [ @@ -166,6 +191,7 @@ export default class ApiService extends TcService { // Enable/disable logging logging: true, }, + // /upload { // Reference: https://github.com/moleculerjs/moleculer-web/blob/master/examples/file/index.js path: '/upload', @@ -217,6 +243,7 @@ export default class ApiService extends TcService { mappingPolicy: 'restrict', }, + // /health { path: '/health', aliases: { @@ -224,6 +251,7 @@ export default class ApiService extends TcService { }, mappingPolicy: 'restrict', }, + // /static 对象存储文件代理 { path: '/static', authentication: false, @@ -257,6 +285,25 @@ export default class ApiService extends TcService { }, mappingPolicy: 'restrict', }, + // 静态文件代理 + { + path: '/', + authentication: false, + authorization: false, + use: [serve('public', {})], + onError(req: IncomingMessage, res: ServerResponse, err) { + if ( + String(req.method).toLowerCase() === 'get' && // get请求 + accepts(req).types(['html']) && // 且请求html页面 + err.code === 404 + ) { + // 如果没有找到, 则返回index.html(for spa) + console.log('fallback to fe entry file'); + send(req, './public/index.html', { root: process.cwd() }).pipe(res); + } + }, + autoAliases: false, + }, ]; }