mikudos-socketio-app
Version:
mikudos-socketio-app for connection and call methods and sync events on mikudos-socketio-app server, which is provided only for socket.io connection.
193 lines (185 loc) • 6.29 kB
text/typescript
import _ from 'lodash';
import { HandlerBase } from '../handler-base';
import { Application } from '../../app';
import { mikudos } from '../../namespace';
import Debug from 'debug';
const debug = Debug('mikudos:chat');
export class CHAT_HANDLER extends HandlerBase {
roomPath: string;
emitToSelfPath: string;
public authenticated: boolean;
constructor(
public app: Application,
{
eventPath = 'message',
roomPath = 'room',
emitToSelfPath = 'emitToSelf',
authenticated = true
} = {},
public hooks: {
before: { [key: string]: Function[] };
after: { [key: string]: Function[] };
} = { before: {}, after: {} }
) {
super(eventPath);
this.authenticated = authenticated;
this.roomPath = roomPath;
this.emitToSelfPath = emitToSelfPath;
}
register(socket: mikudos.Socket) {
debug(
`register chat service ${
this.authenticated ? 'with auth' : 'without auth'
}`
);
socket.on(this.eventPath, async (data, callback: Function) => {
// chat message
try {
let res = await this.handle(data, socket);
callback(res);
} catch (error) {
callback({ error });
}
});
socket.on(
`join ${this.eventPath}`,
async (data, callback: Function) => {
try {
let res = await this.join(data, socket);
callback(res);
} catch (error) {
callback({ error });
}
}
);
socket.on(
`leave ${this.eventPath}`,
async (data, callback: Function) => {
try {
let res = await this.leave(data, socket);
callback(res);
} catch (error) {
callback({ error });
}
}
);
}
getRoom(data: any) {
return _.get(data, this.roomPath);
}
isSelfToBeEmit(data: any) {
return !!_.get(data, this.emitToSelfPath);
}
getUser(socket: mikudos.Socket) {
return socket.mikudos.user;
}
async handle(data: any, socket: mikudos.Socket) {
const beforeHooks = _.compact(
_.concat(this.hooks.before.all, this.hooks.before.chat)
);
const afterHooks = _.compact(
_.concat(this.hooks.after.all, this.hooks.after.chat)
);
for await (const hook of beforeHooks) {
await hook.call(this, data, socket);
}
let room = this.getRoom(data);
let emitToSelf = this.isSelfToBeEmit(data);
if (!room)
return {
error: {
message: `${this.roomPath} key must provided`,
class: 'Common Error',
code: 1
}
};
socket.to(room).emit(this.eventPath, data);
debug('broadcast chat message exclud self:', data);
if (emitToSelf) {
socket.emit(this.eventPath, data);
debug('emit chat message to self');
}
// add after hooks to chat
for await (const hook of afterHooks) {
await hook.call(this, data, socket);
}
return { result: { success: true } };
}
async join(data: any, socket: mikudos.Socket) {
const beforeHooks = _.compact(
_.concat(this.hooks.before.all, this.hooks.before.join)
);
const afterHooks = _.compact(
_.concat(this.hooks.after.all, this.hooks.after.join)
);
for await (const hook of beforeHooks) {
await hook.call(this, data, socket);
}
let room = this.getRoom(data);
if (!room)
return {
error: {
message: `${this.roomPath} key must provided`,
class: 'Common Error',
code: 1
}
};
if (await this.checkRoom(room, socket))
return {
error: {
message: `you already in the room: ${room}`,
class: 'Common Error',
code: 1
}
};
let user = this.getUser(socket);
await socket.mikudos.app.remoteJoin(socket.id, room);
socket.join(room, () => {
debug('joined room: %o, socket: %o', room, socket.id);
socket.to(room).emit(`join ${this.eventPath}`, {
room,
user,
socket_id: socket.id
});
debug('emit join event to room: %o, socket: %o', room, socket.id);
});
for await (const hook of afterHooks) {
await hook.call(this, data, socket);
}
return { result: { success: true } };
}
async leave(data: any, socket: mikudos.Socket) {
const beforeHooks = _.compact(
_.concat(this.hooks.before.all, this.hooks.before.leave)
);
const afterHooks = _.compact(
_.concat(this.hooks.after.all, this.hooks.after.leave)
);
for await (const hook of beforeHooks) {
await hook.call(this, data, socket);
}
let room = this.getRoom(data);
if (!(await this.checkRoom(room, socket)))
return {
error: {
message: `you are not in the room: ${room}`,
class: 'Wrong Room',
code: 2
}
};
let user = this.getUser(socket);
socket.to(room).emit(`leave ${this.eventPath}`, {
room,
user,
socket_id: socket.id
});
debug('emit leave event to room: %o, socket: %o', room, socket.id);
await socket.mikudos.app.remoteLeave(socket.id, room);
socket.leave(room);
debug('leaved room: %o, socket: %o', room, socket.id);
for await (const hook of afterHooks) {
await hook.call(this, data, socket);
}
return { result: { success: true } };
}
}