From 6f0bfbcd0965fa5be49fde8eeeac69685145b7e2 Mon Sep 17 00:00:00 2001 From: Anton SHEPILOV Date: Fri, 24 May 2024 00:19:31 +0200 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8FRemoved=20unused=20websockets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/custom-environment-variables.json | 8 - tdrive/backend/node/config/default.json | 17 -- .../cmds/generate_cmds/users-and-companies.ts | 1 - .../platform/framework/decorators/index.ts | 1 - .../framework/decorators/realtime/created.ts | 41 ----- .../framework/decorators/realtime/deleted.ts | 41 ----- .../framework/decorators/realtime/index.ts | 67 ------- .../framework/decorators/realtime/saved.ts | 41 ----- .../framework/decorators/realtime/updated.ts | 40 ----- .../core/platform/services/realtime/api.ts | 78 --------- .../core/platform/services/realtime/bus.ts | 22 --- .../core/platform/services/realtime/index.ts | 76 -------- .../realtime/services/entity-manager.ts | 54 ------ .../services/realtime/services/index.ts | 2 - .../realtime/services/room-manager.ts | 164 ------------------ .../core/platform/services/realtime/types.ts | 83 --------- .../core/platform/services/websocket/index.ts | 47 ----- .../platform/services/websocket/provider.ts | 17 -- .../services/websocket/services/index.ts | 105 ----------- .../core/platform/services/websocket/types.ts | 39 ----- .../applications-api/web/controllers/index.ts | 26 --- .../src/services/applications/realtime.ts | 13 -- .../web/controllers/company-applications.ts | 6 - .../src/services/documents/services/index.ts | 25 --- .../documents/web/controllers/documents.ts | 17 +- .../node/src/services/global-resolver.ts | 6 - .../node/src/services/user/realtime.ts | 45 ----- .../src/services/user/services/companies.ts | 28 +-- .../services/user/services/users/service.ts | 26 --- .../node/src/services/user/web/controller.ts | 17 +- .../node/src/services/user/web/schemas.ts | 3 - .../node/src/services/workspaces/realtime.ts | 30 ---- .../services/workspaces/services/workspace.ts | 17 +- .../workspaces/web/controllers/workspaces.ts | 2 - .../src/services/workspaces/web/schemas.ts | 2 - tdrive/backend/node/src/utils/types.ts | 42 ----- .../e2e/documents/documents-browser.spec.ts | 1 - .../documents/documents-notifications.spec.ts | 2 - .../e2e/documents/documents-quota.spec.ts | 2 - .../e2e/documents/documents-search.spec.ts | 2 - .../test/e2e/documents/documents-tab.spec.ts | 2 - .../node/test/e2e/documents/documents.spec.ts | 2 - .../node/test/e2e/documents/my-drive.spec.ts | 2 - .../test/e2e/documents/public-links.spec.ts | 2 - tdrive/backend/node/test/e2e/setup/test.json | 10 -- .../node/test/e2e/users/users.quota.spec.ts | 1 - .../node/test/e2e/users/users.search.spec.ts | 1 - .../backend/node/test/e2e/users/users.spec.ts | 1 - .../decorators/realtime/created.test.ts | 116 ------------- .../decorators/realtime/deleted.test.ts | 116 ------------- .../decorators/realtime/updated.test.ts | 118 ------------- 51 files changed, 7 insertions(+), 1620 deletions(-) delete mode 100644 tdrive/backend/node/src/core/platform/framework/decorators/realtime/created.ts delete mode 100644 tdrive/backend/node/src/core/platform/framework/decorators/realtime/deleted.ts delete mode 100644 tdrive/backend/node/src/core/platform/framework/decorators/realtime/index.ts delete mode 100644 tdrive/backend/node/src/core/platform/framework/decorators/realtime/saved.ts delete mode 100644 tdrive/backend/node/src/core/platform/framework/decorators/realtime/updated.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/realtime/api.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/realtime/bus.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/realtime/index.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/realtime/services/entity-manager.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/realtime/services/index.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/realtime/services/room-manager.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/realtime/types.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/websocket/index.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/websocket/provider.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/websocket/services/index.ts delete mode 100644 tdrive/backend/node/src/core/platform/services/websocket/types.ts delete mode 100644 tdrive/backend/node/src/services/applications/realtime.ts delete mode 100644 tdrive/backend/node/src/services/user/realtime.ts delete mode 100644 tdrive/backend/node/src/services/workspaces/realtime.ts delete mode 100644 tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/created.test.ts delete mode 100644 tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/deleted.test.ts delete mode 100644 tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/updated.test.ts diff --git a/tdrive/backend/node/config/custom-environment-variables.json b/tdrive/backend/node/config/custom-environment-variables.json index 7e7cca4d..0c5afee3 100644 --- a/tdrive/backend/node/config/custom-environment-variables.json +++ b/tdrive/backend/node/config/custom-environment-variables.json @@ -25,14 +25,6 @@ "root": "STATIC_ROOT" } }, - "websocket": { - "auth": { - "jwt": { - "secret": "AUTH_JWT_SECRET", - "expiration": "AUTH_JWT_EXPIRATION" - } - } - }, "tracker": { "segment": { "key": "SEGMENT_SECRET_KEY" diff --git a/tdrive/backend/node/config/default.json b/tdrive/backend/node/config/default.json index 7ceafc9b..44e93518 100644 --- a/tdrive/backend/node/config/default.json +++ b/tdrive/backend/node/config/default.json @@ -55,21 +55,6 @@ "root": "./public" } }, - "websocket": { - "path": "/socket/", - "adapters": { - "types": [], - "redis": { - "host": "redis", - "port": 6379 - } - }, - "auth": { - "jwt": { - "secret": "supersecret" - } - } - }, "auth": { "jwt": { "secret": "supersecret", @@ -244,12 +229,10 @@ "push", "storage", "webserver", - "websocket", "database", "cron", "search", "message-queue", - "realtime", "tracker", "general", "user", diff --git a/tdrive/backend/node/src/cli/cmds/generate_cmds/users-and-companies.ts b/tdrive/backend/node/src/cli/cmds/generate_cmds/users-and-companies.ts index d179430c..06634003 100644 --- a/tdrive/backend/node/src/cli/cmds/generate_cmds/users-and-companies.ts +++ b/tdrive/backend/node/src/cli/cmds/generate_cmds/users-and-companies.ts @@ -24,7 +24,6 @@ const services = [ "applications", "statistics", "auth", - "realtime", "push", "platform-services", "user", diff --git a/tdrive/backend/node/src/core/platform/framework/decorators/index.ts b/tdrive/backend/node/src/core/platform/framework/decorators/index.ts index a78685f3..aa9754a7 100644 --- a/tdrive/backend/node/src/core/platform/framework/decorators/index.ts +++ b/tdrive/backend/node/src/core/platform/framework/decorators/index.ts @@ -1,4 +1,3 @@ export * from "./consumes"; export * from "./prefix"; export * from "./service-name"; -export * from "./realtime"; diff --git a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/created.ts b/tdrive/backend/node/src/core/platform/framework/decorators/realtime/created.ts deleted file mode 100644 index 2f88fb9d..00000000 --- a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/created.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { CreateResult } from "../../api/crud-service"; -import { RealtimeEntityEvent, RealtimeEntityActionType } from "../../../services/realtime/types"; -import { websocketEventBus } from "../../../services/realtime/bus"; -import { getRealtimeRecipients, getRoom, RealtimeRecipients } from "."; - -/** - * - * @param path the path to push the notification to - * @param resourcePath the path of the resource itself - */ -export function RealtimeCreated(recipients: RealtimeRecipients): MethodDecorator { - // eslint-disable-next-line @typescript-eslint/ban-types - return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor): void { - const originalMethod = descriptor.value; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - descriptor.value = async function (...args: any[]) { - const result: CreateResult = await originalMethod.apply(this, args); - // context should always be the last arg - const context = args && args[args.length - 1]; - - if (!(result instanceof CreateResult)) { - return result; - } - - getRealtimeRecipients(recipients, result.entity, context).forEach( - ({ room, path, resource }) => { - websocketEventBus.publish(RealtimeEntityActionType.Created, { - type: result.type, - room: getRoom(room, result, context), - resourcePath: path || "/", - entity: resource, - result, - } as RealtimeEntityEvent); - }, - ); - - return result; - }; - }; -} diff --git a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/deleted.ts b/tdrive/backend/node/src/core/platform/framework/decorators/realtime/deleted.ts deleted file mode 100644 index 92b655a9..00000000 --- a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/deleted.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { getRealtimeRecipients, getRoom, RealtimeRecipients } from ".."; -import { DeleteResult } from "../../api/crud-service"; -import { RealtimeEntityEvent, RealtimeEntityActionType } from "../../../services/realtime/types"; -import { websocketEventBus } from "../../../services/realtime/bus"; - -/** - * - * @param path the path to push the notification to - * @param resourcePath the path of the resource itself - */ -export function RealtimeDeleted(recipients: RealtimeRecipients): MethodDecorator { - // eslint-disable-next-line @typescript-eslint/ban-types - return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor): void { - const originalMethod = descriptor.value; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - descriptor.value = async function (...args: any[]) { - const result: DeleteResult = await originalMethod.apply(this, args); - const context = args && args[args.length - 1]; - - if (!(result instanceof DeleteResult)) { - return result; - } - - if (result.deleted) - getRealtimeRecipients(recipients, result.entity, context).forEach( - ({ room, path, resource }) => { - websocketEventBus.publish(RealtimeEntityActionType.Deleted, { - type: result.type, - room: getRoom(room, result, context), - resourcePath: path, - entity: resource, - result, - } as RealtimeEntityEvent); - }, - ); - - return result; - }; - }; -} diff --git a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/index.ts b/tdrive/backend/node/src/core/platform/framework/decorators/realtime/index.ts deleted file mode 100644 index 4e84da93..00000000 --- a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { ResourcePath } from "../../../../../core/platform/services/realtime/types"; -import { EntityTarget, ExecutionContext } from "../../api/crud-service"; - -export * from "./created"; -export * from "./deleted"; -export * from "./updated"; -export * from "./saved"; - -export type RealtimeRecipients = - | RealtimeRecipient - | RealtimeRecipient[] - | ((type: T, context?: ExecutionContext) => RealtimeRecipient[] | RealtimeRecipient); - -export type RealtimeRecipient = { - room: RealtimePath; - path?: string; - resource?: any | T; -}; - -export function getRealtimeRecipients( - recipients: RealtimeRecipients, - type: T, - context?: ExecutionContext, -): RealtimeRecipient[] { - if (typeof recipients === "function") recipients = recipients(type, context); - if (!recipients) return []; - if (!(recipients as RealtimeRecipient[]).length) - recipients = [recipients as RealtimeRecipient]; - - return (recipients as RealtimeRecipient[]).map(recipient => { - return { - resource: recipient.resource || type, - path: recipient.path || "/", - room: recipient.room, - }; - }); -} - -export type RealtimePath = string | ResourcePath | ResourcePathResolver; -export interface ResourcePathResolver { - (type: T, context?: ExecutionContext): ResourcePath; -} -export interface PathResolver { - (type: T, context?: ExecutionContext): string; -} - -export type RealtimeEntity = null | ((type: T, context?: ExecutionContext) => T); - -export function getRoom( - path: RealtimePath = ResourcePath.default(), - entity: EntityTarget, - context: ExecutionContext, -): ResourcePath { - if (typeof path === "string") { - return ResourcePath.get(path); - } - - return typeof path === "function" ? path(entity.entity, context) : path; -} - -export function getPath( - path: string | PathResolver = "/", - entity: EntityTarget, - context: ExecutionContext, -): string { - return typeof path === "function" ? path(entity.entity, context) : path; -} diff --git a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/saved.ts b/tdrive/backend/node/src/core/platform/framework/decorators/realtime/saved.ts deleted file mode 100644 index ca197457..00000000 --- a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/saved.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { getRealtimeRecipients, getRoom, RealtimeRecipients } from ".."; -import { SaveResult } from "../../api/crud-service"; -import { RealtimeEntityEvent, RealtimeEntityActionType } from "../../../services/realtime/types"; -import { websocketEventBus } from "../../../services/realtime/bus"; - -/** - * - * @param path the path to push the notification to - * @param resourcePath the path of the resource itself - */ -export function RealtimeSaved(recipients: RealtimeRecipients): MethodDecorator { - // eslint-disable-next-line @typescript-eslint/ban-types - return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor): void { - const originalMethod = descriptor.value; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - descriptor.value = async function (...args: any[]) { - const result: SaveResult = await originalMethod.apply(this, args); - // context should always be the last arg - const context = args && args[args.length - 1]; - - if (!(result instanceof SaveResult)) { - return result; - } - - getRealtimeRecipients(recipients, result.entity, context).forEach( - ({ room, path, resource }) => { - websocketEventBus.publish(RealtimeEntityActionType.Saved, { - type: result.type, - room: getRoom(room, result, context), - resourcePath: path, - entity: resource, - result, - } as RealtimeEntityEvent); - }, - ); - - return result; - }; - }; -} diff --git a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/updated.ts b/tdrive/backend/node/src/core/platform/framework/decorators/realtime/updated.ts deleted file mode 100644 index 53ace2c2..00000000 --- a/tdrive/backend/node/src/core/platform/framework/decorators/realtime/updated.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { getRealtimeRecipients, getRoom, RealtimeRecipients } from ".."; -import { UpdateResult } from "../../api/crud-service"; -import { RealtimeEntityEvent, RealtimeEntityActionType } from "../../../services/realtime/types"; -import { websocketEventBus } from "../../../services/realtime/bus"; - -/** - * - * @param path the path to push the notification to - * @param resourcePath the path of the resource itself - */ -export function RealtimeUpdated(recipients: RealtimeRecipients): MethodDecorator { - // eslint-disable-next-line @typescript-eslint/ban-types - return function (target: Object, propertyKey: string, descriptor: PropertyDescriptor): void { - const originalMethod = descriptor.value; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - descriptor.value = async function (...args: any[]) { - const result: UpdateResult = await originalMethod.apply(this, args); - const context = args && args[args.length - 1]; - - if (!(result instanceof UpdateResult)) { - return result; - } - - getRealtimeRecipients(recipients, result.entity, context).forEach( - ({ room, path, resource }) => { - websocketEventBus.publish(RealtimeEntityActionType.Updated, { - type: result.type, - room: getRoom(room, result, context), - resourcePath: path, - entity: resource, - result, - } as RealtimeEntityEvent); - }, - ); - - return result; - }; - }; -} diff --git a/tdrive/backend/node/src/core/platform/services/realtime/api.ts b/tdrive/backend/node/src/core/platform/services/realtime/api.ts deleted file mode 100644 index e2ae08d4..00000000 --- a/tdrive/backend/node/src/core/platform/services/realtime/api.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { TdriveServiceProvider } from "../../framework"; -import { WebSocketUser, WebSocket } from "../../services/websocket/types"; -import RealtimeEntityManager from "./services/entity-manager"; -import { RealtimeEntityEvent } from "./types"; - -export interface RealtimeServiceAPI extends TdriveServiceProvider { - /** - * Get the realtime event bus instance - */ - getBus(): RealtimeEventBus; - - /** - * Get the room manager - */ - getRoomManager(): RealtimeRoomManager; - - /** - * Get the entity manager - */ - getEntityManager(): RealtimeEntityManager; - - /** - * Create a token for a room - */ - sign(items: { room: string }[], userId: string): { room: string; token: string }[]; -} - -export interface RealtimeRoomManager { - /** - * Get the number of connected users in the given room - * @param room name of the room - */ - getConnectedUsers(room: string): number; - - /** - * Add the user to a room - * - * @param websocket - * @param room - * @param user - */ - join(websocket: WebSocket, room: string, user: WebSocketUser): void; - - /** - * Remove the user from a room - * - * @param websocket - * @param room - * @param user - */ - leave(websocket: WebSocket, room: string, user: WebSocketUser): void; - - /** - * Remove a user from all the room he joined - * - * @param websocket - * @param user - */ - leaveAll(websocket: WebSocket, user: WebSocketUser): void; -} - -export interface RealtimeEventBus { - /** - * Subscribes to a topic - * - * @param topic Topic to subscribe to - * @param listener Listener to call when event is published in the given topic - */ - subscribe(topic: string, listener: (event: RealtimeEntityEvent) => void): this; - - /** - * Publish event in a topic - * - * @param topic Topic to publish event to - * @param event Event to publish - */ - publish(topic: string, event: RealtimeEntityEvent): boolean; -} diff --git a/tdrive/backend/node/src/core/platform/services/realtime/bus.ts b/tdrive/backend/node/src/core/platform/services/realtime/bus.ts deleted file mode 100644 index 1ae54fbd..00000000 --- a/tdrive/backend/node/src/core/platform/services/realtime/bus.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * EventBus is used internally to exchange events between decorators and realtime manager - */ -import { EventEmitter } from "events"; -import { RealtimeEventBus } from "./api"; -import { RealtimeEntityEvent } from "./types"; - -class WebsocketEventBus extends EventEmitter implements RealtimeEventBus { - constructor() { - super(); - } - - subscribe(topic: string, listener: (event: RealtimeEntityEvent) => void): this { - return this.on(topic, listener); - } - - publish(topic: string, event: RealtimeEntityEvent): boolean { - return this.emit(topic, event); - } -} - -export const websocketEventBus = new WebsocketEventBus(); diff --git a/tdrive/backend/node/src/core/platform/services/realtime/index.ts b/tdrive/backend/node/src/core/platform/services/realtime/index.ts deleted file mode 100644 index c6208068..00000000 --- a/tdrive/backend/node/src/core/platform/services/realtime/index.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { Consumes, ServiceName, TdriveService } from "../../framework"; -import { SkipCLI } from "../../framework/decorators/skip"; -import { localEventBus } from "../../framework/event-bus"; -import WebSocketAPI from "../../services/websocket/provider"; -import AuthService from "../auth/provider"; -import { RealtimeEventBus, RealtimeRoomManager, RealtimeServiceAPI } from "./api"; -import { websocketEventBus } from "./bus"; -import RealtimeEntityManager from "./services/entity-manager"; -import RoomManagerImpl from "./services/room-manager"; -import { RealtimeBaseBusEvent, RealtimeLocalBusEvent } from "./types"; - -@Consumes(["websocket", "auth"]) -@ServiceName("realtime") -export default class RealtimeService - extends TdriveService - implements RealtimeServiceAPI -{ - private roomManager: RoomManagerImpl; - private entityManager: RealtimeEntityManager; - private auth: AuthService; - version = "1"; - - api(): RealtimeServiceAPI { - return this; - } - - @SkipCLI() - async doStart(): Promise { - const ws = this.context.getProvider("websocket"); - this.auth = this.context.getProvider("auth"); - - this.roomManager = new RoomManagerImpl(ws, this.auth); - this.roomManager.init(); - this.entityManager = new RealtimeEntityManager(ws); - this.entityManager.init(); - - localEventBus.subscribe("realtime:event", (event: RealtimeBaseBusEvent) => { - event.data._type = event.type; - ws.getIo().to(event.room).emit("realtime:event", { name: event.room, data: event.data }); - }); - - localEventBus.subscribe("realtime:publish", (data: RealtimeLocalBusEvent) => { - this.getBus().publish(data.topic, data.event); - }); - - return this; - } - - getBus(): RealtimeEventBus { - return websocketEventBus; - } - - getRoomManager(): RealtimeRoomManager { - return this.roomManager; - } - - getEntityManager(): RealtimeEntityManager { - return this.entityManager; - } - - sign(items: { room: string }[], sub: string) { - return items.map(item => { - const token = this.auth.sign({ - sub, - name: item.room, - //Fixme, reduce this number but also in frontend reload the websocket token after this ends - iat: Math.round(new Date().getTime() / 1000) + 60 * 60 * 24 * 31, - nbf: Math.round(new Date().getTime() / 1000) - 60, - }); - return { - ...item, - token, - }; - }); - } -} diff --git a/tdrive/backend/node/src/core/platform/services/realtime/services/entity-manager.ts b/tdrive/backend/node/src/core/platform/services/realtime/services/entity-manager.ts deleted file mode 100644 index 49c5a14b..00000000 --- a/tdrive/backend/node/src/core/platform/services/realtime/services/entity-manager.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { logger } from "../../../framework/logger"; -import { RealtimeEntityActionType, RealtimeEntityEvent } from "../types"; -import WebSocketAPI from "../../../services/websocket/provider"; -import { websocketEventBus } from "../bus"; - -const REALTIME_RESOURCE = "realtime:resource"; - -export default class RealtimeEntityManager { - constructor(private ws: WebSocketAPI) {} - - init(): void { - websocketEventBus.subscribe(RealtimeEntityActionType.Created, event => { - this.pushResourceEvent(event, RealtimeEntityActionType.Created); - }); - - websocketEventBus.subscribe(RealtimeEntityActionType.Updated, event => { - this.pushResourceEvent(event, RealtimeEntityActionType.Updated); - }); - - websocketEventBus.subscribe(RealtimeEntityActionType.Deleted, event => { - this.pushResourceEvent(event, RealtimeEntityActionType.Deleted); - }); - - websocketEventBus.subscribe(RealtimeEntityActionType.Saved, event => { - this.pushResourceEvent(event, RealtimeEntityActionType.Saved); - }); - - websocketEventBus.subscribe(RealtimeEntityActionType.Event, event => { - this.pushResourceEvent(event, RealtimeEntityActionType.Event); - }); - } - - private pushResourceEvent( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - event: RealtimeEntityEvent, - action: RealtimeEntityActionType, - ): void { - event.room.path.forEach(path => { - logger.info(`Pushing ${action} entity to room ${path}`); - const message: unknown = { - action, - room: path, - type: event.type, - path: event.resourcePath, - resource: event.entity, - }; - if (logger.isLevelEnabled("debug")) { - logger.debug(`Entity to push to room ${path}: %o`, message); - } - - this.ws.getIo().to(path).emit(REALTIME_RESOURCE, message); - }); - } -} diff --git a/tdrive/backend/node/src/core/platform/services/realtime/services/index.ts b/tdrive/backend/node/src/core/platform/services/realtime/services/index.ts deleted file mode 100644 index 28041086..00000000 --- a/tdrive/backend/node/src/core/platform/services/realtime/services/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./entity-manager"; -export * from "./room-manager"; diff --git a/tdrive/backend/node/src/core/platform/services/realtime/services/room-manager.ts b/tdrive/backend/node/src/core/platform/services/realtime/services/room-manager.ts deleted file mode 100644 index a735de07..00000000 --- a/tdrive/backend/node/src/core/platform/services/realtime/services/room-manager.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { logger } from "../../../framework/logger"; -import { - JoinLeaveRoomError, - JoinLeaveRoomSuccess, - JoinRoomEvent, - LeaveRoomEvent, - ClientEvent, - WebsocketRoomSignature, -} from "../types"; -import { RealtimeRoomManager } from "../api"; -import WebSocketAPI from "../../../services/websocket/provider"; -import { WebSocketUser, WebSocket } from "../../../services/websocket/types"; -import AuthService from "../../auth/provider"; - -export default class RoomManager implements RealtimeRoomManager { - constructor(private ws: WebSocketAPI, private auth: AuthService) {} - - init(): void { - this.ws.onUserConnected(event => { - logger.info(`User ${event.user.id} is connected`); - - event.socket.on("realtime:join", async (joinEvent: JoinRoomEvent) => { - const canJoin = - joinEvent.name.indexOf("previous::") === 0 || //Compatibility with old collections - (await this.userCanJoinRoom(event.user, joinEvent)); - - if (canJoin) { - this.join(event.socket, joinEvent.name, event.user); - } else { - this.sendError("join", event.socket, { - name: joinEvent.name, - message: "User is not authorized to join room", - }); - } - }); - - event.socket.on("realtime:leave", (leaveEvent: LeaveRoomEvent) => { - this.leave(event.socket, leaveEvent.name, event.user); - }); - - event.socket.on("realtime:event", async (clientEvent: ClientEvent) => { - const canEmit = - clientEvent.name.indexOf("previous::") === 0 || //Compatibility with old collections - (await this.userCanEmitInRoom(event.user, clientEvent)); - if (canEmit) { - this.sendEvent(clientEvent.name, clientEvent.data); - } else { - this.sendError("event", event.socket, { - name: clientEvent.name, - message: "User is not authorized to emit in this room", - }); - } - }); - }); - - this.ws.onUserDisconnected(event => { - logger.info(`User ${event.user.id} is disconnected`); - this.leaveAll(event.socket, event.user); - }); - } - - getConnectedUsers(room: string): number { - if (this.ws.getIo().sockets.adapter.rooms.has(room)) { - return this.ws.getIo().sockets.adapter.rooms.get(room).entries.length; - } - - return 0; - } - - /** - * Check of the user can join room - * - * @param user - * @param joinEvent - * @return Promise true if can join, false otherwise. Never rejects. - */ - async userCanJoinRoom(user: WebSocketUser, joinEvent: JoinRoomEvent): Promise { - logger.info(`Checking if user ${user.id} can join room ${joinEvent.name} with token`); - - try { - //Public rooms we just check the user is logged in - if ( - joinEvent.name.startsWith("/users/") || //User update room - joinEvent.name === "/ping" - ) { - return !!this.auth.verifyToken(joinEvent.token)?.sub; - } - - //Retro-compatibility for mobile up to february 2021 (to remove after this date) - if (joinEvent.token === "tdrive") return true; - - const signature = this.auth.verifyTokenObject(joinEvent.token); - - return ( - signature && - signature.name === joinEvent.name && - signature.sub === user.id && - signature.iat > Math.round(new Date().getTime() / 1000) - ); - } catch (err) { - console.log(err); - return false; - } - } - - userCanEmitInRoom = this.userCanJoinRoom; - - async join(websocket: WebSocket, room: string, user: WebSocketUser): Promise { - logger.info(`User ${user.id} is joining room ${room}`); - - try { - await websocket.join(room); - } catch (err) { - if (err) { - logger.error(`Error while joining room ${room}`, err); - this.sendError("join", websocket, { - name: room, - message: "Error while joining room", - }); - return; - } - } - - this.sendSuccess("join", websocket, { name: room }); - logger.info(`User ${user.id} joined room ${room}`); - } - - async leave(websocket: WebSocket, room: string, user: WebSocketUser): Promise { - logger.info(`User ${user.id} is leaving room ${room}`); - - try { - await websocket.leave(room); - } catch (err) { - if (err) { - logger.error(`Error while leaving room ${room}`, err); - this.sendError("leave", websocket, { - name: room, - message: "Error while leaving room", - }); - return; - } - } - - this.sendSuccess("leave", websocket, { name: room }); - logger.info(`User ${user.id} left room ${room}`); - } - - leaveAll(websocket: WebSocket, user: WebSocketUser): void { - logger.info(`Leaving rooms for user ${user.id}`); - websocket.rooms.forEach(room => websocket.leave(room)); - } - - sendError(event: string, websocket: WebSocket, error: JoinLeaveRoomError): void { - websocket.emit(`realtime:${event}:error`, error); - } - - sendSuccess(event: string, websocket: WebSocket, success: JoinLeaveRoomSuccess): void { - websocket.emit(`realtime:${event}:success`, success); - } - - sendEvent(path: string, data: any): void { - this.ws.getIo().to(path).emit("realtime:event", { name: path, data: data }); - } -} diff --git a/tdrive/backend/node/src/core/platform/services/realtime/types.ts b/tdrive/backend/node/src/core/platform/services/realtime/types.ts deleted file mode 100644 index 0c65b111..00000000 --- a/tdrive/backend/node/src/core/platform/services/realtime/types.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { EntityOperationResult } from "../../framework/api/crud-service"; - -export enum RealtimeEntityActionType { - Created = "created", - Saved = "saved", - Updated = "updated", - Deleted = "deleted", - Event = "event", -} - -export interface WebsocketRoomSignature { - name: string; //Ws room name - sub: string; //User id - iat: number; //Deadline -} - -export class ResourcePath { - constructor(readonly path: string[] = ["/"], readonly name: string = "default") {} - - static default(): ResourcePath { - return new ResourcePath(); - } - - static get(path: string | string[]): ResourcePath { - return new ResourcePath(typeof path === "string" ? [path] : path); - } -} -export class RealtimeEntityEvent { - // the type of the resource - type: string; - // the room to push the resource to - room: ResourcePath; - // the unique full path of the resource, ie where we can get it - resourcePath: string | null; - // the input resource - entity: Entity; - // the action result which fired this event - result: EntityOperationResult | null; -} - -export class RealtimeApplicationEvent { - action: "configure" | "close_configure"; - application: unknown; - form: unknown; - hidden_data: unknown; -} - -export class RealtimeBaseBusEvent { - room: string; - type: string; - data: T; -} - -export class RealtimeLocalBusEvent { - event: RealtimeEntityEvent; - topic: string; -} - -export class JoinRoomEvent { - name: string; - token?: string; -} - -export class LeaveRoomEvent { - name: string; -} - -export class ClientEvent { - name: string; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - data: any; -} - -export interface JoinLeaveRoomError { - name: string; - message?: string; - type?: string; -} - -export interface JoinLeaveRoomSuccess { - name: string; - message?: string; -} diff --git a/tdrive/backend/node/src/core/platform/services/websocket/index.ts b/tdrive/backend/node/src/core/platform/services/websocket/index.ts deleted file mode 100644 index 5cce9045..00000000 --- a/tdrive/backend/node/src/core/platform/services/websocket/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Consumes, ServiceName, TdriveService } from "../../framework"; -import WebServerAPI from "../webserver/provider"; -import WebSocketAPI from "./provider"; -import { WebSocketService } from "./services"; -import { AdaptersConfiguration } from "./types"; -import FastifyIO from "fastify-socket.io"; - -@Consumes(["webserver"]) -@ServiceName("websocket") -export default class WebSocket extends TdriveService { - private service: WebSocketService; - name = "websocket"; - version = "1"; - - api(): WebSocketAPI { - return this.service; - } - - async doInit(): Promise { - const webserver = this.context.getProvider("webserver"); - const fastify = webserver.getServer(); - - const options = { - path: this.configuration.get("path", "/socket"), - }; - - fastify.register(FastifyIO, { - ...options, - allowEIO3: true, - cors: { - //Allow all origins - origin: (origin, callback) => callback(null, origin), - credentials: true, - }, - }); - - this.service = new WebSocketService({ - server: fastify, - options, - ready: webserver.onReady.bind(webserver), - adapters: this.configuration.get("adapters"), - auth: this.configuration.get<{ secret: string }>("auth.jwt"), - }); - - return this; - } -} diff --git a/tdrive/backend/node/src/core/platform/services/websocket/provider.ts b/tdrive/backend/node/src/core/platform/services/websocket/provider.ts deleted file mode 100644 index 0d790dfc..00000000 --- a/tdrive/backend/node/src/core/platform/services/websocket/provider.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { EventEmitter } from "events"; -import socketIO from "socket.io"; -import { TdriveServiceProvider } from "../../framework"; -import { User } from "../../../../utils/types"; -import { WebsocketUserEvent, WebSocket, WebSocketUser } from "./types"; - -export default interface WebSocketAPI extends TdriveServiceProvider, EventEmitter { - getIo(): socketIO.Server; - - isConnected(user: User): boolean; - - onUserConnected(listener: (event: WebsocketUserEvent) => void): this; - - onUserDisconnected(listener: (event: WebsocketUserEvent) => void): this; - - getUser(websocket: WebSocket): WebSocketUser; -} diff --git a/tdrive/backend/node/src/core/platform/services/websocket/services/index.ts b/tdrive/backend/node/src/core/platform/services/websocket/services/index.ts deleted file mode 100644 index 8df71288..00000000 --- a/tdrive/backend/node/src/core/platform/services/websocket/services/index.ts +++ /dev/null @@ -1,105 +0,0 @@ -import socketIO from "socket.io"; -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { createClient } = require("redis"); -import SocketIORedis from "@socket.io/redis-adapter"; -import jwt from "jsonwebtoken"; -import WebSocketAPI from "../provider"; -import { - WebSocket, - WebSocketServiceConfiguration, - WebSocketUser, - WebsocketUserEvent, -} from "../types"; -import { EventEmitter } from "events"; -import { User } from "../../../../../utils/types"; -import { JwtType } from "../../types"; - -export class WebSocketService extends EventEmitter implements WebSocketAPI { - version: "1"; - private io: socketIO.Server; - - constructor(serviceConfiguration: WebSocketServiceConfiguration) { - super(); - - serviceConfiguration.ready(() => { - this.io = serviceConfiguration.server.io; - - if (serviceConfiguration.adapters?.types?.includes("redis")) { - const pubClient = createClient(serviceConfiguration.adapters.redis); - const subClient = pubClient.duplicate(); - this.io.adapter(SocketIORedis.createAdapter(pubClient, subClient)); - } - - this.io.on("connection", socket => { - socket.on("authenticate", message => { - if (message.token) { - jwt.verify( - message.token as string, - serviceConfiguration.auth.secret as string, - (err, decoded) => { - if (err) { - socket.emit("unauthorized", { err }); - socket.disconnect(); - return; - } - (socket as unknown as WebSocket).decoded_token = decoded as JwtType; - const user = this.getUser(socket as WebSocket); - - socket.emit("authenticated"); - - socket.on("message", message => { - this.io.emit("message", message); - }); - - this.emit("user:connected", { - user, - socket, - event: "user:connected", - } as WebsocketUserEvent); - - socket.on("disconnect", () => - this.emit("user:disconnected", { - user, - socket, - event: "user:disconnected", - } as WebsocketUserEvent), - ); - }, - ); - } else { - socket.emit("unauthorized", { err: "No token provided" }); - socket.disconnect(); - return; - } - }); - }); - }); - } - - onUserConnected(listener: (event: WebsocketUserEvent) => void): this { - return this.on("user:connected", listener); - } - - onUserDisconnected(listener: (event: WebsocketUserEvent) => void): this { - return this.on("user:disconnected", listener); - } - - getUser(socket: WebSocket): WebSocketUser { - return { - id: socket.decoded_token.sub, - identity_provider_id: socket.decoded_token.provider_id, - email: socket.decoded_token.email, - token: socket.decoded_token, - allow_tracking: socket.decoded_token.track, - }; - } - - getIo(): socketIO.Server { - return this.io; - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - isConnected(user: User): boolean { - return false; - } -} diff --git a/tdrive/backend/node/src/core/platform/services/websocket/types.ts b/tdrive/backend/node/src/core/platform/services/websocket/types.ts deleted file mode 100644 index 6df3dd3d..00000000 --- a/tdrive/backend/node/src/core/platform/services/websocket/types.ts +++ /dev/null @@ -1,39 +0,0 @@ -import socketIO, { Socket } from "socket.io"; -import { RedisAdapterOptions } from "@socket.io/redis-adapter"; -import { User } from "../../../../utils/types"; -import { JwtType } from "../types"; -import { FastifyInstance } from "fastify"; - -export interface AdaptersConfiguration { - types: Array; - redis: RedisAdapterOptions; -} - -export interface WebSocketServiceConfiguration { - server: FastifyInstance; - // eslint-disable-next-line @typescript-eslint/ban-types - ready: Function; - options?: socketIO.ServerOptions | { path: string }; - adapters?: AdaptersConfiguration; - auth?: { secret: string }; -} - -export interface WebSocketUser extends User { - token?: DecodedToken; -} - -export interface WebSockets { - [index: string]: WebSocket[]; -} - -export interface WebSocket extends Socket { - decoded_token: DecodedToken; -} - -export interface WebsocketUserEvent { - event: string; - socket: WebSocket; - user: WebSocketUser; -} - -type DecodedToken = JwtType; diff --git a/tdrive/backend/node/src/services/applications-api/web/controllers/index.ts b/tdrive/backend/node/src/services/applications-api/web/controllers/index.ts index 8f9d5449..1d4459b2 100644 --- a/tdrive/backend/node/src/services/applications-api/web/controllers/index.ts +++ b/tdrive/backend/node/src/services/applications-api/web/controllers/index.ts @@ -1,12 +1,6 @@ import { FastifyInstance, FastifyReply, FastifyRequest } from "fastify"; import _ from "lodash"; -import { v4 } from "uuid"; import { CrudException } from "../../../../core/platform/framework/api/crud-service"; -import { localEventBus } from "../../../../core/platform/framework/event-bus"; -import { - RealtimeApplicationEvent, - RealtimeBaseBusEvent, -} from "../../../../core/platform/services/realtime/types"; import { ResourceGetResponse } from "../../../../utils/types"; import { ApplicationObject, @@ -84,26 +78,6 @@ export class ApplicationsApiController { throw CrudException.forbidden("Application not found"); } - const body = request.body; - - const data = { - action: "configure", - application: { - id: app_id, - identity: application.identity, - }, - form: body.form, - connection_id: body.connection_id, - hidden_data: {}, - configurator_id: v4(), - }; - - localEventBus.publish("realtime:event", { - room: "/me/" + body.user_id, - type: "application", - data, - } as RealtimeBaseBusEvent); - return { status: "ok" }; } diff --git a/tdrive/backend/node/src/services/applications/realtime.ts b/tdrive/backend/node/src/services/applications/realtime.ts deleted file mode 100644 index 074f8a3e..00000000 --- a/tdrive/backend/node/src/services/applications/realtime.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { WebsocketMetadata } from "../../utils/types"; - -export function getCompanyApplicationRooms(companyId: string): WebsocketMetadata[] { - return [ - { - room: getCompanyApplicationRoom(companyId), - }, - ]; -} - -export function getCompanyApplicationRoom(companyApplicationId: string): string { - return `/company-application/${companyApplicationId}`; -} diff --git a/tdrive/backend/node/src/services/applications/web/controllers/company-applications.ts b/tdrive/backend/node/src/services/applications/web/controllers/company-applications.ts index 495fcb41..d318aa06 100644 --- a/tdrive/backend/node/src/services/applications/web/controllers/company-applications.ts +++ b/tdrive/backend/node/src/services/applications/web/controllers/company-applications.ts @@ -10,7 +10,6 @@ import { import { PublicApplicationObject } from "../../entities/application"; import { CompanyExecutionContext } from "../types"; import { CrudController } from "../../../../core/platform/services/webserver/types"; -import { getCompanyApplicationRooms } from "../../realtime"; import gr from "../../../global-resolver"; export class CompanyApplicationController @@ -55,11 +54,6 @@ export class CompanyApplicationController return { resources: resources.getEntities().map(ca => ca.application), next_page_token: resources.nextPage?.page_token, - websockets: - gr.platformServices.realtime.sign( - getCompanyApplicationRooms(request.params.company_id), - context.user.id, - ) || [], }; } } diff --git a/tdrive/backend/node/src/services/documents/services/index.ts b/tdrive/backend/node/src/services/documents/services/index.ts index 8f953b5b..8eef9a4c 100644 --- a/tdrive/backend/node/src/services/documents/services/index.ts +++ b/tdrive/backend/node/src/services/documents/services/index.ts @@ -53,13 +53,8 @@ import { makeStandaloneAccessLevel, getItemScope, } from "./access-check"; -import { websocketEventBus } from "../../../core/platform/services/realtime/bus"; import archiver from "archiver"; import internal from "stream"; -import { - RealtimeEntityActionType, - ResourcePath, -} from "../../../core/platform/services/realtime/types"; import config from "config"; export class DocumentsService { version: "1"; @@ -410,9 +405,6 @@ export class DocumentsService { //TODO[ASH] update item size only for files, there is not need to do during direcotry creation await updateItemSize(driveItem.parent_id, this.repository, context); - //TODO[ASH] there is no need to notify websocket, until we implement user notification - await this.notifyWebsocket(driveItem.parent_id, context); - await globalResolver.platformServices.messageQueue.publish( "services:documents:process", { @@ -681,11 +673,7 @@ export class DocumentsService { await this.update(item.id, item, context); } await updateItemSize(previousParentId, this.repository, context); - - await this.notifyWebsocket(previousParentId, context); } - - await this.notifyWebsocket("trash", context); }; /** @@ -963,19 +951,6 @@ export class DocumentsService { return archive; }; - notifyWebsocket = async (id: string, context: DriveExecutionContext) => { - websocketEventBus.publish(RealtimeEntityActionType.Event, { - type: "documents:updated", - room: ResourcePath.get(`/companies/${context.company.id}/documents/item/${id}`), - entity: { - companyId: context.company.id, - id: id, - }, - resourcePath: null, - result: null, - }); - }; - /** * Search for Drive items. * diff --git a/tdrive/backend/node/src/services/documents/web/controllers/documents.ts b/tdrive/backend/node/src/services/documents/web/controllers/documents.ts index 2a6214b9..125e3f53 100644 --- a/tdrive/backend/node/src/services/documents/web/controllers/documents.ts +++ b/tdrive/backend/node/src/services/documents/web/controllers/documents.ts @@ -5,11 +5,7 @@ import { CrudException, ListResult } from "../../../../core/platform/framework/a import { File } from "../../../../services/files/entities/file"; import { UploadOptions } from "../../../../services/files/types"; import globalResolver from "../../../../services/global-resolver"; -import { - CompanyUserRole, - PaginationQueryParameters, - ResourceWebsocket, -} from "../../../../utils/types"; +import { CompanyUserRole, PaginationQueryParameters } from "../../../../utils/types"; import { DriveFile } from "../../entities/drive-file"; import { FileVersion } from "../../entities/file-version"; import { @@ -160,18 +156,12 @@ export class DocumentsController { Params: ItemRequestParams; Querystring: PaginationQueryParameters & { public_token?: string }; }>, - ): Promise => { + ): Promise => { const context = getDriveExecutionContext(request); const { id } = request.params; return { ...(await globalResolver.services.documents.documents.get(id, context)), - websockets: request.currentUser?.id - ? globalResolver.platformServices.realtime.sign( - [{ room: `/companies/${context.company.id}/documents/item/${id}` }], - request.currentUser?.id, - ) - : [], }; }; @@ -188,7 +178,7 @@ export class DocumentsController { Body: SearchDocumentsBody; Querystring: PaginationQueryParameters & { public_token?: string }; }>, - ): Promise => { + ): Promise => { const context = getDriveExecutionContext(request); const { id } = request.params; @@ -202,7 +192,6 @@ export class DocumentsController { return { ...(await globalResolver.services.documents.documents.browse(id, options, context)), - websockets: [], }; }; diff --git a/tdrive/backend/node/src/services/global-resolver.ts b/tdrive/backend/node/src/services/global-resolver.ts index 8074ced0..31034cac 100644 --- a/tdrive/backend/node/src/services/global-resolver.ts +++ b/tdrive/backend/node/src/services/global-resolver.ts @@ -9,12 +9,10 @@ import { DatabaseServiceAPI } from "../core/platform/services/database/api"; import EmailPusherAPI from "../core/platform/services/email-pusher/provider"; import { MessageQueueServiceAPI } from "../core/platform/services/message-queue/api"; import { PushServiceAPI } from "../core/platform/services/push/api"; -import { RealtimeServiceAPI } from "../core/platform/services/realtime/api"; import { SearchServiceAPI } from "../core/platform/services/search/api"; import StorageAPI from "../core/platform/services/storage/provider"; import TrackerAPI from "../core/platform/services/tracker/provider"; import WebServerAPI from "../core/platform/services/webserver/provider"; -import WebSocketAPI from "../core/platform/services/websocket/provider"; import assert from "assert"; import { logger } from "../core/platform/framework"; @@ -42,12 +40,10 @@ type PlatformServices = { cron: CronAPI; messageQueue: MessageQueueServiceAPI; push: PushServiceAPI; - realtime: RealtimeServiceAPI; search: SearchServiceAPI; storage: StorageAPI; tracker: TrackerAPI; webserver: WebServerAPI; - websocket: WebSocketAPI; emailPusher: EmailPusherAPI; }; @@ -96,12 +92,10 @@ class GlobalResolver { cron: platform.getProvider("cron"), messageQueue: platform.getProvider("message-queue"), push: platform.getProvider("push"), - realtime: platform.getProvider("realtime"), search: platform.getProvider("search"), storage: platform.getProvider("storage"), tracker: platform.getProvider("tracker"), webserver: platform.getProvider("webserver"), - websocket: platform.getProvider("websocket"), emailPusher: platform.getProvider("email-pusher"), }; diff --git a/tdrive/backend/node/src/services/user/realtime.ts b/tdrive/backend/node/src/services/user/realtime.ts deleted file mode 100644 index f7f131a3..00000000 --- a/tdrive/backend/node/src/services/user/realtime.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { WebsocketMetadata } from "../../utils/types"; -import CompanyEntity from "./entities/company"; -import UserEntity from "./entities/user"; - -/** - * User Rooms - */ -export function getUserRooms(user: UserEntity): WebsocketMetadata[] { - return [ - { - room: getUserRoom(user.id), - }, - ]; -} - -export function getUserRoom(userId: string): string { - return `/me/${userId}`; -} - -export function getPublicUserRoom(userId: string): string { - return `/users/${userId}`; -} - -export function getUserName(userId: string): string { - return `user-room-${userId}`; -} - -/** - * Company Rooms - */ -export function getCompanyRooms(company: CompanyEntity): WebsocketMetadata[] { - return [ - { - room: getCompanyRoom(company.id), - }, - ]; -} - -export function getCompanyRoom(companyId: string): string { - return `/company/${companyId}`; -} - -export function getCompanyName(companyId: string): string { - return `company-room-${companyId}`; -} diff --git a/tdrive/backend/node/src/services/user/services/companies.ts b/tdrive/backend/node/src/services/user/services/companies.ts index f4265c5f..143d54d4 100644 --- a/tdrive/backend/node/src/services/user/services/companies.ts +++ b/tdrive/backend/node/src/services/user/services/companies.ts @@ -30,8 +30,7 @@ import ExternalGroup, { ExternalGroupPrimaryKey, getInstance as getExternalGroupInstance, } from "../entities/external_company"; -import { logger, RealtimeSaved } from "../../../core/platform/framework"; -import { getCompanyRoom, getUserRoom } from "../realtime"; +import { logger } from "../../../core/platform/framework"; import gr from "../../global-resolver"; import { localEventBus } from "../../../core/platform/framework/event-bus"; @@ -59,15 +58,6 @@ export class CompanyServiceImpl { return this.externalCompanyRepository.findOne(pk, {}, context); } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - @RealtimeSaved((company, _context) => { - return [ - { - room: getCompanyRoom(company.id), - resource: company, - }, - ]; - }) async updateCompany( company: Company, // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -186,14 +176,6 @@ export class CompanyServiceImpl { ); } - @RealtimeSaved((companyUser, _) => { - return [ - { - room: getUserRoom(companyUser?.user_id), - resource: companyUser, - }, - ]; - }) async removeUserFromCompany( companyPk: CompanyPrimaryKey, userPk: UserPrimaryKey, @@ -249,14 +231,6 @@ export class CompanyServiceImpl { return new DeleteResult("company", instance, !!instance); } - @RealtimeSaved((companyUser, _) => { - return [ - { - room: getUserRoom(companyUser?.user_id), - resource: companyUser, - }, - ]; - }) async setUserRole( companyId: uuid, userId: uuid, diff --git a/tdrive/backend/node/src/services/user/services/users/service.ts b/tdrive/backend/node/src/services/user/services/users/service.ts index 07f61999..d7209166 100644 --- a/tdrive/backend/node/src/services/user/services/users/service.ts +++ b/tdrive/backend/node/src/services/user/services/users/service.ts @@ -28,11 +28,8 @@ import assert from "assert"; import { localEventBus } from "../../../../core/platform/framework/event-bus"; import { ResourceEventsPayload } from "../../../../utils/types"; import { isNumber, isString } from "lodash"; -import { RealtimeSaved } from "../../../../core/platform/framework"; -import { getPublicUserRoom, getUserRoom } from "../../realtime"; import NodeCache from "node-cache"; import gr from "../../../global-resolver"; -import { formatUser } from "../../../../utils/users"; import { TYPE as DriveFileType, DriveFile } from "../../../documents/entities/drive-file"; export class UserServiceImpl { @@ -99,34 +96,11 @@ export class UserServiceImpl { throw new Error("Method not implemented."); } - @RealtimeSaved((user, _context) => { - return [ - { - room: getPublicUserRoom(user.id), - resource: user, - }, - ]; - }) - async publishPublicUserRealtime(userId: string): Promise { - const user = await this.get({ id: userId }); - new SaveResult("user", formatUser(user, { includeCompanies: true }), OperationType.UPDATE); - } - - @RealtimeSaved((user, _context) => { - return [ - { - room: getUserRoom(user.id), - resource: formatUser(user), // FIX ME we should formatUser here - }, - ]; - }) async save(user: User, context?: ExecutionContext): Promise> { this.assignDefaults(user); await this.repository.save(user, context); await this.updateExtRepository(user); - await this.publishPublicUserRealtime(user.id); - return new SaveResult("user", user, OperationType.UPDATE); } diff --git a/tdrive/backend/node/src/services/user/web/controller.ts b/tdrive/backend/node/src/services/user/web/controller.ts index 2d28fc16..e3b8462e 100644 --- a/tdrive/backend/node/src/services/user/web/controller.ts +++ b/tdrive/backend/node/src/services/user/web/controller.ts @@ -20,19 +20,18 @@ import { CompanyParameters, CompanyStatsObject, CompanyUserObject, + CompanyUsersParameters, DeregisterDeviceParams, RegisterDeviceBody, RegisterDeviceParams, UserListQueryParameters, UserObject, UserParameters, - CompanyUsersParameters, UserQuota, } from "./types"; import Company from "../entities/company"; import CompanyUser from "../entities/company_user"; import coalesce from "../../../utils/coalesce"; -import { getCompanyRooms, getUserRooms } from "../realtime"; import { formatCompany, getCompanyStats } from "../utils"; import { formatUser } from "../../../utils/users"; import gr from "../../global-resolver"; @@ -70,9 +69,6 @@ export class UsersCrudController return { resource: userObject, - websocket: context.user.id - ? gr.platformServices.realtime.sign(getUserRooms(user), context.user.id)[0] - : undefined, }; } @@ -100,11 +96,7 @@ export class UsersCrudController async setPreferences( request: FastifyRequest<{ Body: User["preferences"] }>, ): Promise { - const preferences = await gr.services.users.setPreferences( - { id: request.currentUser.id }, - request.body, - ); - return preferences; + return await gr.services.users.setPreferences({ id: request.currentUser.id }, request.body); } async list( @@ -143,7 +135,6 @@ export class UsersCrudController // return users; return { resources: resUsers, - websockets: gr.platformServices.realtime.sign([], context.user.id), }; } @@ -220,7 +211,6 @@ export class UsersCrudController return { resources: combos.map(combo => formatCompany(...combo)), - websockets: gr.platformServices.realtime.sign([], context.user.id), }; } @@ -253,9 +243,6 @@ export class UsersCrudController companyUserObj, getCompanyStats(company, await gr.services.statistics.get(company.id, "messages")), ), - websocket: context.user?.id - ? gr.platformServices.realtime.sign(getCompanyRooms(company), context.user.id)[0] - : undefined, }; } diff --git a/tdrive/backend/node/src/services/user/web/schemas.ts b/tdrive/backend/node/src/services/user/web/schemas.ts index e61ba49d..bb3e2fbb 100644 --- a/tdrive/backend/node/src/services/user/web/schemas.ts +++ b/tdrive/backend/node/src/services/user/web/schemas.ts @@ -1,4 +1,3 @@ -import { webSocketSchema } from "../../../utils/types"; import { CompanyFeaturesEnum, CompanyLimitsEnum } from "./types"; export const userObjectSchema = { @@ -126,7 +125,6 @@ export const getUserSchema = { type: "object", properties: { resource: userObjectSchema, - websocket: webSocketSchema, }, required: ["resource"], }, @@ -231,7 +229,6 @@ export const getCompanySchema = { type: "object", properties: { resource: companyObjectSchema, - websocket: webSocketSchema, }, required: ["resource"], }, diff --git a/tdrive/backend/node/src/services/workspaces/realtime.ts b/tdrive/backend/node/src/services/workspaces/realtime.ts deleted file mode 100644 index da0c44fd..00000000 --- a/tdrive/backend/node/src/services/workspaces/realtime.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { WebsocketMetadata } from "../../utils/types"; -import Workspace from "./entities/workspace"; -import { WorkspaceExecutionContext } from "./types"; - -export function getWebsocketInformation(workspace: Workspace): WebsocketMetadata { - return { - name: workspace.name, - room: getWorkspacePath(workspace), - }; -} - -export function getWorkspaceRooms(context: WorkspaceExecutionContext): WebsocketMetadata[] { - return [ - { - name: "workspaces", - room: getRoomName(context), - }, - ]; -} - -export function getRoomName(context: Pick): string { - return `/companies/${context.company_id}/workspaces`; -} - -export function getWorkspacePath( - workspace: Pick, - context?: WorkspaceExecutionContext, -): string { - return `/companies/${context?.company_id}/workspaces/${workspace.id}`; -} diff --git a/tdrive/backend/node/src/services/workspaces/services/workspace.ts b/tdrive/backend/node/src/services/workspaces/services/workspace.ts index 6333d3aa..5353c73a 100644 --- a/tdrive/backend/node/src/services/workspaces/services/workspace.ts +++ b/tdrive/backend/node/src/services/workspaces/services/workspace.ts @@ -41,13 +41,7 @@ import { WorkspaceCounterPrimaryKey, } from "../entities/workspace_counters"; import { countRepositoryItems } from "../../../utils/counters"; -import { - Initializable, - RealtimeSaved, - TdriveServiceProvider, -} from "../../../core/platform/framework"; -import { ResourcePath } from "../../../core/platform/services/realtime/types"; -import { getRoomName, getWorkspacePath } from "../realtime"; +import { Initializable, TdriveServiceProvider } from "../../../core/platform/framework"; import { InviteTokenObject, WorkspaceInviteTokenObject } from "../web/types"; import WorkspaceInviteTokens, { getInstance as getWorkspaceInviteTokensInstance, @@ -149,15 +143,6 @@ export class WorkspaceServiceImpl implements TdriveServiceProvider, Initializabl return new CreateResult(TYPE, created.entity); } - // TODO: remove logic from context - @RealtimeSaved((workspace, context) => [ - { - // FIXME: For now the room is defined at the company level - // It meay be good to have a special room where just some users are receiving this event - room: ResourcePath.get(getRoomName(workspace)), - path: getWorkspacePath(workspace, context as WorkspaceExecutionContext), - }, - ]) async save( item: Partial, options?: SaveOptions & { logo_b64?: string }, diff --git a/tdrive/backend/node/src/services/workspaces/web/controllers/workspaces.ts b/tdrive/backend/node/src/services/workspaces/web/controllers/workspaces.ts index 4f1f29e0..2fcb0f6d 100644 --- a/tdrive/backend/node/src/services/workspaces/web/controllers/workspaces.ts +++ b/tdrive/backend/node/src/services/workspaces/web/controllers/workspaces.ts @@ -19,7 +19,6 @@ import { WorkspaceExecutionContext } from "../../types"; import { plainToClass } from "class-transformer"; import { hasCompanyAdminLevel, hasCompanyMemberLevel } from "../../../../utils/company"; import { hasWorkspaceAdminLevel } from "../../../../utils/workspace"; -import { getWorkspaceRooms } from "../../realtime"; import { CrudException, ExecutionContext, @@ -166,7 +165,6 @@ export class WorkspacesCrudController this.formatWorkspace(ws, await this.getWorkspaceUsersCount(ws.id), context.user.id), ), ), - websockets: gr.platformServices.realtime.sign(getWorkspaceRooms(context), context.user.id), }; } diff --git a/tdrive/backend/node/src/services/workspaces/web/schemas.ts b/tdrive/backend/node/src/services/workspaces/web/schemas.ts index 2e2d9543..88c2ef1d 100644 --- a/tdrive/backend/node/src/services/workspaces/web/schemas.ts +++ b/tdrive/backend/node/src/services/workspaces/web/schemas.ts @@ -1,4 +1,3 @@ -import { webSocketSchema } from "../../../utils/types"; import { companyObjectSchema, userObjectSchema } from "../../user/web/schemas"; const workspaceObjectSchema = { @@ -35,7 +34,6 @@ export const getWorkspacesSchema = { type: "object", properties: { resources: { type: "array", items: workspaceObjectSchema }, - websockets: { type: "array", items: webSocketSchema }, }, required: ["resources"], }, diff --git a/tdrive/backend/node/src/utils/types.ts b/tdrive/backend/node/src/utils/types.ts index 50a6c917..2061fb0a 100644 --- a/tdrive/backend/node/src/utils/types.ts +++ b/tdrive/backend/node/src/utils/types.ts @@ -32,51 +32,28 @@ export interface User { public_token_document_id?: string; } -export const webSocketSchema = { - type: "object", - properties: { - name: { type: "string" }, - room: { type: "string" }, - token: { type: "string" }, - }, -}; - export interface Channel extends Workspace { id: string; } -export enum ChannelType { - DIRECT = "direct", -} - export interface Workspace { company_id: string; workspace_id: string; } -export interface WebsocketMetadata { - room: string; - name?: string; - token?: string; -} - export class ResourceListResponse { resources: T[]; - websockets?: ResourceWebsocket[]; next_page_token?: string; total?: number; } export class ResourceGetResponse { - websocket?: ResourceWebsocket; resource: T; } export class ResourceUpdateResponse { - websocket?: ResourceWebsocket; resource: T; } export class ResourceCreateResponse { - websocket?: ResourceWebsocket; resource: T; } @@ -84,16 +61,7 @@ export class ResourceDeleteResponse { status: DeleteStatus; } -export interface ResourceListQueryParameters extends PaginationQueryParameters { - search_query?: string; - mine?: boolean; -} - export declare type DeleteStatus = "success" | "error"; -export interface ResourceWebsocket { - room: string; - token?: string; -} export interface ResourceEventsPayload { user: User; @@ -104,21 +72,11 @@ export interface ResourceEventsPayload { workspace?: WorkspacePrimaryKey; } -export interface DocumentEventsPayload { - user: User; - actor?: User; - document?: { - sender: string; - }; - company?: { id: string }; -} - export interface PaginationQueryParameters { // It is offset for MongoDB and pointer to the next page for ScyllaDB page_token?: string; // Page size limit?: string; - websockets?: boolean; } export interface AccessToken { diff --git a/tdrive/backend/node/test/e2e/documents/documents-browser.spec.ts b/tdrive/backend/node/test/e2e/documents/documents-browser.spec.ts index c132ac2e..f602ca11 100644 --- a/tdrive/backend/node/test/e2e/documents/documents-browser.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/documents-browser.spec.ts @@ -19,7 +19,6 @@ describe("The Documents Browser Window and API", () => { "user", "files", "auth", - "realtime", "statistics", "platform-services", "documents", diff --git a/tdrive/backend/node/test/e2e/documents/documents-notifications.spec.ts b/tdrive/backend/node/test/e2e/documents/documents-notifications.spec.ts index 6470bf11..b02b48cf 100644 --- a/tdrive/backend/node/test/e2e/documents/documents-notifications.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/documents-notifications.spec.ts @@ -28,10 +28,8 @@ describe("the Drive feature", () => { "user", "search", "files", - "websocket", "messages", "auth", - "realtime", "channels", "counter", "statistics", diff --git a/tdrive/backend/node/test/e2e/documents/documents-quota.spec.ts b/tdrive/backend/node/test/e2e/documents/documents-quota.spec.ts index a3f14329..a3894a62 100644 --- a/tdrive/backend/node/test/e2e/documents/documents-quota.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/documents-quota.spec.ts @@ -45,10 +45,8 @@ describe("the Drive feature", () => { "user", "search", "files", - "websocket", "messages", "auth", - "realtime", "channels", "counter", "statistics", diff --git a/tdrive/backend/node/test/e2e/documents/documents-search.spec.ts b/tdrive/backend/node/test/e2e/documents/documents-search.spec.ts index 78404b9e..d002d340 100644 --- a/tdrive/backend/node/test/e2e/documents/documents-search.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/documents-search.spec.ts @@ -25,10 +25,8 @@ describe("the Drive Search feature", () => { "user", "search", "files", - "websocket", "messages", "auth", - "realtime", "channels", "statistics", "platform-services", diff --git a/tdrive/backend/node/test/e2e/documents/documents-tab.spec.ts b/tdrive/backend/node/test/e2e/documents/documents-tab.spec.ts index e5b1fe57..ee4099fb 100644 --- a/tdrive/backend/node/test/e2e/documents/documents-tab.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/documents-tab.spec.ts @@ -39,10 +39,8 @@ describe("the Drive Tdrive tabs feature", () => { "user", "search", "files", - "websocket", "messages", "auth", - "realtime", "channels", "counter", "statistics", diff --git a/tdrive/backend/node/test/e2e/documents/documents.spec.ts b/tdrive/backend/node/test/e2e/documents/documents.spec.ts index 1ebcb5f0..98788bbc 100644 --- a/tdrive/backend/node/test/e2e/documents/documents.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/documents.spec.ts @@ -32,10 +32,8 @@ describe("the Drive feature", () => { "user", "search", "files", - "websocket", "messages", "auth", - "realtime", "channels", "counter", "statistics", diff --git a/tdrive/backend/node/test/e2e/documents/my-drive.spec.ts b/tdrive/backend/node/test/e2e/documents/my-drive.spec.ts index 1313a7a7..c9da81d1 100644 --- a/tdrive/backend/node/test/e2e/documents/my-drive.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/my-drive.spec.ts @@ -44,10 +44,8 @@ describe("the My Drive feature", () => { "user", "search", "files", - "websocket", "messages", "auth", - "realtime", "channels", "counter", "statistics", diff --git a/tdrive/backend/node/test/e2e/documents/public-links.spec.ts b/tdrive/backend/node/test/e2e/documents/public-links.spec.ts index 22a52471..4ab025ed 100644 --- a/tdrive/backend/node/test/e2e/documents/public-links.spec.ts +++ b/tdrive/backend/node/test/e2e/documents/public-links.spec.ts @@ -44,10 +44,8 @@ describe("the public links feature", () => { "user", "search", "files", - "websocket", "messages", "auth", - "realtime", "channels", "counter", "statistics", diff --git a/tdrive/backend/node/test/e2e/setup/test.json b/tdrive/backend/node/test/e2e/setup/test.json index c12ad975..5fff9efe 100644 --- a/tdrive/backend/node/test/e2e/setup/test.json +++ b/tdrive/backend/node/test/e2e/setup/test.json @@ -12,16 +12,6 @@ "endpoint": "http://localhost:9200" } }, - "websocket": { - "path": "/socket", - "adapters": { - "types": ["redis"], - "redis": { - "host": "localhost", - "port": 6379 - } - } - }, "auth": { "jwt": { "secret": "supersecret" diff --git a/tdrive/backend/node/test/e2e/users/users.quota.spec.ts b/tdrive/backend/node/test/e2e/users/users.quota.spec.ts index b1aea3ce..2bd7947d 100644 --- a/tdrive/backend/node/test/e2e/users/users.quota.spec.ts +++ b/tdrive/backend/node/test/e2e/users/users.quota.spec.ts @@ -22,7 +22,6 @@ describe("The /users/quota API", () => { "database", "search", "message-queue", - "websocket", "applications", "webserver", "user", diff --git a/tdrive/backend/node/test/e2e/users/users.search.spec.ts b/tdrive/backend/node/test/e2e/users/users.search.spec.ts index a4cde316..ece0d9c8 100644 --- a/tdrive/backend/node/test/e2e/users/users.search.spec.ts +++ b/tdrive/backend/node/test/e2e/users/users.search.spec.ts @@ -13,7 +13,6 @@ describe("The /users API", () => { "database", "search", "message-queue", - "websocket", "webserver", "user", "auth", diff --git a/tdrive/backend/node/test/e2e/users/users.spec.ts b/tdrive/backend/node/test/e2e/users/users.spec.ts index 8339b0dc..2f116699 100644 --- a/tdrive/backend/node/test/e2e/users/users.spec.ts +++ b/tdrive/backend/node/test/e2e/users/users.spec.ts @@ -27,7 +27,6 @@ describe("The /users API", () => { "database", "search", "message-queue", - "websocket", "applications", "webserver", "user", diff --git a/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/created.test.ts b/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/created.test.ts deleted file mode 100644 index 177b91ef..00000000 --- a/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/created.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { describe, expect, it, jest } from "@jest/globals"; -import { CreateResult } from "../../../../../../../src/core/platform/framework/api/crud-service"; -import { RealtimeCreated } from "../../../../../../../src/core/platform/framework/decorators"; -import { websocketEventBus } from "../../../../../../../src/core/platform/services/realtime/bus"; -import { ResourcePath } from "../../../../../../../src/core/platform/services/realtime/types"; - -describe("The RealtimeCreated decorator", () => { - it("should call the original method send back original result but do not emit event if result type is wrong", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeCreated({ room: "/foo/bar" }) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - reverseMeBaby(input: string): Promise { - return Promise.resolve(input.split("").reverse().join("")); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(0); - - emitSpy.mockRestore(); - - }); - - it("should call the original method send back original result and emit event", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeCreated({ room: "/foo/bar", path: "/foo/bar/baz" }) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - async reverseMeBaby(input: string): Promise> { - return new CreateResult("string", input.split("").reverse().join("")); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result.entity).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(1); - expect(emitSpy).toHaveBeenCalledWith("created", { - room: { - name: "default", - path: ["/foo/bar"], - } as ResourcePath, - resourcePath: "/foo/bar/baz", - entity: "oloy", - type: "string", - result: { - entity: "oloy", - type: "string", - context: undefined, - operation: "create", - raw: undefined, - } as CreateResult, - }); - - emitSpy.mockRestore(); - - }); - - it("should emit event with path computed from function", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeCreated(input => [ - { room: ResourcePath.get(`/foo/bar/${input}`), path: "/foo/bar/baz" }, - ]) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - async reverseMeBaby(input: string): Promise> { - return new CreateResult("string", input.split("").reverse().join("")); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result.entity).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(1); - expect(emitSpy).toHaveBeenCalledWith("created", { - room: { - name: "default", - path: ["/foo/bar/oloy"], - } as ResourcePath, - resourcePath: "/foo/bar/baz", - entity: "oloy", - type: "string", - result: { - entity: "oloy", - context: undefined, - operation: "create", - type: "string", - raw: undefined, - } as CreateResult, - }); - - emitSpy.mockRestore(); - - }); -}); diff --git a/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/deleted.test.ts b/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/deleted.test.ts deleted file mode 100644 index 42b2f27f..00000000 --- a/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/deleted.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { describe, expect, it, jest } from "@jest/globals"; -import { DeleteResult } from "../../../../../../../src/core/platform/framework/api/crud-service"; -import { RealtimeDeleted } from "../../../../../../../src/core/platform/framework/decorators"; -import { websocketEventBus } from "../../../../../../../src/core/platform/services/realtime/bus"; -import { ResourcePath } from "../../../../../../../src/core/platform/services/realtime/types"; - -describe("The RealtimeDeleted decorator", () => { - it("should call the original method send back original result but do not emit event if result type is wrong", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeDeleted({ room: "/foo/bar" }) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - reverseMeBaby(input: string): Promise { - return Promise.resolve(input.split("").reverse().join("")); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(0); - - emitSpy.mockRestore(); - - }); - - it("should call the original method send back original result and emit event", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeDeleted({ room: "/foo/bar", path: "/foo/bar/baz" }) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - async reverseMeBaby(input: string): Promise> { - return new DeleteResult("string", input.split("").reverse().join(""), true); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result.entity).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(1); - expect(emitSpy).toHaveBeenCalledWith("deleted", { - room: { - name: "default", - path: ["/foo/bar"], - } as ResourcePath, - resourcePath: "/foo/bar/baz", - entity: "oloy", - type: "string", - result: { - entity: "oloy", - context: undefined, - operation: "delete", - deleted: true, - type: "string", - } as DeleteResult, - }); - - emitSpy.mockRestore(); - - }); - - it("should emit event with path computed from function", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeDeleted(result => [ - { room: ResourcePath.get(`/foo/bar/${result}`), path: "/foo/bar/baz" }, - ]) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - async reverseMeBaby(input: string): Promise> { - return new DeleteResult("string", input.split("").reverse().join(""), true); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result.entity).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(1); - expect(emitSpy).toHaveBeenCalledWith("deleted", { - room: { - name: "default", - path: ["/foo/bar/oloy"], - } as ResourcePath, - resourcePath: "/foo/bar/baz", - entity: "oloy", - type: "string", - result: { - entity: "oloy", - context: undefined, - operation: "delete", - deleted: true, - type: "string", - } as DeleteResult, - }); - - emitSpy.mockRestore(); - - }); -}); diff --git a/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/updated.test.ts b/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/updated.test.ts deleted file mode 100644 index 51de6176..00000000 --- a/tdrive/backend/node/test/unit/core/platform/framework/decorators/realtime/updated.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { describe, expect, it, jest } from "@jest/globals"; -import { UpdateResult } from "../../../../../../../src/core/platform/framework/api/crud-service"; -import { RealtimeUpdated } from "../../../../../../../src/core/platform/framework/decorators"; -import { websocketEventBus } from "../../../../../../../src/core/platform/services/realtime/bus"; -import { ResourcePath } from "../../../../../../../src/core/platform/services/realtime/types"; - -describe("The RealtimeUpdated decorator", () => { - it("should call the original method send back original result but do not emit event if result type is wrong", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeUpdated({ room: "/foo/bar" }) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - reverseMeBaby(input: string): Promise { - return Promise.resolve(input.split("").reverse().join("")); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(0); - - emitSpy.mockRestore(); - - }); - - it("should call the original method send back original result and emit event", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeUpdated({ room: "/foo/bar", path: "/foo/bar/baz" }) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - async reverseMeBaby(input: string): Promise> { - return new UpdateResult("string", input.split("").reverse().join("")); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result.entity).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(1); - expect(emitSpy).toHaveBeenCalledWith("updated", { - entity: "oloy", - room: { - name: "default", - path: ["/foo/bar"], - } as ResourcePath, - resourcePath: "/foo/bar/baz", - type: "string", - result: { - type: "string", - entity: "oloy", - affected: undefined, - context: undefined, - operation: "update", - raw: undefined, - } as UpdateResult, - }); - - emitSpy.mockRestore(); - - }); - - it("should emit event with path computed from function", async () => { - const emitSpy = jest.spyOn(websocketEventBus, "emit"); - - class TestMe { - @RealtimeUpdated(result => [ - { room: ResourcePath.get(`/foo/bar/${result}`), path: "/foo/bar/baz" }, - ]) - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - async reverseMeBaby(input: string): Promise> { - return new UpdateResult("string", input.split("").reverse().join("")); - } - } - - const test = new TestMe(); - const originalSpy = jest.spyOn(test, "reverseMeBaby"); - const result = await test.reverseMeBaby("yolo"); - - expect(result.entity).toEqual("oloy"); - expect(originalSpy).toHaveBeenCalledTimes(1); - expect(originalSpy).toHaveBeenCalledWith("yolo"); - expect(emitSpy).toHaveBeenCalledTimes(1); - expect(emitSpy).toHaveBeenCalledWith("updated", { - entity: "oloy", - room: { - name: "default", - path: ["/foo/bar/oloy"], - } as ResourcePath, - resourcePath: "/foo/bar/baz", - type: "string", - result: { - type: "string", - context: undefined, - operation: "update", - entity: "oloy", - affected: undefined, - raw: undefined, - } as UpdateResult, - }); - - emitSpy.mockRestore(); - - }); -});