Showing
6 changed files
with
115 additions
and
9 deletions
| ... | @@ -35,7 +35,12 @@ export const RoomInfoRecord = Record({ | ... | @@ -35,7 +35,12 @@ export const RoomInfoRecord = Record({ |
| 35 | uuid: String, | 35 | uuid: String, |
| 36 | name: String, | 36 | name: String, |
| 37 | maxUsers: Number, | 37 | maxUsers: Number, |
| 38 | - users: Array(UserDataRecord), | 38 | + users: Array( |
| 39 | + Record({ | ||
| 40 | + username: String, | ||
| 41 | + admin: Boolean, | ||
| 42 | + }) | ||
| 43 | + ), | ||
| 39 | }); | 44 | }); |
| 40 | 45 | ||
| 41 | export type RoomInfo = Static<typeof RoomInfoRecord>; | 46 | export type RoomInfo = Static<typeof RoomInfoRecord>; | ... | ... |
| ... | @@ -74,6 +74,7 @@ interface ServerOutboundMessageMap { | ... | @@ -74,6 +74,7 @@ interface ServerOutboundMessageMap { |
| 74 | state: "added" | "updated" | "removed"; | 74 | state: "added" | "updated" | "removed"; |
| 75 | user: { | 75 | user: { |
| 76 | username: string; | 76 | username: string; |
| 77 | + admin: boolean; | ||
| 77 | }; | 78 | }; |
| 78 | }; | 79 | }; |
| 79 | 80 | ... | ... |
| ... | @@ -8,6 +8,7 @@ import { | ... | @@ -8,6 +8,7 @@ import { |
| 8 | ServerOutboundMessageKey, | 8 | ServerOutboundMessageKey, |
| 9 | } from "../../common"; | 9 | } from "../../common"; |
| 10 | import { RoomDescription, RoomInfo, UserData } from "../../common/dataType"; | 10 | import { RoomDescription, RoomInfo, UserData } from "../../common/dataType"; |
| 11 | +import { RoomManager } from "./RoomManager"; | ||
| 11 | 12 | ||
| 12 | export class Room { | 13 | export class Room { |
| 13 | public readonly uuid: string; | 14 | public readonly uuid: string; |
| ... | @@ -15,16 +16,26 @@ export class Room { | ... | @@ -15,16 +16,26 @@ export class Room { |
| 15 | public name: string; | 16 | public name: string; |
| 16 | public readonly maxUsers: number; | 17 | public readonly maxUsers: number; |
| 17 | 18 | ||
| 19 | + public readonly roomManager: RoomManager; | ||
| 20 | + | ||
| 18 | public users: User[] = []; | 21 | public users: User[] = []; |
| 22 | + public admin?: User; | ||
| 19 | 23 | ||
| 20 | - private closed: boolean = false; | 24 | + public closed: boolean = false; |
| 21 | 25 | ||
| 22 | public handler: MessageHandler; | 26 | public handler: MessageHandler; |
| 23 | 27 | ||
| 24 | - constructor(name: string, maxUsers: number = 8) { | 28 | + constructor( |
| 29 | + roomManager: RoomManager, | ||
| 30 | + name: string, | ||
| 31 | + admin?: User, | ||
| 32 | + maxUsers: number = 8 | ||
| 33 | + ) { | ||
| 25 | this.uuid = uuidv4(); | 34 | this.uuid = uuidv4(); |
| 26 | this.name = name; | 35 | this.name = name; |
| 27 | this.maxUsers = maxUsers; | 36 | this.maxUsers = maxUsers; |
| 37 | + this.roomManager = roomManager; | ||
| 38 | + this.admin = admin; | ||
| 28 | 39 | ||
| 29 | this.handler = new MessageHandler({ | 40 | this.handler = new MessageHandler({ |
| 30 | chat: (user, message) => { | 41 | chat: (user, message) => { |
| ... | @@ -36,6 +47,10 @@ export class Room { | ... | @@ -36,6 +47,10 @@ export class Room { |
| 36 | return { ok: true }; | 47 | return { ok: true }; |
| 37 | }, | 48 | }, |
| 38 | }); | 49 | }); |
| 50 | + | ||
| 51 | + if (this.admin) { | ||
| 52 | + this.connect(this.admin); | ||
| 53 | + } | ||
| 39 | } | 54 | } |
| 40 | 55 | ||
| 41 | public connect(user: User): void { | 56 | public connect(user: User): void { |
| ... | @@ -43,7 +58,13 @@ export class Room { | ... | @@ -43,7 +58,13 @@ export class Room { |
| 43 | return; | 58 | return; |
| 44 | } | 59 | } |
| 45 | 60 | ||
| 46 | - this.broadcast("updateRoomUser", { state: "added", user: user.getData() }); | 61 | + this.broadcast("updateRoomUser", { |
| 62 | + state: "added", | ||
| 63 | + user: { | ||
| 64 | + username: user.username, | ||
| 65 | + admin: user === this.admin, | ||
| 66 | + }, | ||
| 67 | + }); | ||
| 47 | 68 | ||
| 48 | this.users.push(user); | 69 | this.users.push(user); |
| 49 | user.room = this; | 70 | user.room = this; |
| ... | @@ -57,11 +78,25 @@ export class Room { | ... | @@ -57,11 +78,25 @@ export class Room { |
| 57 | 78 | ||
| 58 | this.broadcast("updateRoomUser", { | 79 | this.broadcast("updateRoomUser", { |
| 59 | state: "removed", | 80 | state: "removed", |
| 60 | - user: user.getData(), | 81 | + user: { |
| 82 | + username: user.username, | ||
| 83 | + admin: user === this.admin, | ||
| 84 | + }, | ||
| 61 | }); | 85 | }); |
| 86 | + | ||
| 87 | + if (this.users.length === 0) { | ||
| 88 | + this.close(); | ||
| 89 | + } else { | ||
| 90 | + this.setNextAdmin(); | ||
| 91 | + } | ||
| 62 | } | 92 | } |
| 63 | } | 93 | } |
| 64 | 94 | ||
| 95 | + private setNextAdmin(): void { | ||
| 96 | + const nextAdmin = this.users[Math.floor(Math.random() * this.users.length)]; | ||
| 97 | + this.admin = nextAdmin; | ||
| 98 | + } | ||
| 99 | + | ||
| 65 | public sendChat(user: User, message: string): void { | 100 | public sendChat(user: User, message: string): void { |
| 66 | this.broadcast("chat", { sender: user.username, message: message }); | 101 | this.broadcast("chat", { sender: user.username, message: message }); |
| 67 | } | 102 | } |
| ... | @@ -76,12 +111,16 @@ export class Room { | ... | @@ -76,12 +111,16 @@ export class Room { |
| 76 | } | 111 | } |
| 77 | 112 | ||
| 78 | public getInfo(): RoomInfo { | 113 | public getInfo(): RoomInfo { |
| 79 | - var users: UserData[] = this.users.map((u) => u.getData()); | ||
| 80 | return { | 114 | return { |
| 81 | uuid: this.uuid, | 115 | uuid: this.uuid, |
| 82 | name: this.name, | 116 | name: this.name, |
| 83 | maxUsers: this.maxUsers, | 117 | maxUsers: this.maxUsers, |
| 84 | - users: users, | 118 | + users: this.users.map((u) => { |
| 119 | + return { | ||
| 120 | + username: u.username, | ||
| 121 | + admin: u === this.admin, | ||
| 122 | + }; | ||
| 123 | + }), | ||
| 85 | }; | 124 | }; |
| 86 | } | 125 | } |
| 87 | 126 | ||
| ... | @@ -101,6 +140,7 @@ export class Room { | ... | @@ -101,6 +140,7 @@ export class Room { |
| 101 | if (!this.closed) { | 140 | if (!this.closed) { |
| 102 | this.users.forEach((u) => this.disconnect(u)); | 141 | this.users.forEach((u) => this.disconnect(u)); |
| 103 | this.closed = true; | 142 | this.closed = true; |
| 143 | + this.roomManager.delete(this.uuid); | ||
| 104 | } | 144 | } |
| 105 | } | 145 | } |
| 106 | } | 146 | } | ... | ... |
| 1 | import { RoomDescription } from "../../common/dataType"; | 1 | import { RoomDescription } from "../../common/dataType"; |
| 2 | +import { User } from "../user/User"; | ||
| 2 | import { Room } from "./Room"; | 3 | import { Room } from "./Room"; |
| 3 | 4 | ||
| 4 | export class RoomManager { | 5 | export class RoomManager { |
| ... | @@ -8,8 +9,8 @@ export class RoomManager { | ... | @@ -8,8 +9,8 @@ export class RoomManager { |
| 8 | this.rooms = new Map<string, Room>(); | 9 | this.rooms = new Map<string, Room>(); |
| 9 | } | 10 | } |
| 10 | 11 | ||
| 11 | - public create(name: string, maxConnections: number): Room { | 12 | + public create(name: string, maxConnections: number, admin?: User): Room { |
| 12 | - const room = new Room(name, maxConnections); | 13 | + const room = new Room(this, name, admin, maxConnections); |
| 13 | this.rooms.set(room.uuid, room); | 14 | this.rooms.set(room.uuid, room); |
| 14 | return room; | 15 | return room; |
| 15 | } | 16 | } | ... | ... |
server/test/admin.test.ts
0 → 100644
| 1 | +import { expect } from "chai"; | ||
| 2 | +import { RoomManager } from "../room/RoomManager"; | ||
| 3 | +import { SocketTester } from "./util/SocketTester"; | ||
| 4 | + | ||
| 5 | +describe("방장", () => { | ||
| 6 | + const roomManager = new RoomManager(); | ||
| 7 | + it("방을 만든 유저가 방장이 됩니다", () => { | ||
| 8 | + const socket = new SocketTester(roomManager); | ||
| 9 | + socket.login("guest"); | ||
| 10 | + | ||
| 11 | + expect(socket.connection.user !== undefined).eq(true); | ||
| 12 | + const room = roomManager.create("테스트", 2, socket.connection.user); | ||
| 13 | + expect(room.admin).eq(socket.connection.user); | ||
| 14 | + }); | ||
| 15 | + it("나중에 들어온 유저는 방장이 되지 않습니다", () => { | ||
| 16 | + const socket1 = new SocketTester(roomManager); | ||
| 17 | + const socket2 = new SocketTester(roomManager); | ||
| 18 | + socket1.login("guest1"); | ||
| 19 | + socket2.login("guest2"); | ||
| 20 | + | ||
| 21 | + expect(socket1.connection.user !== undefined).eq(true); | ||
| 22 | + expect(socket2.connection.user !== undefined).eq(true); | ||
| 23 | + const room = roomManager.create("테스트", 2, socket1.connection.user); | ||
| 24 | + const response = socket2.test("joinRoom", { uuid: room.uuid }); | ||
| 25 | + expect(response.ok).eq(true); | ||
| 26 | + expect(room.admin).eq(socket1.connection.user); | ||
| 27 | + expect(room.admin).not.eq(socket2.connection.user); | ||
| 28 | + expect(response.result?.users[0]?.username).eq("guest1"); | ||
| 29 | + expect(response.result?.users[0]?.admin).eq(true); | ||
| 30 | + }); | ||
| 31 | + it("방장이 나가면 방장이 인계됩니다", () => { | ||
| 32 | + const socket1 = new SocketTester(roomManager); | ||
| 33 | + const socket2 = new SocketTester(roomManager); | ||
| 34 | + socket1.login("guest1"); | ||
| 35 | + socket2.login("guest2"); | ||
| 36 | + | ||
| 37 | + expect(socket1.connection.user !== undefined).eq(true); | ||
| 38 | + expect(socket2.connection.user !== undefined).eq(true); | ||
| 39 | + const room = roomManager.create("테스트", 2, socket1.connection.user); | ||
| 40 | + expect(socket2.test("joinRoom", { uuid: room.uuid }).ok).eq(true); | ||
| 41 | + | ||
| 42 | + expect(room.admin).eq(socket1.connection.user); | ||
| 43 | + expect(room.admin).not.eq(socket2.connection.user); | ||
| 44 | + | ||
| 45 | + expect(socket1.test("leaveRoom", {}).ok).eq(true); | ||
| 46 | + expect(room.admin).eq(socket2.connection.user); | ||
| 47 | + }); | ||
| 48 | +}); |
| ... | @@ -52,4 +52,15 @@ describe("방 퇴장", () => { | ... | @@ -52,4 +52,15 @@ describe("방 퇴장", () => { |
| 52 | expect(updated.state).eq("removed"); | 52 | expect(updated.state).eq("removed"); |
| 53 | expect(updated.user.username).eq("guest2"); | 53 | expect(updated.user.username).eq("guest2"); |
| 54 | }); | 54 | }); |
| 55 | + it("방에서 퇴장한 뒤 아무도 없으면 방이 닫힙니다", () => { | ||
| 56 | + const socket = new SocketTester(roomManager); | ||
| 57 | + socket.login("guest1"); | ||
| 58 | + | ||
| 59 | + const room = roomManager.create("테스트", 1); | ||
| 60 | + | ||
| 61 | + expect(socket.test("joinRoom", { uuid: room.uuid }).ok).eq(true); | ||
| 62 | + expect(room.closed).eq(false); | ||
| 63 | + expect(socket.test("leaveRoom", {}).ok).eq(true); | ||
| 64 | + expect(room.closed).eq(true); | ||
| 65 | + }); | ||
| 55 | }); | 66 | }); | ... | ... |
-
Please register or login to post a comment