Merge pull request #750 from thelounge/xpaw/reduce-save

Avoid unnecessary disk writes when saving user
This commit is contained in:
Maxime Poulin 2016-12-10 18:19:56 -05:00 committed by GitHub
commit 3e5a4c9c38
3 changed files with 32 additions and 42 deletions

View file

@ -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);
});
});
};
@ -464,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});

View file

@ -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) {

View file

@ -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");
}
});