강동현

Message Handler 재작성

import { Socket } from "socket.io";
import { MessageHandlerRegistry } from "../message/MessageHandlerRegistry";
import { Message } from "../message/types";
import { ServerOutboundMessageMap } from "../../common";
import { loginHandler } from "../message/handler/loginHandler";
import { MessageHandlerChain } from "../message/MessageHandlerChain";
import { Room } from "../room/Room";
import { User } from "../user/User";
......@@ -9,17 +10,21 @@ export class Connection {
public user?: User;
private messageHandlerChain: MessageHandlerChain;
constructor(socket: Socket) {
this.socket = socket;
MessageHandlerRegistry.registerHandlers(this);
this.messageHandlerChain = new MessageHandlerChain(this);
}
public get authenticated(): boolean {
return this.user !== undefined;
}
public send(message: Message) {
this.socket.emit(message.type, message);
public send<T extends keyof ServerOutboundMessageMap>(
type: T,
message: ServerOutboundMessageMap[T]
) {
this.socket.emit(type as string, message);
}
}
......
......@@ -15,6 +15,7 @@ export class ConnectionMapper {
}
value = new Connection(socket);
// FIXME: Register connection to the map
return value;
}
......
import { Connection } from "../connection/Connection";
import { ServerInboundMessageMap, ServerResponse } from "../../common/index";
type ServerHandlerMap<T> = {
[Key in keyof ServerInboundMessageMap]?: (
connection: Connection,
message: Omit<ServerInboundMessageMap[Key], "result">,
scope: T
) => ServerResponse<
"result" extends keyof ServerInboundMessageMap[Key]
? ServerInboundMessageMap[Key]["result"]
: undefined
>;
};
export class HandlerMap<T> {
private scope: T;
private handlers: ServerHandlerMap<T>;
constructor(scope: T, handlers: ServerHandlerMap<T>) {
this.scope = scope;
this.handlers = handlers;
}
public handle(
type: keyof ServerInboundMessageMap,
connection: Connection,
message: any,
callback: Function
): boolean {
const handler = this.handlers[type];
if (!handler) return false;
const response = handler(connection, message, this.scope);
callback(response);
return true;
}
}
import { Connection } from "../connection/Connection";
import { ServerInboundMessageMap, ServerResponse } from "../../common/index";
import { keys } from "ts-transformer-keys";
export class MessageHandlerChain {
connection: Connection;
constructor(connection: Connection) {
this.connection = connection;
for (const key in keys<ServerInboundMessageMap>()) {
const type = key as keyof ServerInboundMessageMap;
this.connection.socket.on(key, (message: any, callback: Function) => {
if (
connection?.user &&
connection.user.handler.handle(
type,
connection,
message.data,
callback
)
)
return;
// TODO: Add more handlers
});
}
}
}
import { Connection } from "../connection/Connection";
import { User } from "../user/User";
import { loginHandler } from "./handler/loginHandler";
import { roomChatHandler } from "./handler/roomChatHandler";
import { roomJoinHandler } from "./handler/roomJoinHandler";
import { roomLeaveHandler } from "./handler/roomLeaveHandler";
import { roomListRequestHandler } from "./handler/roomListRequestHandler";
import { Message, MessageResponse, MessageType } from "./types";
export class MessageHandlerRegistry {
static registerHandlers(connection: Connection) {
this.registerHandler(connection, MessageType.LOGIN, loginHandler);
this.registerHandlerAuthed(
connection,
MessageType.ROOM_LIST_REQUEST,
roomListRequestHandler
);
this.registerHandlerAuthed(
connection,
MessageType.ROOM_JOIN,
roomJoinHandler
);
this.registerHandlerAuthed(
connection,
MessageType.ROOM_LEAVE,
roomLeaveHandler
);
this.registerHandlerAuthed(
connection,
MessageType.ROOM_CHAT,
roomChatHandler
);
}
private static registerHandler<T extends Message, S>(
connection: Connection,
typeName: string,
handler: (connection: Connection, message: T) => MessageResponse<S>
) {
connection.socket.on(typeName, (message: T, callback: Function) => {
const response = handler(connection, message);
callback(response);
});
}
private static registerHandlerAuthed<T extends Message, S>(
connection: Connection,
typeName: string,
handler: (user: User, message: T) => MessageResponse<S>
) {
connection.socket.on(typeName, (message: T, callback: Function) => {
if (connection.user !== undefined) {
const response = handler(connection.user, message);
callback(response);
} else {
callback({ ok: false });
}
});
}
}
import { Connection } from "../connection/Connection";
import { HandlerMap } from "../message/MessageHandler";
import { Room } from "../room/Room";
import { UserData } from "./types";
......@@ -9,9 +10,12 @@ export class User {
public room?: Room;
public handler: HandlerMap<User>;
constructor(username: string, connection: Connection) {
this.username = username;
this.connection = connection;
this.handler = new HandlerMap<User>(this, {});
}
public getData(): UserData {
......