969 lines
33 KiB
JavaScript
969 lines
33 KiB
JavaScript
/* jshint -W097 */// jshint strict:false
|
|
/*jslint node: true */
|
|
// check if tmp directory exists
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const child_process = require('child_process');
|
|
const rootDir = path.normalize(__dirname + '/../../');
|
|
const pkg = require(rootDir + 'package.json');
|
|
const debug = typeof v8debug === 'object';
|
|
pkg.main = pkg.main || 'main.js';
|
|
|
|
let JSONLDB;
|
|
|
|
let adapterName = path.normalize(rootDir).replace(/\\/g, '/').split('/');
|
|
adapterName = adapterName[adapterName.length - 2];
|
|
let adapterStarted = false;
|
|
|
|
function getAppName() {
|
|
const parts = __dirname.replace(/\\/g, '/').split('/');
|
|
return parts[parts.length - 3].split('.')[0];
|
|
}
|
|
|
|
function loadJSONLDB() {
|
|
if (!JSONLDB) {
|
|
const dbPath = require.resolve('@alcalzone/jsonl-db', {
|
|
paths: [rootDir + 'tmp/node_modules', rootDir, rootDir + 'tmp/node_modules/' + appName + '.js-controller']
|
|
});
|
|
console.log('JSONLDB path: ' + dbPath);
|
|
try {
|
|
const { JsonlDB } = require(dbPath);
|
|
JSONLDB = JsonlDB;
|
|
} catch (err) {
|
|
console.log('Jsonl require error: ' + err);
|
|
}
|
|
}
|
|
}
|
|
|
|
const appName = getAppName().toLowerCase();
|
|
|
|
let objects;
|
|
let states;
|
|
|
|
let pid = null;
|
|
|
|
let systemConfig = null;
|
|
|
|
function copyFileSync(source, target) {
|
|
|
|
let 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 = path.join(target, path.basename(source));
|
|
}
|
|
}
|
|
|
|
try {
|
|
fs.writeFileSync(targetFile, fs.readFileSync(source));
|
|
}
|
|
catch (err) {
|
|
console.log('file copy error: ' +source +' -> ' + targetFile + ' (error ignored)');
|
|
}
|
|
}
|
|
|
|
function copyFolderRecursiveSync(source, target, ignore) {
|
|
let files = [];
|
|
|
|
let base = path.basename(source);
|
|
if (base === adapterName) {
|
|
base = pkg.name;
|
|
}
|
|
//check if folder needs to be created or integrated
|
|
const targetFolder = path.join(target, base);
|
|
if (!fs.existsSync(targetFolder)) {
|
|
fs.mkdirSync(targetFolder);
|
|
}
|
|
|
|
//copy
|
|
if (fs.lstatSync(source).isDirectory()) {
|
|
files = fs.readdirSync(source);
|
|
files.forEach(function (file) {
|
|
if (ignore && ignore.indexOf(file) !== -1) {
|
|
return;
|
|
}
|
|
|
|
const curSource = path.join(source, file);
|
|
const curTarget = path.join(targetFolder, file);
|
|
if (fs.lstatSync(curSource).isDirectory()) {
|
|
// ignore grunt files
|
|
if (file.indexOf('grunt') !== -1) return;
|
|
if (file === 'chai') return;
|
|
if (file === 'mocha') return;
|
|
copyFolderRecursiveSync(curSource, targetFolder, ignore);
|
|
} else {
|
|
copyFileSync(curSource, curTarget);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!fs.existsSync(rootDir + 'tmp')) {
|
|
fs.mkdirSync(rootDir + 'tmp');
|
|
}
|
|
|
|
async function storeOriginalFiles() {
|
|
console.log('Store original files...');
|
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
|
|
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
|
const f = fs.readFileSync(dataDir + 'objects.json');
|
|
const objects = JSON.parse(f.toString());
|
|
if (objects['system.adapter.admin.0'] && objects['system.adapter.admin.0'].common) {
|
|
objects['system.adapter.admin.0'].common.enabled = false;
|
|
}
|
|
if (objects['system.adapter.admin.1'] && objects['system.adapter.admin.1'].common) {
|
|
objects['system.adapter.admin.1'].common.enabled = false;
|
|
}
|
|
|
|
fs.writeFileSync(dataDir + 'objects.json.original', JSON.stringify(objects));
|
|
console.log('Store original objects.json');
|
|
}
|
|
|
|
if (fs.existsSync(dataDir + 'states.json')) {
|
|
try {
|
|
const f = fs.readFileSync(dataDir + 'states.json');
|
|
fs.writeFileSync(dataDir + 'states.json.original', f);
|
|
console.log('Store original states.json');
|
|
} catch (err) {
|
|
console.log('no states.json found - ignore');
|
|
}
|
|
}
|
|
|
|
if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
|
loadJSONLDB();
|
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
|
await db.open();
|
|
|
|
const admin0 = db.get('system.adapter.admin.0');
|
|
if (admin0) {
|
|
if (admin0.common) {
|
|
admin0.common.enabled = false;
|
|
db.set('system.adapter.admin.0', admin0);
|
|
}
|
|
}
|
|
|
|
const admin1 = db.get('system.adapter.admin.1');
|
|
if (admin1) {
|
|
if (admin1.common) {
|
|
admin1.common.enabled = false;
|
|
db.set('system.adapter.admin.1', admin1);
|
|
}
|
|
}
|
|
await db.close();
|
|
|
|
const f = fs.readFileSync(dataDir + 'objects.jsonl');
|
|
fs.writeFileSync(dataDir + 'objects.jsonl.original', f);
|
|
console.log('Store original objects.jsonl');
|
|
}
|
|
|
|
if (fs.existsSync(dataDir + 'states.jsonl')) {
|
|
const f = fs.readFileSync(dataDir + 'states.jsonl');
|
|
fs.writeFileSync(dataDir + 'states.jsonl.original', f);
|
|
console.log('Store original states.jsonl');
|
|
}
|
|
}
|
|
|
|
function restoreOriginalFiles() {
|
|
console.log('restoreOriginalFiles...');
|
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
|
|
|
if (fs.existsSync(dataDir + 'objects.json.original')) {
|
|
const f = fs.readFileSync(dataDir + 'objects.json.original');
|
|
fs.writeFileSync(dataDir + 'objects.json', f);
|
|
}
|
|
if (fs.existsSync(dataDir + 'objects.json.original')) {
|
|
const f = fs.readFileSync(dataDir + 'states.json.original');
|
|
fs.writeFileSync(dataDir + 'states.json', f);
|
|
}
|
|
|
|
if (fs.existsSync(dataDir + 'objects.jsonl.original')) {
|
|
const f = fs.readFileSync(dataDir + 'objects.jsonl.original');
|
|
fs.writeFileSync(dataDir + 'objects.jsonl', f);
|
|
}
|
|
if (fs.existsSync(dataDir + 'objects.jsonl.original')) {
|
|
const f = fs.readFileSync(dataDir + 'states.jsonl.original');
|
|
fs.writeFileSync(dataDir + 'states.jsonl', f);
|
|
}
|
|
}
|
|
|
|
async function checkIsAdapterInstalled(cb, counter, customName) {
|
|
customName = customName || pkg.name.split('.').pop();
|
|
counter = counter || 0;
|
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
|
console.log('checkIsAdapterInstalled...');
|
|
|
|
try {
|
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
|
const f = fs.readFileSync(dataDir + 'objects.json');
|
|
const objects = JSON.parse(f.toString());
|
|
if (objects['system.adapter.' + customName + '.0']) {
|
|
console.log('checkIsAdapterInstalled: ready!');
|
|
setTimeout(function () {
|
|
if (cb) cb();
|
|
}, 100);
|
|
return;
|
|
} else {
|
|
console.warn('checkIsAdapterInstalled: still not ready');
|
|
}
|
|
} else if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
|
loadJSONLDB();
|
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
|
try {
|
|
await db.open();
|
|
} catch (err) {
|
|
if (err.message.includes('Failed to lock DB file')) {
|
|
console.log('checkIsAdapterInstalled: DB still opened ...');
|
|
}
|
|
throw err;
|
|
}
|
|
|
|
const obj = db.get('system.adapter.' + customName + '.0');
|
|
await db.close();
|
|
|
|
if (obj) {
|
|
console.log('checkIsAdapterInstalled: ready!');
|
|
setTimeout(function () {
|
|
if (cb) cb();
|
|
}, 100);
|
|
return;
|
|
} else {
|
|
console.warn('checkIsAdapterInstalled: still not ready');
|
|
}
|
|
} else {
|
|
console.error('checkIsAdapterInstalled: No objects file found in datadir ' + dataDir);
|
|
}
|
|
|
|
} catch (err) {
|
|
console.log('checkIsAdapterInstalled: catch ' + err);
|
|
}
|
|
|
|
if (counter > 20) {
|
|
console.error('checkIsAdapterInstalled: Cannot install!');
|
|
if (cb) cb('Cannot install');
|
|
} else {
|
|
console.log('checkIsAdapterInstalled: wait...');
|
|
setTimeout(function() {
|
|
checkIsAdapterInstalled(cb, counter + 1);
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
async function checkIsControllerInstalled(cb, counter) {
|
|
counter = counter || 0;
|
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
|
|
|
console.log('checkIsControllerInstalled...');
|
|
try {
|
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
|
const f = fs.readFileSync(dataDir + 'objects.json');
|
|
const objects = JSON.parse(f.toString());
|
|
if (objects['system.certificates']) {
|
|
console.log('checkIsControllerInstalled: installed!');
|
|
setTimeout(function () {
|
|
if (cb) cb();
|
|
}, 100);
|
|
return;
|
|
}
|
|
} else if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
|
loadJSONLDB();
|
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
|
try {
|
|
await db.open();
|
|
} catch (err) {
|
|
if (err.message.includes('Failed to lock DB file')) {
|
|
console.log('checkIsControllerInstalled: DB still opened ...');
|
|
}
|
|
throw err;
|
|
}
|
|
|
|
const obj = db.get('system.certificates');
|
|
await db.close();
|
|
|
|
if (obj) {
|
|
console.log('checkIsControllerInstalled: installed!');
|
|
setTimeout(function () {
|
|
if (cb) cb();
|
|
}, 100);
|
|
return;
|
|
}
|
|
|
|
} else {
|
|
console.error('checkIsControllerInstalled: No objects file found in datadir ' + dataDir);
|
|
}
|
|
} catch (err) {
|
|
|
|
}
|
|
|
|
if (counter > 20) {
|
|
console.log('checkIsControllerInstalled: Cannot install!');
|
|
if (cb) cb('Cannot install');
|
|
} else {
|
|
console.log('checkIsControllerInstalled: wait...');
|
|
setTimeout(function() {
|
|
checkIsControllerInstalled(cb, counter + 1);
|
|
}, 1000);
|
|
}
|
|
}
|
|
|
|
function installAdapter(customName, cb) {
|
|
if (typeof customName === 'function') {
|
|
cb = customName;
|
|
customName = null;
|
|
}
|
|
customName = customName || pkg.name.split('.').pop();
|
|
console.log('Install adapter...');
|
|
const startFile = 'node_modules/' + appName + '.js-controller/' + appName + '.js';
|
|
// make first install
|
|
if (debug) {
|
|
child_process.execSync('node ' + startFile + ' add ' + customName + ' --enabled false', {
|
|
cwd: rootDir + 'tmp',
|
|
stdio: [0, 1, 2]
|
|
});
|
|
checkIsAdapterInstalled(function (error) {
|
|
if (error) console.error(error);
|
|
console.log('Adapter installed.');
|
|
if (cb) cb();
|
|
});
|
|
} else {
|
|
// add controller
|
|
const _pid = child_process.fork(startFile, ['add', customName, '--enabled', 'false'], {
|
|
cwd: rootDir + 'tmp',
|
|
stdio: [0, 1, 2, 'ipc']
|
|
});
|
|
|
|
waitForEnd(_pid, function () {
|
|
checkIsAdapterInstalled(function (error) {
|
|
if (error) console.error(error);
|
|
console.log('Adapter installed.');
|
|
if (cb) cb();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
function waitForEnd(_pid, cb) {
|
|
if (!_pid) {
|
|
cb(-1, -1);
|
|
return;
|
|
}
|
|
_pid.on('exit', function (code, signal) {
|
|
if (_pid) {
|
|
_pid = null;
|
|
cb(code, signal);
|
|
}
|
|
});
|
|
_pid.on('close', function (code, signal) {
|
|
if (_pid) {
|
|
_pid = null;
|
|
cb(code, signal);
|
|
}
|
|
});
|
|
}
|
|
|
|
function installJsController(cb) {
|
|
console.log('installJsController...');
|
|
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller') ||
|
|
!fs.existsSync(rootDir + 'tmp/' + appName + '-data')) {
|
|
// try to detect appName.js-controller in node_modules/appName.js-controller
|
|
// travis CI installs js-controller into node_modules
|
|
if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller')) {
|
|
console.log('installJsController: no js-controller => copy it from "' + rootDir + 'node_modules/' + appName + '.js-controller"');
|
|
// copy all
|
|
// stop controller
|
|
console.log('Stop controller if running...');
|
|
let _pid;
|
|
if (debug) {
|
|
// start controller
|
|
_pid = child_process.exec('node ' + appName + '.js stop', {
|
|
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
|
stdio: [0, 1, 2]
|
|
});
|
|
} else {
|
|
_pid = child_process.fork(appName + '.js', ['stop'], {
|
|
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
|
stdio: [0, 1, 2, 'ipc']
|
|
});
|
|
}
|
|
|
|
waitForEnd(_pid, function () {
|
|
// copy all files into
|
|
if (!fs.existsSync(rootDir + 'tmp')) fs.mkdirSync(rootDir + 'tmp');
|
|
if (!fs.existsSync(rootDir + 'tmp/node_modules')) fs.mkdirSync(rootDir + 'tmp/node_modules');
|
|
|
|
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')){
|
|
console.log('Copy js-controller...');
|
|
copyFolderRecursiveSync(rootDir + 'node_modules/' + appName + '.js-controller', rootDir + 'tmp/node_modules/');
|
|
}
|
|
|
|
console.log('Setup js-controller...');
|
|
let __pid;
|
|
if (debug) {
|
|
// start controller
|
|
_pid = child_process.exec('node ' + appName + '.js setup first --console', {
|
|
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
|
stdio: [0, 1, 2]
|
|
});
|
|
} else {
|
|
__pid = child_process.fork(appName + '.js', ['setup', 'first', '--console'], {
|
|
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
|
stdio: [0, 1, 2, 'ipc']
|
|
});
|
|
}
|
|
waitForEnd(__pid, function () {
|
|
checkIsControllerInstalled(function () {
|
|
// change ports for object and state DBs
|
|
const config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
|
config.objects.port = 19001;
|
|
config.states.port = 19000;
|
|
|
|
// TEST WISE!
|
|
//config.objects.type = 'jsonl';
|
|
//config.states.type = 'jsonl';
|
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
|
console.log('Setup finished.');
|
|
|
|
copyAdapterToController();
|
|
|
|
installAdapter(async function () {
|
|
await storeOriginalFiles();
|
|
if (cb) cb(true);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
// check if port 9000 is free, else admin adapter will be added to running instance
|
|
const client = new require('net').Socket();
|
|
client.on('error', () => {});
|
|
client.connect(9000, '127.0.0.1', function() {
|
|
console.error('Cannot initiate fisrt run of test, because one instance of application is running on this PC. Stop it and repeat.');
|
|
process.exit(0);
|
|
});
|
|
|
|
setTimeout(function () {
|
|
client.destroy();
|
|
if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')) {
|
|
console.log('installJsController: no js-controller => install dev build from npm');
|
|
|
|
child_process.execSync('npm install ' + appName + '.js-controller@dev --prefix ./ --production', {
|
|
cwd: rootDir + 'tmp/',
|
|
stdio: [0, 1, 2]
|
|
});
|
|
} else {
|
|
console.log('Setup js-controller...');
|
|
let __pid;
|
|
if (debug) {
|
|
// start controller
|
|
child_process.exec('node ' + appName + '.js setup first', {
|
|
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
|
stdio: [0, 1, 2]
|
|
});
|
|
} else {
|
|
child_process.fork(appName + '.js', ['setup', 'first'], {
|
|
cwd: rootDir + 'tmp/node_modules/' + appName + '.js-controller',
|
|
stdio: [0, 1, 2, 'ipc']
|
|
});
|
|
}
|
|
}
|
|
|
|
// let npm install admin and run setup
|
|
checkIsControllerInstalled(function () {
|
|
let _pid;
|
|
|
|
if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller/' + appName + '.js')) {
|
|
_pid = child_process.fork(appName + '.js', ['stop'], {
|
|
cwd: rootDir + 'node_modules/' + appName + '.js-controller',
|
|
stdio: [0, 1, 2, 'ipc']
|
|
});
|
|
}
|
|
|
|
waitForEnd(_pid, function () {
|
|
// change ports for object and state DBs
|
|
const config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
|
config.objects.port = 19001;
|
|
config.states.port = 19000;
|
|
|
|
// TEST WISE!
|
|
//config.objects.type = 'jsonl';
|
|
//config.states.type = 'jsonl';
|
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2));
|
|
|
|
copyAdapterToController();
|
|
|
|
installAdapter(async function () {
|
|
await storeOriginalFiles();
|
|
if (cb) cb(true);
|
|
});
|
|
});
|
|
});
|
|
}, 1000);
|
|
}
|
|
} else {
|
|
setTimeout(function () {
|
|
console.log('installJsController: js-controller installed');
|
|
if (cb) cb(false);
|
|
}, 0);
|
|
}
|
|
}
|
|
|
|
function copyAdapterToController() {
|
|
console.log('Copy adapter...');
|
|
// Copy adapter to tmp/node_modules/appName.adapter
|
|
copyFolderRecursiveSync(rootDir, rootDir + 'tmp/node_modules/', ['.idea', 'test', 'tmp', '.git', appName + '.js-controller']);
|
|
console.log('Adapter copied.');
|
|
}
|
|
|
|
function clearControllerLog() {
|
|
const dirPath = rootDir + 'tmp/log';
|
|
let files;
|
|
try {
|
|
if (fs.existsSync(dirPath)) {
|
|
console.log('Clear controller log...');
|
|
files = fs.readdirSync(dirPath);
|
|
} else {
|
|
console.log('Create controller log directory...');
|
|
files = [];
|
|
fs.mkdirSync(dirPath);
|
|
}
|
|
} catch(e) {
|
|
console.error('Cannot read "' + dirPath + '"');
|
|
return;
|
|
}
|
|
if (files.length > 0) {
|
|
try {
|
|
for (let i = 0; i < files.length; i++) {
|
|
const filePath = dirPath + '/' + files[i];
|
|
fs.unlinkSync(filePath);
|
|
}
|
|
console.log('Controller log cleared');
|
|
} catch (err) {
|
|
console.error('cannot clear log: ' + err);
|
|
}
|
|
}
|
|
}
|
|
|
|
function clearDB() {
|
|
const dirPath = rootDir + 'tmp/iobroker-data/sqlite';
|
|
let files;
|
|
try {
|
|
if (fs.existsSync(dirPath)) {
|
|
console.log('Clear sqlite DB...');
|
|
files = fs.readdirSync(dirPath);
|
|
} else {
|
|
console.log('Create controller log directory...');
|
|
files = [];
|
|
fs.mkdirSync(dirPath);
|
|
}
|
|
} catch(e) {
|
|
console.error('Cannot read "' + dirPath + '"');
|
|
return;
|
|
}
|
|
if (files.length > 0) {
|
|
try {
|
|
for (let i = 0; i < files.length; i++) {
|
|
const filePath = dirPath + '/' + files[i];
|
|
fs.unlinkSync(filePath);
|
|
}
|
|
console.log('Clear sqlite DB');
|
|
} catch (err) {
|
|
console.error('cannot clear DB: ' + err);
|
|
}
|
|
}
|
|
}
|
|
|
|
function setupController(cb) {
|
|
installJsController(async function (isInited) {
|
|
try {
|
|
clearControllerLog();
|
|
clearDB();
|
|
|
|
if (!isInited) {
|
|
restoreOriginalFiles();
|
|
copyAdapterToController();
|
|
}
|
|
// read system.config object
|
|
const dataDir = rootDir + 'tmp/' + appName + '-data/';
|
|
|
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
|
let objs;
|
|
try {
|
|
objs = fs.readFileSync(dataDir + 'objects.json');
|
|
objs = JSON.parse(objs);
|
|
} catch (e) {
|
|
console.log('ERROR reading/parsing system configuration. Ignore');
|
|
objs = {'system.config': {}};
|
|
}
|
|
if (!objs || !objs['system.config']) {
|
|
objs = {'system.config': {}};
|
|
}
|
|
|
|
systemConfig = objs['system.config'];
|
|
if (cb) cb(objs['system.config']);
|
|
} else if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
|
loadJSONLDB();
|
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
|
await db.open();
|
|
|
|
let config = db.get('system.config');
|
|
systemConfig = config || {};
|
|
|
|
await db.close();
|
|
|
|
if (cb) cb(systemConfig);
|
|
} else {
|
|
console.error('read SystemConfig: No objects file found in datadir ' + dataDir);
|
|
}
|
|
} catch (err) {
|
|
console.error('setupController: ' + err);
|
|
}
|
|
});
|
|
}
|
|
|
|
async function getSecret() {
|
|
var dataDir = rootDir + 'tmp/' + appName + '-data/';
|
|
|
|
if (systemConfig) {
|
|
return systemConfig.native.secret;
|
|
}
|
|
if (fs.existsSync(dataDir + 'objects.json')) {
|
|
let objs;
|
|
try {
|
|
objs = fs.readFileSync(dataDir + 'objects.json');
|
|
objs = JSON.parse(objs);
|
|
}
|
|
catch (e) {
|
|
console.warn("Could not load secret. Reason: " + e);
|
|
return null;
|
|
}
|
|
if (!objs || !objs['system.config']) {
|
|
objs = {'system.config': {}};
|
|
}
|
|
|
|
return objs['system.config'].native.secre;
|
|
} else if (fs.existsSync(dataDir + 'objects.jsonl')) {
|
|
loadJSONLDB();
|
|
const db = new JSONLDB(dataDir + 'objects.jsonl');
|
|
await db.open();
|
|
|
|
let config = db.get('system.config');
|
|
config = config || {};
|
|
|
|
await db.close();
|
|
|
|
return config.native.secret;
|
|
} else {
|
|
console.error('read secret: No objects file found in datadir ' + dataDir);
|
|
}
|
|
|
|
}
|
|
|
|
function encrypt (key, value) {
|
|
var result = '';
|
|
for (var i = 0; i < value.length; ++i) {
|
|
result += String.fromCharCode(key[i % key.length].charCodeAt(0) ^ value.charCodeAt(i));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function startAdapter(objects, states, callback) {
|
|
if (adapterStarted) {
|
|
console.log('Adapter already started ...');
|
|
if (callback) callback(objects, states);
|
|
return;
|
|
}
|
|
adapterStarted = true;
|
|
console.log('startAdapter...');
|
|
if (fs.existsSync(rootDir + 'tmp/node_modules/' + pkg.name + '/' + pkg.main)) {
|
|
try {
|
|
if (debug) {
|
|
// start controller
|
|
pid = child_process.exec('node node_modules/' + pkg.name + '/' + pkg.main + ' --console silly', {
|
|
cwd: rootDir + 'tmp',
|
|
stdio: [0, 1, 2]
|
|
});
|
|
} else {
|
|
// start controller
|
|
pid = child_process.fork('node_modules/' + pkg.name + '/' + pkg.main, ['--console', 'silly'], {
|
|
cwd: rootDir + 'tmp',
|
|
stdio: [0, 1, 2, 'ipc']
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error(JSON.stringify(error));
|
|
}
|
|
} else {
|
|
console.error('Cannot find: ' + rootDir + 'tmp/node_modules/' + pkg.name + '/' + pkg.main);
|
|
}
|
|
if (callback) callback(objects, states);
|
|
}
|
|
|
|
function startController(isStartAdapter, onObjectChange, onStateChange, callback) {
|
|
if (typeof isStartAdapter === 'function') {
|
|
callback = onStateChange;
|
|
onStateChange = onObjectChange;
|
|
onObjectChange = isStartAdapter;
|
|
isStartAdapter = true;
|
|
}
|
|
|
|
if (onStateChange === undefined) {
|
|
callback = onObjectChange;
|
|
onObjectChange = undefined;
|
|
}
|
|
|
|
if (pid) {
|
|
console.error('Controller is already started!');
|
|
} else {
|
|
console.log('startController...');
|
|
try {
|
|
const config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json');
|
|
|
|
adapterStarted = false;
|
|
let isObjectConnected;
|
|
let isStatesConnected;
|
|
|
|
// rootDir + 'tmp/node_modules
|
|
const objPath = require.resolve(`@iobroker/db-objects-${config.objects.type}`, {
|
|
paths: [ rootDir + 'tmp/node_modules', rootDir, rootDir + 'tmp/node_modules/' + appName + '.js-controller']
|
|
});
|
|
console.log('Objects Path: ' + objPath);
|
|
const Objects = require(objPath).Server;
|
|
objects = new Objects({
|
|
connection: {
|
|
'type': config.objects.type,
|
|
'host': '127.0.0.1',
|
|
'port': 19001,
|
|
'user': '',
|
|
'pass': '',
|
|
'noFileCache': false,
|
|
'connectTimeout': 2000
|
|
},
|
|
logger: {
|
|
silly: function (msg) {
|
|
console.log(msg);
|
|
},
|
|
debug: function (msg) {
|
|
console.log(msg);
|
|
},
|
|
info: function (msg) {
|
|
console.log(msg);
|
|
},
|
|
warn: function (msg) {
|
|
console.warn(msg);
|
|
},
|
|
error: function (msg) {
|
|
console.error(msg);
|
|
}
|
|
},
|
|
connected: function () {
|
|
isObjectConnected = true;
|
|
if (isStatesConnected) {
|
|
console.log('startController: started!');
|
|
if (isStartAdapter) {
|
|
startAdapter(objects, states, callback);
|
|
} else {
|
|
if (callback) {
|
|
callback(objects, states);
|
|
callback = null;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
change: onObjectChange
|
|
});
|
|
|
|
// Just open in memory DB itself
|
|
const statePath = require.resolve(`@iobroker/db-states-${config.states.type}`, {
|
|
paths: [ rootDir + 'tmp/node_modules', rootDir, rootDir + 'tmp/node_modules/' + appName + '.js-controller']
|
|
});
|
|
console.log('States Path: ' + statePath);
|
|
const States = require(statePath).Server;
|
|
states = new States({
|
|
connection: {
|
|
type: config.states.type,
|
|
host: '127.0.0.1',
|
|
port: 19000,
|
|
options: {
|
|
auth_pass: null,
|
|
retry_max_delay: 15000
|
|
}
|
|
},
|
|
logger: {
|
|
silly: function (msg) {
|
|
console.log(msg);
|
|
},
|
|
debug: function (msg) {
|
|
console.log(msg);
|
|
},
|
|
info: function (msg) {
|
|
console.log(msg);
|
|
},
|
|
warn: function (msg) {
|
|
console.log(msg);
|
|
},
|
|
error: function (msg) {
|
|
console.log(msg);
|
|
}
|
|
},
|
|
connected: function () {
|
|
isStatesConnected = true;
|
|
if (isObjectConnected) {
|
|
console.log('startController: started!!');
|
|
if (isStartAdapter) {
|
|
startAdapter(objects, states, callback);
|
|
} else {
|
|
if (callback) {
|
|
callback(objects, states);
|
|
callback = null;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
change: onStateChange
|
|
});
|
|
} catch (err) {
|
|
console.log(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
function stopAdapter(cb) {
|
|
if (!pid) {
|
|
console.error('Controller is not running!');
|
|
if (cb) {
|
|
setTimeout(function () {
|
|
cb(false);
|
|
}, 0);
|
|
}
|
|
} else {
|
|
adapterStarted = false;
|
|
pid.on('exit', function (code, signal) {
|
|
if (pid) {
|
|
console.log('child process terminated due to receipt of signal ' + signal);
|
|
if (cb) cb();
|
|
pid = null;
|
|
}
|
|
});
|
|
|
|
pid.on('close', function (code, signal) {
|
|
if (pid) {
|
|
if (cb) cb();
|
|
pid = null;
|
|
}
|
|
});
|
|
|
|
pid.kill('SIGTERM');
|
|
}
|
|
}
|
|
|
|
function _stopController() {
|
|
if (objects) {
|
|
objects.destroy();
|
|
objects = null;
|
|
}
|
|
if (states) {
|
|
states.destroy();
|
|
states = null;
|
|
}
|
|
}
|
|
|
|
function stopController(cb) {
|
|
let timeout;
|
|
if (objects) {
|
|
console.log('Set system.adapter.' + pkg.name + '.0');
|
|
objects.setObject('system.adapter.' + pkg.name + '.0', {
|
|
common:{
|
|
enabled: false
|
|
}
|
|
});
|
|
}
|
|
|
|
stopAdapter(function () {
|
|
if (timeout) {
|
|
clearTimeout(timeout);
|
|
timeout = null;
|
|
}
|
|
|
|
_stopController();
|
|
|
|
if (cb) {
|
|
cb(true);
|
|
cb = null;
|
|
}
|
|
});
|
|
|
|
timeout = setTimeout(function () {
|
|
timeout = null;
|
|
console.log('child process NOT terminated');
|
|
|
|
_stopController();
|
|
|
|
if (cb) {
|
|
cb(false);
|
|
cb = null;
|
|
}
|
|
pid = null;
|
|
}, 5000);
|
|
}
|
|
|
|
// Setup the adapter
|
|
async function setAdapterConfig(common, native, instance) {
|
|
const id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
|
if (fs.existsSync(rootDir + 'tmp/' + appName + '-data/objects.json')) {
|
|
const objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
|
if (common) objects[id].common = common;
|
|
if (native) objects[id].native = native;
|
|
fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/objects.json', JSON.stringify(objects));
|
|
} else if (fs.existsSync(rootDir + 'tmp/' + appName + '-data/objects.jsonl')) {
|
|
loadJSONLDB();
|
|
const db = new JSONLDB(rootDir + 'tmp/' + appName + '-data/objects.jsonl');
|
|
await db.open();
|
|
|
|
let obj = db.get(id);
|
|
if (common) obj.common = common;
|
|
if (native) obj.native = native;
|
|
db.set(id, obj);
|
|
|
|
await db.close();
|
|
} else {
|
|
console.error('setAdapterConfig: No objects file found in datadir ' + rootDir + 'tmp/' + appName + '-data/');
|
|
}
|
|
}
|
|
|
|
// Read config of the adapter
|
|
async function getAdapterConfig(instance) {
|
|
const id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0);
|
|
if (fs.existsSync(rootDir + 'tmp/' + appName + '-data/objects.json')) {
|
|
const objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString());
|
|
return objects[id];
|
|
} else if (fs.existsSync(rootDir + 'tmp/' + appName + '-data/objects.jsonl')) {
|
|
loadJSONLDB();
|
|
const db = new JSONLDB(rootDir + 'tmp/' + appName + '-data/objects.jsonl');
|
|
await db.open();
|
|
|
|
let obj = db.get(id);
|
|
|
|
await db.close();
|
|
return obj;
|
|
} else {
|
|
console.error('getAdapterConfig: No objects file found in datadir ' + rootDir + 'tmp/' + appName + '-data/');
|
|
}
|
|
}
|
|
|
|
if (typeof module !== undefined && module.parent) {
|
|
module.exports.getAdapterConfig = getAdapterConfig;
|
|
module.exports.setAdapterConfig = setAdapterConfig;
|
|
module.exports.startController = startController;
|
|
module.exports.stopController = stopController;
|
|
module.exports.setupController = setupController;
|
|
module.exports.stopAdapter = stopAdapter;
|
|
module.exports.startAdapter = startAdapter;
|
|
module.exports.installAdapter = installAdapter;
|
|
module.exports.appName = appName;
|
|
module.exports.adapterName = adapterName;
|
|
module.exports.adapterStarted = adapterStarted;
|
|
module.exports.getSecret = getSecret;
|
|
module.exports.encrypt = encrypt;
|
|
}
|