From d89769d41bd66d01a4b58ffe8d20adc8af32f302 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sat, 15 Feb 2020 00:54:20 +0100 Subject: [PATCH 01/13] update testing setup.js --- test/lib/setup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/setup.js b/test/lib/setup.js index 28e5e8b..c175992 100644 --- a/test/lib/setup.js +++ b/test/lib/setup.js @@ -164,7 +164,7 @@ function checkIsControllerInstalled(cb, counter) { try { var f = fs.readFileSync(dataDir + 'objects.json'); var objects = JSON.parse(f.toString()); - if (objects['system.adapter.admin.0']) { + if (objects['system.certificates']) { console.log('checkIsControllerInstalled: installed!'); setTimeout(function () { if (cb) cb(); From 06bc587a759454fc84721c23dc56ac8a4d0cca09 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sat, 15 Feb 2020 08:19:14 +0100 Subject: [PATCH 02/13] update travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0008cbf..2f516ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ os: - windows language: node_js node_js: - - '6' - '8' - '10' + - '12' before_script: - export NPMVERSION=$(echo "$($(which npm) -v)"|cut -c1) - 'if [[ $NPMVERSION == 5 ]]; then npm install -g npm@5; fi' @@ -14,10 +14,10 @@ before_script: - npm install winston@3.2.1 - 'npm install https://github.com/ioBroker/ioBroker.js-controller/tarball/master --production' env: - - CXX=g++-4.9 + - CXX=g++-6 addons: apt: sources: - ubuntu-toolchain-r-test packages: - - g++-4.9 + - g++-6 From ab80c0a5b613531a521bf4521222c621490451c5 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sat, 15 Feb 2020 08:19:14 +0100 Subject: [PATCH 03/13] update appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 98ae8e8..0e6f8f8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,9 @@ version: 'test-{build}' environment: matrix: - - nodejs_version: '6' - nodejs_version: '8' - nodejs_version: '10' + - nodejs_version: '12' platform: - x86 - x64 From 3e17a8afa0852397d3e30afa425a3dfa6d7df003 Mon Sep 17 00:00:00 2001 From: lob Date: Tue, 22 Sep 2020 10:30:50 +0200 Subject: [PATCH 04/13] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 88359b2..a81cb5a 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,8 @@ The Main script works in four steps: 2) Starring the first communication with the device and asking for the current parameters 3) Waiting for a state change like switching the input source or turning power off 4) Executing the change with the device -Please be aware, that the communication with the projector is not possible if the projector is in standby with power saving feature enabled. Therefore, it will not be possible to turn the project on using this adapter. To do so, disable the power saving feature using the projector configuration (Menu > Settings...). + +Note: Please be aware, that the communication with the projector won't be possible if the projector is in standby with power saving feature enabled. Therefore, it will not be possible to turn the project on using this adapter. To do so, disable the power saving feature using the projector configuration (Menu > Settings...). ## Changelog ### 0.1.2 (2019/05/11) From c445a651498ceb1b6c7f5dcdfce28ca710617bd5 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sun, 5 Sep 2021 00:11:12 +0200 Subject: [PATCH 05/13] update testing setup.js --- test/lib/setup.js | 160 ++++++++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 68 deletions(-) diff --git a/test/lib/setup.js b/test/lib/setup.js index c175992..a268d0d 100644 --- a/test/lib/setup.js +++ b/test/lib/setup.js @@ -1,33 +1,33 @@ /* jshint -W097 */// jshint strict:false /*jslint node: true */ // check if tmp directory exists -var fs = require('fs'); -var path = require('path'); -var child_process = require('child_process'); -var rootDir = path.normalize(__dirname + '/../../'); -var pkg = require(rootDir + 'package.json'); -var debug = typeof v8debug === 'object'; +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'; -var adapterName = path.normalize(rootDir).replace(/\\/g, '/').split('/'); +let adapterName = path.normalize(rootDir).replace(/\\/g, '/').split('/'); adapterName = adapterName[adapterName.length - 2]; -var adapterStarted = false; +let adapterStarted = false; function getAppName() { - var parts = __dirname.replace(/\\/g, '/').split('/'); + const parts = __dirname.replace(/\\/g, '/').split('/'); return parts[parts.length - 3].split('.')[0]; } -var appName = getAppName().toLowerCase(); +const appName = getAppName().toLowerCase(); -var objects; -var states; +let objects; +let states; -var pid = null; +let pid = null; function copyFileSync(source, target) { - var targetFile = target; + let targetFile = target; //if target is a directory a new file with the same name will be created if (fs.existsSync(target)) { @@ -40,19 +40,19 @@ function copyFileSync(source, target) { fs.writeFileSync(targetFile, fs.readFileSync(source)); } catch (err) { - console.log("file copy error: " +source +" -> " + targetFile + " (error ignored)"); + console.log('file copy error: ' +source +' -> ' + targetFile + ' (error ignored)'); } } function copyFolderRecursiveSync(source, target, ignore) { - var files = []; + let files = []; - var base = path.basename(source); + let base = path.basename(source); if (base === adapterName) { base = pkg.name; } //check if folder needs to be created or integrated - var targetFolder = path.join(target, base); + const targetFolder = path.join(target, base); if (!fs.existsSync(targetFolder)) { fs.mkdirSync(targetFolder); } @@ -65,8 +65,8 @@ function copyFolderRecursiveSync(source, target, ignore) { return; } - var curSource = path.join(source, file); - var curTarget = path.join(targetFolder, file); + 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; @@ -86,10 +86,10 @@ if (!fs.existsSync(rootDir + 'tmp')) { function storeOriginalFiles() { console.log('Store original files...'); - var dataDir = rootDir + 'tmp/' + appName + '-data/'; + const dataDir = rootDir + 'tmp/' + appName + '-data/'; - var f = fs.readFileSync(dataDir + 'objects.json'); - var objects = JSON.parse(f.toString()); + let 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; } @@ -109,9 +109,9 @@ function storeOriginalFiles() { function restoreOriginalFiles() { console.log('restoreOriginalFiles...'); - var dataDir = rootDir + 'tmp/' + appName + '-data/'; + const dataDir = rootDir + 'tmp/' + appName + '-data/'; - var f = fs.readFileSync(dataDir + 'objects.json.original'); + let f = fs.readFileSync(dataDir + 'objects.json.original'); fs.writeFileSync(dataDir + 'objects.json', f); try { f = fs.readFileSync(dataDir + 'states.json.original'); @@ -126,12 +126,12 @@ function restoreOriginalFiles() { function checkIsAdapterInstalled(cb, counter, customName) { customName = customName || pkg.name.split('.').pop(); counter = counter || 0; - var dataDir = rootDir + 'tmp/' + appName + '-data/'; + const dataDir = rootDir + 'tmp/' + appName + '-data/'; console.log('checkIsAdapterInstalled...'); try { - var f = fs.readFileSync(dataDir + 'objects.json'); - var objects = JSON.parse(f.toString()); + 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 () { @@ -158,12 +158,12 @@ function checkIsAdapterInstalled(cb, counter, customName) { function checkIsControllerInstalled(cb, counter) { counter = counter || 0; - var dataDir = rootDir + 'tmp/' + appName + '-data/'; + const dataDir = rootDir + 'tmp/' + appName + '-data/'; console.log('checkIsControllerInstalled...'); try { - var f = fs.readFileSync(dataDir + 'objects.json'); - var objects = JSON.parse(f.toString()); + const f = fs.readFileSync(dataDir + 'objects.json'); + const objects = JSON.parse(f.toString()); if (objects['system.certificates']) { console.log('checkIsControllerInstalled: installed!'); setTimeout(function () { @@ -193,7 +193,7 @@ function installAdapter(customName, cb) { } customName = customName || pkg.name.split('.').pop(); console.log('Install adapter...'); - var startFile = 'node_modules/' + appName + '.js-controller/' + appName + '.js'; + const startFile = 'node_modules/' + appName + '.js-controller/' + appName + '.js'; // make first install if (debug) { child_process.execSync('node ' + startFile + ' add ' + customName + ' --enabled false', { @@ -207,7 +207,7 @@ function installAdapter(customName, cb) { }); } else { // add controller - var _pid = child_process.fork(startFile, ['add', customName, '--enabled', 'false'], { + const _pid = child_process.fork(startFile, ['add', customName, '--enabled', 'false'], { cwd: rootDir + 'tmp', stdio: [0, 1, 2, 'ipc'] }); @@ -252,7 +252,7 @@ function installJsController(cb) { // copy all // stop controller console.log('Stop controller if running...'); - var _pid; + let _pid; if (debug) { // start controller _pid = child_process.exec('node ' + appName + '.js stop', { @@ -277,7 +277,7 @@ function installJsController(cb) { } console.log('Setup js-controller...'); - var __pid; + let __pid; if (debug) { // start controller _pid = child_process.exec('node ' + appName + '.js setup first --console', { @@ -293,7 +293,7 @@ function installJsController(cb) { waitForEnd(__pid, function () { checkIsControllerInstalled(function () { // change ports for object and state DBs - var config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json'); + const config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json'); config.objects.port = 19001; config.states.port = 19000; fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2)); @@ -310,7 +310,7 @@ function installJsController(cb) { }); } else { // check if port 9000 is free, else admin adapter will be added to running instance - var client = new require('net').Socket(); + 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.'); @@ -320,15 +320,15 @@ function installJsController(cb) { setTimeout(function () { client.destroy(); if (!fs.existsSync(rootDir + 'tmp/node_modules/' + appName + '.js-controller')) { - console.log('installJsController: no js-controller => install from git'); + console.log('installJsController: no js-controller => install dev build from npm'); - child_process.execSync('npm install https://github.com/' + appName + '/' + appName + '.js-controller/tarball/master --prefix ./ --production', { + child_process.execSync('npm install ' + appName + '.js-controller@dev --prefix ./ --production', { cwd: rootDir + 'tmp/', stdio: [0, 1, 2] }); } else { console.log('Setup js-controller...'); - var __pid; + let __pid; if (debug) { // start controller child_process.exec('node ' + appName + '.js setup first', { @@ -345,7 +345,7 @@ function installJsController(cb) { // let npm install admin and run setup checkIsControllerInstalled(function () { - var _pid; + let _pid; if (fs.existsSync(rootDir + 'node_modules/' + appName + '.js-controller/' + appName + '.js')) { _pid = child_process.fork(appName + '.js', ['stop'], { @@ -356,7 +356,7 @@ function installJsController(cb) { waitForEnd(_pid, function () { // change ports for object and state DBs - var config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json'); + const config = require(rootDir + 'tmp/' + appName + '-data/' + appName + '.json'); config.objects.port = 19001; config.states.port = 19000; fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/' + appName + '.json', JSON.stringify(config, null, 2)); @@ -387,8 +387,8 @@ function copyAdapterToController() { } function clearControllerLog() { - var dirPath = rootDir + 'tmp/log'; - var files; + const dirPath = rootDir + 'tmp/log'; + let files; try { if (fs.existsSync(dirPath)) { console.log('Clear controller log...'); @@ -404,8 +404,8 @@ function clearControllerLog() { } if (files.length > 0) { try { - for (var i = 0; i < files.length; i++) { - var filePath = dirPath + '/' + files[i]; + for (let i = 0; i < files.length; i++) { + const filePath = dirPath + '/' + files[i]; fs.unlinkSync(filePath); } console.log('Controller log cleared'); @@ -416,8 +416,8 @@ function clearControllerLog() { } function clearDB() { - var dirPath = rootDir + 'tmp/iobroker-data/sqlite'; - var files; + const dirPath = rootDir + 'tmp/iobroker-data/sqlite'; + let files; try { if (fs.existsSync(dirPath)) { console.log('Clear sqlite DB...'); @@ -433,8 +433,8 @@ function clearDB() { } if (files.length > 0) { try { - for (var i = 0; i < files.length; i++) { - var filePath = dirPath + '/' + files[i]; + for (let i = 0; i < files.length; i++) { + const filePath = dirPath + '/' + files[i]; fs.unlinkSync(filePath); } console.log('Clear sqlite DB'); @@ -454,9 +454,9 @@ function setupController(cb) { copyAdapterToController(); } // read system.config object - var dataDir = rootDir + 'tmp/' + appName + '-data/'; + const dataDir = rootDir + 'tmp/' + appName + '-data/'; - var objs; + let objs; try { objs = fs.readFileSync(dataDir + 'objects.json'); objs = JSON.parse(objs); @@ -473,6 +473,28 @@ function setupController(cb) { }); } +function getSecret() { + var dataDir = rootDir + 'tmp/' + appName + '-data/'; + + try { + var objs = fs.readFileSync(dataDir + 'objects.json'); + objs = JSON.parse(objs); + + return objs['system.config'].native.secret; + } catch (e) { + console.warn("Could not load secret. Reason: " + e); + return null; + } +} + +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 ...'); @@ -523,19 +545,19 @@ function startController(isStartAdapter, onObjectChange, onStateChange, callback } else { console.log('startController...'); adapterStarted = false; - var isObjectConnected; - var isStatesConnected; + let isObjectConnected; + let isStatesConnected; - var Objects = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/objects/objectsInMemServer'); + const Objects = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/objects/objectsInMemServer'); objects = new Objects({ connection: { - "type" : "file", - "host" : "127.0.0.1", - "port" : 19001, - "user" : "", - "pass" : "", - "noFileCache": false, - "connectTimeout": 2000 + 'type' : 'file', + 'host' : '127.0.0.1', + 'port' : 19001, + 'user' : '', + 'pass' : '', + 'noFileCache': false, + 'connectTimeout': 2000 }, logger: { silly: function (msg) { @@ -572,7 +594,7 @@ function startController(isStartAdapter, onObjectChange, onStateChange, callback }); // Just open in memory DB itself - var States = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/states/statesInMemServer'); + const States = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/states/statesInMemServer'); states = new States({ connection: { type: 'file', @@ -660,7 +682,7 @@ function _stopController() { } function stopController(cb) { - var timeout; + let timeout; if (objects) { console.log('Set system.adapter.' + pkg.name + '.0'); objects.setObject('system.adapter.' + pkg.name + '.0', { @@ -700,8 +722,8 @@ function stopController(cb) { // Setup the adapter function setAdapterConfig(common, native, instance) { - var objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString()); - var id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0); + const objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString()); + const id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0); if (common) objects[id].common = common; if (native) objects[id].native = native; fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/objects.json', JSON.stringify(objects)); @@ -709,8 +731,8 @@ function setAdapterConfig(common, native, instance) { // Read config of the adapter function getAdapterConfig(instance) { - var objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString()); - var id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0); + const objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString()); + const id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0); return objects[id]; } @@ -726,4 +748,6 @@ if (typeof module !== undefined && module.parent) { module.exports.appName = appName; module.exports.adapterName = adapterName; module.exports.adapterStarted = adapterStarted; + module.exports.getSecret = getSecret; + module.exports.encrypt = encrypt; } From 08e22f2095ccad1736a92e8dd9c28b347e6db32c Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sun, 5 Sep 2021 16:32:48 +0200 Subject: [PATCH 06/13] update travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2f516ab..96b86af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,9 @@ os: language: node_js node_js: - '8' - - '10' - '12' + - '14' + - '16' before_script: - export NPMVERSION=$(echo "$($(which npm) -v)"|cut -c1) - 'if [[ $NPMVERSION == 5 ]]; then npm install -g npm@5; fi' From 016359eadfe5ca25de30fe1e7de86b389e88f4ad Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sun, 5 Sep 2021 16:32:48 +0200 Subject: [PATCH 07/13] update appveyor.yml --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 0e6f8f8..4f18c82 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,9 +1,9 @@ version: 'test-{build}' environment: matrix: - - nodejs_version: '8' - - nodejs_version: '10' - nodejs_version: '12' + - nodejs_version: '14' + - nodejs_version: '16' platform: - x86 - x64 From f318d88d204695a5df7411fbfa0af42687739516 Mon Sep 17 00:00:00 2001 From: lob Date: Sun, 5 Dec 2021 15:12:14 +0100 Subject: [PATCH 08/13] Update README.md --- README.md | 51 ++------------------------------------------------- 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index a81cb5a..6d9347c 100644 --- a/README.md +++ b/README.md @@ -2,52 +2,5 @@ # iobroker.pjlink ![Number of Installations](http://iobroker.live/badges/pjlink-installed.svg) ![Number of Installations](http://iobroker.live/badges/pjlink-stable.svg) This adapter controls any PJLink compatible projector or display with ioBroker. -PJLink is an unified standard for operating and controlling data projectors and displays. The protocol enables central control of certain devices, manufactured by different vendors. The protocol is used by NEC, Casio, Seiko, Sony, Panasonic, Hitachi, Mitsubishi, Ricoh, Vivitek and even more. Please consult the device manual to check compatibility. - -## Current shortcomings -- Error Handling is not implemented right now. If an unknown parameter is entered or if the device is not accessible using TCP/IP, an error will be shown in the ioBroker Log. In one of the future versions, the device errorcodes will be analyzed and translated. -- Lighting hours are given for one (the first) lamp, even if PJLink supports several lamps. If somebody have a proper device, please contact me for testing. -- The device is not pushing information using the PJLink protocol. Therefore, the adapter will pull certain information frequently (see -polling interval). Do not reduce the polling interval <10 sec. because the device needs up to 2 sec. to answer and the script will query several paramters. -- All dialogs are in English as for now, DE and RU are in progress. Further translations on demand. - -## ToDo -- Implementing a table to translate input ID to name of the port (like 31 = HDMI1) -- Supporting PJLink Class 2 protocol - -## How the adapter works -The adapter consists by three elements: -- Admin interface to define device specific parameters (admin/index.html) -- JavaScript module for device communication, based on PJLink protocol (utils/pjlink.js) -- Main script (main.js) - -The Main script works in four steps: -1) Doing some initial configuration like creating ioBroker objects -2) Starring the first communication with the device and asking for the current parameters -3) Waiting for a state change like switching the input source or turning power off -4) Executing the change with the device - -Note: Please be aware, that the communication with the projector won't be possible if the projector is in standby with power saving feature enabled. Therefore, it will not be possible to turn the project on using this adapter. To do so, disable the power saving feature using the projector configuration (Menu > Settings...). - -## Changelog -### 0.1.2 (2019/05/11) -- fixed some minor bugs - -### 0.1.1 (2018/02/11) -- errorhandling implemented (somekind of...) - -### 0.1.0 (2017/12/31) -- first public flight (beta) - -### 0.0.5 (2017/12/26) -- bugfixing - -### 0.0.3 (2017/12/23) -- build admin interface -- build translate table - -### 0.0.2 (2017/12/18) -- redesign some timings (what / when) - -### 0.0.1 -- Inital version +This version is outdated - don't use it! +Please go to PJLinkV2: https://github.com/oberstel/ioBroker.PJLinkV2.git From f7a18de12fd41b89bd455a3008e4f3b4a871ee40 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sat, 29 Jan 2022 15:27:48 +0100 Subject: [PATCH 09/13] update testing setup.js --- test/lib/setup.js | 535 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 375 insertions(+), 160 deletions(-) diff --git a/test/lib/setup.js b/test/lib/setup.js index a268d0d..f8aa782 100644 --- a/test/lib/setup.js +++ b/test/lib/setup.js @@ -9,6 +9,8 @@ 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; @@ -18,6 +20,21 @@ function getAppName() { 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; @@ -25,6 +42,8 @@ let states; let pid = null; +let systemConfig = null; + function copyFileSync(source, target) { let targetFile = target; @@ -84,26 +103,65 @@ if (!fs.existsSync(rootDir + 'tmp')) { fs.mkdirSync(rootDir + 'tmp'); } -function storeOriginalFiles() { +async function storeOriginalFiles() { console.log('Store original files...'); const dataDir = rootDir + 'tmp/' + appName + '-data/'; - let 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 (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 (objects['system.adapter.admin.1'] && objects['system.adapter.admin.1'].common) { - objects['system.adapter.admin.1'].common.enabled = false; + + 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'); + } } - fs.writeFileSync(dataDir + 'objects.json.original', JSON.stringify(objects)); - try { - f = fs.readFileSync(dataDir + 'states.json'); - fs.writeFileSync(dataDir + 'states.json.original', f); + 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'); } - catch (err) { - console.log('no states.json found - ignore'); + + 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'); } } @@ -111,38 +169,74 @@ function restoreOriginalFiles() { console.log('restoreOriginalFiles...'); const dataDir = rootDir + 'tmp/' + appName + '-data/'; - let f = fs.readFileSync(dataDir + 'objects.json.original'); - fs.writeFileSync(dataDir + 'objects.json', f); - try { - f = fs.readFileSync(dataDir + 'states.json.original'); - fs.writeFileSync(dataDir + 'states.json', f); + if (fs.existsSync(dataDir + 'objects.json.original')) { + const f = fs.readFileSync(dataDir + 'objects.json.original'); + fs.writeFileSync(dataDir + 'objects.json', f); } - catch (err) { - console.log('no states.json.original found - ignore'); + 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); + } } -function checkIsAdapterInstalled(cb, counter, customName) { +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 { - 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; + 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.warn('checkIsAdapterInstalled: still not ready'); + console.error('checkIsAdapterInstalled: No objects file found in datadir ' + dataDir); } - } catch (err) { + } catch (err) { + console.log('checkIsAdapterInstalled: catch ' + err); } if (counter > 20) { @@ -156,20 +250,47 @@ function checkIsAdapterInstalled(cb, counter, customName) { } } -function checkIsControllerInstalled(cb, counter) { +async function checkIsControllerInstalled(cb, counter) { counter = counter || 0; const dataDir = rootDir + 'tmp/' + appName + '-data/'; console.log('checkIsControllerInstalled...'); try { - 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; + 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) { @@ -296,13 +417,17 @@ function installJsController(cb) { 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(function () { - storeOriginalFiles(); + installAdapter(async function () { + await storeOriginalFiles(); if (cb) cb(true); }); }); @@ -359,12 +484,16 @@ function installJsController(cb) { 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(function () { - storeOriginalFiles(); + installAdapter(async function () { + await storeOriginalFiles(); if (cb) cb(true); }); }); @@ -445,46 +574,89 @@ function clearDB() { } function setupController(cb) { - installJsController(function (isInited) { - clearControllerLog(); - clearDB(); + 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 || {}; - if (!isInited) { - restoreOriginalFiles(); - copyAdapterToController(); + 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); } - // read system.config object - const dataDir = rootDir + 'tmp/' + appName + '-data/'; + }); +} + +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.log('ERROR reading/parsing system configuration. Ignore'); - objs = {'system.config': {}}; + console.warn("Could not load secret. Reason: " + e); + return null; } if (!objs || !objs['system.config']) { objs = {'system.config': {}}; } - if (cb) cb(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(); -function getSecret() { - var dataDir = rootDir + 'tmp/' + appName + '-data/'; + let config = db.get('system.config'); + config = config || {}; - try { - var objs = fs.readFileSync(dataDir + 'objects.json'); - objs = JSON.parse(objs); + await db.close(); - return objs['system.config'].native.secret; - } catch (e) { - console.warn("Could not load secret. Reason: " + e); - return null; + return config.native.secret; + } else { + console.error('read secret: No objects file found in datadir ' + dataDir); } + } function encrypt (key, value) { @@ -544,100 +716,115 @@ function startController(isStartAdapter, onObjectChange, onStateChange, callback console.error('Controller is already started!'); } else { console.log('startController...'); - adapterStarted = false; - let isObjectConnected; - let isStatesConnected; - - const Objects = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/objects/objectsInMemServer'); - objects = new Objects({ - connection: { - 'type' : 'file', - '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); + 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 }, - warn: function (msg) { - console.warn(msg); + 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); + } }, - 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; + 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 States = require(rootDir + 'tmp/node_modules/' + appName + '.js-controller/lib/states/statesInMemServer'); - states = new States({ - connection: { - type: 'file', - 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); + 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 + } }, - warn: function (msg) { - console.log(msg); + 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); + } }, - 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; + 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 - }); + }, + change: onStateChange + }); + } catch (err) { + console.log(err); + } } } @@ -721,19 +908,47 @@ function stopController(cb) { } // Setup the adapter -function setAdapterConfig(common, native, instance) { - const objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString()); +async function setAdapterConfig(common, native, instance) { const id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0); - if (common) objects[id].common = common; - if (native) objects[id].native = native; - fs.writeFileSync(rootDir + 'tmp/' + appName + '-data/objects.json', JSON.stringify(objects)); + 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 -function getAdapterConfig(instance) { - const objects = JSON.parse(fs.readFileSync(rootDir + 'tmp/' + appName + '-data/objects.json').toString()); - const id = 'system.adapter.' + adapterName.split('.').pop() + '.' + (instance || 0); - return objects[id]; +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) { From 58727192a2f48c933e5cc77b911a4351fc50f441 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sat, 29 Jan 2022 15:27:48 +0100 Subject: [PATCH 10/13] update testAdapter.js --- test/testAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/testAdapter.js b/test/testAdapter.js index ae9c289..3a4eada 100644 --- a/test/testAdapter.js +++ b/test/testAdapter.js @@ -77,7 +77,7 @@ describe('Test ' + adapterShortName + ' adapter', function() { before('Test ' + adapterShortName + ' adapter: Start js-controller', function (_done) { this.timeout(600000); // because of first install from npm - setup.setupController(function () { + setup.setupController(async function () { var config = setup.getAdapterConfig(); // enable adapter config.common.enabled = true; @@ -85,7 +85,7 @@ describe('Test ' + adapterShortName + ' adapter', function() { //config.native.dbtype = 'sqlite'; - setup.setAdapterConfig(config.common, config.native); + await setup.setAdapterConfig(config.common, config.native); setup.startController(true, function(id, obj) {}, function (id, state) { if (onStateChanged) onStateChanged(id, state); From abdb2ec93a0edc53cdea2be29a537520384fa920 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sat, 29 Jan 2022 15:27:48 +0100 Subject: [PATCH 11/13] add mocha.setup.js --- test/mocha.setup.js | 1 + 1 file changed, 1 insertion(+) create mode 100644 test/mocha.setup.js diff --git a/test/mocha.setup.js b/test/mocha.setup.js new file mode 100644 index 0000000..2adcb98 --- /dev/null +++ b/test/mocha.setup.js @@ -0,0 +1 @@ +process.on("unhandledRejection", (r) => { throw r; }); From cf3a24415883ce5f1489046666877971ecffe270 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sat, 29 Jan 2022 15:27:49 +0100 Subject: [PATCH 12/13] add .mocharc.json --- .mocharc.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .mocharc.json diff --git a/.mocharc.json b/.mocharc.json new file mode 100644 index 0000000..89a1352 --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,5 @@ +{ + "require": [ + "./test/mocha.setup.js" + ] +} From 1a2fffa3389a7dabd2053630286456cdabae4e0f Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Sat, 29 Jan 2022 16:08:37 +0100 Subject: [PATCH 13/13] update testAdapter.js --- test/testAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testAdapter.js b/test/testAdapter.js index 3a4eada..f1814d0 100644 --- a/test/testAdapter.js +++ b/test/testAdapter.js @@ -78,7 +78,7 @@ describe('Test ' + adapterShortName + ' adapter', function() { this.timeout(600000); // because of first install from npm setup.setupController(async function () { - var config = setup.getAdapterConfig(); + var config = await setup.getAdapterConfig(); // enable adapter config.common.enabled = true; config.common.loglevel = 'debug';