Skip to content
This repository was archived by the owner on Dec 2, 2022. It is now read-only.

Commit 6cda291

Browse files
committed
WIP: WebSocket connection control
1 parent 2756900 commit 6cda291

File tree

4 files changed

+131
-5
lines changed

4 files changed

+131
-5
lines changed

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
"editor.formatOnPaste": false,
77
"editor.formatOnType": false,
88
"editor.formatOnSave": true,
9+
"prettier.singleQuote": true,
910
//"editor.formatOnSaveMode": "modifications",
1011
}

src/index.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
1-
import { serve } from "https://deno.land/std@0.76.0/http/server.ts";
2-
const s = serve({ port: 8080 });
3-
console.log("http://localhost:8080/");
4-
for await (const req of s) {
5-
req.respond({ body: "Hello World\n" });
1+
import { serve } from 'https://deno.land/std@0.76.0/http/server.ts';
2+
import {
3+
acceptable,
4+
acceptWebSocket,
5+
} from 'https://deno.land/std@0.76.0/ws/mod.ts';
6+
import { HandleWSConn } from './server/WebSocket.ts';
7+
8+
const PORT = 8080;
9+
const SERVER = serve({ port: PORT });
10+
console.log(`http://localhost:${PORT}/`);
11+
12+
for await (const req of SERVER) {
13+
if (acceptable(req)) {
14+
const { conn, headers, r: bufReader, w: bufWriter } = req;
15+
acceptWebSocket({ conn, bufReader, bufWriter, headers })
16+
.then(HandleWSConn)
17+
.catch(async (err: any) => {
18+
console.error(`failed to accept websocket: ${err}`);
19+
await req.respond({ status: 400 });
20+
});
21+
} else {
22+
req.respond({ body: 'Hello World\n' });
23+
}
624
}

src/server/Connections.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { WebSocket } from 'https://deno.land/std@0.76.0/ws/mod.ts';
2+
3+
type Connection = Readonly<{ id: String; ws: WebSocket }>;
4+
const Connections: Map<String, WebSocket> = new Map();
5+
6+
export function GetConnections(): Promise<Array<Connection>> {
7+
return new Promise((resolve) => {
8+
const lConnection: Array<Connection> = [];
9+
Connections.forEach((pWebSocket, pId) => {
10+
lConnection.push(
11+
Object.freeze({
12+
id: pId,
13+
ws: pWebSocket,
14+
})
15+
);
16+
});
17+
resolve(lConnection);
18+
});
19+
}
20+
21+
let id = 0;
22+
export function AddConn(pWebSocket: WebSocket): Promise<String> {
23+
return new Promise((resolve) => {
24+
const _id = (id++).toString();
25+
Connections.set(_id, pWebSocket);
26+
return resolve(_id);
27+
});
28+
}
29+
30+
export function FindConnById(pId: String): Promise<WebSocket | null> {
31+
return new Promise((resolve) => {
32+
const conn = Connections.get(pId);
33+
return resolve(conn ? conn : null);
34+
});
35+
}
36+
37+
export function RemoveConnById(pId: String): Promise<Boolean> {
38+
return new Promise((resolve) => {
39+
const deleted = Connections.delete(pId);
40+
resolve(deleted);
41+
});
42+
}
43+
44+
export function CheckConnById(pId: String): Promise<Boolean> {
45+
return new Promise((resolve) => {
46+
const conn = Connections.get(pId);
47+
const isValid = !(!conn || conn.isClosed);
48+
resolve(isValid);
49+
});
50+
}
51+
52+
export function CountConn(): Promise<number> {
53+
return new Promise((resolve) => {
54+
return resolve(Connections.size);
55+
});
56+
}

src/server/WebSocket.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import {
2+
isWebSocketCloseEvent,
3+
isWebSocketPingEvent,
4+
WebSocket,
5+
} from 'https://deno.land/std@0.76.0/ws/mod.ts';
6+
7+
import {
8+
GetConnections,
9+
AddConn,
10+
RemoveConnById,
11+
CheckConnById,
12+
} from './Connections.ts';
13+
14+
export async function HandleWSConn(pWebSocket: WebSocket): Promise<void> {
15+
const _connId = await AddConn(pWebSocket);
16+
console.log('socket connected!', _connId);
17+
try {
18+
for await (const event of pWebSocket) {
19+
if (typeof event === 'string') {
20+
// text message.
21+
console.log(`ws:Text = ${event}`);
22+
for (const conn of await GetConnections()) {
23+
if (_connId !== conn.id && (await CheckConnById(conn.id))) {
24+
await conn.ws.send(
25+
`Text: ${_connId} -> ${conn.id}: ${event}`
26+
);
27+
}
28+
}
29+
} else if (event instanceof Uint8Array) {
30+
// binary message.
31+
console.log('ws:Binary', event);
32+
} else if (isWebSocketPingEvent(event)) {
33+
// ping.
34+
const [, body] = event;
35+
console.log('ws:Ping', _connId, body);
36+
} else if (isWebSocketCloseEvent(event)) {
37+
// close.
38+
const { code, reason } = event;
39+
console.log('ws:Close', _connId, code, reason);
40+
await RemoveConnById(_connId);
41+
} else {
42+
console.log('Another type: ', typeof event, event);
43+
}
44+
}
45+
} catch (err) {
46+
console.error(`failed to receive frame: ${err}`);
47+
if (!pWebSocket.isClosed) {
48+
await pWebSocket.close(1000).catch(console.error);
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)