diff --git a/docker-compose.env b/docker-compose.env index 5ee7c346..30653735 100644 --- a/docker-compose.env +++ b/docker-compose.env @@ -11,7 +11,6 @@ MONGO_URL=mongodb://mongo/tailchat SECRET= # file -STAIC_HOST="{BACKEND}" API_URL=https://tailchat-nightly.moonrailgun.com # minio diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6359a278..089b280c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1003,6 +1003,7 @@ importers: server/admin: specifiers: + '@fastify/busboy': ^1.1.0 '@mui/icons-material': ^5.11.0 '@mui/material': ^5.11.3 '@remix-run/dev': ^1.9.0 @@ -1043,6 +1044,7 @@ importers: ts-node: ^10.9.1 typescript: ^4.8.4 dependencies: + '@fastify/busboy': 1.1.0 '@mui/icons-material': 5.11.0_oiuuhmk4wjjpe4qb2sby7usney '@mui/material': 5.11.3_ib3m5ricvtkl2cll7qpr2f6lvq '@remix-run/express': 1.9.0_cwk4saenierp7pa7l5cpbeswge @@ -6593,15 +6595,15 @@ packages: '@commitlint/execute-rule': 17.4.0 '@commitlint/resolve-extends': 17.4.4 '@commitlint/types': 17.4.4 - '@types/node': 15.14.9 + '@types/node': 18.14.1 chalk: 4.1.2 cosmiconfig: 8.0.0 - cosmiconfig-typescript-loader: 4.3.0_p3jpu2hnimj66lgtzn2mehlr2m + cosmiconfig-typescript-loader: 4.3.0_s4dpre5ezutgdzsn47klmddvia lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 resolve-from: 5.0.0 - ts-node: 10.9.1_zlol4fzmmjgb3bdeviopae4asm + ts-node: 10.9.1_uayvamxqnl5yeiojjysxwopmsy typescript: 4.9.5 transitivePeerDependencies: - '@swc/core' @@ -14143,7 +14145,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 18.11.18 + '@types/node': 18.14.1 '@types/responselike': 1.0.0 /@types/codemirror/5.60.5: @@ -14863,7 +14865,7 @@ packages: /@types/react-color/3.0.6: resolution: {integrity: sha512-OzPIO5AyRmLA7PlOyISlgabpYUa3En74LP8mTMa0veCA719SvYQov4WLMsHvCgXP+L+KI9yGhYnqZafVGG0P4w==} dependencies: - '@types/react': 18.0.26 + '@types/react': 17.0.53 '@types/reactcss': 1.2.6 dev: false @@ -14892,7 +14894,7 @@ packages: /@types/react-is/17.0.3: resolution: {integrity: sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==} dependencies: - '@types/react': 18.0.26 + '@types/react': 17.0.53 dev: false /@types/react-mentions/4.1.8: @@ -14994,7 +14996,7 @@ packages: /@types/reactcss/1.2.6: resolution: {integrity: sha512-qaIzpCuXNWomGR1Xq8SCFTtF4v8V27Y6f+b9+bzHiv087MylI/nTCqqdChNeWS7tslgROmYB7yeiruWX7WnqNg==} dependencies: - '@types/react': 18.0.26 + '@types/react': 17.0.53 dev: false /@types/refractor/3.0.2: @@ -15673,7 +15675,6 @@ packages: dependencies: webpack: 5.75.0_webpack-cli@4.10.0 webpack-cli: 4.10.0_hdfrwtmlewz4o7kkfxfrhnzu24 - dev: true /@webpack-cli/info/1.5.0_webpack-cli@4.10.0: resolution: {integrity: sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==} @@ -15682,7 +15683,6 @@ packages: dependencies: envinfo: 7.8.1 webpack-cli: 4.10.0_hdfrwtmlewz4o7kkfxfrhnzu24 - dev: true /@webpack-cli/serve/1.7.0_ud4agclah7rahur6ntojouq57y: resolution: {integrity: sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==} @@ -15695,7 +15695,6 @@ packages: dependencies: webpack-cli: 4.10.0_hdfrwtmlewz4o7kkfxfrhnzu24 webpack-dev-server: 4.11.1_pda42hcaj7d62cr262fr632kue - dev: true /@xobotyi/scrollbar-width/1.9.5: resolution: {integrity: sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ==} @@ -18681,7 +18680,7 @@ packages: dependencies: buffer-from: 1.1.2 inherits: 2.0.4 - readable-stream: 2.3.7 + readable-stream: 2.3.8 typedarray: 0.0.6 dev: true @@ -19231,7 +19230,7 @@ packages: normalize-path: 3.0.0 schema-utils: 4.0.0 serialize-javascript: 6.0.1 - webpack: 5.75.0 + webpack: 5.75.0_webpack-cli@4.10.0 /core-js-compat/3.28.0: resolution: {integrity: sha512-myzPgE7QodMg4nnd3K1TDoES/nADRStM8Gpz0D6nhkwbmwEnE0ZGJgoWsvQ722FR8D7xS0n0LV556RcEicjTyg==} @@ -19276,7 +19275,7 @@ packages: vary: 1.1.2 dev: false - /cosmiconfig-typescript-loader/4.3.0_p3jpu2hnimj66lgtzn2mehlr2m: + /cosmiconfig-typescript-loader/4.3.0_s4dpre5ezutgdzsn47klmddvia: resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==} engines: {node: '>=12', npm: '>=6'} peerDependencies: @@ -19285,9 +19284,9 @@ packages: ts-node: '>=10' typescript: '>=3' dependencies: - '@types/node': 15.14.9 + '@types/node': 18.14.1 cosmiconfig: 8.0.0 - ts-node: 10.9.1_zlol4fzmmjgb3bdeviopae4asm + ts-node: 10.9.1_uayvamxqnl5yeiojjysxwopmsy typescript: 4.9.5 dev: true @@ -21075,7 +21074,6 @@ packages: resolution: {integrity: sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==} engines: {node: '>=4'} hasBin: true - dev: true /eol/0.9.1: resolution: {integrity: sha512-Ds/TEoZjwggRoz/Q2O7SE3i4Jm66mqTDfmdHdq/7DKVk3bro9Q8h6WdXKdPqFLMoqxrDK5SVRzHVPOS6uuGtrg==} @@ -22244,7 +22242,6 @@ packages: /fastest-levenshtein/1.0.16: resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} engines: {node: '>= 4.9.1'} - dev: true /fastest-stable-stringify/2.0.2: resolution: {integrity: sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q==} @@ -22398,7 +22395,7 @@ packages: dependencies: loader-utils: 2.0.4 schema-utils: 3.1.1 - webpack: 5.75.0 + webpack: 5.75.0_webpack-cli@4.10.0 /file-selector/0.5.0: resolution: {integrity: sha512-s8KNnmIDTBoD0p9uJ9uD0XY38SCeBOtj0UMXyQSLg1Ypfrfj8+dAvwsLjYQkQ2GjhVtp2HrnF5cJzMhBjfD8HA==} @@ -24106,7 +24103,7 @@ packages: lodash: 4.17.21 pretty-error: 4.0.0 tapable: 2.2.1 - webpack: 5.75.0 + webpack: 5.75.0_webpack-cli@4.10.0 /htmlparser2/6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} @@ -24473,7 +24470,6 @@ packages: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 - dev: true /imurmurhash/0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -28128,7 +28124,7 @@ packages: webpack: ^5.0.0 dependencies: schema-utils: 4.0.0 - webpack: 5.75.0 + webpack: 5.75.0_webpack-cli@4.10.0 /mini-star/1.3.1: resolution: {integrity: sha512-u9Rw8mPZibaAkEVXBsOQJ1irAURTgjqdKoITFd24+KxIGVXCDK+RYR8KjKRF99VLaCbK6TwTqiJ6iNsqq0G+wA==} @@ -34093,7 +34089,6 @@ packages: engines: {node: '>= 0.10'} dependencies: resolve: 1.22.1 - dev: true /rechoir/0.8.0: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} @@ -34660,7 +34655,6 @@ packages: engines: {node: '>=8'} dependencies: resolve-from: 5.0.0 - dev: true /resolve-dir/1.0.1: resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} @@ -34681,7 +34675,6 @@ packages: /resolve-from/5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - dev: true /resolve-global/1.0.0: resolution: {integrity: sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw==} @@ -37044,7 +37037,7 @@ packages: end-of-stream: 1.4.4 fs-constants: 1.0.0 inherits: 2.0.4 - readable-stream: 3.6.0 + readable-stream: 3.6.1 /tar/6.1.13: resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==} @@ -37189,7 +37182,7 @@ packages: schema-utils: 3.1.1 serialize-javascript: 6.0.1 terser: 5.16.5 - webpack: 5.75.0 + webpack: 5.75.0_webpack-cli@4.10.0 /terser/4.8.1: resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==} @@ -37965,6 +37958,37 @@ packages: yn: 3.1.1 dev: true + /ts-node/10.9.1_uayvamxqnl5yeiojjysxwopmsy: + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 18.14.1 + acorn: 8.8.1 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.9.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + /ts-node/10.9.1_zlol4fzmmjgb3bdeviopae4asm: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true @@ -38904,7 +38928,7 @@ packages: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.1.1 - webpack: 5.75.0 + webpack: 5.75.0_webpack-cli@4.10.0 /url-parse-lax/3.0.0: resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==} @@ -39539,7 +39563,6 @@ packages: webpack-bundle-analyzer: 4.8.0 webpack-dev-server: 4.11.1_pda42hcaj7d62cr262fr632kue webpack-merge: 5.8.0 - dev: true /webpack-dev-middleware/3.7.3_webpack@4.46.0: resolution: {integrity: sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==} @@ -39566,7 +39589,7 @@ packages: mime-types: 2.1.35 range-parser: 1.2.1 schema-utils: 4.0.0 - webpack: 5.75.0 + webpack: 5.75.0_webpack-cli@4.10.0 /webpack-dev-server/4.11.1_pda42hcaj7d62cr262fr632kue: resolution: {integrity: sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==} @@ -39615,7 +39638,6 @@ packages: - debug - supports-color - utf-8-validate - dev: true /webpack-dev-server/4.11.1_webpack@5.75.0: resolution: {integrity: sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==} @@ -39896,7 +39918,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: true /webpackbar/5.0.2_webpack@5.75.0: resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==} @@ -39908,7 +39929,7 @@ packages: consola: 2.15.3 pretty-time: 1.1.0 std-env: 3.3.2 - webpack: 5.75.0 + webpack: 5.75.0_webpack-cli@4.10.0 /websocket-driver/0.7.4: resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} diff --git a/server/.env.example b/server/.env.example index ea0080bf..b9be86f4 100644 --- a/server/.env.example +++ b/server/.env.example @@ -10,7 +10,6 @@ REDIS_URL=redis://localhost:6379/ TRANSPORTER= # 填写服务端可访问的接口地址 -STAIC_HOST="{BACKEND}" API_URL= # 文件存储 diff --git a/server/admin/app/server/broker.ts b/server/admin/app/server/broker.ts index a06d476c..961e56d3 100644 --- a/server/admin/app/server/broker.ts +++ b/server/admin/app/server/broker.ts @@ -13,9 +13,15 @@ broker.start().then(() => { console.log('Linked to Tailchat network, TRANSPORTER: ', transporter); }); -export function call(actionName: string, params: any): Promise { +export function callBrokerAction( + actionName: string, + params: any, + opts?: Record +): Promise { return broker.call(actionName, params, { + ...opts, meta: { + ...opts?.meta, userId: SYSTEM_USERID, }, }); diff --git a/server/admin/app/server/router/api.ts b/server/admin/app/server/router/api.ts index 15b36b12..6131d4a4 100644 --- a/server/admin/app/server/router/api.ts +++ b/server/admin/app/server/router/api.ts @@ -1,10 +1,11 @@ import { Router } from 'express'; import raExpressMongoose from 'express-mongoose-ra-json-server'; import jwt from 'jsonwebtoken'; -import { call } from '../broker'; +import { callBrokerAction } from '../broker'; import { adminAuth, auth, authSecret } from '../middleware/auth'; import { configRouter } from './config'; import { networkRouter } from './network'; +import { fileRouter } from './upload'; const router = Router(); @@ -41,6 +42,7 @@ router.post('/login', (req, res) => { router.use('/network', networkRouter); router.use('/config', configRouter); +router.use('/file', fileRouter); router.use( '/users', @@ -52,7 +54,7 @@ router.use( router.delete('/messages/:id', auth(), async (req, res) => { try { const messageId = req.params.id; - await call('chat.message.deleteMessage', { + await callBrokerAction('chat.message.deleteMessage', { messageId, }); diff --git a/server/admin/app/server/router/upload.ts b/server/admin/app/server/router/upload.ts new file mode 100644 index 00000000..8f97abc6 --- /dev/null +++ b/server/admin/app/server/router/upload.ts @@ -0,0 +1,60 @@ +/** + * Network 相关接口 + */ + +import { Router } from 'express'; +import { callBrokerAction } from '../broker'; +import { auth } from '../middleware/auth'; +import Busboy from '@fastify/busboy'; + +const router = Router(); + +router.put('/upload', auth(), async (req, res) => { + const busboy = new Busboy({ headers: req.headers as any }); + + const promises = []; + busboy.on('file', (fieldname, file, filename, encoding, mimetype) => { + promises.push( + callBrokerAction('file.save', file, { + filename: filename, + }) + .then((data) => { + console.log(data); + return data; + }) + .catch((err) => { + file.resume(); // Drain file stream to continue processing form + busboy.emit('error', err); + return err; + }) + ); + }); + + busboy.on('finish', async () => { + /* istanbul ignore next */ + if (promises.length == 0) { + res.status(500).json('File missing in the request'); + return; + } + + try { + const files = await Promise.all(promises); + + res.json({ files }); + } catch (err) { + console.error(err); + res.status(500).json(String(err)); + } + }); + + busboy.on('error', (err) => { + console.error(err); + req.unpipe(busboy); + req.resume(); + res.status(500).json({ err }); + }); + + req.pipe(busboy); +}); + +export { router as fileRouter }; diff --git a/server/admin/package.json b/server/admin/package.json index 97fc68b7..efeefdff 100644 --- a/server/admin/package.json +++ b/server/admin/package.json @@ -11,6 +11,7 @@ "typecheck": "tsc -b" }, "dependencies": { + "@fastify/busboy": "^1.1.0", "@mui/icons-material": "^5.11.0", "@mui/material": "^5.11.3", "@remix-run/express": "^1.9.0", diff --git a/server/packages/sdk/src/services/lib/settings.ts b/server/packages/sdk/src/services/lib/settings.ts index ef8a9b6f..1e82eabd 100644 --- a/server/packages/sdk/src/services/lib/settings.ts +++ b/server/packages/sdk/src/services/lib/settings.ts @@ -8,7 +8,7 @@ dotenv.config(); */ const port = process.env.PORT ? Number(process.env.PORT) : 11000; const apiUrl = process.env.API_URL || `http://127.0.0.1:${port}`; -const staticHost = process.env.STAIC_HOST || apiUrl; +const staticHost = process.env.STAIC_HOST || '{BACKEND}'; export const config = { port, secret: process.env.SECRET || 'tailchat',