1
0
Fork 0
cc-server-parent/packages/ws/src/builder.ts

95 lines
3.7 KiB
TypeScript

import "reflect-metadata";
import * as io from 'socket.io'
import { Container } from 'inversify'
import { TYPE } from './constants'
import { interfaces, Message, BroadcastMessage } from './interfaces'
import { getNamespaces, getNamespaceMetadata, getNamespaceListenerMetadata } from './utils'
export function buildWebSocket(container: Container, server: io.Server) {
let constructors = getNamespaces();
if (!constructors.length) { return; }
registryNamespace(container, constructors);
// get all namespaces
let namespaces = container.getAll<interfaces.Namespace>(TYPE.Namespace)
for (const namespace of namespaces) {
let namespaceMetadata = getNamespaceMetadata(namespace);
let namespaceEventMetadata = getNamespaceListenerMetadata(namespace);
let ns = server.of(namespaceMetadata.name);
namespace.constructor.prototype.nsp = ns;
applyNamespaceMiddleware(namespaceMetadata, ns);
ns.on('connection', async (socket: io.Socket) => {
let namespaceInstance = container.getNamed<interfaces.Namespace>(TYPE.Namespace, namespace.constructor.name);
await applyEvent(namespaceInstance, socket);
await applyMiddlewares(namespaceEventMetadata, socket);
await applyListeners(namespaceEventMetadata, socket, namespaceInstance);
})
}
}
function registryNamespace(container: Container, constructors: any[]) {
constructors.forEach((constructor) => {
const name = constructor.name;
if (container.isBoundNamed(TYPE.Namespace, name)) {
throw new Error(`DUPLICATED_NAMESPACE(${name})`);
}
container.bind(TYPE.Namespace)
.to(constructor)
.whenTargetNamed(name);
});
}
function applyNamespaceMiddleware(namespaceMetadata: interfaces.NamespaceMetadata, ns: io.Namespace) {
for (const middleware of namespaceMetadata.middleware) {
ns.use(middleware);
}
}
function flatten(arr: Array<any>) {
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
function applyMiddlewares(namespaceEventMetadata: interfaces.ListenerMetadata[], socket: io.Socket) {
let middlewares = [...new Set(flatten(namespaceEventMetadata.map((data) => data.middleware)))];
for (const middleware of middlewares) {
socket.use((packet: io.Packet, next: (err?: any) => void) => { middleware(socket, packet, next); });
}
}
async function applyEvent(namespaceInstance: interfaces.Namespace, socket: io.Socket) {
if (namespaceInstance.connection) {
let result = await namespaceInstance.connection(socket);
if (result != undefined) {
socket.send(result);
}
}
socket.on('disconnect', async () => {
await namespaceInstance.defers.forEach(defer => defer(socket));
if (namespaceInstance.disconnect) {
await namespaceInstance.disconnect(socket);
}
});
}
function applyListeners(namespaceEventMetadata: interfaces.ListenerMetadata[], socket: io.Socket, namespaceInstance: interfaces.Namespace) {
for (const event of namespaceEventMetadata) {
socket.on(event.name, async data => {
let result = await namespaceInstance[event.key](socket, data);
if (result != undefined) {
if (result instanceof Message) {
if (result instanceof BroadcastMessage) {
socket.broadcast.emit(result.event || event.name, result.message);
} else {
socket.emit(result.event || event.name, result.message);
}
} else {
socket.emit(event.name, result);
}
}
});
}
}