UNPKG

nobone-sync

Version:

A simple remote file sync tool for development.

192 lines (171 loc) 6.95 kB
// Watch and sync a local folder with a remote one. // All the local operations will be repeated on the remote. // // This this the remote server. var cs, http, kit, localPath; kit = require('nokit'); cs = kit.require('brush'); http = require('http'); localPath = function(path) { if (process.platform === 'win32') { return path.replace(/\//g, '\\'); } else { return path.replace(/\\/g, '\/'); } }; module.exports = function(conf) { var decodeInfo, service; kit._.defaults(conf, require('./config.default')); decodeInfo = function(str) { return JSON.parse(conf.password ? kit.decrypt(new Buffer(str, 'hex'), conf.password, conf.algorithm) : decodeURIComponent(str)); }; service = http.createServer(function(req, res) { var absPath, absRoot, data, err, mode, p, path, ref, reqStream, type; function httpError (code, err) { kit.err((err != null ? err.stack : void 0) || err); res.statusCode = code; return res.end(http.STATUS_CODES[code]); }; try { ref = decodeInfo(req.url.slice(1)), type = ref.type, path = ref.path, mode = ref.mode; } catch (_error) { err = _error; return httpError(400, err); } path = localPath(path); if (conf.rootAllowed) { absPath = kit.path.normalize(kit.path.resolve(path)); absRoot = kit.path.normalize(kit.path.resolve(conf.rootAllowed)); if (absPath.indexOf(absRoot) !== 0) { return httpError(403, err); } } kit.log(cs.grey("[server] ") + cs.cyan(type) + ': ' + path); p = kit.Promise.resolve(); reqStream = null; function getStream () { var crypto, decipher; if (conf.password) { crypto = kit.require('crypto', __dirname); decipher = crypto.createDecipher(conf.algorithm, conf.password); return req.pipe(decipher); } else { return req; } }; function pipeToFile () { reqStream = getStream(); return kit.mkdirs(kit.path.dirname(path)).then(function() { var f; f = kit.createWriteStream(path, { mode: mode }); f.on('error', function(err) { return p = kit.Promise.reject(err); }); return new kit.Promise(function(resolve) { return reqStream.pipe(f).on('finish', function() { return resolve(); }); }); }); }; switch (type) { case 'create': if (path.slice(-1) === kit.path.sep) { p = kit.mkdirs(path); } else { p = pipeToFile(); } break; case 'modify': p = pipeToFile(); } if (!reqStream) { data = new Buffer(0); req.on('data', function(chunk) { return data = Buffer.concat([data, chunk]); }); } req.on('error', function(err) { return p = kit.Promise.reject(err); }); return req.on('end', function() { var child_process, oldPath, tmpFile; oldPath = null; switch (type) { case 'create': case 'modify': null; break; case 'move': if (conf.password && data.length > 0) { data = kit.decrypt(data, conf.password, conf.algorithm); } oldPath = localPath(data.toString()); p = kit.move(oldPath, path.replace(/\/+$/, '')); break; case 'delete': p = kit.remove(path); break; case 'execute': child_process = kit.require('child_process', __dirname); if (conf.password && data.length > 0) { data = kit.decrypt(data, conf.password, conf.algorithm); } tmpFile = __dirname + '/tmp/' + Date.now() + Math.random() + (path || '.js'); kit.outputFile(tmpFile, data).then(function() { var cipher, crypto, proc; proc = child_process.fork(tmpFile, { silent: true }); res.on('error', function() { return proc.kill('SIGINT'); }); proc.on('close', function() { var ref1; kit.remove(tmpFile); return (ref1 = conf.onChange) != null ? ref1.call(0, type, path) : void 0; }); if (conf.password) { crypto = kit.require('crypto', __dirname); cipher = crypto.createCipher(conf.algorithm, conf.password); proc.on('close', function() { return res.end(cipher.final()); }); proc.stdout.on('data', function(c) { return res.write(cipher.update(c)); }); return proc.stderr.on('data', function(c) { return res.write(cipher.update(c)); }); } else { proc.on('close', function() { return res.end(); }); proc.stdout.on('data', function(c) { return res.write(c); }); return proc.stderr.on('data', function(c) { return res.write(c); }); } }); return; default: return httpError(404, new Error('Unknown Change Type')); } return p.then(function() { var ref1; return kit.Promise.resolve((ref1 = conf.onChange) != null ? ref1.call(0, type, path, oldPath, mode) : void 0); }).then(function() { return res.end(); })["catch"](function(err) { return httpError(500, err); }); }); }); return service.listen(conf.port, function() { return kit.log(cs.cyan("Listen: ") + conf.port); }); };