-
Notifications
You must be signed in to change notification settings - Fork 0
/
ksfw.ts
134 lines (121 loc) · 3.39 KB
/
ksfw.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { extname } from 'https://deno.land/[email protected]/path/mod.ts';
import { contentType } from 'https://deno.land/[email protected]/media_types/mod.ts';
import { DB } from 'https://deno.land/x/[email protected]/mod.ts';
export class ksfw {
constructor() {
this.client_list = [];
this.db = new DB('./ksfw.db');
this.db.execute(`
CREATE TABLE IF NOT EXISTS user (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_uuid TEXT UNIQUE
)
`);
}
get_body(path) {
if (extname(path) !== '.html') return Deno.readFileSync(path);
let body = Deno.readTextFileSync(path);
while (body.match(/<!-- include (\S+) -->/)) {
body = body.replace(/<!-- include (\S+) -->/g, function () {
return this.get_body(arguments[1]).trimEnd();
}.bind(this));
}
return body;
}
async respond(pathname) {
if (pathname === 'ksfw.js') {
let body = '';
for (const path of ['./ksfw.js']) {
const url = new URL(path, import.meta.url);
const res = await fetch(url);
body += await res.text();
}
return new Response(body, {
headers: {
'Content-Type': contentType('.js'),
},
});
}
for (const directory of ['./client', './design/entry_point']) {
try {
const body = this.get_body(directory + '/' + pathname);
return new Response(body, {
headers: {
'Content-Type': contentType(extname(pathname)),
},
});
} catch (error) {
}
}
return new Response('Not Found', {
status: 404,
headers: {
'Content-Type': contentType('.html'),
},
});
}
handler(request) {
const url = new URL(request.url);
const pathname = url.pathname === '/' ? 'index.html' : url.pathname.replace(/^\//, '');
const params = {};
for (const [key, value] of url.searchParams) {
params[key] = value;
}
if (pathname === 'ws') {
const { socket, response } = Deno.upgradeWebSocket(request);
// onopen
socket.onopen = event => {
let user;
let user_uuid = params.user_uuid;
while (true) {
user = this.db.prepareQuery('SELECT * FROM user WHERE user_uuid = :user_uuid').firstEntry({
user_uuid,
});
if (user) break;
user_uuid = crypto.randomUUID()
this.db.prepareQuery('INSERT INTO user (user_uuid) VALUES (:user_uuid)').execute({
user_uuid,
});
}
const new_user = JSON.parse(JSON.stringify(user));
delete new_user.user_uuid;
this.client_list.push({
user: new_user,
socket: event.target,
});
console.log('onopen:', 'number of clients:', this.client_list.length);
const client = this.client_list.find(client => client.socket === event.target);
socket.send(JSON.stringify({
pathname: 'connected',
params: {
user,
}
}));
};
// onmessage
socket.onmessage = event => {
const client = this.client_list.find(client => client.socket === event.target);
const data = JSON.parse(event.data);
this[data.pathname](client, data.params);
}
// onclose
socket.onclose = event => {
this.client_list = this.client_list.filter(client => client.socket !== event.target);
console.log('onclose:', 'number of clients:', this.client_list.length);
}
// onerror
socket.onerror = event => {
console.error('onerror:', event);
}
return response;
}
else {
return this.respond(pathname);
}
}
broadcast(pathname, params) {
for (const client of this.client_list) {
client.socket.send(JSON.stringify({pathname, params}));
}
}
}