var LibraryCLOUDFS = { $CLOUDFS__deps: ['$FS', '$MEMFS', '$PATH'], $CLOUDFS__postset: "var CLOUD_PROVIDERS; if (!CLOUD_PROVIDERS) CLOUD_PROVIDERS = (typeof CLOUD_PROVIDERS !== 'undefined' ? CLOUD_PROVIDERS : null) || {};", $CLOUDFS: { mount: function(mount) { var provider = CLOUDFS.fetchProvider(mount); if (provider) { mount.opts.provider = provider; console.log("Mounting", mount); } else { mount.opts.disabled = true; Module.print("WARNING: Cloud provider not available. Disabling Sync"); } return MEMFS.mount.apply(null, arguments); }, syncfs: function(mount, populate, callback) { if (mount.opts.disabled) { return callback(new Error("Syncing Disabled")); } console.log("Syncing", mount, populate); // re-use IDBFS.getLocalSet for now CLOUDFS.getLocalSet(mount, function(err, local) { if (err) return callback(err); CLOUDFS.getRemoteSet(mount, function(err, remote) { if (err) return callback(err); var src = populate ? remote : local; var dst = populate ? local : remote; console.log('source', src); console.log('destination', dst); // say we completed (for now) callback(null); }); }); }, // Utility functions fetchProvider: function(mount) { if (mount.opts.provider === undefined || CLOUD_PROVIDERS[mount.opts.provider] === undefined) { return false; } var provider = CLOUD_PROVIDERS[mount.opts.provider]; var requiredMethods = ['listFiles', 'downloadFile', 'uploadFile', 'removeFile']; var valid = requiredMethods.every(function(method) { return (method in provider); }); if (valid) { Module.print('Cloud provider vendor: ' + provider.vendor); return provider; } else { return false; } }, // Getting list of entities getLocalSet: function(mount, callback) { var entries = {}; function isRealDir(p) { return p !== '.' && p !== '..'; }; function toAbsolute(root) { return function(p) { return PATH.join2(root, p); } }; var check = FS.readdir(mount.mountpoint).filter(isRealDir); while (check.length) { var path = check.pop(); var stat; var abs_path = PATH.join2(mount.mountpoint, path); try { stat = FS.stat(abs_path); } catch (e) { return callback(e); } if (FS.isDir(stat.mode)) { check.push.apply(check, FS.readdir(abs_path).filter(isRealDir).map(toAbsolute(path))); } entries[abs_path] = { timestamp: stat.mtime, path: path }; } return callback(null, { type: 'local', entries: entries }); }, getRemoteSet: function(mount, callback) { mount.opts.provider.listFiles(mount.opts.cloud, function(data) { var entries = {}, toAbsolute = function(p) { return PATH.join2(mount.mountpoint, p); }; json = JSON.parse(data); for(var k in json.data) { var f = json.data[k], timestamp = new Date(parseInt(f.timestamp)); if (f.path.indexOf('/') !== -1) { // we have folders.. stuff them in the list var parts = f.path.split('/'); // remove the "file" from the end parts.pop(); // remove the empty directory from the beginning if (parts[0] == '') parts.shift(); var prefix = ''; parts.forEach(function(e) { var p = PATH.join2(prefix, e), abs = toAbsolute(p); if (!(abs in entries)) { entries[abs] = { path: p, timestamp: timestamp }; } prefix = p; }); } var p = toAbsolute(f.path); entries[p] = { url: (f.url.substr(0, 1) == '/') ? CLOUDFS.remoteAPIEndpoint + f.url : f.url, path: f.path.trim('/'), timestamp: timestamp, size: f.size }; } return callback(null, { type: 'remote', entries: entries } ); }, function(e) { callback(e || new Error('failed request')); }); } } }; autoAddDeps(LibraryCLOUDFS, '$CLOUDFS'); mergeInto(LibraryManager.library, LibraryCLOUDFS);