import { Injectable } from '@nestjs/common' import { Subscriber } from 'rxjs' import { In } from 'typeorm' import { ROOT_ROLE_ID } from '~/constants/system.constant' import { RoleEntity } from '~/modules/system/role/role.entity' import { UserEntity } from '~/modules/user/user.entity' export interface MessageEvent { data?: string | object id?: string type?: 'ping' | 'close' | 'updatePermsAndMenus' retry?: number } const clientMap: Map<number, Subscriber<MessageEvent>> = new Map() @Injectable() export class SseService { addClient(uid: number, subscriber: Subscriber<MessageEvent>) { clientMap.set(uid, subscriber) } removeClient(uid: number): void { const client = clientMap.get(uid) client?.complete() clientMap.delete(uid) } sendToClient(uid: number, data: MessageEvent): void { const client = clientMap.get(uid) client?.next?.(data) } sendToAll(data: MessageEvent): void { clientMap.forEach((client) => { client.next(data) }) } /** * 通知前端重新获取权限菜单 * @param uid * @constructor */ async noticeClientToUpdateMenusByUserIds(uid: number | number[]) { const userIds = [].concat(uid) as number[] userIds.forEach((uid) => { this.sendToClient(uid, { type: 'updatePermsAndMenus' }) }) } /** * 通过menuIds通知用户更新权限菜单 */ async noticeClientToUpdateMenusByMenuIds(menuIds: number[]): Promise<void> { const roleMenus = await RoleEntity.find({ where: { menus: { id: In(menuIds), }, }, }) const roleIds = roleMenus.map(n => n.id).concat(ROOT_ROLE_ID) await this.noticeClientToUpdateMenusByRoleIds(roleIds) } /** * 通过roleIds通知用户更新权限菜单 */ async noticeClientToUpdateMenusByRoleIds(roleIds: number[]): Promise<void> { const users = await UserEntity.find({ where: { roles: { id: In(roleIds), }, }, }) if (users) { const userIds = users.map(n => n.id) await this.noticeClientToUpdateMenusByUserIds(userIds) } } }