Skip to content

Commit

Permalink
feat(@artusx/plugin-socketio): support nsp and event decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
thonatos committed May 29, 2024
1 parent 039c7ef commit f6644df
Show file tree
Hide file tree
Showing 10 changed files with 148 additions and 30 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'path';
import { ArtusXConfig, NunjucksConfigureOptions } from '@artusx/core';
import { SocketIOServerConfig } from '@artusx/plugin-socketio';
import type { SocketIOServerConfig } from '@artusx/plugin-socketio';

export default () => {
const artusx: ArtusXConfig = {
Expand Down
20 changes: 20 additions & 0 deletions packages/apps/artusx-websocket/src/io/default.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Inject } from '@artusx/core';
import { PluginInjectEnum } from '@artusx/utils';
import { SocketIOServer, Namespace, Event } from '@artusx/plugin-socketio';

@Namespace('/')
export default class DefaultNamespace {
@Inject(PluginInjectEnum.SocketIO)
io: SocketIOServer;

@Event('disconnect')
disconnect() {
console.log('user disconnected');
}

@Event('chat_message')
chat_message(msg: any) {
console.log('chat_message.msg', msg);
this.io.emit('chat_message', msg);
}
}
17 changes: 6 additions & 11 deletions packages/apps/artusx-websocket/src/lifecycle.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { PluginInjectEnum } from '@artusx/utils';

import {
ApplicationLifecycle,
ArtusApplication,
Expand All @@ -6,29 +8,22 @@ import {
LifecycleHookUnit,
LifecycleHook,
} from '@artusx/core';
import { PluginInjectEnum } from '@artusx/utils';
import Server from '@artusx/plugin-socketio/server';

import { SocketIOServer } from '@artusx/plugin-socketio';

@LifecycleHookUnit()
export default class PluginLifecycle implements ApplicationLifecycle {
@Inject(ArtusInjectEnum.Application)
app: ArtusApplication;

@Inject(PluginInjectEnum.SocketIO)
io: Server;
io: SocketIOServer;

@LifecycleHook()
async willReady() {
const io = this.io;
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});

socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
console.log('lifecycle:io:connection', socket.id);
});
}
}
5 changes: 3 additions & 2 deletions packages/apps/artusx-websocket/src/view/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,13 @@
form.addEventListener('submit', (e) => {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
socket.emit('chat_message', input.value);
input.value = '';
}
});

socket.on('chat message', (msg) => {
socket.on('chat_message', (msg) => {
console.log('chat_message', msg);
const item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
Expand Down
14 changes: 11 additions & 3 deletions packages/plugins/socketio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,21 @@
"types": "./lib/constants.d.ts",
"default": "./lib/constants.js"
},
"./server": {
"types": "./lib/server.d.ts",
"default": "./lib/server.js"
"./decorator": {
"types": "./lib/decorator.d.ts",
"default": "./lib/decorator.js"
},
"./lifecycle": {
"types": "./lib/lifecycle.d.ts",
"default": "./lib/lifecycle.js"
},
"./types": {
"types": "./lib/types.d.ts",
"default": "./lib/types.js"
},
"./server": {
"types": "./lib/server.d.ts",
"default": "./lib/server.js"
}
},
"main": "lib/index.js",
Expand Down
29 changes: 29 additions & 0 deletions packages/plugins/socketio/src/decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { addTag, Injectable, ScopeEnum } from '@artus/core';
import { EventMetadata, NamespaceMetadata } from './types';

export const CLASS_NAMESPACE_TAG = 'CLASS_NAMESPACE_TAG';
export const CLASS_NAMESPACE_METADATA = Symbol.for('CLASS_NAMESPACE_METADATA');
export const EVENT_METADATA = Symbol.for('EVENT_METADATA');

export function Namespace(name: string) {
return (target: any) => {
const namespaceMetadata: NamespaceMetadata = {
name,
};

Reflect.defineMetadata(CLASS_NAMESPACE_METADATA, namespaceMetadata, target);
addTag(CLASS_NAMESPACE_TAG, target);
Injectable({ scope: ScopeEnum.EXECUTION })(target);
};
}

export function Event(name: string) {
return (_target: object, _key: string, descriptor: TypedPropertyDescriptor<any>) => {
const eventMetadata: EventMetadata = {
name,
};

Reflect.defineMetadata(EVENT_METADATA, eventMetadata, descriptor.value);
return descriptor;
};
}
4 changes: 3 additions & 1 deletion packages/plugins/socketio/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './server';
export * from './lifecycle';
export * from './decorator';
export * from './server';
export * from './types';
66 changes: 57 additions & 9 deletions packages/plugins/socketio/src/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,73 @@ import {
LifecycleHookUnit,
LifecycleHook,
} from '@artus/core';

import { InjectEnum } from './constants';
import Server from './server';
import { SocketIOServer } from './server';
import { EventMetadata, NamespaceEvent, NamespaceMetadata } from './types';
import { CLASS_NAMESPACE_METADATA, CLASS_NAMESPACE_TAG, EVENT_METADATA } from './decorator';

@LifecycleHookUnit()
export default class PluginLifecycle implements ApplicationLifecycle {
@Inject(ArtusInjectEnum.Application)
app: ArtusApplication;

@Inject(InjectEnum.SocketIO)
io: Server;
io: SocketIOServer;

get container() {
return this.app.container;
}

private registerNsp(nspMetadata: NamespaceMetadata, eventList: NamespaceEvent[]) {
const io = this.io;
io.of(nspMetadata.name).on('connection', (socket) => {
for (const event of eventList) {
const { eventMetadata, handler } = event;

socket.on(eventMetadata.name, (msg: any) => {
handler(msg);
});
}
});
}

private loadNamespace() {
const nspClazzList = this.container.getInjectableByTag(CLASS_NAMESPACE_TAG);
for (const nspClazz of nspClazzList) {
const nsp = this.container.get(nspClazz) as any;
const nspMetadata = Reflect.getMetadata(CLASS_NAMESPACE_METADATA, nspClazz);
const nspDescriptorList = Object.getOwnPropertyDescriptors(nspClazz.prototype);

const eventList: NamespaceEvent[] = [];

for (const key of Object.keys(nspDescriptorList)) {
const nspDescriptor = nspDescriptorList[key];

// skip getter/setter
if (!nspDescriptor.value) {
continue;
}

const eventMetadata: EventMetadata = Reflect.getMetadata(EVENT_METADATA, nspDescriptor.value);

// skip constructor
if (!eventMetadata) {
continue;
}

eventList.push({
eventMetadata,
handler: nsp[key].bind(nsp),
});
}

this.registerNsp(nspMetadata, eventList);
}
}

@LifecycleHook()
async willReady() {
// const io = this.io;
// io.on('connection', (socket) => {
// console.log('a user connected');
// socket.on('disconnect', () => {
// console.log('user disconnected');
// });
// });
this.loadNamespace();
}
}
5 changes: 2 additions & 3 deletions packages/plugins/socketio/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Injectable, Inject, ScopeEnum, ArtusInjectEnum } from '@artus/core';
import { Server } from 'socket.io';
import { InjectEnum } from './constants';
import type { ServerOptions } from 'socket.io';
import { SocketIOServerConfig } from './types';

type SocketIOServerConfig = Partial<ServerOptions>;
interface ISocketIOServer extends Server {}

@Injectable({
Expand All @@ -17,4 +16,4 @@ export default class SocketIOServer extends Server implements ISocketIOServer {
}
}

export { SocketIOServerConfig };
export { SocketIOServer };
16 changes: 16 additions & 0 deletions packages/plugins/socketio/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { ServerOptions } from 'socket.io';

export type SocketIOServerConfig = Partial<ServerOptions>;

export type NamespaceMetadata = {
name: string;
};

export type EventMetadata = {
name: string;
};

export type NamespaceEvent = {
eventMetadata: EventMetadata;
handler: (...args: any[]) => void;
};

0 comments on commit f6644df

Please sign in to comment.