Initial commit
This commit is contained in:
602
lib/setup/setupBackup.js
Normal file
602
lib/setup/setupBackup.js
Normal file
@@ -0,0 +1,602 @@
|
||||
'use strict';
|
||||
|
||||
function BackupRestore(options) {
|
||||
var fs = require('fs');
|
||||
var tools = require(__dirname + '/../tools.js');
|
||||
var pathLib = require('path');
|
||||
var tmpDir = pathLib.normalize(__dirname + '/../../tmp');
|
||||
var bkpDir = pathLib.normalize(__dirname + '/../../backups');
|
||||
var hostname = tools.getHostName();
|
||||
|
||||
// allow use without new operator
|
||||
if (!(this instanceof BackupRestore)) return new BackupRestore(options);
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (!options.states) throw 'Invalid arguments: states is missing';
|
||||
if (!options.objects) throw 'Invalid arguments: objects is missing';
|
||||
if (!options.processExit) throw 'Invalid arguments: processExit is missing';
|
||||
if (!options.cleanDatabase) throw 'Invalid arguments: cleanDatabase is missing';
|
||||
if (!options.restartController) throw 'Invalid arguments: restartController is missing';
|
||||
|
||||
var objects = options.objects;
|
||||
var states = options.states;
|
||||
var processExit = options.processExit;
|
||||
var cleanDatabase = options.cleanDatabase;
|
||||
var restartController = options.restartController;
|
||||
var mime;
|
||||
|
||||
var Upload = require(__dirname + '/setupUpload.js');
|
||||
var upload = new Upload(options);
|
||||
|
||||
// --------------------------------------- BACKUP ---------------------------------------------------
|
||||
function _copyFile(id, srcPath, destPath, callback) {
|
||||
objects.readFile(id, srcPath, "", function (err, data) {
|
||||
if (data) fs.writeFileSync(destPath, data);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function copyDir(id, srcPath, destPath, callback) {
|
||||
var count = 0;
|
||||
if (!fs.existsSync(destPath)) fs.mkdirSync(destPath);
|
||||
objects.readDir(id, srcPath, function (err, res) {
|
||||
if (res) {
|
||||
for (var t = 0; t < res.length; t++) {
|
||||
if (res[t].isDir) {
|
||||
count++;
|
||||
copyDir(id, srcPath + '/' + res[t].file, destPath + '/' + res[t].file, function () {
|
||||
count--;
|
||||
if (!count) callback();
|
||||
});
|
||||
} else {
|
||||
if (!fs.existsSync(destPath)) fs.mkdirSync(destPath);
|
||||
count++;
|
||||
_copyFile(id, srcPath + '/' + res[t].file, destPath + '/' + res[t].file, function () {
|
||||
count--;
|
||||
if (!count) callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!count) callback();
|
||||
});
|
||||
}
|
||||
|
||||
function getBackupDir() {
|
||||
var dataDir = tools.getDefaultDataDir();
|
||||
|
||||
// All pathes are returned always relative to /node_modules/appName.js-controller
|
||||
if (dataDir) {
|
||||
if (dataDir[0] === '.' && dataDir[1] === '.') {
|
||||
dataDir = __dirname + '/../../' + dataDir;
|
||||
} else if (dataDir[0] === '.' && dataDir[1] === '/') {
|
||||
dataDir = __dirname + '/../../' + dataDir.substring(2);
|
||||
}
|
||||
}
|
||||
dataDir = dataDir.replace(/\\/g, '/');
|
||||
if (dataDir[dataDir.length - 1] !== '/') dataDir += '/';
|
||||
|
||||
var parts = dataDir.split('/');
|
||||
parts.pop();// remove data or appName-data
|
||||
parts.pop();
|
||||
|
||||
return parts.join('/') + '/backups/';
|
||||
}
|
||||
|
||||
function copyFileSync(source, target) {
|
||||
var targetFile = target;
|
||||
|
||||
// if target is a directory a new file with the same name will be created
|
||||
if (fs.existsSync(target)) {
|
||||
if (fs.lstatSync(target).isDirectory()) {
|
||||
targetFile = pathLib.join(target, pathLib.basename(source));
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(targetFile, fs.readFileSync(source));
|
||||
}
|
||||
|
||||
function copyFolderRecursiveSync(source, target) {
|
||||
var files = [];
|
||||
|
||||
if (!fs.existsSync(target)) fs.mkdirSync(target);
|
||||
|
||||
// check if folder needs to be created or integrated
|
||||
var targetFolder = pathLib.join(target, pathLib.basename(source));
|
||||
if (!fs.existsSync(targetFolder)) fs.mkdirSync(targetFolder);
|
||||
|
||||
// copy
|
||||
if (fs.lstatSync(source).isDirectory() ) {
|
||||
files = fs.readdirSync(source);
|
||||
files.forEach(function (file) {
|
||||
var curSource = pathLib.join(source, file);
|
||||
if (fs.lstatSync(curSource).isDirectory()) {
|
||||
copyFolderRecursiveSync(curSource, targetFolder);
|
||||
} else {
|
||||
copyFileSync(curSource, targetFolder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.createBackup = function (name, callback) {
|
||||
var count = 0;
|
||||
|
||||
if (!name) {
|
||||
var d = new Date();
|
||||
name = d.getFullYear() + '_' +
|
||||
('0' + (d.getMonth() + 1)).slice(-2) + '_' +
|
||||
('0' + d.getDate()).slice(-2) + '-' +
|
||||
('0' + d.getHours()).slice(-2) + '_' +
|
||||
('0' + d.getMinutes()).slice(-2) + '_' +
|
||||
('0' + d.getSeconds()).slice(-2) + '_backup' + tools.appName;
|
||||
}
|
||||
|
||||
name = name.replace(/\\/g, '/');
|
||||
if (name.indexOf('/') === -1) {
|
||||
var path = getBackupDir();
|
||||
|
||||
// create directory if not exists
|
||||
if (!fs.existsSync(path)) {
|
||||
fs.mkdirSync(path);
|
||||
}
|
||||
|
||||
if (name.indexOf('.tar.gz') === -1) {
|
||||
name = path + name + '.tar.gz';
|
||||
} else {
|
||||
name = path + name;
|
||||
}
|
||||
}
|
||||
|
||||
objects.getObjectList({include_docs: true}, function (err, res) {
|
||||
var result = {objects: null, states: {}, config: null};
|
||||
if (err) {
|
||||
console.error('host.' + hostname + ' Cannot get objects: ' + err);
|
||||
} else {
|
||||
result.objects = res.rows;
|
||||
}
|
||||
|
||||
if (fs.existsSync(tools.getConfigFileName())) result.config = JSON.parse(fs.readFileSync(tools.getConfigFileName(), 'utf8'));
|
||||
|
||||
states.getKeys('io.*', function (err, keys) {
|
||||
/*for (var i = keys.length - 1; i >= 0; i--) {
|
||||
if (keys[i].match(/^messagebox\./) || keys[i].match(/^log\./)) {
|
||||
keys.splice(i, 1);
|
||||
}
|
||||
}*/
|
||||
|
||||
states.getStates(keys, function (err, obj) {
|
||||
var hostname = tools.getHostName();
|
||||
var r = new RegExp('^system\\.host\\.' + hostname + '\\.(\\w+)$');
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
if (obj[i].from === 'system.host.' + hostname) {
|
||||
obj[i].from = 'system.host.$$__hostname__$$';
|
||||
}
|
||||
if (r.test(keys[i])) {
|
||||
keys[i] = keys[i].replace(hostname, '$$__hostname__$$');
|
||||
}
|
||||
result.states[keys[i]] = obj[i];
|
||||
}
|
||||
|
||||
if (!fs.existsSync(bkpDir)) fs.mkdirSync(bkpDir);
|
||||
if (!fs.existsSync(tmpDir)) fs.mkdirSync(tmpDir);
|
||||
if (!fs.existsSync(tmpDir + '/backup')) fs.mkdirSync(tmpDir + '/backup');
|
||||
if (!fs.existsSync(tmpDir + '/backup/files')) fs.mkdirSync(tmpDir + '/backup/files');
|
||||
|
||||
// try to find user files
|
||||
for (var j = 0; j < result.objects.length; j++) {
|
||||
if (!result.objects[j].value || !result.objects[j].value._id) continue;
|
||||
//if (result.objects[j].doc) delete result.objects[j].doc;
|
||||
if (result.objects[j].value._id.match(/^system\.adapter\.([\w\d_-]+).(\d+)$/) &&
|
||||
result.objects[j].value.common.host === hostname) {
|
||||
result.objects[j].value.common.host = '$$__hostname__$$';
|
||||
if (result.objects[j].doc) {
|
||||
result.objects[j].doc.common.host = '$$__hostname__$$';
|
||||
}
|
||||
} else
|
||||
if (r.test(result.objects[j].value._id)) {
|
||||
result.objects[j].value._id = result.objects[j].value._id.replace(hostname, '$$__hostname__$$');
|
||||
result.objects[j].id = result.objects[j].value._id;
|
||||
if (result.objects[j].doc) {
|
||||
result.objects[j].doc._id = result.objects[j].value._id;
|
||||
}
|
||||
} else if (result.objects[j].value._id === 'system.host.' + hostname) {
|
||||
result.objects[j].value._id = 'system.host.$$__hostname__$$';
|
||||
result.objects[j].value.common.name = result.objects[j].value._id;
|
||||
result.objects[j].value.common.hostname = '$$__hostname__$$';
|
||||
if (result.objects[j].value.native && result.objects[j].value.native.os) {
|
||||
result.objects[j].value.native.os.hostname = '$$__hostname__$$';
|
||||
}
|
||||
result.objects[j].id = result.objects[j].value._id;
|
||||
if (result.objects[j].doc) {
|
||||
result.objects[j].doc._id = result.objects[j].value._id;
|
||||
result.objects[j].doc.common.name = result.objects[j].value._id;
|
||||
result.objects[j].doc.common.hostname = '$$__hostname__$$';
|
||||
if (result.objects[j].doc.native && result.objects[j].value.native.os) {
|
||||
result.objects[j].doc.native.os.hostname = '$$__hostname__$$';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read all files
|
||||
if (result.objects[j].value.type === 'meta' &&
|
||||
result.objects[j].value.common &&
|
||||
result.objects[j].value.common.type === 'meta.user') {
|
||||
count++;
|
||||
copyDir(result.objects[j].id, '', tmpDir + '/backup/files/' + result.objects[j].id, function () {
|
||||
count--;
|
||||
if (!count) {
|
||||
// todo: store letsencrypt files too => change it as letitbit will be better integrated
|
||||
var configDir = tools.getConfigFileName().split('/');
|
||||
configDir.pop();
|
||||
configDir.push('letsencrypt');
|
||||
var letsEncrypt = configDir.join('/');
|
||||
if (fs.existsSync(letsEncrypt)) {
|
||||
copyFolderRecursiveSync(letsEncrypt, tmpDir + '/backup');
|
||||
}
|
||||
|
||||
var tar = require('tar');
|
||||
|
||||
var f = fs.createWriteStream(name);
|
||||
f.on('finish', function () {
|
||||
tools.rmdirRecursiveSync(tmpDir + '/backup');
|
||||
if (callback) callback(pathLib.normalize(name));
|
||||
});
|
||||
f.on('error', function (err) {
|
||||
console.error('host.' + hostname + ' Cannot pack directory ' + pathLib.normalize(tmpDir + '/backup') + ': ' + err);
|
||||
processExit(9);
|
||||
});
|
||||
|
||||
try {
|
||||
tar.create({gzip: true, cwd: tmpDir + '/'}, ['backup']).pipe(f);
|
||||
} catch (err) {
|
||||
console.error('host.' + hostname + ' Cannot pack directory ' + pathLib.normalize(tmpDir + '/backup') + ': ' + err);
|
||||
processExit(9);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(tmpDir + '/backup/backup.json', JSON.stringify(result, null, 2));
|
||||
|
||||
if (!count) {
|
||||
var tar = require('tar');
|
||||
|
||||
var f = fs.createWriteStream(name);
|
||||
f.on('finish', function () {
|
||||
tools.rmdirRecursiveSync(tmpDir + '/backup');
|
||||
if (callback) callback(pathLib.normalize(name));
|
||||
});
|
||||
f.on('error', function (err) {
|
||||
console.error('host.' + hostname + ' Cannot pack directory ' + pathLib.normalize(tmpDir + '/backup') + ': ' + err);
|
||||
processExit(9);
|
||||
});
|
||||
|
||||
try {
|
||||
tar.create({gzip: true, cwd: tmpDir + '/'}, ['backup']).pipe(f);
|
||||
} catch (err) {
|
||||
console.error('host.' + hostname + ' Cannot pack directory ' + pathLib.normalize(tmpDir + '/backup') + ': ' + err);
|
||||
processExit(9);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
//--------------------------------------- RESTORE ---------------------------------------------------
|
||||
function _setStateHelper(_index, statesList, stateObjects, callback) {
|
||||
states.setRawState(statesList[_index], stateObjects[statesList[_index]], function () {
|
||||
if ((_index % 200) === 0) console.log('host.' + hostname + ' Processed ' + _index + '/' + statesList.length + ' states');
|
||||
_index++;
|
||||
if (_index < statesList.length) {
|
||||
setImmediate(_setStateHelper, _index, statesList, stateObjects, callback);
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _setObjHelper(_index, _objects, callback) {
|
||||
// Disable all adapters.
|
||||
if (_objects[_index].id.match(/^system\.adapter\./) && !_objects[_index].id.match(/^system\.adapter\.admin/)) {
|
||||
if (_objects[_index].doc.common && _objects[_index].doc.common.enabled) {
|
||||
_objects[_index].doc.common.enabled = false;
|
||||
}
|
||||
}
|
||||
if (_objects[_index].doc && _objects[_index].doc._rev) delete _objects[_index].doc._rev;
|
||||
|
||||
objects.setObject(_objects[_index].id, _objects[_index].doc, function (err /* , obj */) {
|
||||
if (err) {
|
||||
console.warn('host.' + hostname + ' Cannot restore ' + _objects[_index].id + ': ' + err);
|
||||
}
|
||||
|
||||
if ((_index % 200) === 0) console.log('host.' + hostname + ' Processed ' + _index + '/' + _objects.length + ' objects');
|
||||
_index++;
|
||||
if (_index < _objects.length) {
|
||||
setImmediate(_setObjHelper, _index, _objects, callback);
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function reloadAdapterObject(index, objectList, callback) {
|
||||
if (objectList && index < objectList.length) {
|
||||
objects.getObject(objectList[index]._id, function (err, obj) {
|
||||
if (err || !obj) {
|
||||
objects.setObject(objectList[index]._id, objectList[index], function () {
|
||||
console.log('host.' + hostname + ' object ' + objectList[index]._id + ' created');
|
||||
index++;
|
||||
setImmediate(reloadAdapterObject, index, objectList, callback);
|
||||
});
|
||||
} else {
|
||||
index++;
|
||||
setImmediate(reloadAdapterObject, index, objectList, callback);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
}
|
||||
|
||||
function reloadAdaptersObjects(callback, dirs, index) {
|
||||
if (!dirs) {
|
||||
dirs = [];
|
||||
var _modules;
|
||||
if (fs.existsSync(__dirname + '/../../node_modules')) {
|
||||
_modules = fs.readdirSync(__dirname + '/../../node_modules');
|
||||
if (_modules) {
|
||||
var regEx = new RegExp('^' + tools.appName + '\\.', 'i');
|
||||
for (var i = 0; i < _modules.length; i++) {
|
||||
if (regEx.test(_modules[i]) &&
|
||||
dirs.indexOf(_modules[i].substring(tools.appName.length + 1)) === -1) {
|
||||
dirs.push(_modules[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if installed as npm
|
||||
if (fs.existsSync(__dirname + '/../../../../node_modules/' + tools.appName + '.js-controller')) {
|
||||
_modules = fs.readdirSync(__dirname + '/../../..');
|
||||
var regEx_ = new RegExp('^' + tools.appName + '\\.', 'i');
|
||||
for (var j = 0; j < _modules.length; j++) {
|
||||
// if starting from application name + '.'
|
||||
if (regEx_.test(_modules[j]) &&
|
||||
// If not js-controller
|
||||
(_modules[j].substring(tools.appName.length + 1) !== 'js-controller') &&
|
||||
dirs.indexOf(_modules[j].substring(tools.appName.length + 1)) === -1) dirs.push(_modules[j]);
|
||||
}
|
||||
}
|
||||
if (dirs.length) {
|
||||
reloadAdaptersObjects(callback, dirs, 0);
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
} else {
|
||||
if (index < dirs.length) {
|
||||
upload.uploadAdapter(dirs[index], false, true, function () {
|
||||
upload.uploadAdapter(dirs[index], true, true, function () {
|
||||
var pkg = null;
|
||||
if (!dirs[index]) {
|
||||
console.error('Wrong');
|
||||
}
|
||||
var adapterDir = tools.getAdapterDir(dirs[index]);
|
||||
if (fs.existsSync(adapterDir + '/io-package.json')) {
|
||||
pkg = JSON.parse(fs.readFileSync(adapterDir + '/io-package.json', 'utf8'));
|
||||
}
|
||||
|
||||
if (pkg && pkg.objects && pkg.objects.length) {
|
||||
console.log('host.' + hostname + ' Setup "' + dirs[index] + '" adapter');
|
||||
reloadAdapterObject(0, pkg.objects, function () {
|
||||
index++;
|
||||
setImmediate(reloadAdaptersObjects, callback, dirs, index);
|
||||
});
|
||||
} else {
|
||||
index++;
|
||||
reloadAdaptersObjects(callback, dirs, index);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function uploadUserFiles(root, path, callback) {
|
||||
if (typeof path === 'function') {
|
||||
callback = path;
|
||||
path = '';
|
||||
}
|
||||
|
||||
var called = false;
|
||||
if (!fs.existsSync(root)) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
var files = fs.readdirSync(root + path);
|
||||
var count = files.length;
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
var stat = fs.statSync(root + path + '/' + files[i]);
|
||||
if (stat.isDirectory()) {
|
||||
called = true;
|
||||
uploadUserFiles(root, path + '/' + files[i], function (err) {
|
||||
if (err) console.error('Error: ' + err);
|
||||
if (!--count) setImmediate(callback);
|
||||
});
|
||||
} else {
|
||||
var parts = path.split('/');
|
||||
var adapter = parts.splice(0, 2);
|
||||
adapter = adapter[1];
|
||||
var _path = parts.join('/') + '/' + files[i];
|
||||
console.log('host.' + hostname + ' Upload user file "' + adapter + "/" + _path);
|
||||
called = true;
|
||||
objects.writeFile(adapter, _path, fs.readFileSync(root + path + '/' + files[i]), null, function (err) {
|
||||
if (err) console.error('Error: ' + err);
|
||||
if (!--count) setImmediate(callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!called) callback();
|
||||
}
|
||||
|
||||
function restoreAfterStop(restartOnFinish, callback) {
|
||||
// Open file
|
||||
var data = fs.readFileSync(tmpDir + '/backup/backup.json').toString();
|
||||
var hostname = tools.getHostName();
|
||||
data = data.replace(/\$\$__hostname__\$\$/g, hostname);
|
||||
fs.writeFileSync(tmpDir + '/backup/backup_.json', data);
|
||||
var restore;
|
||||
try {
|
||||
restore = JSON.parse(data);
|
||||
} catch (e) {
|
||||
console.error('Cannot parse "' + tmpDir + '/backup/backup_.json": ' + e);
|
||||
if (callback) callback(31);
|
||||
}
|
||||
|
||||
// stop all adapters
|
||||
console.log('host.' + hostname + ' Clear all objects and states...');
|
||||
cleanDatabase(false, function () {
|
||||
console.log('host.' + hostname + ' done.');
|
||||
// upload all data into DB
|
||||
// restore ioBorker.json
|
||||
if (restore.config) fs.writeFileSync(tools.getConfigFileName(), JSON.stringify(restore.config, null, 2));
|
||||
|
||||
var sList = [];
|
||||
for (var state in restore.states) {
|
||||
if (restore.states.hasOwnProperty(state)) {
|
||||
sList.push(state);
|
||||
}
|
||||
}
|
||||
|
||||
_setStateHelper(0, sList, restore.states, function () {
|
||||
console.log(sList.length + ' states restored.');
|
||||
_setObjHelper(0, restore.objects, function () {
|
||||
console.log(restore.objects.length + ' objects restored.');
|
||||
// Required for upload adapter
|
||||
mime = require('mime');
|
||||
// Load user files into DB
|
||||
uploadUserFiles(tmpDir + '/backup/files', function () {
|
||||
// reload objects of adapters
|
||||
reloadAdaptersObjects(function () {
|
||||
// Reload host objects
|
||||
var pckgio = JSON.parse(fs.readFileSync(__dirname + '/../../io-package.json', 'utf8'));
|
||||
reloadAdapterObject(0, pckgio ? pckgio.objects : null, function () {
|
||||
if (restartOnFinish) {
|
||||
restartController(callback);
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.listBackups = function () {
|
||||
var dir = getBackupDir();
|
||||
var result = [];
|
||||
if (fs.existsSync(dir)) {
|
||||
var files = fs.readdirSync(dir);
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
if (files[i].match(/\.tar\.gz$/i)) {
|
||||
result.push(files[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
this.restoreBackup = function (name, callback) {
|
||||
var backups;
|
||||
if (!name && name !== 0) {
|
||||
// List all available backups
|
||||
console.log('Please specify one of the backup names:');
|
||||
backups = this.listBackups();
|
||||
backups.sort(function (a, b) {
|
||||
return b > a;
|
||||
});
|
||||
if (backups.length) {
|
||||
for (var t = 0; t < backups.length; t++){
|
||||
console.log(backups[t] + ' or ' + backups[t].replace('_backup' + tools.appName + '.tar.gz', '') + ' or ' + t);
|
||||
}
|
||||
} else {
|
||||
console.warn('No backups found');
|
||||
}
|
||||
processExit(10);
|
||||
}
|
||||
|
||||
if (!options.cleanDatabase) throw "Invalid arguments: cleanDatabase is missing";
|
||||
if (!options.restartController) throw "Invalid arguments: restartController is missing";
|
||||
|
||||
if (parseInt(name, 10).toString() === name.toString()) {
|
||||
backups = this.listBackups();
|
||||
backups.sort(function (a, b) {
|
||||
return b > a;
|
||||
});
|
||||
name = backups[parseInt(name, 10)];
|
||||
console.log('host.' + hostname + ' Using backup file ' + name);
|
||||
}
|
||||
|
||||
name = (name || '').toString().replace(/\\/g, '/');
|
||||
if (name.indexOf('/') === -1) {
|
||||
name = getBackupDir() + name;
|
||||
var regEx = new RegExp('_backup' + tools.appName, 'i');
|
||||
if (!regEx.test(name)) name += '_backup' + tools.appName;
|
||||
if (!name.match(/\.tar\.gz$/i)) name += '.tar.gz';
|
||||
}
|
||||
if (!fs.existsSync(name)) {
|
||||
console.error('host.' + hostname + ' Cannot find ' + name);
|
||||
processExit(11);
|
||||
}
|
||||
var tar = require('tar');
|
||||
if (fs.existsSync(tmpDir + '/backup/backup.json')) {
|
||||
fs.unlinkSync(tmpDir + '/backup/backup.json');
|
||||
}
|
||||
|
||||
tar.extract({
|
||||
file: name,
|
||||
cwd: tmpDir
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
console.error('host.' + hostname + ' Cannot extract from file "' + name + '"');
|
||||
processExit(9);
|
||||
}
|
||||
if (!fs.existsSync(tmpDir + '/backup/backup.json')) {
|
||||
console.error('host.' + hostname + ' Cannot find extracted file from file "' + tmpDir + '/backup/backup.json"');
|
||||
processExit(9);
|
||||
}
|
||||
// Stop controller
|
||||
var daemon = require('daemonize2').setup({
|
||||
main: '../../controller.js',
|
||||
name: tools.appName + ' controller',
|
||||
pidfile: __dirname + '/../' + tools.appName + '.pid',
|
||||
cwd: '../../',
|
||||
stopTimeout: 1000
|
||||
});
|
||||
daemon.on('error', function (/* error */) {
|
||||
restoreAfterStop(false, callback);
|
||||
});
|
||||
daemon.on('stopped', function () {
|
||||
restoreAfterStop(true, callback);
|
||||
});
|
||||
daemon.on('notrunning', function () {
|
||||
console.log('host.' + hostname + ' OK.');
|
||||
restoreAfterStop(false, callback);
|
||||
});
|
||||
daemon.stop();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BackupRestore;
|
||||
1397
lib/setup/setupInstall.js
Normal file
1397
lib/setup/setupInstall.js
Normal file
File diff suppressed because it is too large
Load Diff
76
lib/setup/setupLicense.js
Normal file
76
lib/setup/setupLicense.js
Normal file
@@ -0,0 +1,76 @@
|
||||
'use strict';
|
||||
function License(options) {
|
||||
const fs = require('fs');
|
||||
const jwt = require('jsonwebtoken');
|
||||
options = options || {};
|
||||
|
||||
let objects = options.objects;
|
||||
// read info from '/etc/iob_vendor.json' and executes instructions stored there
|
||||
this.setLicense = file => {
|
||||
if (fs.existsSync(file)) {
|
||||
try {
|
||||
file = fs.readFileSync(file).toString('utf8');
|
||||
} catch (e) {
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}
|
||||
// try to encode license
|
||||
let license = jwt.decode(file);
|
||||
if (!license) {
|
||||
return Promise.reject('License cannot be decoded');
|
||||
}
|
||||
if (!license.name) {
|
||||
return Promise.reject('Name not found in the license');
|
||||
}
|
||||
let adapter = license.name.split('.')[1];
|
||||
if (!adapter) {
|
||||
return Promise.reject(`Invalid license name ${license.name}`);
|
||||
}
|
||||
// read all instances of this adapter
|
||||
return objects.getObjectListAsync({
|
||||
startkey: 'system.adapter.' + adapter + '.',
|
||||
endkey: 'system.adapter.' + adapter + '.\u9999'
|
||||
}, {checked: true}).then(arr => {
|
||||
let promises = [];
|
||||
if (arr && arr.rows && arr.rows.length) {
|
||||
for (let g = 0; g < arr.rows.length; g++) {
|
||||
let obj = arr.rows[g].value;
|
||||
if (obj && obj.type === 'instance') {
|
||||
obj.native = obj.native || {};
|
||||
obj.native.license = file;
|
||||
promises.push(objects.setObjectAsync(obj._id, obj).then(() => {
|
||||
console.log(`Instance "${obj._id}" updated`);
|
||||
}).catch(err => {
|
||||
console.error(`Cannot update "${obj._id}": ${err}`);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!promises.length) {
|
||||
console.warn(`no instances of ${adapter} found`);
|
||||
if (arr && arr.rows && arr.rows.length) {
|
||||
for (let g = 0; g < arr.rows.length; g++) {
|
||||
let obj = arr.rows[g].value;
|
||||
if (obj && obj.type === 'adapter') {
|
||||
obj.native = obj.native || {};
|
||||
obj.native.license = file;
|
||||
promises.push(objects.setObjectAsync(obj._id, obj).then(() => {
|
||||
console.log(`Adapter "${obj._id}" updated`);
|
||||
}).catch(err => {
|
||||
console.error(`Cannot update "${obj._id}": ${err}`);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!promises.length) {
|
||||
console.error(`no installations of ${adapter} found`);
|
||||
}
|
||||
return Promise.all(promises);
|
||||
});
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
module.exports = License;
|
||||
627
lib/setup/setupList.js
Normal file
627
lib/setup/setupList.js
Normal file
@@ -0,0 +1,627 @@
|
||||
'use strict';
|
||||
function List(options) {
|
||||
var fs = require('fs');
|
||||
var tools = require(__dirname + '/../tools.js');
|
||||
|
||||
var that = this;
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (!options.states) throw 'Invalid arguments: states is missing';
|
||||
if (!options.objects) throw 'Invalid arguments: objects is missing';
|
||||
if (!options.processExit) throw 'Invalid arguments: processExit is missing';
|
||||
|
||||
var objects = options.objects;
|
||||
var states = options.states;
|
||||
var processExit = options.processExit;
|
||||
|
||||
function perm2str(perm) {
|
||||
var result = '';
|
||||
// user
|
||||
result += (perm & 0x400) ? 'r' : '-';
|
||||
result += (perm & 0x200) ? 'w' : '-';
|
||||
result += (perm & 0x100) ? 'x' : '-';
|
||||
// group
|
||||
result += (perm & 0x040) ? 'r' : '-';
|
||||
result += (perm & 0x020) ? 'w' : '-';
|
||||
result += (perm & 0x010) ? 'x' : '-';
|
||||
// any
|
||||
result += (perm & 0x004) ? 'r' : '-';
|
||||
result += (perm & 0x002) ? 'w' : '-';
|
||||
result += (perm & 0x001) ? 'x' : '-';
|
||||
return result;
|
||||
}
|
||||
|
||||
this.showFileHeader = function () {
|
||||
console.log(' Modified at |Permission| User | Group | Size | Name');
|
||||
console.log('----------------+----------+--------------+--------------+------+---------');
|
||||
};
|
||||
|
||||
this.showFile = function (adapter, path, file) {
|
||||
//drwxr-xr-x 1 odroid odroid 43 Oct 3 2013 .xsessionrc
|
||||
var text = '';
|
||||
var time;
|
||||
if (file.modifiedAt) {
|
||||
var ts = new Date(file.modifiedAt);
|
||||
time = ts.toISOString();
|
||||
time = time.replace('T', ' ');
|
||||
time = time.substring(0, 16) + ' ';
|
||||
} else {
|
||||
time = Array(18).join(' ');
|
||||
}
|
||||
text += time;
|
||||
|
||||
if (file.acl){
|
||||
text += (file.isDir ? 'd' : '-') + perm2str(file.acl.permissions || 0);
|
||||
var owner = file.acl.owner;
|
||||
if (owner) {
|
||||
owner = owner.substring(12);
|
||||
if (owner.length < 15) owner = Array(15 - owner.length).join(' ') + owner;
|
||||
} else {
|
||||
owner = Array(15).join(' ');
|
||||
}
|
||||
text += ' ' + owner;
|
||||
var group = file.acl.ownerGroup;
|
||||
if (group) {
|
||||
group = group.substring(13);
|
||||
if (group.length < 15) group = Array(15 - group.length).join(' ') + group;
|
||||
} else {
|
||||
group = Array(15).join(' ');
|
||||
}
|
||||
|
||||
text += ' ' + group;
|
||||
} else {
|
||||
text += (file.isDir ? 'd' : '-') + '?????????' + Array(31).join(' ');
|
||||
}
|
||||
var size = (file.stats) ? file.stats.size.toString() : '';
|
||||
if (size.length < 7) size = Array(7 - size.length).join(' ') + size;
|
||||
|
||||
text += ' ' + size + ' ' + adapter + ((!path || path[0] === '/') ? '' : '/') + path + '/' + file.file;
|
||||
if (file.isDir) {
|
||||
text += '/';
|
||||
console.log(text);
|
||||
} else {
|
||||
console.log(text);
|
||||
}
|
||||
};
|
||||
|
||||
this.showObjectHeader = function () {
|
||||
console.log('ObjectAC | StateAC | User | Group | ID');
|
||||
console.log('---------+---------+--------------+--------------+--------------');
|
||||
};
|
||||
|
||||
this.showObject = function (obj) {
|
||||
//drwxr-xr-x 1 odroid odroid 43 Oct 3 2013 .xsessionrc
|
||||
var text = '';
|
||||
if (obj.acl){
|
||||
text += perm2str(obj.acl.object || 0) + ' ' + ((obj.type === 'state') ? perm2str(obj.acl.state || 0) : ' ');
|
||||
var owner = obj.acl.owner;
|
||||
if (owner) {
|
||||
owner = owner.substring(12);
|
||||
if (owner.length < 15) owner = Array(15 - owner.length).join(' ') + owner;
|
||||
} else {
|
||||
owner = Array(15).join(' ');
|
||||
}
|
||||
text += ' ' + owner;
|
||||
var group = obj.acl.ownerGroup;
|
||||
if (group) {
|
||||
group = group.substring(13);
|
||||
if (group.length < 15) group = Array(15 - group.length).join(' ') + group;
|
||||
} else {
|
||||
group = Array(15).join(' ');
|
||||
}
|
||||
text += ' ' + group;
|
||||
} else {
|
||||
text += '?????????' + ((obj.type === 'state') ? ' ?????????' : ' ') + Array(31).join(' ');
|
||||
}
|
||||
text += ' ' + obj._id;
|
||||
console.log(text);
|
||||
};
|
||||
|
||||
this.listDirectory = function (adapter, path, allFiles, callback) {
|
||||
if (typeof path === 'function') {
|
||||
callback = path;
|
||||
path = '';
|
||||
allFiles = [];
|
||||
}
|
||||
if (typeof allFiles === 'function') {
|
||||
callback = allFiles;
|
||||
allFiles = [];
|
||||
}
|
||||
allFiles = allFiles || [];
|
||||
|
||||
path = path || '';
|
||||
|
||||
objects.readDir(adapter, path, null, function (err, files) {
|
||||
if (err && err.code === 'ENOTDIR') {
|
||||
var pos = path.lastIndexOf('/');
|
||||
if (pos !== -1) {
|
||||
var dir = path.substring(0, pos);
|
||||
var fname = path.substring(pos + 1);
|
||||
objects.readDir(adapter, dir, null, function (err, files) {
|
||||
if (err) {
|
||||
console.log('Cannot read "' + path + '": ' + err);
|
||||
callback(allFiles);
|
||||
} else {
|
||||
for (var f = 0; f < files.length; f++) {
|
||||
if (files[f].file === '.' || files[f].file === '..') continue;
|
||||
if (files[f].file === fname) {
|
||||
allFiles.push({adapter: adapter, path: path, file: files[f]});
|
||||
break;
|
||||
}
|
||||
}
|
||||
callback(allFiles);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback(allFiles);
|
||||
}
|
||||
} else {
|
||||
var count = 0;
|
||||
for (var f = 0; f < files.length; f++) {
|
||||
if (files[f].file === '.' || files[f].file === '..') continue;
|
||||
allFiles.push({adapter: adapter, path: path, file: files[f]});
|
||||
if (files[f].isDir) {
|
||||
count++;
|
||||
that.listDirectory(adapter, path + '/' + files[f].file, allFiles, function () {
|
||||
if (!--count && callback) {
|
||||
callback(allFiles);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!count && callback) callback(allFiles);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function pattern2RegEx(pattern) {
|
||||
if (pattern !== '*') {
|
||||
if (pattern[0] === '*' && pattern[pattern.length - 1] !== '*') pattern += '$';
|
||||
if (pattern[0] !== '*' && pattern[pattern.length - 1] === '*') pattern = '^' + pattern;
|
||||
}
|
||||
pattern = pattern.replace(/\./g, '\\.');
|
||||
pattern = pattern.replace(/\*/g, '.*');
|
||||
return pattern;
|
||||
}
|
||||
|
||||
function sortFiles (a, b) {
|
||||
var a1 = a.path + a.file.file;
|
||||
if (a1[0] !== '/') a1 = '/' + a1;
|
||||
var b1 = b.path + b.file.file;
|
||||
if (b1[0] !== '/') b1 = '/' + b1;
|
||||
return a1.localeCompare(b1);
|
||||
}
|
||||
|
||||
this.listAdaptersFiles = function (adapters, filter, callback) {
|
||||
if (typeof filter === 'function') {
|
||||
callback = filter;
|
||||
filter = null;
|
||||
}
|
||||
if (filter) {
|
||||
filter = filter.replace('*', '');
|
||||
if (filter[filter.length - 1] === '/') filter = filter.substring(0, filter.length - 1);
|
||||
}
|
||||
|
||||
|
||||
if (adapters && adapters.length) {
|
||||
var adapter = adapters.pop();
|
||||
this.listDirectory(adapter, filter, function (files) {
|
||||
files.sort(sortFiles);
|
||||
that.showFileHeader();
|
||||
for (var k = 0; k < files.length; k++) {
|
||||
if (filter && filter !== (files[k].path + '/'+ files[k].file.file).substring(0, filter.length)) continue;
|
||||
|
||||
that.showFile(files[k].adapter, files[k].path, files[k].file);
|
||||
}
|
||||
|
||||
that.listDirectory(adapter + '.admin', filter, function (files) {
|
||||
files.sort(sortFiles);
|
||||
for (var k = 0; k < files.length; k++) {
|
||||
if (filter && filter !== (files[k].path + '/'+ files[k].file.file).substring(0, filter.length)) continue;
|
||||
|
||||
that.showFile(files[k].adapter, files[k].path, files[k].file);
|
||||
}
|
||||
|
||||
that.listAdaptersFiles(adapters, callback);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
if (callback) callback ();
|
||||
}
|
||||
};
|
||||
|
||||
this.list = function (type, filter, flags) {
|
||||
switch (type) {
|
||||
case 'objects':
|
||||
case 'o':
|
||||
objects.getObjectList(null, function (err, objs) {
|
||||
var reg = filter ? new RegExp(pattern2RegEx(filter)) : null;
|
||||
for (var i = 0; i < objs.rows.length; i++) {
|
||||
if (!reg || reg.test(objs.rows[i].value._id) || (objs.rows[i].value.common && reg.test(objs.rows[i].value.common.name))) {
|
||||
if (objs.rows[i].value.type) {
|
||||
var id = objs.rows[i].value._id;
|
||||
var type = objs.rows[i].value.type;
|
||||
if (id.length < 40) id += Array(40 - id.length).join(' ');
|
||||
if (type.length < 10) type += Array(10 - type.length).join(' ');
|
||||
|
||||
console.log(id + ': ' + type + ' - ' + (objs.rows[i].value.common.name || ''));
|
||||
} else {
|
||||
console.log(objs.rows[i].value._id);
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'states':
|
||||
case 's':
|
||||
states.getKeys(filter || '*', function (err, keys) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
processExit(23);
|
||||
}
|
||||
states.getStates(keys, function (err, states) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
processExit(23);
|
||||
}
|
||||
for (var i = 0; i < states.length; i++) {
|
||||
var id = keys[i];
|
||||
var from = states[i].from || '';
|
||||
var type = typeof states[i].val;
|
||||
if (type.length < 10) type += Array(10 - type.length).join(' ');
|
||||
if (id.length < 40) id += Array(40 - id.length).join(' ');
|
||||
if (from.length < 30) from += Array(30 - from.length).join(' ');
|
||||
console.log(id + ': from [' + from + '] (' + type + ') ' + (states[i].ack ? ' ack': 'not ack') + ' ' + JSON.stringify(states[i].val));
|
||||
}
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
case 'adapters':
|
||||
case 'a':
|
||||
objects.getObjectList({startkey: 'system.adapter.', endkey: 'system.adapter.\u9999'}, function (err, objs) {
|
||||
var reg = filter ? new RegExp(pattern2RegEx('system.adapter.' + filter)) : null;
|
||||
for (var i = 0; i < objs.rows.length; i++) {
|
||||
if (objs.rows[i].value.type !== 'adapter') continue;
|
||||
if (!reg || reg.test(objs.rows[i].value._id) || (objs.rows[i].value.common && reg.test(objs.rows[i].value.common.name))) {
|
||||
var id = objs.rows[i].value._id;
|
||||
var name = objs.rows[i].value.common.name;
|
||||
|
||||
if (id.length < 40) id += Array(40 - id.length).join(' ');
|
||||
if (name.length < 12) name += Array(12 - name.length).join(' ');
|
||||
|
||||
var text = id + ': ' + name + ' - ' +
|
||||
objs.rows[i].value.common.version;
|
||||
|
||||
console.log(text);
|
||||
}
|
||||
}
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'instances':
|
||||
case 'i':
|
||||
objects.getObjectList({startkey: 'system.adapter.', endkey: 'system.adapter.\u9999'}, function (err, objs) {
|
||||
var reg = filter ? new RegExp(pattern2RegEx('system.adapter.' + filter)) : null;
|
||||
objs.rows.sort(function (a, b) {
|
||||
if (a.id > b.id) return 1;
|
||||
if (a.id < b.id) return -1;
|
||||
return 0;
|
||||
});
|
||||
for (var i = 0; i < objs.rows.length; i++) {
|
||||
if (objs.rows[i].value.type !== 'instance') continue;
|
||||
if (!reg || reg.test(objs.rows[i].value._id) || (objs.rows[i].value.common && reg.test(objs.rows[i].value.common.name))) {
|
||||
if (flags.enabled && !objs.rows[i].value.common.enabled) continue;
|
||||
if (flags.disabled && objs.rows[i].value.common.enabled) continue;
|
||||
if (flags.port && objs.rows[i].value.native.port === undefined) continue;
|
||||
if (flags.ssl && objs.rows[i].value.native.secure === undefined) continue;
|
||||
if (flags.ip && objs.rows[i].value.native.bind === undefined) continue;
|
||||
|
||||
var id = objs.rows[i].value._id;
|
||||
var name = objs.rows[i].value.common.name;
|
||||
|
||||
if (id.length < 40) id += Array(40 - id.length).join(' ');
|
||||
if (name && name.length < 12) name += Array(12 - name.length).join(' ');
|
||||
|
||||
var text = id + ': ' + (name || '') + ' - ' +
|
||||
(objs.rows[i].value.common.enabled ? ' enabled' : 'disabled');
|
||||
|
||||
if (objs.rows[i].value.native && objs.rows[i].value.native.port) {
|
||||
text += ', port: ' + objs.rows[i].value.native.port;
|
||||
}
|
||||
if (objs.rows[i].value.native && objs.rows[i].value.native.bind) {
|
||||
text += ', bind: ' + objs.rows[i].value.native.bind;
|
||||
}
|
||||
if (objs.rows[i].value.native && objs.rows[i].value.native.secure) {
|
||||
text += ' (SSL)';
|
||||
}
|
||||
if (objs.rows[i].value.native && objs.rows[i].value.native.defaultUser) {
|
||||
text += ', run as: ' + objs.rows[i].value.native.defaultUser;
|
||||
}
|
||||
console.log(text);
|
||||
}
|
||||
}
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'users':
|
||||
case 'u':
|
||||
objects.getObjectList({startkey: 'system.user.', endkey: 'system.user.\u9999'}, function (err, objs) {
|
||||
objects.getObjectList({startkey: 'system.group.', endkey: 'system.group.\u9999'}, function (err, groups) {
|
||||
var reg = filter ? new RegExp(pattern2RegEx('system.user.' + filter)) : null;
|
||||
console.log(' ID | Name | Active | Groups');
|
||||
console.log('---------------------------------------+-------------+----------+--------------');
|
||||
for (var i = 0; i < objs.rows.length; i++) {
|
||||
if (objs.rows[i].value.type !== 'user') continue;
|
||||
|
||||
if (!reg || reg.test(objs.rows[i].value._id) || (objs.rows[i].value.common && reg.test(objs.rows[i].value.common.name))) {
|
||||
var id = objs.rows[i].value._id;
|
||||
var name = objs.rows[i].value.common.name;
|
||||
|
||||
if (id.length < 40) id += Array(40 - id.length).join(' ');
|
||||
if (name.length < 12) name += Array(12 - name.length).join(' ');
|
||||
|
||||
var text = id + '| ' + name + ' | ' +
|
||||
(objs.rows[i].value.common.enabled ? ' enabled' : 'disabled') + ' |';
|
||||
var gs = [];
|
||||
// find all groups
|
||||
for (var g = 0; g < groups.rows.length; g++) {
|
||||
if (groups.rows[g].value.common.members && groups.rows[g].value.common.members.indexOf(objs.rows[i].value._id) !== -1) {
|
||||
gs.push(groups.rows[g].value._id.substring(13));
|
||||
}
|
||||
}
|
||||
console.log(text + ' ' + gs.join(', '));
|
||||
}
|
||||
}
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
case 'groups':
|
||||
case 'g':
|
||||
objects.getObjectList({startkey: 'system.group.', endkey: 'system.group.\u9999'}, function (err, objs) {
|
||||
var reg = filter ? new RegExp(pattern2RegEx('system.group.' + filter)) : null;
|
||||
console.log('');
|
||||
console.log(' system.group | object | state | file | user | others | users');
|
||||
console.log(' | l r w d | l r w d | l r w c d | w c d | |');
|
||||
console.log('--------------------+---------+---------+-----------+-------+------------------------+---------');
|
||||
for (var i = 0; i < objs.rows.length; i++) {
|
||||
if (objs.rows[i].value.type !== 'group') continue;
|
||||
if (!reg || reg.test(objs.rows[i].value._id) || (objs.rows[i].value.common && reg.test(objs.rows[i].value.common.name))) {
|
||||
var id = objs.rows[i].value._id.substring(13);
|
||||
//var name = objs.rows[i].value.common.name;
|
||||
|
||||
if (id === 'administrator') {
|
||||
objs.rows[i].value.common.acl = {
|
||||
file: {
|
||||
read: true,
|
||||
write: true,
|
||||
'delete': true,
|
||||
create: true,
|
||||
list: true
|
||||
},
|
||||
object: {
|
||||
read: true,
|
||||
write: true,
|
||||
'delete': true,
|
||||
list: true
|
||||
},
|
||||
state: {
|
||||
read: true,
|
||||
write: true,
|
||||
'delete': true,
|
||||
create: true,
|
||||
list: true
|
||||
},
|
||||
user: {
|
||||
write: true,
|
||||
create: true,
|
||||
'delete': true
|
||||
},
|
||||
other: {
|
||||
execute: true,
|
||||
http: true,
|
||||
sendto: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (id.length < 20) id += Array(20 - id.length).join(' ');
|
||||
var text = id;
|
||||
text += ' | ';
|
||||
if (objs.rows[i].value.common.acl && objs.rows[i].value.common.acl.object) {
|
||||
text += (objs.rows[i].value.common.acl.object.list ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.object.read ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.object.write ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.object.delete ? '+': '-') + ' ';
|
||||
text += '|';
|
||||
} else {
|
||||
text += ' |';
|
||||
}
|
||||
if (objs.rows[i].value.common.acl && objs.rows[i].value.common.acl.state) {
|
||||
text += ' ';
|
||||
text +=(objs.rows[i].value.common.acl.state.list ? '+': '-') + ' ';
|
||||
text +=(objs.rows[i].value.common.acl.state.read ? '+': '-') + ' ';
|
||||
text +=(objs.rows[i].value.common.acl.state.write ? '+': '-') + ' ';
|
||||
text +=(objs.rows[i].value.common.acl.state.delete ? '+': '-') + ' ';
|
||||
text += '|';
|
||||
} else {
|
||||
text += ' |';
|
||||
}
|
||||
if (objs.rows[i].value.common.acl && objs.rows[i].value.common.acl.file) {
|
||||
text += ' ';
|
||||
text += (objs.rows[i].value.common.acl.file.list ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.file.read ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.file.write ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.file.create ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.file.delete ? '+': '-') + ' ';
|
||||
text += '|';
|
||||
} else {
|
||||
text += ' |';
|
||||
}
|
||||
if (objs.rows[i].value.common.acl && objs.rows[i].value.common.acl.users) {
|
||||
text += ' ';
|
||||
text += (objs.rows[i].value.common.acl.users.write ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.users.create ? '+': '-') + ' ';
|
||||
text += (objs.rows[i].value.common.acl.users.delete ? '+': '-') + ' ';
|
||||
text += '|';
|
||||
} else {
|
||||
text += ' |';
|
||||
}
|
||||
if (objs.rows[i].value.common.acl && objs.rows[i].value.common.acl.other) {
|
||||
text += ' ';
|
||||
var others = '';
|
||||
for (var r in objs.rows[i].value.common.acl.other) {
|
||||
others += r + (objs.rows[i].value.common.acl.other[r] ? '+' : '-') + ' ';
|
||||
}
|
||||
if (others.length < 23) others += Array(23 - others.length).join(' ');
|
||||
text += others + '|';
|
||||
} else {
|
||||
text += Array(25).join(' ') + '|';
|
||||
}
|
||||
|
||||
//if (name.length < 30) name += Array(30 - name.length).join(' ');
|
||||
if ( objs.rows[i].value.common.members) {
|
||||
for (var m = 0; m < objs.rows[i].value.common.members.length; m++) {
|
||||
objs.rows[i].value.common.members[m] = objs.rows[i].value.common.members[m].substring(12);
|
||||
}
|
||||
text += ' ' + objs.rows[i].value.common.members.join(', ');
|
||||
}
|
||||
//text += '| (' + name + ')';
|
||||
console.log(text);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('--------------------+---------+---------+-----------+-------+------------------------+---------');
|
||||
console.log('Legend: (l)ist, (r)ead, (w)rite, (c)reate, (d)elete');
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case 'hosts':
|
||||
objects.getObjectList({startkey: 'system.host.', endkey: 'system.host.\u9999'}, function (err, objs) {
|
||||
states.getKeys('system.host.*', function (err, keys) {
|
||||
states.getStates(keys, function (err, states) {
|
||||
var reg = filter ? new RegExp(pattern2RegEx('system.host.' + filter)) : null;
|
||||
|
||||
for (var i = 0; i < objs.rows.length; i++) {
|
||||
if (objs.rows[i].value.type !== 'host') continue;
|
||||
if (!reg || reg.test(objs.rows[i].value._id) || (objs.rows[i].value.common && reg.test(objs.rows[i].value.common.name))) {
|
||||
var id = objs.rows[i].value._id.substring(12);
|
||||
var name = objs.rows[i].value.common.name;
|
||||
if (id.length < 20) id += Array(20 - id.length).join(' ');
|
||||
var hostname = objs.rows[i].value.common.hostname;
|
||||
if (hostname.length < 15) hostname += Array(15 - hostname.length).join(' ');
|
||||
var version = objs.rows[i].value.common.installedVersion;
|
||||
var alive = '';
|
||||
var uptime = '';
|
||||
for (var k = 0; k < keys.length; k++) {
|
||||
if (keys[k] === objs.rows[i].value._id + '.alive') {
|
||||
alive = states[k].val;
|
||||
}
|
||||
if (keys[k] === objs.rows[i].value._id + '.uptime') {
|
||||
uptime = states[k].val;
|
||||
}
|
||||
}
|
||||
alive = alive ? 'alive' : ' dead';
|
||||
//if (uptime.toString().length < 10) uptime = Array(10 - uptime.toString().length).join(' ') + uptime.toString();
|
||||
if (!uptime) uptime = '-';
|
||||
var text = id + ' ' + name + ' (version: ' + version + ', hostname: ' + hostname + ', ' + alive + ', uptime: ' + uptime + ')';
|
||||
// todo
|
||||
console.log(text);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
case 'enums':
|
||||
case 'e':
|
||||
objects.getObjectList({startkey: 'enum.', endkey: 'enum.\u9999'}, function (err, objs) {
|
||||
var reg = filter ? new RegExp(pattern2RegEx('enum.' + filter)) : null;
|
||||
for (var i = 0; i < objs.rows.length; i++) {
|
||||
if (objs.rows[i].value.type !== 'enum') continue;
|
||||
if (!reg || reg.test(objs.rows[i].value._id) || (objs.rows[i].value.common && reg.test(objs.rows[i].value.common.name))) {
|
||||
console.log('\n=====================================================================================');
|
||||
var id = objs.rows[i].value._id.substring(5);
|
||||
var name = objs.rows[i].value.common.name;
|
||||
if (id.length < 20) id += Array(20 - id.length).join(' ');
|
||||
console.log(id + '(' + name + ')');
|
||||
console.log('-------------------------------------------------------------------------------------');
|
||||
|
||||
if (objs.rows[i].value.common.members) {
|
||||
console.log(objs.rows[i].value.common.members.join(', '));
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
break;
|
||||
|
||||
case 'files':
|
||||
case 'f':
|
||||
objects.getObjectList({startkey: 'system.adapter.', endkey: 'system.adapter.\u9999'}, function (err, objs) {
|
||||
var adapter = filter || null;
|
||||
var names = filter ? filter.split('/') : null;
|
||||
if (names && !names[0]) names.splice(0, 1);
|
||||
|
||||
var adapters = [];
|
||||
for (var i = 0; i < objs.rows.length; i++) {
|
||||
if (objs.rows[i].value.type === 'adapter') {
|
||||
if (adapter && objs.rows[i].value.common.name !== names[0]) continue;
|
||||
adapters.push(objs.rows[i].value.common.name);
|
||||
} else if (objs.rows[i].value.type === 'instance') {
|
||||
if (adapter && objs.rows[i].value._id.substring(15) !== names[0]) continue;
|
||||
adapters.push(objs.rows[i].value._id.substring(15));
|
||||
}
|
||||
}
|
||||
if (names) names.shift();
|
||||
that.listAdaptersFiles(adapters, names ? names.join('/') : null, function () {
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 1000);
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
if (type) {
|
||||
console.error('Unknown type: ' + type);
|
||||
processExit(23);
|
||||
} else {
|
||||
console.log('Please specify type: objects, states, instances, adapters, users, groups, enums, files');
|
||||
processExit();
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = List;
|
||||
294
lib/setup/setupMultihost.js
Normal file
294
lib/setup/setupMultihost.js
Normal file
@@ -0,0 +1,294 @@
|
||||
'use strict';
|
||||
function Multihost(options) {
|
||||
var fs = require('fs');
|
||||
var tools = require(__dirname + '/../tools.js');
|
||||
var configName = tools.getConfigFileName();
|
||||
var that = this;
|
||||
|
||||
options = options || {};
|
||||
|
||||
var params = options.params || {};
|
||||
var objects = options.objects;
|
||||
|
||||
function getConfig() {
|
||||
var config;
|
||||
// read actual configuration
|
||||
try {
|
||||
if (fs.existsSync(configName)) {
|
||||
config = JSON.parse(fs.readFileSync(configName, 'utf8'));
|
||||
} else {
|
||||
config = require(__dirname + '/../../conf/' + tools.appName + '-dist.json');
|
||||
}
|
||||
} catch (e) {
|
||||
config = require(__dirname + '/../../conf/' + tools.appName + '-dist.json');
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
function leftPad(text, len) {
|
||||
text = text || '';
|
||||
if (text.length >= len) return len;
|
||||
return new Array(len - text.length).join(' ') + text;
|
||||
}
|
||||
|
||||
this.showHosts = function (list) {
|
||||
if (!list || !list.length) {
|
||||
console.info('Nothing found');
|
||||
} else {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
console.log((i + 1) + ' | ' + leftPad(list[i].hostname, 20) + ' | ' + (list[i].slave ? 'slave' : ' host') + ' | ' + leftPad(list[i].ip, 20) + ' | ' + JSON.stringify(list[i].info));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.browse = function (callback) {
|
||||
var MHClient = require(__dirname + '/../multihostClient');
|
||||
var mhClient = new MHClient();
|
||||
mhClient.browse(2000, params.debug, function (err, list) {
|
||||
if (err) {
|
||||
callback('Cannot browse: ' + err);
|
||||
} else {
|
||||
callback(null, list);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function showMHState(config, changed, callback) {
|
||||
if (config.multihostService.enabled) {
|
||||
if (config.objects.type === 'file' && (config.objects.host === '127.0.0.1' || config.objects.host === 'localhost')) {
|
||||
console.log('Server accept connections for objects on all IP addresses.');
|
||||
config.objects.host = '0.0.0.0';
|
||||
changed = true;
|
||||
} else if (config.objects.type === 'redis') {
|
||||
console.log('Please check the binding of redis service. By default it is only local: http://download.redis.io/redis-stable/redis.conf\nChange "bind 127.0.0.1" to "bind 0.0.0.0" or to others.')
|
||||
}
|
||||
if (config.states.type === 'file' && (config.states.host === '127.0.0.1' || config.states.host === 'localhost')) {
|
||||
console.log('Server accept connections for states on all IP addresses.');
|
||||
config.states.host = '0.0.0.0';
|
||||
changed = true;
|
||||
} else if (config.states.type === 'redis') {
|
||||
console.log('Please check the binding of redis service. By default it is only local: http://download.redis.io/redis-stable/redis.conf\nChange "bind 127.0.0.1" to "bind 0.0.0.0" or to others.')
|
||||
}
|
||||
}
|
||||
if (!changed) {
|
||||
console.log('Nothing changed.');
|
||||
} else {
|
||||
fs.writeFileSync(configName, JSON.stringify(config, null, 2));
|
||||
console.log('Please restart yunkong2: "yunkong2 restart"');
|
||||
}
|
||||
console.log('\n');
|
||||
console.log('Miltihost: ' + (config.multihostService.enabled ? 'enabled' : 'disabled'));
|
||||
console.log('Authentication: ' + (config.multihostService.secure ? 'enabled' : 'disabled'));
|
||||
console.log('Objects: ' + config.objects.type + ' on ' + config.objects.host);
|
||||
console.log('States: ' + config.states.type + ' on ' + config.states.host);
|
||||
callback();
|
||||
}
|
||||
|
||||
this.enable = function (isEnable, callback) {
|
||||
var changed = false;
|
||||
var config = getConfig();
|
||||
config.multihostService = config.multihostService || {enabled: false, secure: true};
|
||||
|
||||
if (isEnable && !config.multihostService.enabled) {
|
||||
changed = true;
|
||||
config.multihostService.enabled = true;
|
||||
config.multihostService.password = '';
|
||||
console.log('Miltihost activated.')
|
||||
} else if (!isEnable && config.multihostService.enabled) {
|
||||
changed = true;
|
||||
config.multihostService.enabled = false;
|
||||
config.multihostService.password = '';
|
||||
console.log('Miltihost deactivated.')
|
||||
}
|
||||
if (params.secure === undefined) {
|
||||
params.secure = true;
|
||||
}
|
||||
|
||||
if (isEnable && (config.multihostService.secure !== params.secure || (config.multihostService.secure && !config.multihostService.password))) {
|
||||
changed = true;
|
||||
config.multihostService.secure = params.secure;
|
||||
console.log('Authentication ' + (params.secure ? 'activated' : 'deactivated') + '.');
|
||||
if (config.multihostService.secure) {
|
||||
var prompt = require('prompt');
|
||||
prompt.message = '';
|
||||
prompt.delimiter = '';
|
||||
var schema = {
|
||||
properties: {
|
||||
password: {
|
||||
description: 'Enter secret phrase for connection:',
|
||||
pattern: /^[^'"]+$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: true
|
||||
},
|
||||
passwordRepeat: {
|
||||
description: 'Repeat secret phrase for connection:',
|
||||
pattern: /^[^'"]+$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: true
|
||||
}
|
||||
}
|
||||
};
|
||||
prompt.start();
|
||||
|
||||
prompt.get(schema, function (err, password) {
|
||||
if (password && password.password) {
|
||||
if (password.password !== password.passwordRepeat) {
|
||||
callback('Secret phrases are not equal!');
|
||||
} else {
|
||||
objects.getObject('system.config', function (err, obj) {
|
||||
tools.encryptPhrase(obj.native.secret, password.password, function (encoded) {
|
||||
config.multihostService.password = encoded;
|
||||
showMHState(config, changed, callback);
|
||||
})
|
||||
});
|
||||
}
|
||||
} else {
|
||||
callback('No secret phrase entered!');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
showMHState(config, changed, callback);
|
||||
}
|
||||
} else {
|
||||
showMHState(config, changed, callback);
|
||||
}
|
||||
};
|
||||
|
||||
this.status = function (callback) {
|
||||
var config = getConfig();
|
||||
config.multihostService = config.multihostService || {enabled: false, secure: true};
|
||||
showMHState(config, false, callback);
|
||||
};
|
||||
|
||||
function readPassword(callback) {
|
||||
var readline = require('readline');
|
||||
|
||||
var rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
function hidden(query, callback) {
|
||||
var stdin = process.openStdin();
|
||||
process.stdin.on('data', function (char) {
|
||||
char = char + '';
|
||||
switch (char) {
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\u0004':
|
||||
stdin.pause();
|
||||
break;
|
||||
|
||||
default:
|
||||
process.stdout.write('\x1B[2K\x1B[200D' + query + new Array(rl.line.length + 1).join('*'));
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
rl.question(query, function (value) {
|
||||
rl.history = rl.history.slice(1);
|
||||
callback(value);
|
||||
});
|
||||
}
|
||||
|
||||
hidden('Enter secret phrase for connection: ', function(password) {
|
||||
callback(password);
|
||||
});
|
||||
}
|
||||
|
||||
function connect(mhClient, ip, pass, callback) {
|
||||
mhClient.connect(ip, pass, function (err, oObjects, oStates, ipHost) {
|
||||
if (err) {
|
||||
callback('Cannot connect to "' + ip + '": ' + err);
|
||||
} else if (oObjects && oStates) {
|
||||
var config = getConfig();
|
||||
config.objects = oObjects;
|
||||
config.states = oStates;
|
||||
if (config.objects.host === '127.0.0.1' || config.objects.host === 'localhost' || config.states.host === '127.0.0.1' || config.states.host === 'localhost') {
|
||||
callback('IP Address of the host is 127.0.0.1. It accepts no connections. Please change.');
|
||||
} else {
|
||||
if (config.states.host === '0.0.0.0') {
|
||||
config.states.host = ipHost;
|
||||
}
|
||||
if (config.objects.host === '0.0.0.0') {
|
||||
config.objects.host = ipHost;
|
||||
}
|
||||
|
||||
fs.writeFileSync(configName, JSON.stringify(config, null, 2));
|
||||
console.log('Config ok. Please restart yunkong2: "yunkong2 restart"');
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
callback('No configuration received!');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.connect = function (number, pass, callback) {
|
||||
if (typeof pass === 'function') {
|
||||
callback = pass;
|
||||
pass = null;
|
||||
}
|
||||
if (typeof number === 'function') {
|
||||
callback = number;
|
||||
number = null;
|
||||
}
|
||||
var MHClient = require(__dirname + '/../multihostClient');
|
||||
var mhClient = new MHClient();
|
||||
|
||||
mhClient.browse(2000, params.debug, function (err, list) {
|
||||
if (err) {
|
||||
callback('Cannot browse: ' + err);
|
||||
} else {
|
||||
that.showHosts(list);
|
||||
|
||||
if (number !== null && number !== undefined && parseInt(number, 10) > 0) {
|
||||
number = parseInt(number, 10);
|
||||
if (list && number < list.length + 1) {
|
||||
if (!pass) {
|
||||
callback('No password defined: please use "multihost connect <NUMBER> <PASSWORD>"');
|
||||
} else {
|
||||
connect(mhClient, list[number - 1].ip, pass, callback);
|
||||
}
|
||||
} else {
|
||||
callback('Invalid index: ' + number);
|
||||
}
|
||||
} else
|
||||
if (list && list.length) {
|
||||
var readline = require('readline');
|
||||
|
||||
var rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
rl.question('Please select host [1]: ', function (answer) {
|
||||
if (answer === '' || answer === null || answer === undefined) {
|
||||
answer = 1;
|
||||
}
|
||||
answer = parseInt(answer, 10) - 1;
|
||||
if (!list[answer]) {
|
||||
rl.close();
|
||||
callback('Invalid index: ' + answer);
|
||||
} else {
|
||||
if (list[answer].auth) {
|
||||
readPassword(function (password) {
|
||||
if (password) {
|
||||
connect(mhClient, list[answer].ip, password, callback);
|
||||
} else {
|
||||
callback('No password entered!');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
connect(mhClient, list[answer].ip, null, callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback(null, list);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Multihost;
|
||||
279
lib/setup/setupRepo.js
Normal file
279
lib/setup/setupRepo.js
Normal file
@@ -0,0 +1,279 @@
|
||||
'use strict';
|
||||
function Repo(options) {
|
||||
const tools = require(__dirname + '/../tools.js');
|
||||
const extend = require('node.extend');
|
||||
let defaultSystemRepo = {
|
||||
"common": {
|
||||
"name": "System repositories",
|
||||
"dontDelete": true
|
||||
},
|
||||
"native": {
|
||||
"repositories": {
|
||||
"default": {
|
||||
"link": "http://download.yunkong2.net/sources-dist.json",
|
||||
"json": null
|
||||
},
|
||||
"latest": {
|
||||
"link": "http://download.yunkong2.net/sources-dist-latest.json",
|
||||
"json": null
|
||||
}
|
||||
}
|
||||
},
|
||||
"_id": "system.repositories",
|
||||
"type": "config"
|
||||
};
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (!options.objects) throw 'Invalid arguments: objects is missing';
|
||||
|
||||
var objects = options.objects;
|
||||
|
||||
function updateRepo(repoUrl, callback) {
|
||||
var result = {};
|
||||
|
||||
if (!repoUrl || typeof repoUrl !== 'object') {
|
||||
tools.getRepositoryFile(repoUrl, function (err, sources) {
|
||||
updateRepo(sources, callback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
var sources = repoUrl;
|
||||
var downloads = [];
|
||||
|
||||
function download() {
|
||||
if (downloads.length < 1) {
|
||||
console.log('update done');
|
||||
if (callback) callback(result);
|
||||
} else {
|
||||
var name = downloads.pop();
|
||||
|
||||
if (sources[name].version) {
|
||||
result[name] = sources[name];
|
||||
} else if (sources[name].meta) {
|
||||
tools.getJson(sources[name].meta, function (ioPack) {
|
||||
if (ioPack && ioPack.common) {
|
||||
result[name] = extend(true, sources[name], ioPack.common);
|
||||
}
|
||||
setImmediate(download);
|
||||
});
|
||||
return;
|
||||
} else if (sources[name].url) {
|
||||
console.log('Cannot get version of "' + name + '".');
|
||||
result[name] = sources[name];
|
||||
} else {
|
||||
console.log('Cannot get any information of "' + name + '". Ignored.');
|
||||
}
|
||||
setImmediate(download);
|
||||
}
|
||||
}
|
||||
|
||||
// Read repository file, local or by url
|
||||
for (var name in sources) {
|
||||
if (!sources.hasOwnProperty(name)) continue;
|
||||
downloads.push(name);
|
||||
}
|
||||
|
||||
download(/*sources*/);
|
||||
}
|
||||
|
||||
this.showRepo = function (repoUrl, flags, callback) {
|
||||
if (typeof flags === 'function') {
|
||||
callback = flags;
|
||||
flags = {};
|
||||
}
|
||||
|
||||
function showRepoResult(_name, sources) {
|
||||
var installed = tools.getInstalledInfo();
|
||||
var updatable;
|
||||
var keys = [];
|
||||
for (var key in sources) {
|
||||
if (!sources.hasOwnProperty(key)) continue;
|
||||
keys.push(key);
|
||||
}
|
||||
keys.sort();
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var name = keys[i];
|
||||
if (!sources.hasOwnProperty(name)) continue;
|
||||
updatable = false;
|
||||
var text = (sources[name].controller ? 'Controller ' : 'Adapter ');
|
||||
text += '"' + name + '"' + ((name.length < 15) ? new Array(15 - name.length).join(' ') : '');
|
||||
|
||||
var tLen = 10;
|
||||
if (name.length >= 15) tLen -= (name.length > tLen ? 1 : 0);
|
||||
if (tLen < 0) tLen = 0;
|
||||
|
||||
if (sources[name].version) {
|
||||
text += ': ' + sources[name].version + ((sources[name].version.length < tLen) ? new Array(tLen - sources[name].version.length).join(' ') : '');
|
||||
} else {
|
||||
text += new Array(tLen).join(' ')
|
||||
}
|
||||
if ((flags.installed || flags.i) && !installed[name]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (installed[name] && installed[name].version) {
|
||||
text += ', installed ' + installed[name].version;
|
||||
if (sources[name].version !== installed[name].version &&
|
||||
sources[name].version &&
|
||||
!tools.upToDate(sources[name].version, installed[name].version)) {
|
||||
updatable = true;
|
||||
text += ' [Updateable]';
|
||||
}
|
||||
}
|
||||
if ((flags.updatable || flags.u) && !updatable) {
|
||||
continue;
|
||||
}
|
||||
console.log(text);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the repositories
|
||||
objects.getObject('system.config', function (err, sysConfig) {
|
||||
objects.getObject('system.repositories', function (err, obj) {
|
||||
if (err || !obj) {
|
||||
console.log('Error: Object "system.config" not found');
|
||||
} else {
|
||||
if (!obj.native || !obj.native.repositories) {
|
||||
console.log('Error: no repositories found in the "system.config');
|
||||
} else {
|
||||
repoUrl = repoUrl || sysConfig.common.activeRepo;
|
||||
|
||||
console.log('Used repository: ' + repoUrl);
|
||||
|
||||
// If known repository
|
||||
if (obj.native.repositories[repoUrl]) {
|
||||
if (typeof obj.native.repositories[repoUrl] === 'string') {
|
||||
obj.native.repositories[repoUrl] = {
|
||||
link: obj.native.repositories[repoUrl],
|
||||
json: null
|
||||
};
|
||||
}
|
||||
|
||||
updateRepo(obj.native.repositories[repoUrl].link, function (sources) {
|
||||
obj.native.repositories[repoUrl].json = sources;
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject(obj._id, obj, function () {
|
||||
showRepoResult(repoUrl, sources);
|
||||
if (callback) callback();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
updateRepo(repoUrl, function (sources) {
|
||||
showRepoResult(null, sources);
|
||||
if (callback) callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.showRepoStatus = function (callback) {
|
||||
objects.getObject('system.repositories', function (err, obj) {
|
||||
if (err || !obj) {
|
||||
console.error('Cannot get list: ' + err);
|
||||
callback(102);
|
||||
} else {
|
||||
if (obj.native.repositories) {
|
||||
for (var r in obj.native.repositories) {
|
||||
if (obj.native.repositories.hasOwnProperty(r)){
|
||||
console.log(r + (r.length < 12 ? new Array(12 - r.length).join(' ') : '') + ': ' + obj.native.repositories[r].link);
|
||||
}
|
||||
}
|
||||
objects.getObject('system.config', function (err, obj) {
|
||||
if (obj) {
|
||||
console.log('\nActive repo: ' + obj.common.activeRepo);
|
||||
}
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
console.error('Cannot get list: ' + err);
|
||||
callback(102);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.add = function (repoName, repoUrl, callback) {
|
||||
objects.getObject('system.repositories', function (err, obj) {
|
||||
if (err) {
|
||||
callback && callback(err);
|
||||
} else
|
||||
if (!obj) {
|
||||
obj = defaultSystemRepo;
|
||||
}
|
||||
|
||||
if (obj.native.repositories[repoName]) {
|
||||
callback && callback('Repository "' + repoName + '" yet exists: ' + obj.native.repositories[repoName].link);
|
||||
} else {
|
||||
obj.native.repositories[repoName] = {
|
||||
link: repoUrl,
|
||||
json: null
|
||||
};
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject('system.repositories', obj, callback);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.del = function (repoName, callback) {
|
||||
objects.getObject('system.config', function (err, obj) {
|
||||
if (err) {
|
||||
callback && callback(err);
|
||||
} else {
|
||||
if (obj.common.activeRepo === repoName) {
|
||||
callback && callback('Cannot delete active repository: ' + repoName);
|
||||
} else {
|
||||
objects.getObject('system.repositories', function (err, obj) {
|
||||
if (err) {
|
||||
callback && callback(err);
|
||||
} else if (!obj) {
|
||||
callback && callback();
|
||||
} else {
|
||||
if (!obj.native.repositories[repoName]) {
|
||||
callback && callback('Repository "' + repoName + '" not found.');
|
||||
} else {
|
||||
delete obj.native.repositories[repoName];
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject('system.repositories', obj, callback);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.setActive = function (repoName, callback) {
|
||||
objects.getObject('system.repositories', function (err, obj) {
|
||||
if (err) {
|
||||
callback && callback(err);
|
||||
} else
|
||||
if (!obj) {
|
||||
obj = defaultSystemRepo;
|
||||
}
|
||||
if (!obj.native.repositories[repoName]) {
|
||||
callback && callback('Repository "' + repoName + '" not found.');
|
||||
} else {
|
||||
objects.getObject('system.config', function (err, obj) {
|
||||
if (err) {
|
||||
callback && callback(err);
|
||||
} else {
|
||||
obj.common.activeRepo = repoName;
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject('system.config', obj, callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Repo;
|
||||
199
lib/setup/setupSetup.js
Normal file
199
lib/setup/setupSetup.js
Normal file
@@ -0,0 +1,199 @@
|
||||
'use strict';
|
||||
|
||||
function Setup(options) {
|
||||
var fs = require('fs');
|
||||
var tools = require(__dirname + '/../tools.js');
|
||||
|
||||
options = options || {};
|
||||
|
||||
var processExit = options.processExit;
|
||||
var dbConnect = options.dbConnect;
|
||||
var params = options.params;
|
||||
var password;
|
||||
var objects;
|
||||
|
||||
function mkpathSync(rootpath, dirpath) {
|
||||
// Remove filename
|
||||
dirpath = dirpath.split('/');
|
||||
dirpath.pop();
|
||||
if (!dirpath.length) return;
|
||||
|
||||
for (var i = 0; i < dirpath.length; i++) {
|
||||
rootpath += dirpath[i] + '/';
|
||||
if (!fs.existsSync(rootpath)) {
|
||||
if (dirpath[i] !== '..') {
|
||||
fs.mkdirSync(rootpath);
|
||||
} else {
|
||||
throw 'Cannot create ' + rootpath + dirpath.join('/');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setupReady(callback) {
|
||||
if (!callback) {
|
||||
console.log('database setup done. you can add adapters and start ' + tools.appName + ' now');
|
||||
processExit(0);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
function dbSetup(iopkg, callback) {
|
||||
if (iopkg.objects && iopkg.objects.length > 0) {
|
||||
var obj = iopkg.objects.pop();
|
||||
objects.getObject(obj._id, function (err, _obj) {
|
||||
if (err || !_obj) {
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject(obj._id, obj, function () {
|
||||
console.log('object ' + obj._id + ' created');
|
||||
setTimeout(dbSetup, 25, iopkg, callback);
|
||||
});
|
||||
} else {
|
||||
console.log('object ' + obj._id + ' yet exists');
|
||||
setTimeout(dbSetup, 25, iopkg, callback);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
tools.createUuid(objects, function () {
|
||||
// check if encrypt secret exists
|
||||
objects.getObject('system.config', function (err, obj) {
|
||||
if (obj && (!obj.native || !obj.native.secret)) {
|
||||
require('crypto').randomBytes(24, function (ex, buf) {
|
||||
obj.native = obj.native || {};
|
||||
obj.native.secret = buf.toString('hex');
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject('system.config', obj, function () {
|
||||
setupReady(callback);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
setupReady(callback);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function setupObjects(callback) {
|
||||
dbConnect(params, function (_objects, _states) {
|
||||
objects = _objects;
|
||||
var iopkg = JSON.parse(fs.readFileSync(__dirname + '/../../io-package.json', 'utf8'));
|
||||
dbSetup(iopkg, callback);
|
||||
});
|
||||
}
|
||||
|
||||
this.setup = function (callback, ignoreIfExist, useRedis) {
|
||||
password = require(__dirname + '/../password');
|
||||
|
||||
var config;
|
||||
var isCreated = false;
|
||||
var platform = require('os').platform();
|
||||
var otherInstallDirs = [];
|
||||
|
||||
// Delete files for other OS
|
||||
if (platform.match(/^win/)) {
|
||||
otherInstallDirs.push(__dirname + '/../../' + tools.appName);
|
||||
otherInstallDirs.push(__dirname + '/../../killall.sh');
|
||||
otherInstallDirs.push(__dirname + '/../../reinstall.sh');
|
||||
} else {
|
||||
otherInstallDirs.push(__dirname + '/../../_service_' + tools.appName + '.bat');
|
||||
otherInstallDirs.push(__dirname + '/../../' + tools.appName + '.bat');
|
||||
// copy scripts to root directory
|
||||
if (fs.existsSync(__dirname + '/../../../../node_modules/')) {
|
||||
try {
|
||||
if (fs.existsSync(__dirname + '/../../killall.sh')) {
|
||||
fs.writeFileSync(__dirname + '/../../../../killall.sh', fs.readFileSync(__dirname + '/../../killall.sh'));
|
||||
}
|
||||
if (fs.existsSync(__dirname + '/../../reinstall.sh')) {
|
||||
fs.writeFileSync(__dirname + '/../../../../reinstall.sh', fs.readFileSync(__dirname + '/../../reinstall.sh'));
|
||||
}
|
||||
if (fs.existsSync(__dirname + '/../..' + tools.appName)) {
|
||||
fs.writeFileSync(__dirname + '/../../../..' + tools.appName, fs.readFileSync(__dirname + '/../..' + tools.appName));
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Cannot write file. Not critical: ' + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var t = 0; t < otherInstallDirs.length; t++) {
|
||||
if (fs.existsSync(otherInstallDirs[t])) {
|
||||
var stat = fs.statSync(otherInstallDirs[t]);
|
||||
if (stat.isDirectory()) {
|
||||
var files = fs.readdirSync(otherInstallDirs[t]);
|
||||
for (var f = 0; f < files.length; f++) {
|
||||
fs.unlinkSync(otherInstallDirs[t] + '/' + files[f]);
|
||||
}
|
||||
fs.rmdirSync(otherInstallDirs[t]);
|
||||
} else {
|
||||
try {
|
||||
fs.unlinkSync(otherInstallDirs[t]);
|
||||
}
|
||||
catch(e) {
|
||||
console.warn('Cannot delete file. Not critical: ' + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create log and tmp directory
|
||||
if (!fs.existsSync(__dirname + '/../../tmp')) fs.mkdirSync(__dirname + '/../../tmp');
|
||||
|
||||
if (!fs.existsSync(tools.getConfigFileName())) {
|
||||
isCreated = true;
|
||||
if (fs.existsSync(__dirname + '/../../conf/' + tools.appName + '-dist.json')) {
|
||||
config = require(__dirname + '/../../conf/' + tools.appName + '-dist.json');
|
||||
} else {
|
||||
config = require(__dirname + '/../../conf/' + tools.appName.toLowerCase() + '-dist.json');
|
||||
}
|
||||
console.log('creating conf/' + tools.appName + '.json');
|
||||
config.objects.host = params.objects || '127.0.0.1';
|
||||
config.states.host = params.states || '127.0.0.1';
|
||||
if (useRedis) {
|
||||
config.states.type = 'redis';
|
||||
config.states.port = 6379;
|
||||
}
|
||||
|
||||
// this path is relative to yunkong2.js-controller
|
||||
config.dataDir = tools.getDefaultDataDir();
|
||||
if (fs.existsSync(__dirname + '/../../../node_modules/' + tools.appName + '.js-controller')) {
|
||||
mkpathSync(__dirname + '/../', config.dataDir);
|
||||
} else {
|
||||
mkpathSync(__dirname + '/../', '../' + config.dataDir);
|
||||
}
|
||||
|
||||
// Create default data dir
|
||||
fs.writeFileSync(tools.getConfigFileName(), JSON.stringify(config, null, 2));
|
||||
|
||||
try {
|
||||
// Create
|
||||
if (__dirname.toLowerCase().replace(/\\/g, '/').indexOf('node_modules/' + tools.appName + '.js-controller') !== -1) {
|
||||
var parts = config.dataDir.split('/');
|
||||
// Remove appName-data/
|
||||
parts.pop();
|
||||
parts.pop();
|
||||
var path = parts.join('/');
|
||||
|
||||
if (!fs.existsSync(__dirname + '/../../' + path + '/log')) fs.mkdirSync(__dirname + '/../../' + path + '/log');
|
||||
} else {
|
||||
if (!fs.existsSync(__dirname + '/../../log')) fs.mkdirSync(__dirname + '/../../log');
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Non-critical error: ' + e.message);
|
||||
}
|
||||
} else if (ignoreIfExist) {
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
setupObjects(function () {
|
||||
if (callback) callback(isCreated);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = Setup;
|
||||
360
lib/setup/setupUpgrade.js
Normal file
360
lib/setup/setupUpgrade.js
Normal file
@@ -0,0 +1,360 @@
|
||||
'use strict';
|
||||
|
||||
function Upgrade(options) {
|
||||
var fs = require('fs');
|
||||
var tools = require(__dirname + '/../tools.js');
|
||||
|
||||
var that = this;
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (!options.objects) throw 'Invalid arguments: objects is missing';
|
||||
if (!options.processExit) throw 'Invalid arguments: processExit is missing';
|
||||
if (!options.installNpm) throw 'Invalid arguments: installNpm is missing';
|
||||
if (!options.restartController) throw 'Invalid arguments: restartController is missing';
|
||||
if (!options.getRepository) throw 'Invalid arguments: getRepository is missing';
|
||||
|
||||
var objects = options.objects;
|
||||
var processExit = options.processExit;
|
||||
var installNpm = options.installNpm;
|
||||
var restartController = options.restartController;
|
||||
var getRepository = options.getRepository;
|
||||
var params = options.params;
|
||||
var semver;
|
||||
|
||||
var Upload = require(__dirname + '/setupUpload.js');
|
||||
var upload = new Upload(options);
|
||||
|
||||
var Install = require(__dirname + '/setupInstall.js');
|
||||
var install = new Install(options);
|
||||
|
||||
this.upgradeAdapterHelper = function (repoUrl, list, i, forceDowngrade, callback) {
|
||||
that.upgradeAdapter(repoUrl, list[i], forceDowngrade, function () {
|
||||
i++;
|
||||
while (repoUrl[list[i]] && repoUrl[list[i]].controller) {
|
||||
i++;
|
||||
}
|
||||
|
||||
if (list[i]) {
|
||||
setImmediate(function () {
|
||||
that.upgradeAdapterHelper(repoUrl, list, i, forceDowngrade, callback);
|
||||
});
|
||||
} else if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function checkDependencies(dependencies) {
|
||||
if (!dependencies) return '';
|
||||
// like [{"js-controller": ">=0.10.1"}]
|
||||
var adapters;
|
||||
if (dependencies instanceof Array) {
|
||||
adapters = {};
|
||||
for (var a = 0; a < dependencies.length; a++) {
|
||||
if (typeof dependencies[a] === 'string') continue;
|
||||
for (var b in dependencies[a]) adapters[b] = dependencies[a][b];
|
||||
}
|
||||
} else {
|
||||
adapters = dependencies;
|
||||
}
|
||||
|
||||
for (var adapter in adapters) {
|
||||
var adapterDir = tools.getAdapterDir(adapter);
|
||||
var iopack;
|
||||
if (!semver) semver = require('semver');
|
||||
if (adapter === 'js-controller') {
|
||||
try {
|
||||
iopack = JSON.parse(fs.readFileSync(__dirname + '/../../io-package.json', 'utf8'));
|
||||
} catch (e) {
|
||||
return 'Cannot find io-package.json in "' + __dirname + '/../../": ' + e;
|
||||
}
|
||||
if (!iopack || !iopack.common || !iopack.common.version) return 'No version of "js-controller"';
|
||||
if (!semver.satisfies(iopack.common.version, adapters[adapter])) return 'Invalid version of js-controler. Required ' + adapters[adapter];
|
||||
} else {
|
||||
try {
|
||||
iopack = JSON.parse(fs.readFileSync(adapterDir + '/io-package.json', 'utf8'));
|
||||
} catch (e) {
|
||||
return 'Cannot find io-package.json in "' + adapterDir + '": ' + e;
|
||||
}
|
||||
|
||||
if (!iopack || !iopack.common || !iopack.common.version) return 'No version of "' + adapter + '"';
|
||||
if (!semver.satisfies(iopack.common.version, adapters[adapter])) return 'Invalid version of "' + adapter + '"';
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
this.upgradeAdapter = function (repoUrl, adapter, forceDowngrade, callback) {
|
||||
if (!repoUrl || typeof repoUrl !== 'object') {
|
||||
getRepository(repoUrl, params, function (err, sources) {
|
||||
if (err) {
|
||||
processExit(err);
|
||||
} else {
|
||||
that.upgradeAdapter(sources, adapter, forceDowngrade, callback);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
function finishUpgrade(name, iopack, callback) {
|
||||
if (!iopack) {
|
||||
var adapterDir = tools.getAdapterDir(name);
|
||||
try {
|
||||
iopack = JSON.parse(fs.readFileSync(adapterDir + '/io-package.json', 'utf8'));
|
||||
} catch (e) {
|
||||
console.error('Cannot find io-package.json in ' + adapterDir);
|
||||
processExit(10);
|
||||
}
|
||||
}
|
||||
|
||||
var count = 0;
|
||||
installNpm(name, function (err, _name) {
|
||||
if (err) {
|
||||
processExit(err);
|
||||
} else {
|
||||
// Upload www and admin files of adapter into CouchDB
|
||||
count++;
|
||||
upload.uploadAdapter(name, false, true, function () {
|
||||
// extend all adapter instance default configs with current config
|
||||
// (introduce potentially new attributes while keeping current settings)
|
||||
upload.upgradeAdapterObjects(name, iopack, function () {
|
||||
count--;
|
||||
if (!count) {
|
||||
console.log('Adapter "' + name + '" updated');
|
||||
if (callback) callback(name);
|
||||
}
|
||||
});
|
||||
});
|
||||
count++;
|
||||
upload.uploadAdapter(name, true, true, function () {
|
||||
count--;
|
||||
if (!count) {
|
||||
console.log('Adapter "' + name + '" updated');
|
||||
if (callback) callback(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var sources = repoUrl;
|
||||
var version;
|
||||
if (adapter.indexOf('@') !== -1) {
|
||||
var parts = adapter.split('@');
|
||||
adapter = parts[0];
|
||||
version = parts[1];
|
||||
} else {
|
||||
version = '';
|
||||
}
|
||||
if (version) forceDowngrade = true;
|
||||
|
||||
var adapterDir = tools.getAdapterDir(adapter);
|
||||
|
||||
// Read actual description of installed adapter with version
|
||||
if (!version && !fs.existsSync(adapterDir + '/io-package.json')) {
|
||||
console.log('Adapter "' + adapter + '"' + ((adapter.length < 15) ? new Array(15 - adapter.length).join(' '): '') + ' is not installed.');
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
// Get the url of io-package.json or direct the version
|
||||
if (!repoUrl[adapter]) {
|
||||
console.log('Adapter "' + adapter + '" is not in the repository and cannot be updated.');
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
|
||||
var ioInstalled;
|
||||
if (fs.existsSync(adapterDir + '/io-package.json')) {
|
||||
ioInstalled = require(adapterDir + '/io-package.json');
|
||||
}
|
||||
if (!ioInstalled) {
|
||||
ioInstalled = {common: {version: '0.0.0'}};
|
||||
}
|
||||
|
||||
// If version is included in repository
|
||||
if (repoUrl[adapter].version) {
|
||||
if (!forceDowngrade) {
|
||||
var error = checkDependencies(repoUrl[adapter].dependencies);
|
||||
if (error) {
|
||||
console.error(error);
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!forceDowngrade && (repoUrl[adapter].version === ioInstalled.common.version ||
|
||||
tools.upToDate(repoUrl[adapter].version, ioInstalled.common.version))) {
|
||||
console.log('Adapter "' + adapter + '"' + ((adapter.length < 15) ? new Array(15 - adapter.length).join(' '): '') + ' is up to date.');
|
||||
if (callback) callback();
|
||||
} else {
|
||||
console.log('Update ' + adapter + ' from @' + ioInstalled.common.version + ' to @' + (version || repoUrl[adapter].version));
|
||||
// Get the adapter from web site
|
||||
install.downloadPacket(sources, adapter + '@' + (version || repoUrl[adapter].version), null, function (name, ioPack) {
|
||||
finishUpgrade(name, ioPack, callback);
|
||||
});
|
||||
}
|
||||
} else if (repoUrl[adapter].meta) {
|
||||
// Read repository from url or file
|
||||
tools.getJson(repoUrl[adapter].meta, function (iopack) {
|
||||
if (!iopack) {
|
||||
console.error('Cannot parse file' + repoUrl[adapter].meta);
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!forceDowngrade) {
|
||||
var error = checkDependencies(iopack.common ? iopack.common.dependencies : null);
|
||||
if (error) {
|
||||
console.error(error);
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!version && (iopack.common.version === ioInstalled.common.version ||
|
||||
(!forceDowngrade && tools.upToDate(iopack.common.version, ioInstalled.common.version)))) {
|
||||
console.log('Adapter "' + adapter + '"' + ((adapter.length < 15) ? new Array(15 - adapter.length).join(' '): '') + ' is up to date.');
|
||||
if (callback) callback();
|
||||
} else {
|
||||
// Get the adapter from web site
|
||||
console.log('Update ' + adapter + ' from @' + ioInstalled.common.version + ' to @' + (version || iopack.common.version));
|
||||
install.downloadPacket(sources, adapter + '@' + (version || iopack.common.version), null, function (name, ioPack) {
|
||||
finishUpgrade(name, ioPack, callback);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (forceDowngrade) {
|
||||
console.warn('Unable to get version for "' + adapter + '". Update anyway.');
|
||||
console.log('Update ' + adapter + ' from @' + ioInstalled.common.version + ' to @' + version);
|
||||
// Get the adapter from web site
|
||||
install.downloadPacket(sources, adapter + '@' + version, null, function (name, ioPack) {
|
||||
finishUpgrade(name, ioPack, callback);
|
||||
});
|
||||
} else {
|
||||
console.error('Unable to get version for "' + adapter + '".');
|
||||
if (callback) callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.upgradeController = function (repoUrl, forceDowngrade, callback) {
|
||||
if (!repoUrl || typeof repoUrl !== 'object') {
|
||||
getRepository(repoUrl, params, function (err, sources) {
|
||||
if (!sources) {
|
||||
console.warn('Cannot get repository under "' + repoUrl + '"');
|
||||
if (callback) callback(err);
|
||||
} else {
|
||||
that.upgradeController(sources, forceDowngrade, callback);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
var hostname = tools.getHostName();
|
||||
var installed = JSON.parse(fs.readFileSync(__dirname + '/../../io-package.json', 'utf8'));
|
||||
if (!installed || !installed.common || !installed.common.version) {
|
||||
console.error('Host "' + hostname + '"' + ((hostname.length < 15) ? new Array(15 - hostname.length).join(' '): '') + ' is not installed.');
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
if (!repoUrl[installed.common.name]) {
|
||||
// no info for controller
|
||||
console.error('Cannot find this controller "' + installed.common.name + '" in repository.');
|
||||
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
|
||||
if (repoUrl[installed.common.name].version) {
|
||||
if (!forceDowngrade && (repoUrl[installed.common.name].version === installed.common.version ||
|
||||
tools.upToDate(repoUrl[installed.common.name].version, installed.common.version))) {
|
||||
console.log('Host "' + hostname + '"' + ((hostname.length < 15) ? new Array(15 - hostname.length).join(' '): '') + ' is up to date.');
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
} else {
|
||||
console.log('Update ' + installed.common.name + ' from @' + installed.common.version + ' to @' + repoUrl[installed.common.name].version);
|
||||
// Get the controller from web site
|
||||
install.downloadPacket(repoUrl, installed.common.name + '@' + repoUrl[installed.common.name].version, null, function (name) {
|
||||
installNpm(function (err, _name) {
|
||||
if (err) {
|
||||
processExit(err);
|
||||
} else {
|
||||
setChmod(function () {
|
||||
restartController(callback);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
tools.getJson(repoUrl[installed.common.name].meta, function (ioPack) {
|
||||
if ((!ioPack || !ioPack.common) && !forceDowngrade) {
|
||||
console.warn('Cannot read version. Write "' + tools.appName + ' upgrade self --force" to upgrade controller anyway.');
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
return;
|
||||
}
|
||||
var version = ioPack && ioPack.common ? ioPack && ioPack.common.version : '';
|
||||
if (version) {
|
||||
version = '@' + version;
|
||||
}
|
||||
|
||||
if ((ioPack && ioPack.common && ioPack.common.version === installed.common.version) ||
|
||||
(!forceDowngrade && ioPack && ioPack.common && tools.upToDate(ioPack.common.version, installed.common.version))) {
|
||||
console.log('Host "' + hostname + '"' + ((hostname.length < 15) ? new Array(15 - hostname.length).join(' '): '') + ' is up to date.');
|
||||
if (callback) callback();
|
||||
} else {
|
||||
var name = (ioPack && ioPack.common && ioPack.common.name) ? ioPack.common.name : installed.common.name;
|
||||
console.log('Update ' + name + ' from @' + installed.common.version + ' to ' + version);
|
||||
// Get the controller from web site
|
||||
install.downloadPacket(repoUrl, name + version, null, function (name) {
|
||||
installNpm(function (err, _name) {
|
||||
if (err) {
|
||||
processExit(err);
|
||||
} else {
|
||||
setChmod(function () {
|
||||
restartController(callback);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function setChmod(callback) {
|
||||
var platform = require('os').platform();
|
||||
console.log('Host "' + tools.getHostName() + '" (' + platform + ') updated');
|
||||
// Call command chmod +x __dirname if under linux or darwin
|
||||
if (platform === 'linux' || platform === 'darwin') {
|
||||
var exec = require('child_process').exec;
|
||||
var dir;
|
||||
if (__dirname.toLowerCase().replace(/\\/g, '/').indexOf('node_modules/' + tools.appName + '.js-controller') !== -1) {
|
||||
dir = require('path').normalize(__dirname + '/../../../..').replace(/\\/g, '/');
|
||||
} else {
|
||||
dir = require('path').normalize(__dirname + '/../..').replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
var cmd = 'chmod -R 777 ' + dir;
|
||||
console.log('Execute: ' + cmd);
|
||||
var child = exec(cmd);
|
||||
child.stderr.pipe(process.stdout);
|
||||
child.on('exit', function () {
|
||||
console.log('Chmod finished. Restart controller');
|
||||
if (callback) callback();
|
||||
});
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports = Upgrade;
|
||||
543
lib/setup/setupUpload.js
Normal file
543
lib/setup/setupUpload.js
Normal file
@@ -0,0 +1,543 @@
|
||||
'use strict';
|
||||
|
||||
function Upload(options) {
|
||||
const fs = require('fs');
|
||||
const tools = require(__dirname + '/../tools.js');
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (!options.states) throw 'Invalid arguments: states is missing';
|
||||
if (!options.objects) throw 'Invalid arguments: objects is missing';
|
||||
|
||||
let states = options.states;
|
||||
let objects = options.objects;
|
||||
let mime;
|
||||
|
||||
// get all instances of one adapter
|
||||
function getInstances(adapter, callback) {
|
||||
objects.getObjectList({startkey: 'system.adapter.' + adapter + '.', endkey: 'system.adapter.' + adapter + '.\u9999'}, (err, arr) => {
|
||||
let instances = [];
|
||||
if (!err && arr && arr.rows) {
|
||||
for (let i = 0; i < arr.rows.length; i++) {
|
||||
if (arr.rows[i].value.type !== 'instance') continue;
|
||||
instances.push(arr.rows[i].value._id);
|
||||
}
|
||||
}
|
||||
callback(instances);
|
||||
});
|
||||
}
|
||||
|
||||
// get all instances of all adapters in the list
|
||||
function getAllInstances(adapters, callback) {
|
||||
let instances = [];
|
||||
let count = 0;
|
||||
for (let k = 0; k < adapters.length; k++) {
|
||||
if (!adapters[k]) continue;
|
||||
if (adapters[k].indexOf('.') === -1) count++;
|
||||
}
|
||||
for (let i = 0; i < adapters.length; i++) {
|
||||
if (!adapters[i]) continue;
|
||||
if (adapters[i].indexOf('.') === -1) {
|
||||
getInstances(adapters[i], inst => {
|
||||
for (let j = 0; j < inst.length; j++) {
|
||||
if (instances.indexOf(inst[j]) === -1) {
|
||||
instances.push(inst[j]);
|
||||
}
|
||||
}
|
||||
if (!--count && callback) {
|
||||
callback(instances);
|
||||
callback = null;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (instances.indexOf(adapters[i]) === -1) {
|
||||
instances.push(adapters[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!count && callback) {
|
||||
callback(instances);
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if some adapters must be restarted and restart them
|
||||
function checkRestartOther(adapter, callback) {
|
||||
let adapterDir = tools.getAdapterDir(adapter);
|
||||
try {
|
||||
let adapterConf = JSON.parse(fs.readFileSync(adapterDir + '/io-package.json').toString());
|
||||
if (adapterConf.common.restartAdapters) {
|
||||
if (typeof adapterConf.common.restartAdapters !== 'object') adapterConf.common.restartAdapters = [adapterConf.common.restartAdapters];
|
||||
|
||||
if (adapterConf.common.restartAdapters.length && adapterConf.common.restartAdapters[0]) {
|
||||
getAllInstances(adapterConf.common.restartAdapters, instances => {
|
||||
if (!instances || !instances.length) {
|
||||
if (callback) {
|
||||
callback();
|
||||
callback = null;
|
||||
}
|
||||
} else {
|
||||
let instancesCount = instances.length;
|
||||
for (let r = 0; r < instances.length; r++) {
|
||||
objects.getObject(instances[r], (err, obj) => {
|
||||
// if instance is enabled
|
||||
if (!err && obj && obj.common.enabled) {
|
||||
|
||||
obj.common.enabled = false; // disable instance
|
||||
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = Date.now();
|
||||
|
||||
objects.setObject(obj._id, obj, err => {
|
||||
if (!err) {
|
||||
|
||||
obj.common.enabled = true; // enable instance
|
||||
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = Date.now();
|
||||
|
||||
objects.setObject(obj._id, obj, err => {
|
||||
console.log('Adapter "' + obj._id + '" restarted.');
|
||||
if (!--instancesCount && callback) {
|
||||
callback();
|
||||
callback = null;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (err) {
|
||||
console.error('Cannot restart adapter "' + obj._id + '": ' + err);
|
||||
} else {
|
||||
console.warn('Adapter "' + obj._id + '" is disabled and cannot be restarted.');
|
||||
}
|
||||
if (!--instancesCount && callback) {
|
||||
callback();
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (!--instancesCount && callback) {
|
||||
callback();
|
||||
callback = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if (callback) {
|
||||
callback();
|
||||
callback = null;
|
||||
}
|
||||
} else if (callback) {
|
||||
callback();
|
||||
callback = null;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Cannot parse ' + adapterDir + '/io-package.json:' + e);
|
||||
if (callback) {
|
||||
callback();
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.uploadAdapterFull = (adapters, callback) => {
|
||||
if (!adapters || !adapters.length) {
|
||||
if (callback) callback();
|
||||
return;
|
||||
}
|
||||
const adapter = adapters.pop();
|
||||
this.uploadAdapter(adapter, true, true, () => {
|
||||
this.upgradeAdapterObjects(adapter, () => {
|
||||
this.uploadAdapter(adapter, false, true, () => {
|
||||
setImmediate(() => this.uploadAdapterFull(adapters, callback));
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.uploadFile = (source, target, callback) => {
|
||||
const request = require('request');
|
||||
target = target.replace(/\\/g, '/');
|
||||
source = source.replace(/\\/g, '/');
|
||||
if (target[0] === '/') target = target.substring(1);
|
||||
if (target[target.length - 1] === '/') {
|
||||
let name = source.split('/').pop();
|
||||
name = name.split('?')[0];
|
||||
if (name.indexOf('.') === -1) name = 'index.html';
|
||||
target += name;
|
||||
}
|
||||
let parts = target.split('/');
|
||||
const adapter = parts[0];
|
||||
parts.splice(0, 1);
|
||||
target = parts.join('/');
|
||||
|
||||
if (source.match(/^http:\/\/|^https:\/\//)) {
|
||||
request(source, (error, response, body) => {
|
||||
if (!error && response.statusCode === 200) {
|
||||
objects.writeFile(adapter, target, body, err => {
|
||||
if (err) console.error(err);
|
||||
if (typeof callback === 'function') callback(err, adapter + '/' + target);
|
||||
});
|
||||
} else {
|
||||
console.error('Cannot get URL: ' + error || response.statusCode);
|
||||
if (typeof callback === 'function') callback(error || response.statusCode, adapter + '/' + target);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
try {
|
||||
objects.writeFile(adapter, target, fs.readFileSync(source), err => {
|
||||
if (err) console.error(err);
|
||||
if (typeof callback === 'function') callback(err, adapter + '/' + target);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Cannot read file "' + source + '": ' + err);
|
||||
if (typeof callback === 'function') callback(err, adapter + '/' + target);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Upload www folder of adapter into ObjectsDB
|
||||
this.uploadAdapter = (adapter, isAdmin, forceUpload, subTree, callback) => {
|
||||
const id = adapter + (isAdmin ? '.admin' : '');
|
||||
const adapterDir = tools.getAdapterDir(adapter);
|
||||
let dir = adapterDir + (isAdmin ? '/admin' : '/www');
|
||||
let files = [];
|
||||
let rev;
|
||||
|
||||
if (typeof subTree === 'function') {
|
||||
callback = subTree;
|
||||
subTree = null;
|
||||
}
|
||||
if (subTree) {
|
||||
dir += '/' + subTree;
|
||||
}
|
||||
|
||||
if (!isAdmin) {
|
||||
let cfg;
|
||||
// check for common.wwwDontUpload (required for legacy adapter)
|
||||
if (fs.existsSync(adapterDir + '/io-package.json')) {
|
||||
cfg = require(adapterDir + '/io-package.json');
|
||||
}
|
||||
if (cfg && cfg.common && cfg.common.wwwDontUpload) {
|
||||
if (typeof callback === 'function') callback(adapter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// do not upload www dir of admin adapter
|
||||
if (adapter === 'admin' && !isAdmin) {
|
||||
// To DO remove after a while
|
||||
console.log('This should never happens!');
|
||||
if (typeof callback === 'function') callback(adapter);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create "upload progress" object if not exists
|
||||
if (!isAdmin) {
|
||||
objects.getObject('system.adapter.' + adapter + '.upload', (err, obj) => {
|
||||
if (err || !obj) {
|
||||
objects.setObject('system.adapter.' + adapter + '.upload',
|
||||
{
|
||||
_id: 'system.adapter.' + adapter + '.upload',
|
||||
type: 'state',
|
||||
common: {
|
||||
name: adapter + '.upload',
|
||||
type: 'number',
|
||||
role: 'indicator.state',
|
||||
unit: '%',
|
||||
def: 0,
|
||||
desc: 'Upload process indicator'
|
||||
},
|
||||
from: 'system.host.' + tools.getHostName() + '.cli',
|
||||
ts: Date.now(),
|
||||
native: {}
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
// Set indicator to 0
|
||||
states.setState('system.adapter.' + adapter + '.upload', 0, true);
|
||||
}
|
||||
|
||||
if (!mime) mime = require('mime');
|
||||
|
||||
function done(err, res) {
|
||||
if (err) {
|
||||
callback();
|
||||
} else {
|
||||
console.log('got ' + dir);
|
||||
files = res;
|
||||
setTimeout(_adapter => {
|
||||
maxFiles = files.length || 1;
|
||||
upload(_adapter);
|
||||
}, 25, adapter);
|
||||
}
|
||||
}
|
||||
|
||||
let maxFiles = 0;
|
||||
let lastProgressUpdate = (new Date()).getTime();
|
||||
|
||||
function upload(adapter) {
|
||||
let file;
|
||||
if (!files.length) {
|
||||
if (!isAdmin) {
|
||||
states.setState('system.adapter.' + adapter + '.upload', {val: 0, ack: true}, () => {
|
||||
if (typeof callback === 'function') callback(adapter);
|
||||
});
|
||||
} else {
|
||||
if (typeof callback === 'function') callback(adapter);
|
||||
}
|
||||
} else {
|
||||
file = files.pop();
|
||||
if (file === '.gitignore') {
|
||||
upload(adapter);
|
||||
return;
|
||||
}
|
||||
|
||||
const mimeType = mime.lookup(file);
|
||||
let attName;
|
||||
attName = file.split('/' + tools.appName + '.');
|
||||
if (attName.length === 1) {
|
||||
// try to find anyway if adapter is not lower case
|
||||
const pos = file.toLowerCase().indexOf(tools.appName.toLowerCase());
|
||||
if (pos !== -1) {
|
||||
attName = ['', file.substring(tools.appName.length + 2)];
|
||||
}
|
||||
}
|
||||
|
||||
attName = attName.pop();
|
||||
attName = attName.split('/').slice(2).join('/');
|
||||
if (files.length > 100) {
|
||||
if (!(files.length % 50)) {
|
||||
console.log('upload [' + files.length + ']', id, file, attName, mimeType);
|
||||
}
|
||||
|
||||
} else if (files.length > 20) {
|
||||
if (!(files.length % 10)) {
|
||||
console.log('upload [' + files.length + ']', id, file, attName, mimeType);
|
||||
}
|
||||
} else {
|
||||
console.log('upload [' + files.length + ']', id, file, attName, mimeType);
|
||||
}
|
||||
|
||||
// Update upload indicator
|
||||
if (!isAdmin) {
|
||||
const now = (new Date()).getTime();
|
||||
if (now - lastProgressUpdate > 1000) {
|
||||
lastProgressUpdate = now;
|
||||
states.setState('system.adapter.' + adapter + '.upload', {val: Math.round(1000 * (maxFiles - files.length) / maxFiles) / 10, ack: true});
|
||||
}
|
||||
}
|
||||
|
||||
fs.createReadStream(file).pipe(
|
||||
objects.insert(id, attName, null, mimeType, {
|
||||
rev: rev
|
||||
}, (err, res) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
if (typeof callback === 'function') callback(adapter);
|
||||
}
|
||||
if (res) rev = res.rev;
|
||||
setTimeout(upload, 50, adapter);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function walk(dir, done) {
|
||||
let results = [];
|
||||
fs.readdir(dir, (err, list) => {
|
||||
if (err) return done(err);
|
||||
let i = 0;
|
||||
(function next() {
|
||||
let file = list[i++];
|
||||
if (!file) return done(null, results);
|
||||
file = dir + '/' + file;
|
||||
fs.stat(file, (err, stat) => {
|
||||
if (stat && stat.isDirectory()) {
|
||||
walk(file, (err, res) => {
|
||||
results = results.concat(res);
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
if (!file.match(/\.npmignore$/) && !file.match(/\.gitignore$/)) results.push(file);
|
||||
next();
|
||||
}
|
||||
});
|
||||
})();
|
||||
});
|
||||
}
|
||||
|
||||
objects.getObject(id, (err, res) => {
|
||||
if (err || !res) {
|
||||
objects.setObject(id, {
|
||||
type: 'meta',
|
||||
common: {
|
||||
name: id.split('.').pop(),
|
||||
type: isAdmin ? 'admin' : 'www'
|
||||
},
|
||||
from: 'system.host.' + tools.getHostName() + '.cli',
|
||||
ts: Date.now(),
|
||||
native: {}
|
||||
}, (err, res) => {
|
||||
if (res) rev = res.rev;
|
||||
if (!isAdmin) {
|
||||
checkRestartOther(adapter, () => walk(dir, done));
|
||||
} else {
|
||||
walk(dir, done);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (!forceUpload) {
|
||||
if (typeof callback === 'function') callback(adapter);
|
||||
} else {
|
||||
rev = res.rev;
|
||||
if (!isAdmin) {
|
||||
checkRestartOther(adapter, () => walk(dir, done));
|
||||
} else {
|
||||
walk(dir, done);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function extendNative(target, additional) {
|
||||
for (let attr in additional) {
|
||||
if (additional.hasOwnProperty(attr)) {
|
||||
if (target[attr] === undefined) {
|
||||
target[attr] = additional[attr];
|
||||
} else if (typeof additional[attr] === 'object' && !(additional[attr] instanceof Array)) {
|
||||
try {
|
||||
target[attr] = target[attr] || {};
|
||||
} catch (e) {
|
||||
console.warn(`Cannot update attribute ${attr} of native`);
|
||||
}
|
||||
extendNative(target[attr], additional[attr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
function extendCommon(target, additional) {
|
||||
for (let attr in additional) {
|
||||
if (additional.hasOwnProperty(attr)) {
|
||||
if (attr === 'title' || attr === 'schedule' || attr === 'mode' || attr === 'loglevel' || attr === 'enabled') {
|
||||
if (target[attr] === undefined) {
|
||||
target[attr] = additional[attr];
|
||||
}
|
||||
} else if (typeof additional[attr] !== 'object' || (additional[attr] instanceof Array)) {
|
||||
try {
|
||||
target[attr] = additional[attr];
|
||||
} catch (e) {
|
||||
console.warn(`Cannot update attribute ${attr} of common`);
|
||||
}
|
||||
} else {
|
||||
target[attr] = target[attr] || {};
|
||||
if (typeof target[attr] !== 'object') {
|
||||
target[attr] = {}; // here we clean the simple value with object
|
||||
}
|
||||
|
||||
extendCommon(target[attr], additional[attr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
this.upgradeAdapterObjects = (name, iopack, callback) => {
|
||||
if (typeof iopack === 'function') {
|
||||
callback = iopack;
|
||||
iopack = null;
|
||||
}
|
||||
if (!iopack) {
|
||||
const adapterDir = tools.getAdapterDir(name);
|
||||
try {
|
||||
iopack = JSON.parse(fs.readFileSync(adapterDir + '/io-package.json', 'utf8'));
|
||||
} catch (e) {
|
||||
console.error('Cannot find io-package.json in ' + adapterDir);
|
||||
iopack = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iopack) {
|
||||
callback(name);
|
||||
} else {
|
||||
objects.getObject('system.adapter.' + name, (err, obj) => {
|
||||
if (err || !obj) {
|
||||
console.error('system.adapter.' + name + ' does not exist');
|
||||
callback(name);
|
||||
} else {
|
||||
obj.common = iopack.common || {};
|
||||
obj.native = iopack.native || {};
|
||||
|
||||
obj.common.installedVersion = iopack.common.version;
|
||||
|
||||
const hostname = tools.getHostName();
|
||||
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = Date.now();
|
||||
|
||||
objects.setObject('system.adapter.' + name, obj, () => {
|
||||
// Update all instances of this host
|
||||
objects.getObjectView('system', 'instance', {startkey: 'system.adapter.' + name + '.', endkey: 'system.adapter.' + name + '.\u9999'}, null, function (err, res) {
|
||||
let cntr = 0;
|
||||
|
||||
if (res) {
|
||||
for (let i = 0; i < res.rows.length; i++) {
|
||||
if (res.rows[i].value.common.host === hostname) {
|
||||
cntr++;
|
||||
objects.getObject(res.rows[i].id, (err, _obj) => {
|
||||
let newObject = JSON.parse(JSON.stringify(_obj));
|
||||
|
||||
// all common settings should be taken from new one
|
||||
newObject.common = extendCommon(newObject.common, iopack.common);
|
||||
newObject.native = extendNative(newObject.native, iopack.native);
|
||||
|
||||
newObject.common.installedVersion = iopack.common.version;
|
||||
newObject.common.version = iopack.common.version;
|
||||
|
||||
// Compare objects to reduce restarts of instances
|
||||
if (JSON.stringify(newObject) !== JSON.stringify(_obj)) {
|
||||
console.log('Update "' + newObject._id + '"');
|
||||
|
||||
newObject.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
newObject.ts = Date.now();
|
||||
|
||||
objects.setObject(newObject._id, newObject, () => {
|
||||
if (!--cntr && callback) callback(name);
|
||||
});
|
||||
} else {
|
||||
if (!--cntr && callback) callback(name);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// updates "_design/system" and co
|
||||
if (iopack.objects && typeof iopack.objects === 'object') {
|
||||
for (let _id in iopack.objects) {
|
||||
if (!iopack.objects.hasOwnProperty(_id)) continue;
|
||||
cntr++;
|
||||
|
||||
iopack.objects[_id].from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
iopack.objects[_id].ts = Date.now();
|
||||
|
||||
objects.setObject(iopack.objects[_id]._id, iopack.objects[_id], err => {
|
||||
if (err) console.error('Cannot update object: ' + err);
|
||||
if (!--cntr && callback) callback(name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!cntr && callback) callback(name);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Upload;
|
||||
522
lib/setup/setupUsers.js
Normal file
522
lib/setup/setupUsers.js
Normal file
@@ -0,0 +1,522 @@
|
||||
'use strict';
|
||||
|
||||
function Users(options) {
|
||||
var fs = require('fs');
|
||||
var tools = require(__dirname + '/../tools.js');
|
||||
|
||||
var that = this;
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (!options.objects) throw 'Invalid arguments: objects is missing';
|
||||
if (!options.processExit) throw 'Invalid arguments: processExit is missing';
|
||||
|
||||
var objects = options.objects;
|
||||
var processExit = options.processExit;
|
||||
|
||||
this.addUser = function (user, pw, callback) {
|
||||
var _user = user.replace(/\s/g, '_');
|
||||
objects.getObject('system.user.' + _user, function (err, obj) {
|
||||
if (obj) {
|
||||
if (callback) callback('User yet exists');
|
||||
} else {
|
||||
objects.setObject('system.user.' + _user, {
|
||||
type: 'user',
|
||||
common: {
|
||||
name: user,
|
||||
enabled: true
|
||||
},
|
||||
from: 'system.host.' + tools.getHostName() + '.cli',
|
||||
ts: new Date().getTime(),
|
||||
native: {}
|
||||
}, function (err) {
|
||||
if (!err) {
|
||||
that.setPassword(user, pw, callback);
|
||||
} else {
|
||||
if (typeof callback === 'function') callback(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.isUser = function (user, callback) {
|
||||
var _user = user.replace(/\s/g, '_');
|
||||
objects.getObject('system.user.' + _user, function (err, obj) {
|
||||
if (callback) callback(null, !!obj);
|
||||
});
|
||||
};
|
||||
|
||||
this.setPassword = function (user, pw, callback) {
|
||||
var _user = user.replace(/\s/g, '_');
|
||||
|
||||
objects.getObject('system.user.' + _user, function (err, obj) {
|
||||
if (err || !obj) {
|
||||
if (typeof callback === 'function') callback('User does not exist');
|
||||
return;
|
||||
}
|
||||
var password = require(__dirname + '/../password');
|
||||
|
||||
password(pw).hash(null, null, function (err, res) {
|
||||
if (err) {
|
||||
if (typeof callback === 'function') callback(err);
|
||||
return;
|
||||
}
|
||||
obj.common.password = res;
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject('system.user.' + _user, obj, function (err) {
|
||||
if (typeof callback === 'function') callback(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.checkPassword = function (user, pw, callback) {
|
||||
objects.getObject('system.user.' + user, function (err, obj) {
|
||||
if (err || !obj) {
|
||||
if (typeof callback === 'function') callback('User does not exist');
|
||||
return;
|
||||
}
|
||||
var password = require(__dirname + '/../password');
|
||||
|
||||
password(pw).check(obj.common.password, function (err, res) {
|
||||
if (typeof callback === 'function') callback(err, res);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.delUser = function (user, callback) {
|
||||
if (!user) {
|
||||
if (callback) callback('Please define user name, like: "userdel user"');
|
||||
return;
|
||||
}
|
||||
|
||||
var _user = user.replace(/\s/g, '_');
|
||||
|
||||
objects.getObject('system.user.' + _user, function (err, obj) {
|
||||
if (err || !obj) {
|
||||
if (callback) callback('User does not exist');
|
||||
} else {
|
||||
if (obj.common.dontDelete) {
|
||||
if (callback) callback('Cannot delete user, while is system user');
|
||||
} else {
|
||||
objects.delObject('system.user.' + _user, function (err) {
|
||||
// Remove this user from all groups
|
||||
if (!err) {
|
||||
objects.getObjectList({startkey: 'system.group.', endkey: 'system.group.\u9999'}, function (err, groups) {
|
||||
var count = 0;
|
||||
for (var i = 0; i < groups.rows.length; i++) {
|
||||
if (groups.rows[i].value.type != 'group') continue;
|
||||
// find all groups
|
||||
if (groups.rows[i].value.common.members && groups.rows[i].value.common.members.indexOf('system.user.' + _user) != -1) {
|
||||
var pos = groups.rows[i].value.common.members.indexOf('system.user.' + _user);
|
||||
groups.rows[i].value.common.members.splice(pos, 1);
|
||||
count++;
|
||||
groups.rows[i].value.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
groups.rows[i].value.ts = new Date().getTime();
|
||||
objects.setObject(groups.rows[i].value._id, groups.rows[i].value, function (err) {
|
||||
if (!(--count)) callback(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!count) callback();
|
||||
});
|
||||
} else if (callback) {
|
||||
callback(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.addUserToGroup = function (user, group, callback) {
|
||||
var _user = user.replace(/\s/g, '_');
|
||||
if (!group.match(/^system\.group\./)) group = 'system.group.' + group;
|
||||
if (!_user.match(/^system\.user\./)) _user = 'system.user.' + _user;
|
||||
|
||||
objects.getObject(_user, function (err, obj) {
|
||||
if (err || !obj) {
|
||||
if (typeof callback === 'function') callback('User does not exist');
|
||||
return;
|
||||
}
|
||||
objects.getObject(group, function (err, obj) {
|
||||
if (err || !obj) {
|
||||
if (typeof callback === 'function') callback('Group does not exist');
|
||||
return;
|
||||
}
|
||||
obj.common = obj.common || {};
|
||||
obj.common.members = obj.common.members || [];
|
||||
|
||||
if (obj.common.members.indexOf(_user) == -1) {
|
||||
obj.common.members.push(_user);
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject(group, obj, function (err) {
|
||||
callback(err);
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
this.addUserPrompt = function (user, group, password, callback) {
|
||||
if (!user) {
|
||||
if (callback) callback('Please define user name, like: "adduser newUser"');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check group
|
||||
if (group.substring(0, 13) !== 'system.group.' ) group = 'system.group.' + group;
|
||||
|
||||
objects.getObject(group, function (err, obj) {
|
||||
if (!obj) {
|
||||
if (callback) callback('Unknown group: ' + group);
|
||||
return;
|
||||
}
|
||||
if (!password) {
|
||||
var prompt = require('prompt');
|
||||
prompt.message = '';
|
||||
prompt.delimiter = '';
|
||||
var schema = {
|
||||
properties: {
|
||||
password: {
|
||||
description: 'Enter your password:',
|
||||
pattern: /^[^'"]+$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: true
|
||||
},
|
||||
repeatPassword: {
|
||||
description: 'Repeat your password:',
|
||||
pattern: /^[^'"]+$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: true
|
||||
}
|
||||
}
|
||||
};
|
||||
prompt.start();
|
||||
|
||||
prompt.get(schema, function (err, result) {
|
||||
if (result) {
|
||||
if (result.password !== result.repeatPassword) {
|
||||
console.log('Passwords are not identical!');
|
||||
processExit(31);
|
||||
}
|
||||
//create user
|
||||
that.addUser(user, result.password, function (err) {
|
||||
if (err) {
|
||||
if (callback) callback(err);
|
||||
} else {
|
||||
that.addUserToGroup(user, group, function (err) {
|
||||
if (err) {
|
||||
if (callback) callback(err);
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (callback) callback(err);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
that.addUser(user, password, function (err) {
|
||||
if (err) {
|
||||
if (callback) callback(err);
|
||||
} else {
|
||||
that.addUserToGroup(user, group, function (err) {
|
||||
if (err) {
|
||||
if (callback) callback(err);
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.setUserPassword = function (user, password, callback) {
|
||||
if (!user) {
|
||||
if (callback) callback('Please define user name, like: "passwd username"');
|
||||
return;
|
||||
}
|
||||
|
||||
this.isUser(user, function (err, result) {
|
||||
if (err) console.error('Cannot read user: ' + err);
|
||||
if (!result) {
|
||||
if (callback) callback('User "' + user + '" does not exist.');
|
||||
} else {
|
||||
// Check group
|
||||
if (!password) {
|
||||
var prompt = require('prompt');
|
||||
prompt.message = '';
|
||||
prompt.delimiter = '';
|
||||
var schema = {
|
||||
properties: {
|
||||
password: {
|
||||
description: 'Enter your password:',
|
||||
pattern: /^[^'"]*$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: true
|
||||
},
|
||||
repeatPassword: {
|
||||
description: 'Repeat your password:',
|
||||
pattern: /^[^'"]*$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: true
|
||||
}
|
||||
}
|
||||
};
|
||||
prompt.start();
|
||||
|
||||
prompt.get(schema, function (err, result) {
|
||||
if (result) {
|
||||
if (result.password !== result.repeatPassword) {
|
||||
if (callback) callback('Passwords are not identical!');
|
||||
return;
|
||||
}
|
||||
// set user password
|
||||
that.setPassword(user, result.password, function (err) {
|
||||
if (err) {
|
||||
if (callback) callback(err);
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (callback) callback('No password entered!');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
that.setPassword(user, password, function (err) {
|
||||
if (err) {
|
||||
if (callback) callback(err);
|
||||
} else {
|
||||
if (callback) callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.enableUser = function (user, enable, callback) {
|
||||
if (!user) {
|
||||
if (callback) callback('Please define user name, like: "enable username"');
|
||||
return;
|
||||
}
|
||||
if (user && user.match(/^system\.user\./)) user = user.substring('system.user.'.length);
|
||||
|
||||
if (user === 'admin' && !enable) {
|
||||
if (callback) callback('User admin cannot be disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
objects.getObject('system.user.' + user, function (err, obj) {
|
||||
if (err) {
|
||||
if (callback) callback('Cannot read user: ' + err);
|
||||
} if (!obj) {
|
||||
if (callback) callback('User "' + user + '" not found');
|
||||
} else {
|
||||
obj.common.enabled = enable;
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject(obj._id, obj, function (err) {
|
||||
if (typeof callback === 'function') callback(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.checkUserPassword = function (user, password, callback) {
|
||||
var prompt;
|
||||
var schema;
|
||||
if (!user && !password) {
|
||||
prompt = require('prompt');
|
||||
prompt.message = '';
|
||||
prompt.delimiter = '';
|
||||
schema = {
|
||||
properties: {
|
||||
username: {
|
||||
description: 'Enter username to check password:',
|
||||
pattern: /^[^'"]+$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: false
|
||||
},
|
||||
password: {
|
||||
description: 'Enter current password:',
|
||||
pattern: /^[^'"]+$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: true
|
||||
}
|
||||
}
|
||||
};
|
||||
prompt.start();
|
||||
|
||||
prompt.get(schema, function (err, result) {
|
||||
that.checkPassword(result.username, result.password, function (err, res) {
|
||||
if (err || !res) {
|
||||
if (callback) callback('Password for user "' + result.username + '" does not matched' + (err ? ': ' + err : ''));
|
||||
} else {
|
||||
if (callback) callback(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else if (!password) {
|
||||
prompt = require('prompt');
|
||||
prompt.message = '';
|
||||
prompt.delimiter = '';
|
||||
schema = {
|
||||
properties: {
|
||||
password: {
|
||||
description: 'Enter current password:',
|
||||
pattern: /^[^'"]+$/,
|
||||
message: 'No " are allowed',
|
||||
hidden: true
|
||||
}
|
||||
}
|
||||
};
|
||||
prompt.start();
|
||||
|
||||
prompt.get(schema, function (err, result) {
|
||||
that.checkPassword(user, result.password, function (err, res) {
|
||||
if (err || !res) {
|
||||
if (callback) callback('Password for user "' + user + '" does not matched' + (err ? ': ' + err : ''));
|
||||
} else {
|
||||
if (callback) callback(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else{
|
||||
this.checkPassword(user, password, function (err, res) {
|
||||
if (err || !res) {
|
||||
if (callback) callback('Password for user "' + user + '" does not matched' + (err ? ': ' + err : ''));
|
||||
} else {
|
||||
if (callback) callback(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.getUser = function (user, callback) {
|
||||
objects.getObject('system.user.' + user, function (err, obj) {
|
||||
if (err) {
|
||||
if (callback) callback('Cannot read user: ' + err);
|
||||
} if (!obj) {
|
||||
if (callback) callback('User "' + user + '" not found');
|
||||
} else {
|
||||
if (callback) callback(null, obj.common.enabled);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.getGroup = function (group, callback) {
|
||||
objects.getObject('system.group.' + group, function (err, obj) {
|
||||
if (err) {
|
||||
if (callback) callback('Cannot read group: ' + err);
|
||||
} if (!obj) {
|
||||
if (callback) callback('Group "' + group + '" not found');
|
||||
} else {
|
||||
if (callback) callback(null, obj.common.enabled, obj.common.members);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.enableGroup = function (group, enable, callback) {
|
||||
if (!group) {
|
||||
if (callback) callback('Please define group name, like: "enable groupname"');
|
||||
return;
|
||||
}
|
||||
if (group && group.match(/^system\.group\./)) group = group.substring('system.group.'.length);
|
||||
|
||||
if (group === 'administrator' && !enable) {
|
||||
if (callback) callback('Group "administrator" cannot be disabled');
|
||||
return;
|
||||
}
|
||||
|
||||
objects.getObject('system.group.' + group, function (err, obj) {
|
||||
if (err) {
|
||||
if (callback) callback('Cannot read group: ' + err);
|
||||
} if (!obj) {
|
||||
if (callback) callback('Group "' + group + '" not found');
|
||||
} else {
|
||||
obj.common.enabled = enable;
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject(obj._id, obj, function (err) {
|
||||
if (typeof callback === 'function') callback(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.addGroup = function (group, callback) {
|
||||
var _group = group.replace(/\s/g, '_');
|
||||
objects.getObject('system.group.' + _group, function (err, obj) {
|
||||
if (obj) {
|
||||
if (callback) callback('Group yet exists');
|
||||
} else {
|
||||
objects.setObject('system.group.' + _group, {
|
||||
type: 'group',
|
||||
common: {
|
||||
name: group,
|
||||
enabled: true,
|
||||
members: []
|
||||
},
|
||||
from: 'system.host.' + tools.getHostName() + '.cli',
|
||||
ts: new Date().getTime(),
|
||||
native: {}
|
||||
}, function (err) {
|
||||
if (typeof callback === 'function') callback(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
this.delGroup = function (group, callback) {
|
||||
var _group = group.replace(/\s/g, '_');
|
||||
|
||||
if (group === 'administrator') {
|
||||
if (typeof callback === 'function') callback('Group "administrator" cannot be deleted');
|
||||
} else {
|
||||
objects.getObject('system.group.' + _group, function (err, obj) {
|
||||
if (!obj) {
|
||||
if (callback) callback('Group does not exists');
|
||||
} else {
|
||||
objects.delObject('system.group.' + _group, function (err) {
|
||||
if (typeof callback === 'function') callback(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.removeUserFromGroup = function (user, group, callback) {
|
||||
var _group = group.replace(/\s/g, '_');
|
||||
objects.getObject('system.group.' + _group, function (err, obj) {
|
||||
if (!obj) {
|
||||
if (callback) callback('Group does not exists');
|
||||
} else {
|
||||
var pos = obj.common.members.indexOf('system.user.' + user);
|
||||
if (pos === -1) {
|
||||
if (typeof callback === 'function') callback('User not in group');
|
||||
} else {
|
||||
obj.common.members.splice(pos, 1);
|
||||
obj.from = 'system.host.' + tools.getHostName() + '.cli';
|
||||
obj.ts = new Date().getTime();
|
||||
objects.setObject(obj._id, obj, function (err) {
|
||||
if (typeof callback === 'function') callback(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = Users;
|
||||
197
lib/setup/setupVendor.js
Normal file
197
lib/setup/setupVendor.js
Normal file
@@ -0,0 +1,197 @@
|
||||
'use strict';
|
||||
function Vendor(options) {
|
||||
const fs = require('fs');
|
||||
const tools = require(__dirname + '/../tools.js');
|
||||
options = options || {};
|
||||
|
||||
let objects = options.objects;
|
||||
// read info from '/etc/iob_vendor.json' and executes instructions stored there
|
||||
this.checkVendor = (file, password) => {
|
||||
file = file || '/etc/iob-vendor.json';
|
||||
let data;
|
||||
if (fs.existsSync(file)) {
|
||||
try {
|
||||
data = JSON.parse(fs.readFileSync(file).toString('utf8'));
|
||||
} catch (e) {
|
||||
return Promise.reject(`cannot read or parse "${file}": ${JSON.stringify(e)}`);
|
||||
}
|
||||
} else {
|
||||
return Promise.reject(`"${file}" does not exist`);
|
||||
}
|
||||
|
||||
let promises = [];
|
||||
if (data.uuid) {
|
||||
const uuid = data.uuid;
|
||||
data.uuid = null;
|
||||
|
||||
// check UUID
|
||||
promises.push(objects.getObjectAsync('system.meta.uuid').then(obj => {
|
||||
if (obj && obj.native) {
|
||||
if (obj.native.uuid !== uuid) {
|
||||
obj.native.uuid = uuid;
|
||||
|
||||
console.log(`Update "system.meta.uuid:native.uuid" = "${obj.native.uuid}"`);
|
||||
|
||||
obj.nonEdit = obj.nonEdit || {};
|
||||
obj.nonEdit.password = password;
|
||||
return objects.setObjectAsync('system.meta.uuid', obj).then(() => {
|
||||
console.log('object system.meta.uuid updated: ' + uuid);
|
||||
}).catch(err => {
|
||||
console.error(`Cannot update system.meta.uuid: ${err}`);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return objects.setObjectAsync('system.meta.uuid', {
|
||||
type: 'meta',
|
||||
common: {
|
||||
name: 'uuid',
|
||||
type: 'uuid'
|
||||
},
|
||||
ts: new Date().getTime(),
|
||||
from: 'system.host.' + tools.getHostName() + '.tools',
|
||||
native: {
|
||||
uuid: uuid
|
||||
}
|
||||
}).then(() => {
|
||||
console.log('object system.meta.uuid created: ' + uuid);
|
||||
}).catch(err => {
|
||||
console.error(`Cannot create system.meta.uuid: ${err}`);
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (data.model) {
|
||||
const model = data.model;
|
||||
data.model = null;
|
||||
const hostname = tools.getHostName();
|
||||
promises.push(objects.getObjectAsync('system.host.' + hostname).then(obj => {
|
||||
if (obj && obj.common) {
|
||||
if ((model.name && model.name !== 'JS controller' && obj.common.title === 'JS controller') ||
|
||||
(model.icon && !obj.common.icon) ||
|
||||
(model.color && !obj.common.color)) {
|
||||
obj.common.title = model.name;
|
||||
obj.common.icon = model.icon;
|
||||
obj.common.color = model.color;
|
||||
|
||||
obj.nonEdit = obj.nonEdit || {};
|
||||
obj.nonEdit.password = password;
|
||||
|
||||
console.log(`Update "system.host.${hostname}:common.title" = "${obj.common.title}"`);
|
||||
console.log(`Update "system.host.${hostname}:common.icon" = "${!!obj.common.icon}"`);
|
||||
console.log(`Update "system.host.${hostname}:common.color" = "${obj.common.color}"`);
|
||||
|
||||
return objects.setObjectAsync(obj._id, obj).then(() => {
|
||||
console.log(`object "system.host.${hostname}" updated`);
|
||||
}).catch(err => {
|
||||
console.error(`Cannot update "system.host.${hostname}": ${err}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
if (data.vendor) {
|
||||
const vendor = JSON.parse(JSON.stringify(data.vendor));
|
||||
data._vendor = JSON.parse(JSON.stringify(vendor));
|
||||
data.vendor = null;
|
||||
|
||||
// store vendor
|
||||
promises.push(objects.getObjectAsync('system.config').then(obj => {
|
||||
if (obj && obj.native) {
|
||||
if (JSON.stringify(obj.native.vendor) !== JSON.stringify(vendor)) {
|
||||
obj.native.vendor = vendor;
|
||||
obj.nonEdit = obj.nonEdit || {};
|
||||
obj.nonEdit.password = password;
|
||||
return objects.setObjectAsync(obj._id, obj).then(() => {
|
||||
console.log('object system.config updated');
|
||||
}).catch(err => {
|
||||
console.error(`Cannot update system.config: ${err}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
let _promises = [];
|
||||
// update all existing objects according to vendor
|
||||
if (data.objects) {
|
||||
for (let id in data.objects) {
|
||||
if (!data.objects.hasOwnProperty(id)) continue;
|
||||
if (id.indexOf('*') === -1) {
|
||||
((_id, _obj) => {
|
||||
_promises.push(objects.getObjectAsync(_id).then(obj => {
|
||||
if (obj) {
|
||||
obj.nonEdit = obj.nonEdit || {};
|
||||
const originalObj = JSON.stringify(obj);
|
||||
_obj.nonEdit = _obj.nonEdit || {};
|
||||
_obj.nonEdit.passHash = obj.nonEdit.passHash;
|
||||
// merge objects
|
||||
tools.copyAttributes(_obj, obj);
|
||||
|
||||
if (originalObj !== JSON.stringify(obj)) {
|
||||
delete obj.nonEdit.passHash;
|
||||
obj.nonEdit.password = password;
|
||||
console.log(`Update "${obj._id}"`);
|
||||
return objects.setObjectAsync(obj._id, obj).then(() => {
|
||||
console.log(`object "${obj._id}" updated`);
|
||||
}).catch(err => {
|
||||
console.error(`Cannot update "${obj._id}": ${err}`);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return objects.setObjectAsync(_id, _obj).then(() => {
|
||||
console.log(`object "${obj._id}" updated`);
|
||||
}).catch(err => {
|
||||
console.error(`Cannot update "${obj._id}": ${err}`);
|
||||
});
|
||||
}
|
||||
}));
|
||||
})(id, data.objects[id]);
|
||||
} else {
|
||||
id = id.replace('*', '');
|
||||
((_id, _obj) => {
|
||||
_promises.push(objects.getObjectListAsync({
|
||||
startkey: _id,
|
||||
endkey: _id + '\u9999'
|
||||
}, {checked: true}).then(arr => {
|
||||
let tasks = [];
|
||||
if (arr && arr.rows && arr.rows.length) {
|
||||
for (let g = 0; g < arr.rows.length; g++) {
|
||||
let obj = arr.rows[g].value;
|
||||
if (obj) {
|
||||
obj.nonEdit = obj.nonEdit || {};
|
||||
const originalObj = JSON.stringify(obj);
|
||||
_obj.nonEdit = _obj.nonEdit || {};
|
||||
_obj.nonEdit.passHash = obj.nonEdit.passHash;
|
||||
// merge objects
|
||||
tools.copyAttributes(_obj, obj);
|
||||
if (originalObj !== JSON.stringify(obj)) {
|
||||
delete obj.nonEdit.passHash;
|
||||
obj.nonEdit.password = password;
|
||||
console.log(`Update "${obj._id}"`);
|
||||
tasks.push(objects.setObjectAsync(obj._id, obj).then(() => {
|
||||
console.log(`object "${obj._id}" updated`);
|
||||
}).catch(err => {
|
||||
console.error(`Cannot update "${obj._id}": ${err}`);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.all(tasks);
|
||||
}));
|
||||
})(id, data.objects[id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(_promises);
|
||||
});
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
module.exports = Vendor;
|
||||
175
lib/setup/setupVisDebug.js
Normal file
175
lib/setup/setupVisDebug.js
Normal file
@@ -0,0 +1,175 @@
|
||||
'use strict';
|
||||
|
||||
function VisDebug(options) {
|
||||
var fs = require('fs');
|
||||
var tools = require(__dirname + '/../tools.js');
|
||||
var path = require('path');
|
||||
|
||||
// allow use without new operator
|
||||
if (!(this instanceof VisDebug)) return new VisDebug(options);
|
||||
|
||||
options = options || {};
|
||||
|
||||
if (!options.objects) throw 'Invalid arguments: objects is missing';
|
||||
if (!options.processExit) throw 'Invalid arguments: processExit is missing';
|
||||
|
||||
var objects = options.objects;
|
||||
var processExit = options.processExit;
|
||||
|
||||
// upload widget directory to vis directory
|
||||
function uploadWidgets(dir, adapter, path, callback) {
|
||||
var dirs = fs.readdirSync(dir);
|
||||
var count = 0;
|
||||
for (var d = 0; d < dirs.length; d++) {
|
||||
var stat = fs.statSync(dir + '/' + dirs[d]);
|
||||
count++;
|
||||
if (stat.isDirectory()) {
|
||||
uploadWidgets(dir + '/' + dirs[d], adapter, path + '/' + dirs[d], function () {
|
||||
if (!--count && callback) callback();
|
||||
});
|
||||
} else {
|
||||
console.log('Upload "' + dir + '/' + dirs[d] + '"');
|
||||
objects.writeFile(adapter, path + '/' + dirs[d], fs.readFileSync(dir + '/' + dirs[d]), function () {
|
||||
if (!--count && callback) callback();
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!count && callback) callback();
|
||||
}
|
||||
|
||||
this.enableDebug = function (widgetset) {
|
||||
|
||||
if (widgetset) {
|
||||
// Try to find out the adapter directory out of a list of options
|
||||
var adapterDir;
|
||||
var adapterNames2Try = ['vis-' + widgetset, widgetset];
|
||||
if (adapterNames2Try[0] === adapterNames2Try[1]) adapterNames2Try.splice(1, 1);
|
||||
for (var i = 0; i < adapterNames2Try.length; i++) {
|
||||
try {
|
||||
var adapterDir2Try = tools.getAdapterDir(adapterNames2Try[i]);
|
||||
// Query the entry
|
||||
var stats = fs.lstatSync(adapterDir2Try);
|
||||
|
||||
// Is it a directory?
|
||||
if (stats.isDirectory()) {
|
||||
//found it!
|
||||
adapterDir = adapterDir2Try;
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!adapterDir) throw 'Adapter not found. Tried: ' + adapterNames2Try.join(', ');
|
||||
}
|
||||
|
||||
|
||||
// copy index.html.original to index.html
|
||||
// copy edit.html.original to edit.html
|
||||
// correct appName.json
|
||||
// correct config.js
|
||||
var visDir = __dirname + '/../../node_modules/' + tools.appName + '.vis';
|
||||
if (!fs.existsSync(visDir)) {
|
||||
visDir = __dirname + '/../../node_modules/' + tools.appName.toLowerCase() + '.vis';
|
||||
if (!fs.existsSync(visDir)) {
|
||||
visDir = __dirname + '/../../../' + tools.appName + '.vis';
|
||||
if (!fs.existsSync(visDir)) {
|
||||
visDir = __dirname + '/../../../' + tools.appName.toLowerCase() + '.vis';
|
||||
if (!fs.existsSync(visDir)) {
|
||||
console.error('Cannot find ' + tools.appName + '.vis');
|
||||
processExit(40);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Upload "' + path.normalize(visDir + '/www/index.html.original') + '"');
|
||||
var file = fs.readFileSync(visDir + '/www/index.html.original');
|
||||
objects.writeFile('vis', 'index.html', file);
|
||||
|
||||
console.log('Upload "' + path.normalize(visDir + '/www/edit.html.original') + '"');
|
||||
file = fs.readFileSync(visDir + '/www/edit.html.original');
|
||||
objects.writeFile('vis', 'edit.html', file);
|
||||
|
||||
console.log('Modify "' + path.normalize(visDir + '/www/cache.manifest') + '"');
|
||||
file = fs.readFileSync(visDir + '/www/cache.manifest', 'utf8');
|
||||
var n = file.match(/# dev build (\d+)/, '5');
|
||||
n = n[1];
|
||||
file = file.replace('# dev build '+ n, '# dev build ' + (parseInt(n, 10) + 1));
|
||||
objects.writeFile('vis', 'cache.manifest', file);
|
||||
|
||||
file = fs.readFileSync(tools.getConfigFileName(), 'utf8');
|
||||
file = JSON.parse(file);
|
||||
|
||||
var count = 0;
|
||||
if (!file.objects.noFileCache) {
|
||||
file.objects.noFileCache = true;
|
||||
fs.writeFileSync(tools.getConfigFileName(), JSON.stringify(file, null, 2));
|
||||
count++;
|
||||
objects.enableFileCache(false, function (err, actual) {
|
||||
console.log('Disable cache');
|
||||
if (!--count) processExit();
|
||||
});
|
||||
}
|
||||
|
||||
if (widgetset) {
|
||||
count++;
|
||||
objects.readFile('vis', 'js/config.js', null, function (err, data) {
|
||||
data = data.replace(/[\r\n]/g, '');
|
||||
var json = JSON.parse(data.match(/"widgetSets":\s(.*)};/)[1]);
|
||||
var found = false;
|
||||
for (var f = 0; f < json.length; f++) {
|
||||
if (json[f] === widgetset || json[f].name === widgetset) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if widget-set not found in config.js
|
||||
if (!found) {
|
||||
console.log('Modify config.js');
|
||||
var pckg = JSON.parse(fs.readFileSync(adapterDir + '/io-package.json').toString());
|
||||
if (pckg.native && pckg.native.dependencies && pckg.native.dependencies.length){
|
||||
json.push({
|
||||
name: widgetset,
|
||||
depends: pckg.native.dependencies
|
||||
});
|
||||
} else {
|
||||
json.push(widgetset);
|
||||
}
|
||||
|
||||
data = data.replace(/"widgetSets":\s+.*};/, '"widgetSets": ' + JSON.stringify(json, null, 2) + '};');
|
||||
|
||||
objects.writeFile('vis', 'js/config.js', data, function () {
|
||||
// upload all files into vis
|
||||
console.log('Upload ' + adapterDir + '/widgets');
|
||||
uploadWidgets(adapterDir + '/widgets', 'vis', 'widgets', function () {
|
||||
if (!--count) {
|
||||
// timeoout to print all messages
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// upload all files into vis
|
||||
console.log('Upload "' + adapterDir + '/widgets' + '"');
|
||||
uploadWidgets(adapterDir + '/widgets', 'vis', 'widgets', function () {
|
||||
if (!--count) {
|
||||
// timeoout to print all messages
|
||||
setTimeout(function () {
|
||||
processExit();
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
} else {
|
||||
if (!count) processExit();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = VisDebug;
|
||||
Reference in New Issue
Block a user