-
Notifications
You must be signed in to change notification settings - Fork 2
/
Socket.ts
116 lines (99 loc) · 2.54 KB
/
Socket.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { ServerRequest } from "https://deno.land/std/http/server.ts";
import { Router } from "./Router.ts";
import {
acceptWebSocket,
acceptable,
WebSocket,
isWebSocketCloseEvent,
} from "https://deno.land/std/ws/mod.ts";
import { v4 } from "https://deno.land/std/uuid/mod.ts";
export class Socket {
private router: Router;
private connections: Map<string, WebSocket> = new Map();
private events: Map<
string,
(msg: Broadcast, connId: string) => void
> = new Map();
constructor(route: string = "/ws") {
this.router = new Router(route);
this.router.get("/", this.conn.bind(this));
}
public get routes() {
return this.router.routes;
}
public conn(req: ServerRequest): void {
if (acceptable(req)) {
acceptWebSocket({
conn: req.conn,
bufReader: req.r,
bufWriter: req.w,
headers: req.headers,
}).then(async (ws: WebSocket) => {
const connId = v4.generate();
this.connections.set(connId, ws);
this.broadcast({
from: connId,
event: "connect",
body: `${connId} has connected`,
});
for await (const event of ws) {
try {
const msg: Broadcast = typeof event === "string"
? JSON.parse(event)
: null;
if (msg && msg.event) {
this.events.get(msg.event)?.(msg, connId);
} else if (!msg && isWebSocketCloseEvent(event)) {
this.connections.delete(connId);
this.broadcast({
from: connId,
event: "disconnect",
body: `${connId} has disconnected`,
});
break;
}
} catch (e) {
console.error(e);
// Do nothing
}
}
});
}
}
public on(event: string, func: (msg: Broadcast, connId: string) => void) {
this.events.set(event, func);
}
public emit(
event: string,
body: any,
options?: {
to?: string;
from?: string;
},
) {
this.broadcast({
event,
body,
to: options?.to,
from: options?.from,
});
}
public broadcast(msg: Broadcast): void {
if (!msg.body) return;
if (msg.to) {
const conn = this.connections.get(msg.to);
if (!conn) return;
conn.send(JSON.stringify(msg));
} else {
for (const conn of this.connections.values()) {
conn.send(JSON.stringify(msg));
}
}
}
}
type Broadcast = {
from?: string;
to?: string;
event?: string;
body: any;
};