From 0a1265b78ca37ad643c5df59b00997a4dff6410c Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Thu, 7 Dec 2023 15:45:03 +0700 Subject: [PATCH 1/3] feat: folder size --- .../src/controllers/cabinetController.ts | 17 ++ .../src/controllers/drawerController.ts | 18 ++ .../src/controllers/folderController.ts | 25 ++ .../src/controllers/subFolderController.ts | 27 ++ Services/server/src/routes.ts | 110 ++++++++ Services/server/src/swagger.json | 234 ++++++++++++++++++ 6 files changed, 431 insertions(+) diff --git a/Services/server/src/controllers/cabinetController.ts b/Services/server/src/controllers/cabinetController.ts index 463cb43..ec6a6a2 100644 --- a/Services/server/src/controllers/cabinetController.ts +++ b/Services/server/src/controllers/cabinetController.ts @@ -182,4 +182,21 @@ export class CabinetController extends Controller { return this.setStatus(HttpStatusCode.NO_CONTENT); } + + /** + * @example cabinetName "ตู้เอกสาร 1" + */ + @Get("/{cabinetName}/size") + @Tags("ตู้เอกสาร") + @Security("bearerAuth") + @SuccessResponse(HttpStatusCode.OK, "สำเร็จ") + public async calc(@Path() cabinetName: string) { + const list = await listItem(DEFAULT_BUCKET!, `${cabinetName}/`, true).catch((e) => + console.error(`Error List Folder: ${e}`), + ); + + if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง"); + + return { size: list.reduce((a, c) => a + c.size, 0) }; + } } diff --git a/Services/server/src/controllers/drawerController.ts b/Services/server/src/controllers/drawerController.ts index 9d3a505..1bf437d 100644 --- a/Services/server/src/controllers/drawerController.ts +++ b/Services/server/src/controllers/drawerController.ts @@ -203,4 +203,22 @@ export class DrawerController extends Controller { return this.setStatus(HttpStatusCode.NO_CONTENT); } + + /** + * @example cabinetName "ตู้เอกสาร 1" + * @example drawerName "ลิ้นชัก 1" + */ + @Get("/{drawerName}/size") + @Tags("ลิ้นชัก") + @Security("bearerAuth") + @SuccessResponse(HttpStatusCode.OK, "สำเร็จ") + public async calc(@Path() cabinetName: string, @Path() drawerName: string) { + const list = await listItem(DEFAULT_BUCKET!, `${cabinetName}/${drawerName}/`, true).catch((e) => + console.error(`Error List Folder: ${e}`), + ); + + if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง"); + + return { size: list.reduce((a, c) => a + c.size, 0) }; + } } diff --git a/Services/server/src/controllers/folderController.ts b/Services/server/src/controllers/folderController.ts index 9a2e663..f1567e8 100644 --- a/Services/server/src/controllers/folderController.ts +++ b/Services/server/src/controllers/folderController.ts @@ -215,4 +215,29 @@ export class FolderController extends Controller { return this.setStatus(HttpStatusCode.NO_CONTENT); } + + /** + * @example cabinetName "ตู้เอกสาร 1" + * @example drawerName "ลิ้นชัก 1" + * @example folderName "แฟ้ม 1" + */ + @Get("/{folderName}/size") + @Tags("แฟ้ม") + @Security("bearerAuth") + @SuccessResponse(HttpStatusCode.OK, "สำเร็จ") + public async calc( + @Path() cabinetName: string, + @Path() drawerName: string, + @Path() folderName: string, + ) { + const list = await listItem( + DEFAULT_BUCKET!, + `${cabinetName}/${drawerName}/${folderName}/`, + true, + ).catch((e) => console.error(`Error List Folder: ${e}`)); + + if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง"); + + return { size: list.reduce((a, c) => a + c.size, 0) }; + } } diff --git a/Services/server/src/controllers/subFolderController.ts b/Services/server/src/controllers/subFolderController.ts index 9199a30..a2d29e2 100644 --- a/Services/server/src/controllers/subFolderController.ts +++ b/Services/server/src/controllers/subFolderController.ts @@ -220,4 +220,31 @@ export class SubFolderController extends Controller { return this.setStatus(HttpStatusCode.NO_CONTENT); } + + /** + * @example cabinetName "ตู้เอกสาร 1" + * @example drawerName "ลิ้นชัก 1" + * @example folderName "แฟ้ม 1" + * @example subFolderName "แฟ้มย่อย 1" + */ + @Get("/{subFolderName}/size") + @Tags("แฟ้มย่อย") + @Security("bearerAuth") + @SuccessResponse(HttpStatusCode.OK, "สำเร็จ") + public async calc( + @Path() cabinetName: string, + @Path() drawerName: string, + @Path() folderName: string, + @Path() subFolderName: string, + ) { + const list = await listItem( + DEFAULT_BUCKET!, + `${cabinetName}/${drawerName}/${folderName}/${subFolderName}`, + true, + ).catch((e) => console.error(`Error List Folder: ${e}`)); + + if (!list) throw new Error("เกิดข้อผิดพลาด ไม่สามารถแสดงรายการแฟ้มได้ กรุณาลองใหม่ในภายหลัง"); + + return { size: list.reduce((a, c) => a + c.size, 0) }; + } } diff --git a/Services/server/src/routes.ts b/Services/server/src/routes.ts index a056828..7b3897c 100644 --- a/Services/server/src/routes.ts +++ b/Services/server/src/routes.ts @@ -180,6 +180,32 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.get('/cabinet/:cabinetName/size', + authenticateMiddleware([{"bearerAuth":[]}]), + ...(fetchMiddlewares(CabinetController)), + ...(fetchMiddlewares(CabinetController.prototype.calc)), + + function CabinetController_calc(request: any, response: any, next: any) { + const args = { + cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = getValidatedArgs(args, request, response); + + const controller = new CabinetController(); + + + const promise = controller.calc.apply(controller, validatedArgs as any); + promiseHandler(controller, promise, response, 200, next); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.get('/cabinet/:cabinetName/drawer', authenticateMiddleware([{"bearerAuth":[]}]), ...(fetchMiddlewares(DrawerController)), @@ -289,6 +315,33 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.get('/cabinet/:cabinetName/drawer/:drawerName/size', + authenticateMiddleware([{"bearerAuth":[]}]), + ...(fetchMiddlewares(DrawerController)), + ...(fetchMiddlewares(DrawerController.prototype.calc)), + + function DrawerController_calc(request: any, response: any, next: any) { + const args = { + cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"}, + drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = getValidatedArgs(args, request, response); + + const controller = new DrawerController(); + + + const promise = controller.calc.apply(controller, validatedArgs as any); + promiseHandler(controller, promise, response, 200, next); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/file', authenticateMiddleware([{"bearerAuth":[]}]), ...(fetchMiddlewares(FileController)), @@ -549,6 +602,34 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/size', + authenticateMiddleware([{"bearerAuth":[]}]), + ...(fetchMiddlewares(FolderController)), + ...(fetchMiddlewares(FolderController.prototype.calc)), + + function FolderController_calc(request: any, response: any, next: any) { + const args = { + cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"}, + drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"}, + folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = getValidatedArgs(args, request, response); + + const controller = new FolderController(); + + + const promise = controller.calc.apply(controller, validatedArgs as any); + promiseHandler(controller, promise, response, 200, next); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.post('/search', authenticateMiddleware([{"bearerAuth":[]}]), ...(fetchMiddlewares(SearchController)), @@ -692,6 +773,35 @@ export function RegisterRoutes(app: Router) { } }); // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/size', + authenticateMiddleware([{"bearerAuth":[]}]), + ...(fetchMiddlewares(SubFolderController)), + ...(fetchMiddlewares(SubFolderController.prototype.calc)), + + function SubFolderController_calc(request: any, response: any, next: any) { + const args = { + cabinetName: {"in":"path","name":"cabinetName","required":true,"dataType":"string"}, + drawerName: {"in":"path","name":"drawerName","required":true,"dataType":"string"}, + folderName: {"in":"path","name":"folderName","required":true,"dataType":"string"}, + subFolderName: {"in":"path","name":"subFolderName","required":true,"dataType":"string"}, + }; + + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa + + let validatedArgs: any[] = []; + try { + validatedArgs = getValidatedArgs(args, request, response); + + const controller = new SubFolderController(); + + + const promise = controller.calc.apply(controller, validatedArgs as any); + promiseHandler(controller, promise, response, 200, next); + } catch (err) { + return next(err); + } + }); + // WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa app.get('/cabinet/:cabinetName/drawer/:drawerName/folder/:folderName/subfolder/:subFolderName/file', authenticateMiddleware([{"bearerAuth":[]}]), ...(fetchMiddlewares(SubFolderFileController)), diff --git a/Services/server/src/swagger.json b/Services/server/src/swagger.json index 37ab26f..7dd5811 100644 --- a/Services/server/src/swagger.json +++ b/Services/server/src/swagger.json @@ -375,6 +375,51 @@ ] } }, + "/cabinet/{cabinetName}/size": { + "get": { + "operationId": "Calc", + "responses": { + "200": { + "description": "สำเร็จ", + "content": { + "application/json": { + "schema": { + "properties": { + "size": { + "type": "number", + "format": "double" + } + }, + "required": [ + "size" + ], + "type": "object" + } + } + } + } + }, + "tags": [ + "ตู้เอกสาร" + ], + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "cabinetName", + "required": true, + "schema": { + "type": "string" + }, + "example": "ตู้เอกสาร 1" + } + ] + } + }, "/cabinet/{cabinetName}/drawer": { "get": { "operationId": "ListDrawer", @@ -592,6 +637,60 @@ ] } }, + "/cabinet/{cabinetName}/drawer/{drawerName}/size": { + "get": { + "operationId": "Calc", + "responses": { + "200": { + "description": "สำเร็จ", + "content": { + "application/json": { + "schema": { + "properties": { + "size": { + "type": "number", + "format": "double" + } + }, + "required": [ + "size" + ], + "type": "object" + } + } + } + } + }, + "tags": [ + "ลิ้นชัก" + ], + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "cabinetName", + "required": true, + "schema": { + "type": "string" + }, + "example": "ตู้เอกสาร 1" + }, + { + "in": "path", + "name": "drawerName", + "required": true, + "schema": { + "type": "string" + }, + "example": "ลิ้นชัก 1" + } + ] + } + }, "/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/file": { "get": { "operationId": "GetFile", @@ -1461,6 +1560,69 @@ ] } }, + "/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/size": { + "get": { + "operationId": "Calc", + "responses": { + "200": { + "description": "สำเร็จ", + "content": { + "application/json": { + "schema": { + "properties": { + "size": { + "type": "number", + "format": "double" + } + }, + "required": [ + "size" + ], + "type": "object" + } + } + } + } + }, + "tags": [ + "แฟ้ม" + ], + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "cabinetName", + "required": true, + "schema": { + "type": "string" + }, + "example": "ตู้เอกสาร 1" + }, + { + "in": "path", + "name": "drawerName", + "required": true, + "schema": { + "type": "string" + }, + "example": "ลิ้นชัก 1" + }, + { + "in": "path", + "name": "folderName", + "required": true, + "schema": { + "type": "string" + }, + "example": "แฟ้ม 1" + } + ] + } + }, "/search": { "post": { "operationId": "SearchFile", @@ -1788,6 +1950,78 @@ ] } }, + "/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder/{subFolderName}/size": { + "get": { + "operationId": "Calc", + "responses": { + "200": { + "description": "สำเร็จ", + "content": { + "application/json": { + "schema": { + "properties": { + "size": { + "type": "number", + "format": "double" + } + }, + "required": [ + "size" + ], + "type": "object" + } + } + } + } + }, + "tags": [ + "แฟ้มย่อย" + ], + "security": [ + { + "bearerAuth": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "cabinetName", + "required": true, + "schema": { + "type": "string" + }, + "example": "ตู้เอกสาร 1" + }, + { + "in": "path", + "name": "drawerName", + "required": true, + "schema": { + "type": "string" + }, + "example": "ลิ้นชัก 1" + }, + { + "in": "path", + "name": "folderName", + "required": true, + "schema": { + "type": "string" + }, + "example": "แฟ้ม 1" + }, + { + "in": "path", + "name": "subFolderName", + "required": true, + "schema": { + "type": "string" + }, + "example": "แฟ้มย่อย 1" + } + ] + } + }, "/cabinet/{cabinetName}/drawer/{drawerName}/folder/{folderName}/subfolder/{subFolderName}/file": { "get": { "operationId": "GetFile", From 25752dac1958eb5dabe9208c377547265e859a4f Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:25:56 +0700 Subject: [PATCH 2/3] feat: socketio event --- Services/server/package.json | 1 + Services/server/pnpm-lock.yaml | 96 ++++++++++++++++++- Services/server/src/app.ts | 22 ++++- .../src/controllers/cabinetController.ts | 10 ++ .../src/controllers/drawerController.ts | 15 +++ .../src/controllers/folderController.ts | 13 +++ .../src/controllers/subFolderController.ts | 15 +++ Services/server/src/lib/websocket.ts | 11 +++ Services/server/src/rabbitmq/handler.ts | 25 +++-- 9 files changed, 200 insertions(+), 8 deletions(-) create mode 100644 Services/server/src/lib/websocket.ts diff --git a/Services/server/package.json b/Services/server/package.json index 669e1c2..6598d58 100644 --- a/Services/server/package.json +++ b/Services/server/package.json @@ -28,6 +28,7 @@ "minio": "^7.1.3", "prettier": "^3.1.0", "promise.any": "^2.0.6", + "socket.io": "^4.7.2", "swagger-ui-express": "^5.0.0", "tsoa": "^5.1.1" }, diff --git a/Services/server/pnpm-lock.yaml b/Services/server/pnpm-lock.yaml index 40bc60c..25109c4 100644 --- a/Services/server/pnpm-lock.yaml +++ b/Services/server/pnpm-lock.yaml @@ -38,6 +38,9 @@ dependencies: promise.any: specifier: ^2.0.6 version: 2.0.6 + socket.io: + specifier: ^4.7.2 + version: 4.7.2 swagger-ui-express: specifier: ^5.0.0 version: 5.0.0(express@4.18.2) @@ -154,6 +157,10 @@ packages: engines: {node: '>=8'} dev: false + /@socket.io/component-emitter@3.1.0: + resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==} + dev: false + /@tsconfig/node10@1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} dev: true @@ -215,11 +222,14 @@ packages: dependencies: '@types/node': 20.9.0 + /@types/cookie@0.4.1: + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + dev: false + /@types/cors@2.8.17: resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} dependencies: '@types/node': 20.9.0 - dev: true /@types/express-serve-static-core@4.17.41: resolution: {integrity: sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==} @@ -420,6 +430,11 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + dev: false + /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -576,6 +591,11 @@ packages: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} dev: false + /cookie@0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + dev: false + /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} @@ -706,6 +726,31 @@ packages: engines: {node: '>= 0.8'} dev: false + /engine.io-parser@5.2.1: + resolution: {integrity: sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==} + engines: {node: '>=10.0.0'} + dev: false + + /engine.io@6.5.4: + resolution: {integrity: sha512-KdVSDKhVKyOi+r5uEabrDLZw2qXStVvCsEB/LN3mw4WFi6Gx50jTyuxYVCwAAC0U46FdnzP/ScKRBTXb/NiEOg==} + engines: {node: '>=10.2.0'} + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.17 + '@types/node': 20.9.0 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.4.2 + cors: 2.8.5 + debug: 4.3.4 + engine.io-parser: 5.2.1 + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /es-abstract@1.22.3: resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} engines: {node: '>= 0.4'} @@ -1786,6 +1831,42 @@ packages: semver: 7.5.4 dev: true + /socket.io-adapter@2.5.2: + resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} + dependencies: + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /socket.io@4.7.2: + resolution: {integrity: sha512-bvKVS29/I5fl2FGLNHuXlQaUH/BlzX1IN6S+NKLNZpBsPZIDH+90eQmCs2Railn4YUiww4SzUedJ6+uzwFnKLw==} + engines: {node: '>=10.2.0'} + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + cors: 2.8.5 + debug: 4.3.4 + engine.io: 6.5.4 + socket.io-adapter: 2.5.2 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -2192,6 +2273,19 @@ packages: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: false + /ws@8.11.0: + resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /xml2js@0.5.0: resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} engines: {node: '>=4.0.0'} diff --git a/Services/server/src/app.ts b/Services/server/src/app.ts index d0d7c7b..fdff76d 100644 --- a/Services/server/src/app.ts +++ b/Services/server/src/app.ts @@ -2,6 +2,8 @@ import "dotenv/config"; import express from "express"; import swaggerUi from "swagger-ui-express"; import cors from "cors"; +import { createServer } from "http"; +import { Server } from "socket.io"; import { RegisterRoutes } from "./routes"; import errorHandler from "./middlewares/exception"; @@ -9,6 +11,7 @@ import rabbitmq from "./rabbitmq"; import swaggerSpecs from "./swagger.json"; import { handler as amqHandler } from "./rabbitmq/handler"; +import { setInstance } from "./lib/websocket"; const PORT = +(process.env.PORT || 80); @@ -31,7 +34,24 @@ app.use((_req, res, _next) => { res.sendFile(`${process.cwd()}/static/index.html`); }); -app.listen(PORT, "0.0.0.0", () => +const server = createServer(app); +const io = new Server(server, { + cors: { + origin: "*", + }, +}); + +setInstance(io); + +io.on("connection", (socket) => { + console.log("User Connected"); + + socket.on("disconnected", () => { + console.log("User Disconnected"); + }); +}); + +server.listen(PORT, "0.0.0.0", () => console.log(`[APP] Application is running on http://localhost:${PORT}`), ); diff --git a/Services/server/src/controllers/cabinetController.ts b/Services/server/src/controllers/cabinetController.ts index ec6a6a2..8d20f3f 100644 --- a/Services/server/src/controllers/cabinetController.ts +++ b/Services/server/src/controllers/cabinetController.ts @@ -22,6 +22,7 @@ import { copyCond, listFolder, listItem, replaceIllegalChars } from "../utils/mi import HttpStatusCode from "../interfaces/http-status"; import { StorageFile, StorageFolder } from "../interfaces/storage-fs"; +import { getInstance } from "../lib/websocket"; const DEFAULT_BUCKET = process.env.MINIO_BUCKET; const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX; @@ -86,6 +87,9 @@ export class CabinetController extends Controller { if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์"); + const io = getInstance(); + io?.emit("CreateFolder", { pathname: `${replaceIllegalChars(body.name)}/` }); + return this.setStatus(HttpStatusCode.CREATED); } @@ -155,6 +159,9 @@ export class CabinetController extends Controller { }), ); + const io = getInstance(); + io?.emit("EditFolder", { from: `${cabinetName}/`, to: `${replaceIllegalChars(body.name)}/` }); + return this.setStatus(HttpStatusCode.NO_CONTENT); } @@ -180,6 +187,9 @@ export class CabinetController extends Controller { stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้"))); }); + const io = getInstance(); + io?.emit("DeleteFolder", { pathname: `${cabinetName}/` }); + return this.setStatus(HttpStatusCode.NO_CONTENT); } diff --git a/Services/server/src/controllers/drawerController.ts b/Services/server/src/controllers/drawerController.ts index 1bf437d..1311697 100644 --- a/Services/server/src/controllers/drawerController.ts +++ b/Services/server/src/controllers/drawerController.ts @@ -23,6 +23,7 @@ import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from " import HttpStatusCode from "../interfaces/http-status"; import { StorageFile, StorageFolder } from "../interfaces/storage-fs"; import HttpError from "../interfaces/http-error"; +import { getInstance } from "../lib/websocket"; const DEFAULT_BUCKET = process.env.MINIO_BUCKET; const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX; @@ -101,6 +102,9 @@ export class DrawerController extends Controller { if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์"); + const io = getInstance(); + io?.emit("CreateFolder", { pathname: `${basePath}${replaceIllegalChars(body.name)}/` }); + return this.setStatus(HttpStatusCode.CREATED); } @@ -172,6 +176,12 @@ export class DrawerController extends Controller { }), ); + const io = getInstance(); + io?.emit("EditFolder", { + from: `${cabinetName}/${drawerName}/`, + to: `${cabinetName}/${replaceIllegalChars(body.name)}/`, + }); + return this.setStatus(HttpStatusCode.NO_CONTENT); } @@ -201,6 +211,11 @@ export class DrawerController extends Controller { stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้"))); }); + const io = getInstance(); + io?.emit("DeleteFolder", { + pathname: `${cabinetName}/${drawerName}/`, + }); + return this.setStatus(HttpStatusCode.NO_CONTENT); } diff --git a/Services/server/src/controllers/folderController.ts b/Services/server/src/controllers/folderController.ts index f1567e8..06bd264 100644 --- a/Services/server/src/controllers/folderController.ts +++ b/Services/server/src/controllers/folderController.ts @@ -23,6 +23,7 @@ import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from " import HttpStatusCode from "../interfaces/http-status"; import { StorageFile, StorageFolder } from "../interfaces/storage-fs"; import HttpError from "../interfaces/http-error"; +import { getInstance } from "../lib/websocket"; const DEFAULT_BUCKET = process.env.MINIO_BUCKET; const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX; @@ -106,6 +107,9 @@ export class FolderController extends Controller { if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์"); + const io = getInstance(); + io?.emit("CreateFolder", { pathname: `${basePath}${replaceIllegalChars(body.name)}/` }); + return this.setStatus(HttpStatusCode.CREATED); } @@ -179,6 +183,12 @@ export class FolderController extends Controller { }), ); + const io = getInstance(); + io?.emit("EditFolder", { + from: `${cabinetName}/${drawerName}/${folderName}`, + to: `${cabinetName}/${drawerName}/${replaceIllegalChars(body.name)}/`, + }); + return this.setStatus(HttpStatusCode.NO_CONTENT); } @@ -213,6 +223,9 @@ export class FolderController extends Controller { stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้"))); }); + const io = getInstance(); + io?.emit("DeleteFolder", { pathname: `${cabinetName}/${drawerName}/${folderName}/` }); + return this.setStatus(HttpStatusCode.NO_CONTENT); } diff --git a/Services/server/src/controllers/subFolderController.ts b/Services/server/src/controllers/subFolderController.ts index a2d29e2..1454aa6 100644 --- a/Services/server/src/controllers/subFolderController.ts +++ b/Services/server/src/controllers/subFolderController.ts @@ -23,6 +23,7 @@ import { copyCond, listFolder, listItem, pathExist, replaceIllegalChars } from " import HttpStatusCode from "../interfaces/http-status"; import { StorageFile, StorageFolder } from "../interfaces/storage-fs"; import HttpError from "../interfaces/http-error"; +import { getInstance } from "../lib/websocket"; const DEFAULT_BUCKET = process.env.MINIO_BUCKET; const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX; @@ -105,6 +106,9 @@ export class SubFolderController extends Controller { if (!created) throw new Error("เกิดข้อผิดพลาดกับระบบจัดการไฟล์"); + const io = getInstance(); + io?.emit("CreateFolder", { pathname: `${basePath}${replaceIllegalChars(body.name)}/` }); + return this.setStatus(HttpStatusCode.CREATED); } @@ -182,6 +186,12 @@ export class SubFolderController extends Controller { }), ); + const io = getInstance(); + io?.emit("EditFolder", { + from: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}/`, + to: `${cabinetName}/${drawerName}/${folderName}/${replaceIllegalChars(body.name)}/`, + }); + return this.setStatus(HttpStatusCode.NO_CONTENT); } @@ -218,6 +228,11 @@ export class SubFolderController extends Controller { stream.on("error", () => reject(new Error("เกิดข้อผิดพลาด ไม่สามารถลบไฟล์ได้"))); }); + const io = getInstance(); + io?.emit("DeleteFolder", { + pathname: `${cabinetName}/${drawerName}/${folderName}/${subFolderName}`, + }); + return this.setStatus(HttpStatusCode.NO_CONTENT); } diff --git a/Services/server/src/lib/websocket.ts b/Services/server/src/lib/websocket.ts new file mode 100644 index 0000000..6783db2 --- /dev/null +++ b/Services/server/src/lib/websocket.ts @@ -0,0 +1,11 @@ +import { Server } from "socket.io"; + +let io: Server | null = null; + +export function setInstance(server: Server) { + io = server; +} + +export function getInstance() { + return io; +} diff --git a/Services/server/src/rabbitmq/handler.ts b/Services/server/src/rabbitmq/handler.ts index f00a990..0beefe0 100644 --- a/Services/server/src/rabbitmq/handler.ts +++ b/Services/server/src/rabbitmq/handler.ts @@ -1,6 +1,7 @@ import { StorageFile } from "../interfaces/storage-fs"; import esClient from "../elasticsearch"; import minioClient from "../minio"; +import { getInstance } from "../lib/websocket"; const DEFAULT_INDEX = process.env.ELASTICSEARCH_INDEX; @@ -27,7 +28,7 @@ export async function handler(key: string, event: string): Promise { cachedBuffer[key] = buffer; } catch (e: any) { if (e.code === "NoSuchKey") { - console.info(`[AMQ] Key: ${key} received but cannot be found.`) + console.info(`[AMQ] Key: ${key} received but cannot be found.`); delete cachedBuffer[key]; delete cachedMetadata[key]; await ensureDelete(pathname); @@ -43,7 +44,7 @@ export async function handler(key: string, event: string): Promise { const rec = await popInfo(pathname); - console.info(`[AMQ] Key: ${key} - ${rec ?? 'Not Found.'}`) + console.info(`[AMQ] Key: ${key} - ${rec ?? "Not Found."}`); const result = rec ? await handleFoundRecord(rec, cachedBuffer[key], cachedMetadata[key]) @@ -94,6 +95,10 @@ async function ensureDelete(pathname: string) { conflicts: "proceed", }) .catch((e) => console.error(e)); + + const io = getInstance(); + io?.send("FileDelete", { pathname }); + return true; } @@ -132,12 +137,16 @@ async function handleNotFoundRecord( pipeline: "attachment", index: DEFAULT_INDEX!, document: { data: base64, ...metadata }, + refresh: "wait_for", }) .catch((e) => console.error(e)); - if (result) return true; + if (!result) return false; - return false; + const io = getInstance(); + io?.send("FileUpdate", metadata); + + return true; } async function handleFoundRecord( @@ -154,10 +163,14 @@ async function handleFoundRecord( pipeline: "attachment", index: DEFAULT_INDEX!, document: { data: Buffer.from(buffer).toString("base64"), ...metadata }, + refresh: "wait_for", }) .catch((e) => console.error(e)); - if (result) return true; + if (!result) return false; - return false; + const io = getInstance(); + io?.send("FileUpdate", metadata); + + return true; } From 0ba7b1a5f1d835034977b9da40a90ee8850b6bb1 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Thu, 7 Dec 2023 17:26:26 +0700 Subject: [PATCH 3/3] chore: add deps --- Services/client/package.json | 1 + Services/client/pnpm-lock.yaml | 84 ++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/Services/client/package.json b/Services/client/package.json index b210883..86cf8ca 100644 --- a/Services/client/package.json +++ b/Services/client/package.json @@ -24,6 +24,7 @@ "nanoid": "^5.0.4", "pinia": "^2.1.7", "quasar": "^2.14.0", + "socket.io-client": "^4.7.2", "vite-plugin-pwa": "^0.17.2", "vue": "^3.3.9", "vue-router": "^4.2.5" diff --git a/Services/client/pnpm-lock.yaml b/Services/client/pnpm-lock.yaml index 9a7f93b..6ee3805 100644 --- a/Services/client/pnpm-lock.yaml +++ b/Services/client/pnpm-lock.yaml @@ -17,6 +17,9 @@ dependencies: keycloak-js: specifier: ^23.0.0 version: 23.0.0 + mime: + specifier: ^4.0.0 + version: 4.0.0 nanoid: specifier: ^5.0.4 version: 5.0.4 @@ -26,6 +29,9 @@ dependencies: quasar: specifier: ^2.14.0 version: 2.14.0 + socket.io-client: + specifier: ^4.7.2 + version: 4.7.2 vite-plugin-pwa: specifier: ^0.17.2 version: 0.17.2(vite@5.0.2)(workbox-build@7.0.0)(workbox-window@7.0.0) @@ -49,6 +55,9 @@ devDependencies: '@types/jsdom': specifier: ^21.1.6 version: 21.1.6 + '@types/mime-types': + specifier: ^2.1.4 + version: 2.1.4 '@types/node': specifier: ^20.10.0 version: 20.10.0 @@ -1801,6 +1810,10 @@ packages: resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} dev: true + /@socket.io/component-emitter@3.1.0: + resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==} + dev: false + /@surma/rollup-plugin-off-main-thread@2.2.3: resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} dependencies: @@ -1840,6 +1853,10 @@ packages: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} dev: true + /@types/mime-types@2.1.4: + resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} + dev: true + /@types/node@20.10.0: resolution: {integrity: sha512-D0WfRmU9TQ8I9PFx9Yc+EBHw+vSpIub4IDvQivcp26PtPrdMGAq5SDcpXEo/epqa/DXotVpekHiLNTg3iaKXBQ==} dependencies: @@ -2823,6 +2840,25 @@ packages: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true + /engine.io-client@6.5.3: + resolution: {integrity: sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + engine.io-parser: 5.2.1 + ws: 8.11.0 + xmlhttprequest-ssl: 2.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /engine.io-parser@5.2.1: + resolution: {integrity: sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==} + engines: {node: '>=10.0.0'} + dev: false + /entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} @@ -3967,6 +4003,12 @@ packages: dependencies: mime-db: 1.52.0 + /mime@4.0.0: + resolution: {integrity: sha512-pzhgdeqU5pJ9t5WK9m4RT4GgGWqYJylxUf62Yb9datXRwdcw5MjiD1BYI5evF8AgTXN9gtKX3CFLvCUL5fAhEA==} + engines: {node: '>=16'} + hasBin: true + dev: false + /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -4709,6 +4751,30 @@ packages: engines: {node: '>=8'} dev: true + /socket.io-client@4.7.2: + resolution: {integrity: sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + engine.io-client: 6.5.3 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -5676,6 +5742,19 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /ws@8.11.0: + resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /ws@8.14.2: resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} engines: {node: '>=10.0.0'} @@ -5703,6 +5782,11 @@ packages: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} dev: true + /xmlhttprequest-ssl@2.0.0: + resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} + engines: {node: '>=0.4.0'} + dev: false + /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}