var Fs = require("fs"); var Fse = require("fs-extra"); var Path = require("path"); var nacl = require("tweetnacl"); var nThen = require("nthen"); var Tasks = module.exports; var encode = function (time, command, args) { if (typeof(time) !== 'number') { return null; } if (typeof(command) !== 'string') { return null; } if (!Array.isArray(args)) { return [time, command]; } return [time, command].concat(args); }; var randomId = function () { var bytes = Array.prototype.slice.call(nacl.randomBytes(16)); return bytes.map(function (b) { var n = Number(b & 0xff).toString(16); return n.length === 1? '0' + n: n; }).join(''); }; var mkPath = function (env, id) { return Path.join(env.root, id.slice(0, 2), id) + '.ndjson'; }; var getFreeId = function (env, cb, tries) { if (tries > 5) { return void cb('ETOOMANYTRIES'); } // generate a unique id var id = randomId(); // derive a path from that id var path = mkPath(env, id); Fs.stat(path, function (err) { if (err && err.code === "ENOENT") { cb(void 0, id); } else { getFreeId(env, cb); } }); }; var write = function (env, task, cb) { var str = JSON.stringify(task) + '\n'; var id = nacl.util.encodeBase64(nacl.hash(nacl.util.decodeUTF8(str))).replace(/\//g, '-'); var path = mkPath(env, id); nThen(function (w) { // check if the file already exists... Fs.stat(path, w(function (err) { if (err && err.code === 'ENOENT') { return; } w.abort(); cb(); })); }).nThen(function (w) { // create the parent directory if it does not exist var dir = id.slice(0, 2); var dirpath = Path.join(env.root, dir); Fse.mkdirp(dirpath, 0x1ff, w(function (err) { if (err) { return void cb(err); } })); }).nThen(function () { // write the file to the path Fs.writeFile(mkPath(env, id), str, function (e) { if (e) { return void cb(e); } cb(); }); }); }; // TODO implement a standard API for removing tasks // currently they are deleted manually in 'expire-channels.js' // var remove = function (env, id, cb) { }; Tasks.create = function (config, cb) { var env = { root: config.taskPath || './tasks', }; // make sure the path exists... Fse.mkdirp(env.root, 0x1ff, function (err) { if (err && err.code !== 'EEXIST') { throw err; } cb(void 0, { write: function (time, command, args, cb) { var task = encode(time, command, args); write(env, task, cb); }, }); }); };