forked from VictorTaelin/uwuchat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
201 lines (166 loc) · 5.26 KB
/
server.js
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import ws from 'ws';
import fs from 'fs-extra';
import path from 'path';
import lib from './lib.js';
const { createServer } = ws;
const port = Number(process.argv[2] || "7171");
// Globals
// =======
// type RoomID = u64
var RoomPosts = {}; // Map RoomID [Uint8Array] -- past messages to sync w/ room
var Watchlist = {}; // Map RoomID [WsPeer] -- ws peers watching given room
var Connected = 0;
// Startup
// =======
// Creates the data directory
if (!fs.existsSync("data")) {
fs.mkdirSync("data");
}
// Loads existing posts
var files = fs.readdirSync("data");
for (var file of files) {
if (file.slice(-5) === ".room") {
var room_name = file.slice(0, -5);
var file_data = fs.readFileSync(path.join("data",file));
var room_posts = [];
for (var i = 0; i < file_data.length; i += 4 + size) {
var size = lib.hex_to_u32(file_data.slice(i, i + 4).toString("hex"));
var head = Buffer.from([lib.SHOW]);
var body = file_data.slice(i + 4, i + 4 + size);
room_posts.push(new Uint8Array(Buffer.concat([head, body])));
}
console.log("Loaded "+room_posts.length+" posts on room "+room_name+".");
RoomPosts[room_name] = room_posts;
}
}
// Methods
// =======
// Returns current time
function get_time() {
return Date.now();
}
// Adds a user to a room's watchlist
function watch_room(room_name, ws) {
// Creates watcher list
if (!Watchlist[room_name]) {
Watchlist[room_name] = [];
}
// Gets watcher list
var watchlist = Watchlist[room_name];
// Makes sure user isn't watching already
for (var i = 0; i < watchlist.length; ++i) {
if (watchlist[i] === ws) {
return;
};
}
// Sends old messages
if (RoomPosts[room_name]) {
for (var i = 0; i < RoomPosts[room_name].length; ++i) {
ws.send(RoomPosts[room_name][i]);
}
}
// Adds user to watcher list
watchlist.push(ws);
};
// Removes a user from a room's watchlist
function unwatch_room(room_name, ws) {
// Gets watcher list
var watchlist = Watchlist[room_name] || [];
// Removes user from watcher list
for (var i = 0; i < watchlist.length; ++i) {
if (watchlist[i] === ws) {
for (var j = i; j < watchlist.length - 1; ++j) {
watchlist[j] = watchlist[j + 1];
};
return;
}
};
};
// Saves a post (room id, user address, data)
function save_post(post_room, post_user, post_data) {
var post_room = lib.check_hex(64, post_room);
var post_time = lib.u64_to_hex(get_time());
var post_user = lib.check_hex(64, post_user);
var post_data = lib.check_hex(null, post_data);
var post_list = [post_room, post_time, post_user, post_data];
var post_buff = lib.hexs_to_bytes([lib.u8_to_hex(lib.SHOW)].concat(post_list));
var post_seri = lib.hexs_to_bytes([lib.u32_to_hex(post_buff.length-1)].concat(post_list));
var post_file = path.join("data", post_room+".room");
var log_msg = "";
log_msg += "Saving post!\n";
log_msg += "- post_room: " + post_room + "\n";
log_msg += "- post_user: " + post_user + "\n";
log_msg += "- post_data: " + post_data + "\n";
log_msg += "- post_file: " + post_room+".room" + "\n";
// Creates reconnection array for this room
if (!RoomPosts[post_room]) {
RoomPosts[post_room] = [];
}
// Adds post to reconnection array
RoomPosts[post_room].push(post_buff);
// Broadcasts
if (Watchlist[post_room]) {
log_msg += "- broadcasting to " + Watchlist[post_room].length + " watcher(s).\n";
for (var ws of Watchlist[post_room]) {
ws.send(post_buff);
}
}
// Create file for this room
if (!fs.existsSync(post_file)) {
fs.closeSync(fs.openSync(post_file, "w"));
}
// Adds post to file
fs.appendFileSync(post_file, Buffer.from(post_seri));
// Log messages
console.log(log_msg);
};
// TCP API
// =======
const wss = new ws.Server({port});
wss.binaryType = "arraybuffer";
wss.on("connection", function connection(ws) {
console.log("["+(++Connected)+" connected]");
ws.on("message", function incoming(data) {
var msge = new Uint8Array(data);
switch (msge[0]) {
// User wants to watch a room
case lib.WATCH:
var room = lib.bytes_to_hex(msge.slice(1, 9));
watch_room(room, ws);
break;
// User wants to unwatch a room
case lib.UNWATCH:
var room = lib.bytes_to_hex(msge.slice(1, 9));
unwatch_room(room, ws);
break;
// User wants to know the time
case lib.TIME:
var msge_buff = lib.hexs_to_bytes([
lib.u8_to_hex(lib.TIME),
lib.u64_to_hex(Date.now()),
lib.bytes_to_hex(msge.slice(1, 9)),
]);
ws.send(msge_buff);
break;
// User wants to post a message
case lib.POST:
var post_room = lib.bytes_to_hex(msge.slice(1, 9));
var post_user = lib.bytes_to_hex(msge.slice(9, 17));
var post_data = lib.bytes_to_hex(msge.slice(17, msge.length));
save_post(post_room, post_user, post_data);
break;
};
});
ws.on("close", function() {
for (var room_name in Watchlist) {
Watchlist[room_name] = Watchlist[room_name].filter(watcher => watcher !== ws);
};
console.log("["+(--Connected)+" connected]");
});
});
process.on("SIGINT", function() {
console.log("\nClosing server...");
wss.close();
process.exit();
});
console.log("Started server on ws://localhost:"+port+".");