From 463a63aed3033459b9a4a635c07a131b783df580 Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Sat, 19 Nov 2016 22:54:16 +0200 Subject: [PATCH 1/2] Avoid unnecessary disk writes if user object has not changed, make updateUser async --- src/client.js | 18 +++++++----------- src/clientManager.js | 34 ++++++++++++++++++++-------------- src/server.js | 4 +--- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/client.js b/src/client.js index 77db906b..d786bf88 100644 --- a/src/client.js +++ b/src/client.js @@ -292,19 +292,15 @@ Client.prototype.setPassword = function(hash, callback) { client.manager.updateUser(client.name, { token: token, password: hash - }); + }, function(err) { + if (err) { + log.error("Failed to update password of", client.name, err); + return callback(false); + } - // re-read the hash off disk to ensure we use whatever is saved. this will - // prevent situations where the password failed to save properly and so - // a restart of the server would forget the change and use the old - // password again. - var user = client.manager.readUserConfig(client.name); - if (user.password === hash) { client.config.password = hash; - callback(true); - } else { - callback(false); - } + return callback(true); + }); }); }; diff --git a/src/clientManager.js b/src/clientManager.js index f5afb9cf..8dd6af70 100644 --- a/src/clientManager.js +++ b/src/clientManager.js @@ -94,8 +94,8 @@ ClientManager.prototype.addUser = function(name, password) { return true; }; -ClientManager.prototype.updateUser = function(name, opts) { - var users = this.getUsers(); +ClientManager.prototype.updateUser = function(name, opts, callback) { + const users = this.getUsers(); if (users.indexOf(name) === -1) { return false; } @@ -103,19 +103,25 @@ ClientManager.prototype.updateUser = function(name, opts) { return false; } - var user = {}; - try { - user = this.readUserConfig(name); - _.assign(user, opts); - fs.writeFileSync( - Helper.getUserConfigPath(name), - JSON.stringify(user, null, "\t") - ); - } catch (e) { - log.error("Failed to update user", e); - return; + let user = this.readUserConfig(name); + const currentUser = JSON.stringify(user, null, "\t"); + _.assign(user, opts); + const newUser = JSON.stringify(user, null, "\t"); + + // Do not touch the disk if object has not changed + if (currentUser === newUser) { + return callback ? callback() : true; } - return true; + + fs.writeFile(Helper.getUserConfigPath(name), newUser, (err) => { + if (err) { + log.error("Failed to update user", err); + } + + if (callback) { + callback(err); + } + }); }; ClientManager.prototype.readUserConfig = function(name) { diff --git a/src/server.js b/src/server.js index d8cb0d9f..1e03e918 100644 --- a/src/server.js +++ b/src/server.js @@ -273,9 +273,7 @@ function localAuth(client, user, password, callback) { var hash = Helper.password.hash(password); client.setPassword(hash, function(success) { - if (!success) { - log.error("Failed to update password of", client.name, "to match new security requirements"); - } else { + if (success) { log.info("User", client.name, "logged in and their hashed password has been updated to match new security requirements"); } }); From 4fe3c5e96abadef1bb17350d9c38d690a474abc0 Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Sat, 19 Nov 2016 23:00:54 +0200 Subject: [PATCH 2/2] Change ghetto timer to debounce --- src/client.js | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/src/client.js b/src/client.js index d786bf88..d217009c 100644 --- a/src/client.js +++ b/src/client.js @@ -460,23 +460,13 @@ Client.prototype.clientDetach = function(socketId) { delete this.attachedClients[socketId]; }; -var timer; -Client.prototype.save = function(force) { - var client = this; - +Client.prototype.save = _.debounce(function SaveClient() { if (Helper.config.public) { return; } - if (!force) { - clearTimeout(timer); - timer = setTimeout(function() { - client.save(true); - }, 1000); - return; - } - - var json = {}; + const client = this; + let json = {}; json.networks = this.networks.map(n => n.export()); client.manager.updateUser(client.name, json); -}; +}, 1000, {maxWait: 10000});