Parcourir la source

server: use async functions instead of callbacks

This makes the code more readable.
Also add the automatic deletion of empty board files.
dev_h
Ophir LOJKINE il y a 5 ans
Parent
révision
63db84f7dd
2 fichiers modifiés avec 89 ajouts et 79 suppressions
  1. 47
    37
      server/boardData.js
  2. 42
    42
      server/sockets.js

+ 47
- 37
server/boardData.js Voir le fichier

@@ -159,30 +159,39 @@ BoardData.prototype.delaySave = function (file) {
159 159
 /** Saves the data in the board to a file.
160 160
  * @param {string} [file=this.file] - Path to the file where the board data will be saved.
161 161
 */
162
-BoardData.prototype.save = function (file) {
162
+BoardData.prototype.save = async function (file) {
163 163
 	this.lastSaveDate = Date.now();
164 164
 	this.clean();
165 165
 	if (!file) file = this.file;
166 166
 	var tmp_file = backupFileName(file);
167 167
 	var board_txt = JSON.stringify(this.board);
168
-	var that = this;
169
-	function afterSave(err) {
170
-		if (err) {
168
+	if (board_txt === "{}") { // empty board
169
+		try {
170
+			await fs.promises.unlink(file);
171
+			log("removed empty board", { 'name': this.name });
172
+		} catch (err) {
173
+			if (err.code !== "ENOENT") {
174
+				// If the file already wasn't saved, this is not an error
175
+				log("board deletion error", { "e": err })
176
+			}
177
+		}
178
+	} else {
179
+		try {
180
+			await fs.promises.writeFile(tmp_file, board_txt);
181
+			await fs.promises.rename(tmp_file, file);
182
+			log("saved board", {
183
+				'name': this.name,
184
+				'size': board_txt.length,
185
+				'delay_ms': (Date.now() - this.lastSaveDate),
186
+			});
187
+		} catch (err) {
171 188
 			log("board saving error", {
172
-				'err': err,
189
+				'err': err.toString(),
173 190
 				'tmp_file': tmp_file,
174 191
 			});
175
-		} else {
176
-			log("saved board", {
177
-				'name': that.name,
178
-				'delay_ms': (Date.now() - that.lastSaveDate)
179
-			});
192
+			return;
180 193
 		}
181 194
 	}
182
-	fs.writeFile(tmp_file, board_txt, function onBoardSaved(err) {
183
-		if (err) afterSave(err);
184
-		else fs.rename(tmp_file, file, afterSave);
185
-	});
186 195
 };
187 196
 
188 197
 /** Remove old elements from the board */
@@ -231,31 +240,32 @@ BoardData.prototype.validate = function validate(item, parent) {
231 240
 /** Load the data in the board from a file.
232 241
  * @param {string} file - Path to the file where the board data will be read.
233 242
 */
234
-BoardData.load = function loadBoard(name) {
235
-	var boardData = new BoardData(name);
236
-	return new Promise((accept) => {
237
-		fs.readFile(boardData.file, function (err, data) {
243
+BoardData.load = async function loadBoard(name) {
244
+	var boardData = new BoardData(name), data;
245
+	try {
246
+		data = await fs.promises.readFile(boardData.file);
247
+		boardData.board = JSON.parse(data);
248
+		for (id in boardData.board) boardData.validate(boardData.board[id]);
249
+		log('disk load', { 'board': boardData.name });
250
+	} catch (e) {
251
+		log('empty board creation', {
252
+			'board': boardData.name,
253
+			// If the file doesn't exist, this is not an error
254
+			"error": e.code !== "ENOENT" && e.toString(),
255
+		});
256
+		boardData.board = {}
257
+		if (data) {
258
+			// There was an error loading the board, but some data was still read
259
+			var backup = backupFileName(boardData.file);
260
+			log("Writing the corrupted file to " + backup);
238 261
 			try {
239
-				if (err) throw err;
240
-				boardData.board = JSON.parse(data);
241
-				for (id in boardData.board) boardData.validate(boardData.board[id]);
242
-				log('disk load', { 'board': boardData.name });
243
-			} catch (e) {
244
-				console.error("Unable to read history from " + boardData.file + ". The following error occured: " + e);
245
-				log('empty board creation', { 'board': boardData.name });
246
-				boardData.board = {}
247
-				if (data) {
248
-					// There was an error loading the board, but some data was still read
249
-					var backup = backupFileName(boardData.file);
250
-					log("Writing the corrupted file to " + backup);
251
-					fs.writeFile(backup, data, function (err) {
252
-						if (err) log("Error writing " + backup + ": " + err);
253
-					});
254
-				}
262
+				await fs.promises.writeFile(backup, data);
263
+			} catch (err) {
264
+				log("Error writing " + backup + ": " + err);
255 265
 			}
256
-			accept(boardData);
257
-		});
258
-	});
266
+		}
267
+	}
268
+	return boardData;
259 269
 };
260 270
 
261 271
 function backupFileName(baseName) {

+ 42
- 42
server/sockets.js Voir le fichier

@@ -5,7 +5,9 @@ var iolib = require('socket.io')
5 5
 var MAX_EMIT_COUNT = 64; // Maximum number of draw operations before getting banned
6 6
 var MAX_EMIT_COUNT_PERIOD = 5000; // Duration (in ms) after which the emit count is reset
7 7
 
8
-// Map from name to *promises* of BoardData
8
+/** Map from name to *promises* of BoardData
9
+	@type {Object<string, Promise<BoardData>>}
10
+*/
9 11
 var boards = {};
10 12
 
11 13
 function noFail(fn) {
@@ -24,7 +26,9 @@ function startIO(app) {
24 26
 	return io;
25 27
 }
26 28
 
27
-/** Returns a promise to a BoardData with the given name*/
29
+/** Returns a promise to a BoardData with the given name
30
+ * @returns {Promise<BoardData>}
31
+*/
28 32
 function getBoard(name) {
29 33
 	if (boards.hasOwnProperty(name)) {
30 34
 		return boards[name];
@@ -37,30 +41,28 @@ function getBoard(name) {
37 41
 
38 42
 function socketConnection(socket) {
39 43
 
40
-	function joinBoard(name) {
44
+	async function joinBoard(name) {
41 45
 		// Default to the public board
42 46
 		if (!name) name = "anonymous";
43 47
 
44 48
 		// Join the board
45 49
 		socket.join(name);
46 50
 
47
-		return getBoard(name).then(board => {
48
-			board.users.add(socket.id);
49
-			log('board joined', { 'board': board.name, 'users': board.users.size });
50
-			return board;
51
-		});
51
+		var board = await getBoard(name);
52
+		board.users.add(socket.id);
53
+		log('board joined', { 'board': board.name, 'users': board.users.size });
54
+		return board;
52 55
 	}
53 56
 
54 57
 	socket.on("error", noFail(function onError(error) {
55 58
 		log("ERROR", error);
56 59
 	}));
57 60
 
58
-	socket.on("getboard", noFail(function onGetBoard(name) {
59
-		joinBoard(name).then(board => {
60
-			//Send all the board's data as soon as it's loaded
61
-			socket.emit("broadcast", { _children: board.getAll() });
62
-		});
63
-	}));
61
+	socket.on("getboard", async function onGetBoard(name) {
62
+		var board = await joinBoard(name);
63
+		//Send all the board's data as soon as it's loaded
64
+		socket.emit("broadcast", { _children: board.getAll() });
65
+	});
64 66
 
65 67
 	socket.on("joinboard", noFail(joinBoard));
66 68
 
@@ -102,41 +104,39 @@ function socketConnection(socket) {
102 104
 	}));
103 105
 
104 106
 	socket.on('disconnecting', function onDisconnecting(reason) {
105
-		Object.keys(socket.rooms).forEach(function disconnectFrom(room) {
107
+		Object.keys(socket.rooms).forEach(async function disconnectFrom(room) {
106 108
 			if (boards.hasOwnProperty(room)) {
107
-				boards[room].then(board => {
108
-					board.users.delete(socket.id);
109
-					var userCount = board.users.size;
110
-					log('disconnection', { 'board': board.name, 'users': board.users.size });
111
-					if (userCount === 0) {
112
-						board.save();
113
-						delete boards[room];
114
-					}
115
-				});
109
+				var board = await boards[room];
110
+				board.users.delete(socket.id);
111
+				var userCount = board.users.size;
112
+				log('disconnection', { 'board': board.name, 'users': board.users.size });
113
+				if (userCount === 0) {
114
+					board.save();
115
+					delete boards[room];
116
+				}
116 117
 			}
117 118
 		});
118 119
 	});
119 120
 }
120 121
 
121
-function saveHistory(boardName, message) {
122
+async function saveHistory(boardName, message) {
122 123
 	var id = message.id;
123
-	getBoard(boardName).then(board => {
124
-		switch (message.type) {
125
-			case "delete":
126
-				if (id) board.delete(id);
127
-				break;
128
-			case "update":
129
-				delete message.type;
130
-				if (id) board.update(id, message);
131
-				break;
132
-			case "child":
133
-				board.addChild(message.parent, message);
134
-				break;
135
-			default: //Add data
136
-				if (!id) throw new Error("Invalid message: ", message);
137
-				board.set(id, message);
138
-		}
139
-	});
124
+	var board = await getBoard(boardName);
125
+	switch (message.type) {
126
+		case "delete":
127
+			if (id) board.delete(id);
128
+			break;
129
+		case "update":
130
+			delete message.type;
131
+			if (id) board.update(id, message);
132
+			break;
133
+		case "child":
134
+			board.addChild(message.parent, message);
135
+			break;
136
+		default: //Add data
137
+			if (!id) throw new Error("Invalid message: ", message);
138
+			board.set(id, message);
139
+	}
140 140
 }
141 141
 
142 142
 function generateUID(prefix, suffix) {

Chargement…
Annuler
Enregistrer