diff --git a/HELP.md b/HELP.md index 956b0191..df51d3c3 100644 --- a/HELP.md +++ b/HELP.md @@ -69,6 +69,7 @@ Cloud Commander supports command line parameters: | `-p, --password` | set password | `-c, --config` | configuration file path | `--editor` | set editor: "dword", "edward" or "deepword" +| `--packer` | set packer: "tar" or "zip" | `--root` | set root directory | `--prefix` | set url prefix | `--port` | set port number @@ -236,6 +237,7 @@ Here is description of options: "password" : "toor", /* password hash in sha-1 for authentication*/ "algo" : "sha512WithRSAEncryption", /* cryptographic algorithm */ "editor" : "edward", /* default, could be "dword" or "edward" */ + "packer" : "tar", /* default, could be "tar" or "zip" */ "diff" : true, /* when save - send patch, not whole file */ "zip" : true, /* zip text before send / unzip before save */ "notifications" : false, /* show notifications when tab is not active*/ diff --git a/bin/cloudcmd.js b/bin/cloudcmd.js index 237d882b..8d4f6fd8 100755 --- a/bin/cloudcmd.js +++ b/bin/cloudcmd.js @@ -18,6 +18,7 @@ const args = require('minimist')(argv.slice(2), { 'username', 'config', 'editor', + 'packer', 'root', 'prefix' ], @@ -42,6 +43,8 @@ const args = require('minimist')(argv.slice(2), { online : config('online'), open : config('open'), editor : config('editor') || 'edward', + packer : config('packer') || 'tar', + zip : config('zip'), username : config('username'), root : config('root') || '/', prefix : config('prefix') || '', @@ -96,6 +99,7 @@ if (args.version) { const options = { root: args.root, editor: args.editor, + packer: args.packer, prefix: args.prefix }; diff --git a/img/screen/config.png b/img/screen/config.png index b18a07a7..311c96b2 100644 Binary files a/img/screen/config.png and b/img/screen/config.png differ diff --git a/img/screen/console.png b/img/screen/console.png index ca360d1f..f93d611c 100644 Binary files a/img/screen/console.png and b/img/screen/console.png differ diff --git a/img/screen/edit.png b/img/screen/edit.png index a0222328..e24c64b1 100644 Binary files a/img/screen/edit.png and b/img/screen/edit.png differ diff --git a/img/screen/menu.png b/img/screen/menu.png index dd288c55..4074764e 100644 Binary files a/img/screen/menu.png and b/img/screen/menu.png differ diff --git a/img/screen/one-panel-mode.png b/img/screen/one-panel-mode.png index 0f73b2c6..97ca488d 100644 Binary files a/img/screen/one-panel-mode.png and b/img/screen/one-panel-mode.png differ diff --git a/img/screen/view.png b/img/screen/view.png index b80f805c..a89d5382 100644 Binary files a/img/screen/view.png and b/img/screen/view.png differ diff --git a/json/config.json b/json/config.json index 2d17ca4b..e15321f0 100644 --- a/json/config.json +++ b/json/config.json @@ -4,6 +4,7 @@ "password": "2b64f2e3f9fee1942af9ff60d40aa5a719db33b8ba8dd4864bb4f11e25ca2bee00907de32a59429602336cac832c8f2eeff5177cc14c864dd116c8bf6ca5d9a9", "algo": "sha512WithRSAEncryption", "editor": "edward", + "packer": "tar", "diff": true, "zip" : true, "notifications": false, diff --git a/json/help.json b/json/help.json index 12088dbb..1b2269c9 100644 --- a/json/help.json +++ b/json/help.json @@ -8,6 +8,7 @@ "-p, --password ": "set password", "-c, --config ": "configuration file path", "--editor ": "set editor: \"dword\" or \"edward\"", + "--packer ": "set packer: \"tar\" or \"zip\"", "--root ": "set root directory", "--prefix ": "set url prefix", "--port ": "set port number", diff --git a/lib/client/config.js b/lib/client/config.js index d1247577..82a1988a 100644 --- a/lib/client/config.js +++ b/lib/client/config.js @@ -144,6 +144,9 @@ var CloudCmd, Util, DOM, io; obj[obj.editor + '-selected'] = 'selected'; delete obj.editor; + obj[obj.packer + '-selected'] = 'selected'; + delete obj.packer; + data = rendy(Template, obj); Element = DOM.load({ name : 'div', diff --git a/lib/client/dom.js b/lib/client/dom.js index d722cdb7..943ac7e8 100644 --- a/lib/client/dom.js +++ b/lib/client/dom.js @@ -1516,6 +1516,13 @@ var CloudCmd, Util, DOM, CloudFunc; return this; }; + this.getPackerExt = function(type) { + if (type === 'zip') + return '.zip'; + + return '.tar.gz'; + } + this.goToDirectory = function() { var msg = 'Go to directory:', path = CurrentInfo.dirPath, diff --git a/lib/client/listeners.js b/lib/client/listeners.js index f903f071..a8f97795 100644 --- a/lib/client/listeners.js +++ b/lib/client/listeners.js @@ -17,14 +17,24 @@ var Util, DOM, CloudFunc, CloudCmd; 'touchstart': Util.exec.with(execIfNotUL, onTouch) }; + var EXT; + this.init = function () { contextMenu(); dragndrop(); unload(); pop(); resize(); + config(); }; + function config() { + DOM.Files.get('config', function(e, config) { + var type = config && config.packer; + EXT = DOM.getPackerExt(type); + }); + } + this.initKeysPanel = function() { var keysElement = DOM.getById('js-keyspanel'); @@ -226,17 +236,16 @@ var Util, DOM, CloudFunc, CloudCmd; function onDragStart(event) { var apiURL = CloudFunc.apiURL, element = getLIElement(event.target), - EXT = '.tar.gz', isDir = Info.isDir, link = DOM.getCurrentLink(element), name = DOM.getCurrentName(element); /* if it's directory - adding json extension */ if (isDir) { - name += EXT; - link = document.createElement('a'); - link.textContent = name; - link.href = apiURL + '/pack' + Info.path + EXT; + name += EXT; + link = document.createElement('a'); + link.textContent = name; + link.href = apiURL + '/pack' + Info.path + EXT; } event.dataTransfer.setData('DownloadURL', diff --git a/lib/client/menu.js b/lib/client/menu.js index 5805d30b..5fa9759b 100644 --- a/lib/client/menu.js +++ b/lib/client/menu.js @@ -187,7 +187,7 @@ var CloudCmd, Util, DOM, CloudFunc, MenuIO; 'Extract' : function() { CloudCmd.Operation.show('extract'); }, - 'Download' : download, + 'Download' : preDownload, 'Upload To Cloud': curry(uploadTo, 'Cloud'), 'Cut' : function() { isCurrent(Buffer.cut, function() { @@ -281,7 +281,13 @@ var CloudCmd, Util, DOM, CloudFunc, MenuIO; }); } - function download() { + function preDownload() { + DOM.Files.get('config', function(e, config) { + download(config && config.packer); + }); + } + + function download(type) { var TIME = 30 * 1000, prefixUr = CloudCmd.PREFIX_URL, FS = CloudFunc.FS, @@ -310,7 +316,7 @@ var CloudCmd, Util, DOM, CloudFunc, MenuIO; path = encodeURI(path); if (isDir) - path = prefixUr + PACK + path + '.tar.gz'; + path = prefixUr + PACK + path + DOM.getPackerExt(type); else path = prefixUr + FS + path + '?download'; diff --git a/lib/client/operation.js b/lib/client/operation.js index 8ceb020c..08be3975 100644 --- a/lib/client/operation.js +++ b/lib/client/operation.js @@ -6,6 +6,7 @@ /* global spero */ /* global remedy */ /* global ishtar */ +/* global salam */ (function(CloudCmd, Util, DOM, rendy) { 'use strict'; @@ -116,8 +117,8 @@ }); } - function _initIshtar(prefix, fn) { - ishtar(prefix + '/ishtar', prefix, function(packer) { + function _setPacker(prefix, name, pack, fn) { + pack(prefix + '/' + name, prefix, function(packer) { fn(); packer.on('connect', function() { authCheck(packer, function() { @@ -140,15 +141,27 @@ }); } + function _initPacker(prefix, fn) { + DOM.Files.get('config', function(e, config) { + if (e) + CloudCmd.log(e); + + if (config.packer === 'zip') + return _setPacker(prefix, 'salam', salam, fn); + + _setPacker(prefix, 'ishtar', ishtar, fn); + }); + } + function create(prefix) { var initSpero = currify(_initSpero); var initRemedy = currify(_initRemedy); - var initIshtar = currify(_initIshtar); + var initPacker = currify(_initPacker); exec.parallel([ initSpero(prefix), initRemedy(prefix), - initIshtar(prefix), + initPacker(prefix) ], exec.ret); } @@ -251,14 +264,19 @@ }; this.pack = function() { - twopack('pack'); + DOM.Files.get('config', function(e, config) { + var zip = config && config.packer === 'zip'; + twopack('pack', zip ? 'zip' : 'tar'); + }); }; this.extract = function() { - twopack('extract'); + DOM.Files.get('config', function(e, config) { + var zip = config && config.packer === 'zip'; + twopack('extract', zip ? 'zip' : 'tar'); + }); }; - /** * prompt and delete current file or selected files * @@ -444,16 +462,23 @@ } } - function twopack(operation) { + function getTypeReg(type) { + if (type === 'zip') + return /\.zip$/; + + return /\.tar\.gz$/ + } + + function twopack(operation, type) { var op, + fileFrom, Images = DOM.Images, Info = DOM.CurrentInfo, name = Info.name, path = Info.path, dirPath = Info.dirPath, activeFiles = DOM.getActiveFiles(), - names = DOM.getFilenames(activeFiles), - fileFrom; + names = DOM.getFilenames(activeFiles); Util.check(arguments, ['operation']); @@ -462,14 +487,14 @@ } else { switch(operation) { case 'extract': - op = extractFn; + op = extractFn; fileFrom = { from : path, to : dirPath }; - name = name.replace(/\.tar\.gz$/, ''); + name = name.replace(getTypeReg(type), ''); break; @@ -479,7 +504,7 @@ if (names.length > 1) name = Info.dir; - name += '.tar.gz'; + name += DOM.getPackerExt(type); fileFrom = { from : dirPath, @@ -525,7 +550,8 @@ files = [ '/spero/spero.js', '/remedy/remedy.js', - '/ishtar/ishtar.js' + '/ishtar/ishtar.js', + '/salam/salam.js' ].map(function(name) { return prefix + name; }); diff --git a/lib/cloudcmd.js b/lib/cloudcmd.js index 044181a1..262dee32 100644 --- a/lib/cloudcmd.js +++ b/lib/cloudcmd.js @@ -25,6 +25,7 @@ var DIR = __dirname + '/', spero = require('spero'), remedy = require('remedy'), ishtar = require('ishtar'), + salam = require('salam/legacy'), criton = require('criton'), root = function() { @@ -66,6 +67,9 @@ module.exports = function(params) { case 'editor': validate.editor(value); break; + case 'packer': + validate.packer(value); + break; case 'password': /* could be useful when used as middleware */ value = criton(value, config('algo')); @@ -147,6 +151,12 @@ function listen(prefix, socket) { authCheck: authCheck }); + salam.listen(socket, { + root: root, + prefix: prefix + '/salam', + authCheck: authCheck + }); + config('console') && konsole.listen(socket, { prefix: prefix + '/console', authCheck: authCheck @@ -217,6 +227,10 @@ function cloudcmd(prefix) { online : isOnline }), + salam({ + prefix: prefix + '/salam', + }), + setUrl(prefix), logout, diff --git a/lib/server/rest.js b/lib/server/rest.js index 7092d236..1d87f2a6 100644 --- a/lib/server/rest.js +++ b/lib/server/rest.js @@ -12,6 +12,7 @@ var DIR = './', markdown = require(DIR + 'markdown'), jaguar = require('jaguar/legacy'), + onezip = require('onezip/legacy'), flop = require('flop'), pullout = require('pullout/legacy'), @@ -142,9 +143,16 @@ function onGET(params, callback) { } } +function getPackReg() { + if (config('zip') === 'zip') + return /\.zip$/; + + return /\.tar\.gz$/; +} + function streamPack(cmd, response) { var noop = function() {}; - var filename = cmd.replace(/\.tar\.gz$/, ''); + var filename = cmd.replace(getPackReg(), ''); var dir = path.dirname(filename); var names = [ path.basename(filename) @@ -261,9 +269,14 @@ function extract(from, to, fn) { operation('extract', from, to, fn); } -function operation(op, from, to, names, fn) { - var packer; +function getPacker() { + if (config('packer') === 'zip') + return onezip; + return jaguar; +} + +function operation(op, from, to, names, fn) { if (!fn) { fn = names; names = [ @@ -271,7 +284,7 @@ function operation(op, from, to, names, fn) { ]; } - packer = jaguar[op](from, to, names); + var packer = getPacker()[op](from, to, names); packer.on('error', function(error) { fn(error); diff --git a/lib/server/validate.js b/lib/server/validate.js index dc8a2096..6db4c245 100644 --- a/lib/server/validate.js +++ b/lib/server/validate.js @@ -2,8 +2,9 @@ var exit = require('./exit'); -module.exports.root = root; -module.exports.editor = editor; +module.exports.root = root; +module.exports.editor = editor; +module.exports.packer = packer; function root(dir, fn) { var fs; @@ -26,3 +27,10 @@ function editor(name) { exit('cloudcmd --editor: could be "dword", "edward" or "deepword" only'); } +function packer(name) { + var reg = /^(tar|zip)$/; + + if (!reg.test(name)) + exit('cloudcmd --packer: could be "tar" or "zip" only'); +} + diff --git a/man/cloudcmd.1 b/man/cloudcmd.1 index b7b4a306..45efcf3b 100644 --- a/man/cloudcmd.1 +++ b/man/cloudcmd.1 @@ -31,6 +31,7 @@ programs in browser from any computer, mobile or tablet device. -p, --password set password -c, --config configuration file path --editor set editor: "dword", "edward" or "deepword" + --packer set packer: "tar" or "zip" --root set root directory --prefix set url prefix --port set port number diff --git a/package.json b/package.json index 0f055963..16335187 100644 --- a/package.json +++ b/package.json @@ -111,6 +111,7 @@ "minify": "^2.0.0", "minimist": "^1.2.0", "mollify": "^1.0.0", + "onezip": "^1.0.5", "opn": "^4.0.1", "os-homedir": "^1.0.0", "package-json": "^2.3.0", @@ -120,6 +121,7 @@ "remedy": "^1.5.0", "rendy": "^1.1.0", "restafary": "^1.6.0", + "salam": "^1.0.0", "socket.io": "^1.4.3", "spero": "^1.5.0", "squad": "^1.1.3", diff --git a/test/fixture/pack.zip b/test/fixture/pack.zip new file mode 100644 index 00000000..c5f31a8d Binary files /dev/null and b/test/fixture/pack.zip differ diff --git a/test/rest/pack.js b/test/rest/pack.js index 8cd418ac..0a368079 100644 --- a/test/rest/pack.js +++ b/test/rest/pack.js @@ -14,8 +14,13 @@ const warp = (fn, ...a) => (...b) => fn(...b, ...a); const _pullout = promisify(pullout); -const pathFixture = path.join(__dirname, '..', 'fixture/pack.tar.gz'); -const fixture = fs.readFileSync(pathFixture); +const pathTarFixture = path.join(__dirname, '..', 'fixture/pack.tar.gz'); +const pathZipFixture = path.join(__dirname, '..', 'fixture/pack.zip'); + +const fixture = { + tar: fs.readFileSync(pathTarFixture), + zip: fs.readFileSync(pathZipFixture), +}; const get = promisify((url, fn) => { fn(null, request(url)); @@ -25,12 +30,13 @@ const put = promisify((options, fn) => { fn(null, request.put(options)); }); -test('cloudcmd: rest: pack: get', (t) => { - before((port, after) => { +test('cloudcmd: rest: pack: tar: get', (t) => { + const options = {packer: 'tar'}; + before(options, (port, after) => { get(`http://localhost:${port}/api/v1/pack/fixture/pack`) .then(_pullout) .then((pack) => { - t.ok(fixture.compare(pack), 'should pack data'); + t.ok(fixture.tar.compare(pack), 'should pack data'); t.end(); after(); }) @@ -40,8 +46,9 @@ test('cloudcmd: rest: pack: get', (t) => { }); }); -test('cloudcmd: rest: pack: put: file', (t) => { - before((port, after) => { +test('cloudcmd: rest: pack: tar: put: file', (t) => { + const options = {packer: 'tar'}; + before(options, (port, after) => { const name = String(Math.random()) + '.tar.gz'; const options = getPackOptions(port, name); @@ -51,7 +58,7 @@ test('cloudcmd: rest: pack: put: file', (t) => { const file = fs.readFileSync(__dirname + '/../' + name); fs.unlinkSync(`${__dirname}/../${name}`); - t.ok(fixture.compare(file), 'should create archive'); + t.ok(fixture.tar.compare(file), 'should create archive'); t.end(); after(); @@ -62,8 +69,9 @@ test('cloudcmd: rest: pack: put: file', (t) => { }); }); -test('cloudcmd: rest: pack: put: response', (t) => { - before((port, after) => { +test('cloudcmd: rest: pack: tar: put: response', (t) => { + const options = {packer: 'tar'}; + before(options, (port, after) => { const name = String(Math.random()) + '.tar.gz'; const options = getPackOptions(port, name); @@ -83,8 +91,91 @@ test('cloudcmd: rest: pack: put: response', (t) => { }); }); -test('cloudcmd: rest: pack: put: error', (t) => { - before((port, after) => { +test('cloudcmd: rest: pack: tar: put: error', (t) => { + const options = {packer: 'tar'}; + before(options, (port, after) => { + const options = getPackOptions(port, 'name', [ + 'not found' + ]); + + put(options) + .then(warp(_pullout, 'string')) + .then((msg) => { + t.ok(/^ENOENT: no such file or directory/.test(msg), 'should return error'); + + t.end(); + after(); + }) + .catch((error) => { + console.log(error); + }); + }); +}); + +test('cloudcmd: rest: pack: zip: get', (t) => { + const options = {packer: 'zip'}; + before(options, (port, after) => { + get(`http://localhost:${port}/api/v1/pack/fixture/pack`) + .then(_pullout) + .then((pack) => { + t.ok(fixture.zip.compare(pack), 'should pack data'); + t.end(); + after(); + }) + .catch((error) => { + console.log(error); + }); + }); +}); + +test('cloudcmd: rest: pack: zip: put: file', (t) => { + const options = {packer: 'zip'}; + before(options, (port, after) => { + const name = String(Math.random()) + '.zip'; + const options = getPackOptions(port, name); + + put(options) + .then(warp(_pullout, 'string')) + .then(() => { + const file = fs.readFileSync(__dirname + '/../' + name); + + fs.unlinkSync(`${__dirname}/../${name}`); + t.ok(fixture.zip.compare(file), 'should create archive'); + + t.end(); + after(); + }) + .catch((error) => { + console.log(error); + }); + }); +}); + +test('cloudcmd: rest: pack: zip: put: response', (t) => { + const options = {packer: 'zip'}; + before(options, (port, after) => { + const name = String(Math.random()) + '.zip'; + const options = getPackOptions(port, name); + + put(options) + .then(warp(_pullout, 'string')) + .then((msg) => { + t.equal(msg, 'pack: ok("fixture")', 'should return result message'); + + fs.unlinkSync(`${__dirname}/../${name}`); + + t.end(); + after(); + }) + .catch((error) => { + console.log(error); + }); + }); +}); + +test('cloudcmd: rest: pack: zip: put: error', (t) => { + const options = {packer: 'zip'}; + before(options, (port, after) => { const options = getPackOptions(port, 'name', [ 'not found' ]); diff --git a/tmpl/config.hbs b/tmpl/config.hbs index 9afda97c..12d41066 100644 --- a/tmpl/config.hbs +++ b/tmpl/config.hbs @@ -91,6 +91,12 @@ Online +
  • + +
  • -