From a2a881237190379d7f170706dc75ae3ecaa46e95 Mon Sep 17 00:00:00 2001 From: Johannes Zellner Date: Fri, 7 Feb 2014 09:21:54 -0800 Subject: [PATCH] Make volume.getVolume() async --- api/routes/test/file-test.js | 2 + api/routes/volume.js | 28 +++++------ api/test/volume-test.js | 17 ++++--- api/volume.js | 92 ++++++++++++++++++++++-------------- 4 files changed, 83 insertions(+), 56 deletions(-) diff --git a/api/routes/test/file-test.js b/api/routes/test/file-test.js index b994aeee0..ce6e72e37 100644 --- a/api/routes/test/file-test.js +++ b/api/routes/test/file-test.js @@ -32,6 +32,8 @@ var server; function setup(done) { server = new Server(CONFIG); server.start(function (err) { + expect(err).to.not.be.ok(); + SERVER_URL = 'http://localhost:' + CONFIG.port; database.USERS_TABLE.removeAll(function () { request.post(SERVER_URL + '/api/v1/createadmin') diff --git a/api/routes/volume.js b/api/routes/volume.js index e88c7d5be..a2a77f703 100644 --- a/api/routes/volume.js +++ b/api/routes/volume.js @@ -41,8 +41,6 @@ function listVolumes(req, res, next) { return next(new HttpError(500, 'Unable to list volumes: ' + error)); } - var ret = []; - async.map(result, function (volume, callback) { var ret = {}; ret.name = volume.name; @@ -68,16 +66,16 @@ function createVolume(req, res, next) { return next(new HttpError(400, 'New volume name not specified')); } - if (volume.get(req.body.name, req.user.username, config)) { - return next(new HttpError(409, 'Volume already exists')); - } + volume.get(req.body.name, req.user.username, config, function (error, result) { + if (result) next(new HttpError(409, 'Volume already exists')); - volume.create(req.body.name, req.user, config, function (error, result) { - if (error) { - return next(new HttpError(500, 'Volume creation failed: ' + error)); - } + volume.create(req.body.name, req.user, config, function (error, result) { + if (error) { + return next(new HttpError(500, 'Volume creation failed: ' + error)); + } - res.send(201, {}); + res.send(201, {}); + }); }); } @@ -131,11 +129,11 @@ function isMounted(req, res, next) { function attachVolume(req, res, next, volumeId) { if (!volumeId) return next(new HttpError(400, 'Volume not specified')); - req.volume = volume.get(volumeId, req.user.username, config); - - if (!req.volume) return next(new HttpError(404, 'No such volume')); - - next(); + volume.get(volumeId, req.user.username, config, function (error, result) { + if (error) return next(new HttpError(404, 'No such volume')); + req.volume = result; + next(); + }); } function requireMountedVolume(req, res, next) { diff --git a/api/test/volume-test.js b/api/test/volume-test.js index 79f5795c9..25134ead4 100644 --- a/api/test/volume-test.js +++ b/api/test/volume-test.js @@ -85,15 +85,20 @@ describe('Volume', function () { }); describe('get', function () { - it('succeeds', function () { - var vol = volume.get(VOLUME, USERNAME, config); - expect(vol).to.be.ok(); - expect(vol).to.be.an(volume.Volume); + it('succeeds', function (done) { + volume.get(VOLUME, USERNAME, config, function (error, result) { + expect(error).to.not.be.ok(); + expect(result).to.be.ok(); + expect(result).to.be.an(volume.Volume); + done(); + }); }); it('fails, no such volume', function () { - var vol = volume.get(VOLUME_3, USERNAME, config); - expect(vol).to.not.be.ok(); + volume.get(VOLUME_3, USERNAME, config, function (error, result) { + expect(error).to.be.ok(); + expect(result).to.not.be.ok(); + }); }); it('list', function (done) { diff --git a/api/volume.js b/api/volume.js index e8de2ffa4..d680364b8 100644 --- a/api/volume.js +++ b/api/volume.js @@ -8,7 +8,8 @@ var fs = require('fs'), path = require('path'), assert = require('assert'), crypto = require('crypto'), - aes = require("./aes-helper"), + aes = require('./aes-helper'), + async = require('async'), util = require('util'), HttpError = require('./httperror.js'), Repo = require('./repo.js'), @@ -50,7 +51,7 @@ VolumeError.NO_SUCH_VOLUME = 5; function generateNewVolumePassword() { var chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+?{}[]|:;'~`<>,.-="; var charsLength = chars.length; - var password = ""; + var password = ''; for (var i = 0; i < 64; ++i) { password += chars.charAt(Math.floor(Math.random() * charsLength)); @@ -66,8 +67,10 @@ function Volume(name, config) { this.mountPoint = this._resolveVolumeMountPoint(); this.tmpPath = path.join(this.mountPoint, 'tmp'); this.encfs = new encfs.Root(this.dataPath, this.mountPoint); - this.repo = undefined; - this.meta = undefined; + this.repo = null; + this.meta = null; + + this._initMetaDatabase(); } Volume.prototype._resolveVolumeRootPath = function() { @@ -107,8 +110,6 @@ Volume.prototype.open = function (username, password, callback) { var that = this; - this._initMetaDatabase(); - this.encfs.isMounted(function (error, mounted) { if (error) { return callback(error); @@ -266,6 +267,18 @@ Volume.prototype.removeUser = function (user, callback) { this.meta.remove(user.username, callback); }; +Volume.prototype.hasUserByName = function (username, callback) { + if (!this.meta) { + debug('Invalid volume "' + this.name + '". Misses the meta database.'); + return callback(new VolumeError(null, VolumeError.META_MISSING)); + } + + this.meta.get(username, function (error, result) { + // TODO maybe more error checking? + callback(null, !!result); + }); +}; + function listVolumes(username, config, callback) { assert(typeof username === 'string'); assert(username.length !== 0); @@ -282,28 +295,31 @@ function listVolumes(username, config, callback) { var ret = []; - files.forEach(function (file) { - var stat = safe.fs.statSync(path.join(config.dataRoot, file)); - if (!stat) { - debug('Unable to stat "' + file + '".'); - return; - } + async.each(files, function (file, callback) { + fs.stat(path.join(config.dataRoot, file), function (error, stat) { + if (error) { + debug('Unable to stat "' + file + '".', error); + return callback(null); + } - // ignore everythin else than directories - if (!stat.isDirectory()) { - return; - } + // ignore everythin else than directories + if (!stat.isDirectory()) { + return callback(null); + } - var vol = getVolume(file, username, config); - if (!vol) { - return; - } + getVolume(file, username, config, function (error, result) { + if (!error) { + debug('Detected volume with repo: "' + file + '".'); + ret.push(result); + } - ret.push(vol); - debug('Detected volume with repo: "' + file + '".'); + callback(null); + }); + }); + }, function (error) { + if (error) debug('This should never happen.'); + callback(null, ret); }); - - callback(null, ret); }); } @@ -358,35 +374,41 @@ function destroyVolume(name, username, config, callback) { assert(username.length !== 0); assert(typeof callback === 'function'); - var vol = getVolume(name, username, config); - if (!vol) { - return callback(new VolumeError(null, VolumeError.NO_SUCH_VOLUME)); - } - - vol.destroy(callback); + getVolume(name, username, config, function (error, result) { + if (error) return callback(new VolumeError(null, VolumeError.NO_SUCH_VOLUME)); + result.destroy(callback); + }); } -function getVolume(name, username, config) { +function getVolume(name, username, config, callback) { assert(typeof name === 'string'); assert(name.length !== 0); assert(typeof username === 'string'); assert(username.length !== 0); assert(typeof config === 'object'); + assert(typeof callback === 'function'); // TODO check if username has access and if it exists var vol = new Volume(name, config); if (!safe.fs.existsSync(vol.dataPath)) { debug('No volume "' + name + '" for user "' + username + '". ' + safe.JSON.stringify(safe.error)); - return null; + return callback(new VolumeError()); } // Check if that volume has a meta information file, if not it is not created properly or broken if (!safe.fs.existsSync(path.join(vol.dataPath, VOLUME_META_FILENAME))) { debug('Volume "' + name + '" for user "' + username + '" does not have meta information, it is possibly broken.'); - return null; + return callback(new VolumeError()); } - vol.repo = new Repo(path.join(vol.mountPoint, REPO_SUBFOLDER), vol.tmpPath); + vol.hasUserByName(username, function (error, result) { + if (error || !result) { + debug('User "' + username + '" has no access to volume "' + name + '".'); + return callback(new VolumeError()); + } - return vol; + vol.repo = new Repo(path.join(vol.mountPoint, REPO_SUBFOLDER), vol.tmpPath); + + callback(null, vol); + }); }