iobroker.javascript 8.9.2 → 9.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/admin/assets/{createSvgIcon-BdRvDw53.js → createSvgIcon-BQT-7-GS.js} +1 -1
- package/admin/assets/{docs-6na4NFtj.js → docs-BrInh2Pn.js} +2 -2
- package/admin/assets/index-BzKS5vx-.js +1329 -0
- package/admin/assets/index-CfuHVX2B.js +193 -0
- package/admin/assets/index-CuCs5aLs.js +5 -0
- package/admin/assets/index-tExaxF69.js +930 -0
- package/admin/assets/inheritsLoose--KnFDOw1.js +36 -0
- package/admin/assets/{useTheme-Cl1QmYFL.js → useTheme-DF6qfrtI.js} +1 -1
- package/admin/custom/assets/{Components-ChpTW7sE.js → Components-D9kRsHNY.js} +1 -1
- package/admin/custom/assets/{DefaultPropsProvider-CHpMCMgA.js → DefaultPropsProvider-9qubdy-V.js} +2 -2
- package/admin/custom/assets/{FilledInput-CtcQVKyj.js → FilledInput-BpuM_GyB.js} +1 -1
- package/admin/custom/assets/Tabs-CvEv0KOT.js +138 -0
- package/admin/custom/assets/ThemeProvider-DZTpMR8n.js +29 -0
- package/admin/custom/assets/{createSvgIcon-C_vAELFU.js → createSvgIcon-BQThUM-f.js} +1 -1
- package/admin/custom/assets/hostInit-CrAs5YZS.js +1 -1
- package/admin/custom/assets/index-BXmu6lpn.js +904 -0
- package/admin/custom/assets/{index-DwsbskQy.js → index-DIWNdd4a.js} +1 -1
- package/admin/custom/assets/index-DZqbj5K4.js +55 -0
- package/admin/custom/assets/{index-D5apCzjJ.js → index-Dbe-II7_.js} +6 -6
- package/admin/custom/assets/index-sawv1cUe.js +1399 -0
- package/admin/custom/assets/{virtualExposes-BPncCdUy.js → virtualExposes-BMKIjWrE.js} +2 -2
- package/admin/custom/customComponents.js +2 -2
- package/admin/custom/i18n/de.json +29 -29
- package/admin/custom/i18n/es.json +29 -29
- package/admin/custom/i18n/fr.json +29 -29
- package/admin/custom/i18n/it.json +29 -29
- package/admin/custom/i18n/nl.json +29 -29
- package/admin/custom/i18n/pl.json +29 -29
- package/admin/custom/i18n/pt.json +29 -29
- package/admin/custom/i18n/ru.json +29 -29
- package/admin/custom/i18n/uk.json +29 -29
- package/admin/custom/i18n/zh-cn.json +29 -29
- package/admin/google-blockly/blockly_compressed.js +875 -887
- package/admin/google-blockly/blocks_compressed.js +38 -41
- package/admin/google-blockly/javascript_compressed.js +19 -54
- package/admin/google-blockly/media/delete-icon.svg +1 -0
- package/admin/google-blockly/media/foldout-icon.svg +1 -0
- package/admin/google-blockly/media/resize-handle.svg +3 -0
- package/admin/i18n/de.json +61 -0
- package/admin/i18n/en.json +61 -0
- package/admin/i18n/es.json +61 -0
- package/admin/i18n/fr.json +61 -0
- package/admin/i18n/it.json +61 -0
- package/admin/i18n/nl.json +61 -0
- package/admin/i18n/pl.json +61 -0
- package/admin/i18n/pt.json +61 -0
- package/admin/i18n/ru.json +61 -0
- package/admin/i18n/uk.json +61 -0
- package/admin/i18n/zh-cn.json +61 -0
- package/admin/jsonConfig.json +2 -0
- package/admin/mf-manifest.json +1 -1
- package/admin/remoteEntry.js +2 -2
- package/admin/tab.html +4 -4
- package/admin/vsFont/README.md +1 -1
- package/admin/vsFont/createJson.js +1 -1
- package/build-backend/lib/consts.js +346 -0
- package/build-backend/lib/consts.js.map +1 -0
- package/build-backend/lib/convert.js +120 -0
- package/build-backend/lib/convert.js.map +1 -0
- package/build-backend/lib/debug.js +163 -0
- package/build-backend/lib/debug.js.map +1 -0
- package/{lib → build-backend/lib}/debugger.js +261 -232
- package/build-backend/lib/debugger.js.map +1 -0
- package/build-backend/lib/eventObj.js +177 -0
- package/build-backend/lib/eventObj.js.map +1 -0
- package/build-backend/lib/inspect.js +728 -0
- package/build-backend/lib/inspect.js.map +1 -0
- package/build-backend/lib/javascript.d.ts +1972 -0
- package/{lib → build-backend/lib}/mirror.js +185 -182
- package/build-backend/lib/mirror.js.map +1 -0
- package/build-backend/lib/nodeModulesManagement.js +25 -0
- package/build-backend/lib/nodeModulesManagement.js.map +1 -0
- package/build-backend/lib/patternCompareFunctions.js +321 -0
- package/build-backend/lib/patternCompareFunctions.js.map +1 -0
- package/build-backend/lib/protectFs.js +477 -0
- package/build-backend/lib/protectFs.js.map +1 -0
- package/build-backend/lib/request.js +89 -0
- package/build-backend/lib/request.js.map +1 -0
- package/{lib → build-backend/lib}/sandbox.js +2046 -1852
- package/build-backend/lib/sandbox.js.map +1 -0
- package/build-backend/lib/scheduler.js +553 -0
- package/build-backend/lib/scheduler.js.map +1 -0
- package/build-backend/lib/tools.js +183 -0
- package/build-backend/lib/tools.js.map +1 -0
- package/build-backend/lib/typescriptSettings.js +39 -0
- package/build-backend/lib/typescriptSettings.js.map +1 -0
- package/build-backend/lib/typescriptTools.js +435 -0
- package/build-backend/lib/typescriptTools.js.map +1 -0
- package/build-backend/lib/utils.js +66 -0
- package/build-backend/lib/utils.js.map +1 -0
- package/{lib → build-backend/lib}/words.js +23 -30
- package/build-backend/lib/words.js.map +1 -0
- package/build-backend/main.js +2671 -0
- package/build-backend/main.js.map +1 -0
- package/build-backend/types.d.ts +742 -0
- package/docs/de/README.md +1 -1
- package/docs/en/README.md +1 -1
- package/docs/en/javascript.md +10 -6
- package/docs/en/upgrade-guide.md +5 -2
- package/docs/ru/README.md +1 -1
- package/install/installTypings.js +34 -47
- package/io-package.json +14 -14
- package/package.json +14 -14
- package/admin/assets/index-DCkkMRRa.js +0 -1335
- package/admin/assets/index-DJfSBoBB.js +0 -192
- package/admin/assets/index-DTiA4WdK.js +0 -930
- package/admin/assets/index-qABB1JVe.js +0 -5
- package/admin/assets/inheritsLoose-BW-3V39H.js +0 -36
- package/admin/custom/assets/Tabs-C1KOyWRi.js +0 -137
- package/admin/custom/assets/ThemeProvider-Buvx5nSd.js +0 -29
- package/admin/custom/assets/index-BGCRznKh.js +0 -904
- package/admin/custom/assets/index-DfBPYXqA.js +0 -55
- package/admin/custom/assets/index-jIr6kOLK.js +0 -1398
- package/admin/i18n/de/flat.txt +0 -427
- package/admin/i18n/de/translations.json +0 -429
- package/admin/i18n/en/flat.txt +0 -427
- package/admin/i18n/en/translations.json +0 -429
- package/admin/i18n/es/flat.txt +0 -427
- package/admin/i18n/es/translations.json +0 -429
- package/admin/i18n/flat.txt +0 -427
- package/admin/i18n/fr/flat.txt +0 -427
- package/admin/i18n/fr/translations.json +0 -429
- package/admin/i18n/it/flat.txt +0 -427
- package/admin/i18n/it/translations.json +0 -429
- package/admin/i18n/nl/flat.txt +0 -427
- package/admin/i18n/nl/translations.json +0 -429
- package/admin/i18n/pl/flat.txt +0 -427
- package/admin/i18n/pl/translations.json +0 -429
- package/admin/i18n/pt/flat.txt +0 -427
- package/admin/i18n/pt/translations.json +0 -429
- package/admin/i18n/ru/flat.txt +0 -427
- package/admin/i18n/ru/translations.json +0 -429
- package/admin/i18n/uk/flat.txt +0 -427
- package/admin/i18n/uk/translations.json +0 -429
- package/admin/i18n/zh-cn/flat.txt +0 -427
- package/admin/i18n/zh-cn/translations.json +0 -429
- package/lib/adapter-config.d.ts +0 -16
- package/lib/consts.js +0 -83
- package/lib/convert.js +0 -106
- package/lib/debug.js +0 -154
- package/lib/eventObj.js +0 -201
- package/lib/inspect.js +0 -688
- package/lib/javascript.d.ts +0 -1858
- package/lib/nodeModulesManagement.js +0 -26
- package/lib/patternCompareFunctions.js +0 -391
- package/lib/protectFs.js +0 -401
- package/lib/request.js +0 -72
- package/lib/scheduler.js +0 -447
- package/lib/tools.js +0 -192
- package/lib/typescriptSettings.js +0 -44
- package/lib/typescriptTools.js +0 -529
- package/lib/utils.js +0 -87
- package/main.js +0 -2653
package/main.js
DELETED
|
@@ -1,2653 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Javascript adapter
|
|
3
|
-
*
|
|
4
|
-
* The MIT License (MIT)
|
|
5
|
-
*
|
|
6
|
-
* Copyright (c) 2014-2024 bluefox <dogafox@gmail.com>,
|
|
7
|
-
*
|
|
8
|
-
* Copyright (c) 2014 hobbyquaker
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/* jshint -W097 */
|
|
12
|
-
/* jshint -W083 */
|
|
13
|
-
/* jshint strict: false */
|
|
14
|
-
/* jslint node: true */
|
|
15
|
-
/* jshint shadow: true */
|
|
16
|
-
'use strict';
|
|
17
|
-
|
|
18
|
-
const vm = require('node:vm');
|
|
19
|
-
const nodeFS = require('node:fs');
|
|
20
|
-
const nodePath = require('node:path');
|
|
21
|
-
const tsc = require('virtual-tsc');
|
|
22
|
-
const Mirror = require('./lib/mirror');
|
|
23
|
-
const fork = require('child_process').fork;
|
|
24
|
-
|
|
25
|
-
const mods = {
|
|
26
|
-
fs: {},
|
|
27
|
-
dgram: require('node:dgram'),
|
|
28
|
-
crypto: require('node:crypto'),
|
|
29
|
-
dns: require('node:dns'),
|
|
30
|
-
events: require('node:events'),
|
|
31
|
-
http: require('node:http'),
|
|
32
|
-
https: require('node:https'),
|
|
33
|
-
http2: require('node:http2'),
|
|
34
|
-
net: require('node:net'),
|
|
35
|
-
os: require('node:os'),
|
|
36
|
-
path: require('node:path'),
|
|
37
|
-
util: require('node:util'),
|
|
38
|
-
child_process: require('node:child_process'),
|
|
39
|
-
stream: require('node:stream'),
|
|
40
|
-
zlib: require('node:zlib'),
|
|
41
|
-
suncalc: require('suncalc2'),
|
|
42
|
-
axios: require('axios'),
|
|
43
|
-
wake_on_lan: require('wake_on_lan'),
|
|
44
|
-
nodeSchedule: require('node-schedule')
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* List of forbidden Locations for a mirror directory
|
|
49
|
-
* relative to the default data directory
|
|
50
|
-
* ATTENTION: the same list is also located in index_m.html!!
|
|
51
|
-
* @type {*[]}
|
|
52
|
-
*/
|
|
53
|
-
const forbiddenMirrorLocations = [
|
|
54
|
-
'backup-objects',
|
|
55
|
-
'files',
|
|
56
|
-
'backitup',
|
|
57
|
-
'../backups',
|
|
58
|
-
'../node_modules',
|
|
59
|
-
'../log',
|
|
60
|
-
];
|
|
61
|
-
|
|
62
|
-
const utils = require('@iobroker/adapter-core');
|
|
63
|
-
const words = require('./lib/words');
|
|
64
|
-
const sandBox = require('./lib/sandbox');
|
|
65
|
-
const { requestModuleNameByUrl } = require('./lib/nodeModulesManagement.js');
|
|
66
|
-
const eventObj = require('./lib/eventObj');
|
|
67
|
-
const Scheduler = require('./lib/scheduler');
|
|
68
|
-
const { targetTsLib, tsCompilerOptions, jsDeclarationCompilerOptions } = require('./lib/typescriptSettings');
|
|
69
|
-
const { hashSource, isObject } = require('./lib/tools');
|
|
70
|
-
const { isDeepStrictEqual } = require('node:util');
|
|
71
|
-
const {
|
|
72
|
-
resolveTypescriptLibs,
|
|
73
|
-
resolveTypings,
|
|
74
|
-
scriptIdToTSFilename,
|
|
75
|
-
transformScriptBeforeCompilation,
|
|
76
|
-
transformGlobalDeclarations
|
|
77
|
-
} = require('./lib/typescriptTools');
|
|
78
|
-
|
|
79
|
-
const packageJson = require('./package.json');
|
|
80
|
-
const SCRIPT_CODE_MARKER = 'script.js.';
|
|
81
|
-
|
|
82
|
-
const stopCounters = {};
|
|
83
|
-
let setStateCountCheckInterval = null;
|
|
84
|
-
|
|
85
|
-
let webstormDebug;
|
|
86
|
-
let debugMode;
|
|
87
|
-
if (process.argv) {
|
|
88
|
-
for (let a = 1; a < process.argv.length; a++) {
|
|
89
|
-
if (process.argv[a].startsWith('--webstorm')) {
|
|
90
|
-
webstormDebug = process.argv[a].replace(/^(.*?=\s*)/, '');
|
|
91
|
-
}
|
|
92
|
-
if (process.argv[a] === '--debugScript') {
|
|
93
|
-
if (!process.argv[a + 1]) {
|
|
94
|
-
console.log('No script name provided');
|
|
95
|
-
process.exit(300);
|
|
96
|
-
} else {
|
|
97
|
-
debugMode = process.argv[a + 1];
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const isCI = !!process.env.CI;
|
|
104
|
-
|
|
105
|
-
// ambient declarations for typescript
|
|
106
|
-
/** @type {Record<string, string>} */
|
|
107
|
-
let tsAmbient;
|
|
108
|
-
|
|
109
|
-
// TypeScript's scripts are only recompiled if their source hash changes.
|
|
110
|
-
// If an adapter update fixes the compilation bugs, a user won't notice until the changes and re-saves the script.
|
|
111
|
-
// To avoid that, we also include the
|
|
112
|
-
// adapter version and TypeScript version in the hash
|
|
113
|
-
const tsSourceHashBase = `versions:adapter=${packageJson.version},typescript=${packageJson.dependencies.typescript}`;
|
|
114
|
-
|
|
115
|
-
let mirror;
|
|
116
|
-
|
|
117
|
-
/** @type {boolean} if logs are subscribed or not */
|
|
118
|
-
let logSubscribed;
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* @param {string} scriptID - The current script the declarations were generated from
|
|
122
|
-
* @param {string} declarations
|
|
123
|
-
*/
|
|
124
|
-
function provideDeclarationsForGlobalScript(scriptID, declarations) {
|
|
125
|
-
// Remember which declarations this global script had access to,
|
|
126
|
-
// we need this so the editor doesn't show a duplicate identifier error
|
|
127
|
-
if (globalDeclarations != null && globalDeclarations !== '') {
|
|
128
|
-
knownGlobalDeclarationsByScript[scriptID] = globalDeclarations;
|
|
129
|
-
}
|
|
130
|
-
// and concatenate the global declarations for the next scripts
|
|
131
|
-
globalDeclarations += declarations + '\n';
|
|
132
|
-
// remember all previously generated global declarations,
|
|
133
|
-
// so global scripts can reference each other
|
|
134
|
-
const globalDeclarationPath = 'global.d.ts';
|
|
135
|
-
tsAmbient[globalDeclarationPath] = globalDeclarations;
|
|
136
|
-
// make sure the next script compilation has access to the updated declarations
|
|
137
|
-
tsServer.provideAmbientDeclarations({
|
|
138
|
-
[globalDeclarationPath]: globalDeclarations
|
|
139
|
-
});
|
|
140
|
-
jsDeclarationServer.provideAmbientDeclarations({
|
|
141
|
-
[globalDeclarationPath]: globalDeclarations
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// taken from here: https://stackoverflow.com/questions/11887934/how-to-check-if-dst-daylight-saving-time-is-in-effect-and-if-so-the-offset
|
|
146
|
-
function dstOffsetAtDate(dateInput) {
|
|
147
|
-
const fullYear = dateInput.getFullYear() | 0;
|
|
148
|
-
// "Leap Years are any year that can be exactly divided by 4 (2012, 2016, etc)
|
|
149
|
-
// except if it can be exactly divided by 100, then it isn't (2100, 2200, etc)
|
|
150
|
-
// except if it can be exactly divided by 400, then it is (2000, 2400)"
|
|
151
|
-
// (https://www.mathsisfun.com/leap-years.html).
|
|
152
|
-
const isLeapYear = ((fullYear & 3) | (fullYear/100 & 3)) === 0 ? 1 : 0;
|
|
153
|
-
// (fullYear & 3) = (fullYear % 4), but faster
|
|
154
|
-
//Alternative:var isLeapYear=(new Date(currentYear,1,29,12)).getDate()===29?1:0
|
|
155
|
-
const fullMonth = dateInput.getMonth() | 0;
|
|
156
|
-
return (
|
|
157
|
-
// 1. We know what the time since the Epoch really is
|
|
158
|
-
(+dateInput) // same as the dateInput.getTime() method
|
|
159
|
-
// 2. We know what the time since the Epoch at the start of the year is
|
|
160
|
-
- (+new Date(fullYear, 0)) // day defaults to 1 if not explicitly zeroed
|
|
161
|
-
// 3. Now, subtract what we would expect the time to be if daylight savings
|
|
162
|
-
// did not exist. This yields the time-offset due to daylight savings.
|
|
163
|
-
- ((
|
|
164
|
-
((
|
|
165
|
-
// Calculate the day of the year in the Gregorian calendar
|
|
166
|
-
// The code below works based upon the facts of signed right shifts
|
|
167
|
-
// • (x) >> n: shifts n and fills in the n highest bits with 0s
|
|
168
|
-
// • (-x) >> n: shifts n and fills in the n highest bits with 1s
|
|
169
|
-
// (This assumes that x is a positive integer)
|
|
170
|
-
-1 + // first day in the year is day 1
|
|
171
|
-
(31 & ((-fullMonth) >> 4)) + // January // (-11)>>4 = -1
|
|
172
|
-
((28 + isLeapYear) & ((1 - fullMonth) >> 4)) + // February
|
|
173
|
-
(31 & ((2 - fullMonth) >> 4)) + // March
|
|
174
|
-
(30 & ((3 - fullMonth) >> 4)) + // April
|
|
175
|
-
(31 & ((4 - fullMonth) >> 4)) + // May
|
|
176
|
-
(30 & ((5 - fullMonth) >> 4)) + // June
|
|
177
|
-
(31 & ((6 - fullMonth) >> 4)) + // July
|
|
178
|
-
(31 & ((7 - fullMonth) >> 4)) + // August
|
|
179
|
-
(30 & ((8 - fullMonth) >> 4)) + // September
|
|
180
|
-
(31 & ((9 - fullMonth) >> 4)) + // October
|
|
181
|
-
(30 & ((10 - fullMonth) >> 4)) + // November
|
|
182
|
-
// There are no months past December: the year rolls into the next.
|
|
183
|
-
// Thus, fullMonth is 0-based, so it will never be 12 in Javascript
|
|
184
|
-
|
|
185
|
-
(dateInput.getDate() | 0) // get day of the month
|
|
186
|
-
|
|
187
|
-
) & 0xffff) * 24 * 60 // 24 hours in a day, 60 minutes in an hour
|
|
188
|
-
+ (dateInput.getHours() & 0xff) * 60 // 60 minutes in an hour
|
|
189
|
-
+ (dateInput.getMinutes() & 0xff)
|
|
190
|
-
)|0) * 60 * 1000 // 60 seconds in a minute * 1000 milliseconds in a second
|
|
191
|
-
- (dateInput.getSeconds() & 0xff) * 1000 // 1000 milliseconds in a second
|
|
192
|
-
- dateInput.getMilliseconds()
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function loadTypeScriptDeclarations() {
|
|
197
|
-
// try to load the typings on disk for all 3rd party modules
|
|
198
|
-
const packages = [
|
|
199
|
-
'node', // this provides auto-completion for most builtins
|
|
200
|
-
'request', // preloaded by the adapter
|
|
201
|
-
];
|
|
202
|
-
// Also include user-selected libraries (but only those that are also installed)
|
|
203
|
-
if (
|
|
204
|
-
adapter.config
|
|
205
|
-
&& typeof adapter.config.libraries === 'string'
|
|
206
|
-
&& typeof adapter.config.libraryTypings === 'string'
|
|
207
|
-
) {
|
|
208
|
-
const installedLibs = adapter.config.libraries
|
|
209
|
-
.split(/[,;\s]+/)
|
|
210
|
-
.map((s) => s.trim().split('@')[0])
|
|
211
|
-
.filter((s) => !!s);
|
|
212
|
-
|
|
213
|
-
const wantsTypings = adapter.config.libraryTypings.split(/[,;\s]+/).map(s => s.trim()).filter(s => !!s);
|
|
214
|
-
// Add all installed libraries the user has requested typings for to the list of packages
|
|
215
|
-
for (const lib of installedLibs) {
|
|
216
|
-
if (wantsTypings.includes(lib) && !packages.includes(lib)) {
|
|
217
|
-
packages.push(lib);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
// Some packages have sub-modules (e.g., rxjs/operators) that are not exposed through the main entry point
|
|
221
|
-
// If typings are requested for them, also add them if the base module is installed
|
|
222
|
-
for (const lib of wantsTypings) {
|
|
223
|
-
// Extract the package name and check if we need to add it
|
|
224
|
-
if (!lib.includes('/')) {
|
|
225
|
-
continue;
|
|
226
|
-
}
|
|
227
|
-
const pkgName = lib.substr(0, lib.indexOf('/'));
|
|
228
|
-
|
|
229
|
-
if (installedLibs.includes(pkgName) && !packages.includes(lib)) {
|
|
230
|
-
packages.push(lib);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
for (const pkg of packages) {
|
|
235
|
-
let pkgTypings = resolveTypings(pkg,
|
|
236
|
-
adapter.getAdapterScopedPackageIdentifier ? adapter.getAdapterScopedPackageIdentifier(pkg) : pkg,
|
|
237
|
-
// node needs ambient typings, so we don't wrap it in declare module
|
|
238
|
-
pkg !== 'node'
|
|
239
|
-
);
|
|
240
|
-
if (!pkgTypings) {
|
|
241
|
-
// Create the empty dummy declarations so users don't get the "not found" error
|
|
242
|
-
// for installed packages
|
|
243
|
-
pkgTypings = {
|
|
244
|
-
[`node_modules/@types/${pkg}/index.d.ts`]: `declare module "${pkg}";`,
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
adapter.log.debug(`Loaded TypeScript definitions for ${pkg}: ${JSON.stringify(Object.keys(pkgTypings))}`);
|
|
248
|
-
// remember the declarations for the editor
|
|
249
|
-
Object.assign(tsAmbient, pkgTypings);
|
|
250
|
-
// and give the language servers access to them
|
|
251
|
-
tsServer.provideAmbientDeclarations(pkgTypings);
|
|
252
|
-
jsDeclarationServer.provideAmbientDeclarations(pkgTypings);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const context = {
|
|
257
|
-
mods,
|
|
258
|
-
objects: {},
|
|
259
|
-
states: {},
|
|
260
|
-
interimStateValues: {},
|
|
261
|
-
stateIds: [],
|
|
262
|
-
errorLogFunction: null,
|
|
263
|
-
subscriptions: [],
|
|
264
|
-
subscriptionsFile: [],
|
|
265
|
-
subscriptionsObject: [],
|
|
266
|
-
subscribedPatterns: {},
|
|
267
|
-
subscribedPatternsFile: {},
|
|
268
|
-
adapterSubs: {},
|
|
269
|
-
cacheObjectEnums: {},
|
|
270
|
-
isEnums: false, // If some subscription wants enum
|
|
271
|
-
channels: null,
|
|
272
|
-
devices: null,
|
|
273
|
-
logWithLineInfo: null,
|
|
274
|
-
scheduler: null,
|
|
275
|
-
timers: {},
|
|
276
|
-
enums: [],
|
|
277
|
-
timerId: 0,
|
|
278
|
-
names: {},
|
|
279
|
-
scripts: {},
|
|
280
|
-
messageBusHandlers: {},
|
|
281
|
-
logSubscriptions: {},
|
|
282
|
-
tempDirectories: {},
|
|
283
|
-
folderCreationVerifiedObjects: {},
|
|
284
|
-
updateLogSubscriptions,
|
|
285
|
-
convertBackStringifiedValues,
|
|
286
|
-
updateObjectContext,
|
|
287
|
-
prepareStateObject,
|
|
288
|
-
debugMode,
|
|
289
|
-
timeSettings: {
|
|
290
|
-
format12: false,
|
|
291
|
-
leadingZeros: true
|
|
292
|
-
},
|
|
293
|
-
rulesOpened: null, //opened rules
|
|
294
|
-
getAbsoluteDefaultDataDir: utils.getAbsoluteDefaultDataDir,
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
const regExGlobalOld = /_global$/;
|
|
298
|
-
const regExGlobalNew = /script\.js\.global\./;
|
|
299
|
-
|
|
300
|
-
function checkIsGlobal(obj) {
|
|
301
|
-
return obj && obj.common && (regExGlobalOld.test(obj.common.name) || regExGlobalNew.test(obj._id));
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function convertBackStringifiedValues(id, state) {
|
|
305
|
-
if (state && typeof state.val === 'string' &&
|
|
306
|
-
context.objects[id] && context.objects[id].common &&
|
|
307
|
-
(context.objects[id].common.type === 'array' || context.objects[id].common.type === 'object')) {
|
|
308
|
-
try {
|
|
309
|
-
state.val = JSON.parse(state.val);
|
|
310
|
-
} catch (err) {
|
|
311
|
-
if (id.startsWith('javascript.') || id.startsWith('0_userdata.0')) {
|
|
312
|
-
adapter.log.info(`Could not parse value for id ${id} into ${context.objects[id].common.type}: ${err.message}`);
|
|
313
|
-
} else {
|
|
314
|
-
adapter.log.debug(`Could not parse value for id ${id} into ${context.objects[id].common.type}: ${err.message}`);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
return state;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
function prepareStateObject(id, state, isAck) {
|
|
322
|
-
if (state === null) {
|
|
323
|
-
state = { val: null };
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
if (isAck === true || isAck === false || isAck === 'true' || isAck === 'false') {
|
|
327
|
-
if (isObject(state) && state.val !== undefined) {
|
|
328
|
-
// we assume that we were given a state object if
|
|
329
|
-
// state is an object that contains a `val` property
|
|
330
|
-
if (!Object.prototype.hasOwnProperty.call(state, 'ack')) {
|
|
331
|
-
state.ack = isAck;
|
|
332
|
-
}
|
|
333
|
-
} else {
|
|
334
|
-
// otherwise assume that the given state is the value to be set
|
|
335
|
-
state = {val: state, ack: isAck};
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (adapter.config.subscribe) {
|
|
340
|
-
return state;
|
|
341
|
-
}
|
|
342
|
-
// set other values to have a full state object
|
|
343
|
-
// mirrors logic from statesInRedis
|
|
344
|
-
if (state.ts === undefined) {
|
|
345
|
-
state.ts = Date.now();
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
if (state.q === undefined) {
|
|
349
|
-
state.q = 0;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
state.from =
|
|
353
|
-
typeof state.from === 'string' && state.from !== '' ? state.from : `system.adapter.${adapter.namespace}`;
|
|
354
|
-
|
|
355
|
-
if (state.lc === undefined) {
|
|
356
|
-
const formerStateValue = context.interimStateValues[id] || context.states[id];
|
|
357
|
-
if (!formerStateValue) {
|
|
358
|
-
state.lc = state.ts;
|
|
359
|
-
} else {
|
|
360
|
-
// isDeepStrictEqual works on objects and primitive values
|
|
361
|
-
const hasChanged = !isDeepStrictEqual(formerStateValue.val, state.val);
|
|
362
|
-
if (!formerStateValue.lc || hasChanged) {
|
|
363
|
-
state.lc = state.ts;
|
|
364
|
-
} else {
|
|
365
|
-
state.lc = formerStateValue.lc;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
return state;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function fileMatching(sub, id, fileName) {
|
|
374
|
-
if (sub.idRegEx) {
|
|
375
|
-
if (!sub.idRegEx.test(id)) {
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
378
|
-
} else {
|
|
379
|
-
if (sub.id !== id) {
|
|
380
|
-
return false;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
if (sub.fileRegEx) {
|
|
384
|
-
if (!sub.fileRegEx.test(fileName)) {
|
|
385
|
-
return false;
|
|
386
|
-
}
|
|
387
|
-
} else {
|
|
388
|
-
if (sub.fileNamePattern !== fileName) {
|
|
389
|
-
return false;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return true;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/**
|
|
397
|
-
* @type {Set<string>}
|
|
398
|
-
* Stores the IDs of script objects whose change should be ignored because
|
|
399
|
-
* the compiled source was just updated
|
|
400
|
-
*/
|
|
401
|
-
const ignoreObjectChange = new Set();
|
|
402
|
-
|
|
403
|
-
let objectsInitDone = false;
|
|
404
|
-
let statesInitDone = false;
|
|
405
|
-
|
|
406
|
-
/** @type {ioBroker.Adapter} */
|
|
407
|
-
let adapter;
|
|
408
|
-
|
|
409
|
-
function startAdapter(options) {
|
|
410
|
-
options = options || {};
|
|
411
|
-
Object.assign(options, {
|
|
412
|
-
name: 'javascript',
|
|
413
|
-
useFormatDate: true, // load float formatting
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* @param id { string }
|
|
417
|
-
* @param obj { ioBroker.Object }
|
|
418
|
-
*/
|
|
419
|
-
objectChange: (id, obj) => {
|
|
420
|
-
// Check if we should ignore this change (once!) because we just updated the compiled sources
|
|
421
|
-
if (ignoreObjectChange.has(id)) {
|
|
422
|
-
// Update the cached script object and do nothing more
|
|
423
|
-
context.objects[id] = obj;
|
|
424
|
-
ignoreObjectChange.delete(id);
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
// When still in initializing: already remember current values,
|
|
429
|
-
// but data structures are initialized elsewhere
|
|
430
|
-
if (!objectsInitDone) {
|
|
431
|
-
if (obj) {
|
|
432
|
-
context.objects[id] = obj;
|
|
433
|
-
}
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
if (id.startsWith('enum.')) {
|
|
439
|
-
// clear cache
|
|
440
|
-
context.cacheObjectEnums = {};
|
|
441
|
-
|
|
442
|
-
// update context.enums array
|
|
443
|
-
if (obj) {
|
|
444
|
-
// If new
|
|
445
|
-
if (!context.enums.includes(id)) {
|
|
446
|
-
context.enums.push(id);
|
|
447
|
-
context.enums.sort();
|
|
448
|
-
}
|
|
449
|
-
} else {
|
|
450
|
-
const pos = context.enums.indexOf(id);
|
|
451
|
-
// if deleted
|
|
452
|
-
if (pos !== -1) {
|
|
453
|
-
context.enums.splice(pos, 1);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
if (obj && id === 'system.config') {
|
|
459
|
-
// set language for debug messages
|
|
460
|
-
if (obj.common && obj.common.language) {
|
|
461
|
-
words.setLanguage(obj.common.language);
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// update stored time format for variables.dayTime
|
|
466
|
-
if (id === adapter.namespace + '.variables.dayTime' && obj && obj.native) {
|
|
467
|
-
context.timeSettings.format12 = obj.native.format12 || false;
|
|
468
|
-
context.timeSettings.leadingZeros = obj.native.leadingZeros === undefined ? true : obj.native.leadingZeros;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// send changes to disk mirror
|
|
472
|
-
mirror && mirror.onObjectChange(id, obj);
|
|
473
|
-
|
|
474
|
-
const formerObj = context.objects[id];
|
|
475
|
-
|
|
476
|
-
updateObjectContext(id, obj); // Update all Meta object data
|
|
477
|
-
|
|
478
|
-
// for alias object changes on state objects we need to manually update the
|
|
479
|
-
// state cache value because new value is only published on next change
|
|
480
|
-
if (obj && obj.type === 'state' && id.startsWith('alias.0.')) {
|
|
481
|
-
adapter.getForeignState(id, (err, state) => {
|
|
482
|
-
if (err) {
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
if (state) {
|
|
486
|
-
context.states[id] = state;
|
|
487
|
-
} else if (context.states[id] !== undefined) {
|
|
488
|
-
delete context.states[id];
|
|
489
|
-
}
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
context.subscriptionsObject.forEach(sub => {
|
|
494
|
-
// ToDo: implement comparing with id.0.* too
|
|
495
|
-
if (sub.pattern === id) {
|
|
496
|
-
try {
|
|
497
|
-
sub.callback(id, obj);
|
|
498
|
-
} catch (err) {
|
|
499
|
-
adapter.log.error(`Error in callback: ${err}`);
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
});
|
|
503
|
-
|
|
504
|
-
// handle Script object updates
|
|
505
|
-
if (!obj && formerObj && formerObj.type === 'script') {
|
|
506
|
-
// Object Deleted just now
|
|
507
|
-
if (checkIsGlobal(formerObj)) {
|
|
508
|
-
// it was a global Script, and it was enabled and is now deleted => restart adapter
|
|
509
|
-
if (formerObj.enabled) {
|
|
510
|
-
adapter.log.info(`Active global Script ${id} deleted. Restart instance.`);
|
|
511
|
-
adapter.restart();
|
|
512
|
-
}
|
|
513
|
-
} else if (formerObj.common && formerObj.common.engine === `system.adapter.${adapter.namespace}`) {
|
|
514
|
-
// It was a non-global Script and deleted => stop and remove it
|
|
515
|
-
stop(id);
|
|
516
|
-
|
|
517
|
-
// delete scriptEnabled.blabla variable
|
|
518
|
-
const idActive = 'scriptEnabled.' + id.substring(SCRIPT_CODE_MARKER.length);
|
|
519
|
-
adapter.delObject(idActive);
|
|
520
|
-
adapter.delState(idActive);
|
|
521
|
-
|
|
522
|
-
// delete scriptProblem.blabla variable
|
|
523
|
-
const idProblem = 'scriptProblem.' + id.substring(SCRIPT_CODE_MARKER.length);
|
|
524
|
-
adapter.delObject(idProblem);
|
|
525
|
-
adapter.delState(idProblem);
|
|
526
|
-
}
|
|
527
|
-
} else if (!formerObj && obj && obj.type === 'script') {
|
|
528
|
-
// New script that does not exist before
|
|
529
|
-
if (checkIsGlobal(obj)) {
|
|
530
|
-
// new global script added => restart adapter
|
|
531
|
-
if (obj.common.enabled) {
|
|
532
|
-
adapter.log.info(`Active global Script ${id} created. Restart instance.`);
|
|
533
|
-
adapter.restart();
|
|
534
|
-
}
|
|
535
|
-
} else if (obj.common && obj.common.engine === `system.adapter.${adapter.namespace}`) {
|
|
536
|
-
// new non-global script - create states for scripts
|
|
537
|
-
createActiveObject(id, obj.common.enabled, () => createProblemObject(id));
|
|
538
|
-
if (obj.common.enabled) {
|
|
539
|
-
// if enabled => Start script
|
|
540
|
-
load(id);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
} else if (obj && obj.type === 'script' && formerObj && formerObj.common) {
|
|
544
|
-
// Script changed ...
|
|
545
|
-
if (checkIsGlobal(obj)) {
|
|
546
|
-
if (obj.common.enabled || formerObj.common.enabled) {
|
|
547
|
-
adapter.log.info(`Global Script ${id} updated. Restart instance.`);
|
|
548
|
-
adapter.restart();
|
|
549
|
-
}
|
|
550
|
-
} else { // No global script
|
|
551
|
-
if (obj.common && obj.common.engine === 'system.adapter.' + adapter.namespace) {
|
|
552
|
-
// create states for scripts
|
|
553
|
-
createActiveObject(id, obj.common.enabled, () => createProblemObject(id));
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
if ((formerObj.common.enabled && !obj.common.enabled) ||
|
|
557
|
-
(formerObj.common.engine === 'system.adapter.' + adapter.namespace && obj.common.engine !== 'system.adapter.' + adapter.namespace)) {
|
|
558
|
-
|
|
559
|
-
// Script disabled
|
|
560
|
-
if (formerObj.common.enabled && formerObj.common.engine === 'system.adapter.' + adapter.namespace) {
|
|
561
|
-
// Remove it from executing
|
|
562
|
-
stop(id);
|
|
563
|
-
}
|
|
564
|
-
} else if ((!formerObj.common.enabled && obj.common.enabled) ||
|
|
565
|
-
(formerObj.common.engine !== 'system.adapter.' + adapter.namespace && obj.common.engine === 'system.adapter.' + adapter.namespace)) {
|
|
566
|
-
// Script enabled
|
|
567
|
-
|
|
568
|
-
if (obj.common.enabled && obj.common.engine === 'system.adapter.' + adapter.namespace) {
|
|
569
|
-
// Start script
|
|
570
|
-
load(id);
|
|
571
|
-
}
|
|
572
|
-
} else { //if (obj.common.source !== formerObj.common.source) {
|
|
573
|
-
// Source changed => restart it
|
|
574
|
-
stopCounters[id] = stopCounters[id] ? stopCounters[id] + 1 : 1;
|
|
575
|
-
stop(id, (res, _id) =>
|
|
576
|
-
// only start again after stop when "last" object change to prevent problems on
|
|
577
|
-
// multiple changes in fast frequency
|
|
578
|
-
!--stopCounters[id] && load(_id));
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
},
|
|
583
|
-
|
|
584
|
-
stateChange: (id, state) => {
|
|
585
|
-
if (context.interimStateValues[id] !== undefined) {
|
|
586
|
-
// any update invalidates the remembered interim value
|
|
587
|
-
delete context.interimStateValues[id];
|
|
588
|
-
}
|
|
589
|
-
if (!id || id.startsWith('messagebox.') || id.startsWith('log.')) {
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
if (id === `${adapter.namespace}.debug.to` && state && !state.ack) {
|
|
594
|
-
return !debugMode && debugSendToInspector(state.val);
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// When still in initializing: already remember current values,
|
|
598
|
-
// but data structures are initialized elsewhere
|
|
599
|
-
if (!statesInitDone) {
|
|
600
|
-
if (state) {
|
|
601
|
-
context.states[id] = state;
|
|
602
|
-
}
|
|
603
|
-
return;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
const oldState = context.states[id];
|
|
607
|
-
if (state) {
|
|
608
|
-
if (oldState) {
|
|
609
|
-
// enable or disable script
|
|
610
|
-
if (!state.ack && id.startsWith(activeStr) && context.objects[id] && context.objects[id].native && context.objects[id].native.script) {
|
|
611
|
-
adapter.extendForeignObject(context.objects[id].native.script, { common: { enabled: state.val } });
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// monitor if adapter is alive and send all subscriptions once more, after adapter goes online
|
|
615
|
-
if (/*oldState && */oldState.val === false && state.val && id.endsWith('.alive')) {
|
|
616
|
-
if (context.adapterSubs[id]) {
|
|
617
|
-
const parts = id.split('.');
|
|
618
|
-
const a = `${parts[2]}.${parts[3]}`;
|
|
619
|
-
for (let t = 0; t < context.adapterSubs[id].length; t++) {
|
|
620
|
-
adapter.log.info(`Detected coming adapter "${a}". Send subscribe: ${context.adapterSubs[id][t]}`);
|
|
621
|
-
adapter.sendTo(a, 'subscribe', context.adapterSubs[id][t]);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
} else if (/*!oldState && */!context.stateIds.includes(id)) {
|
|
626
|
-
context.stateIds.push(id);
|
|
627
|
-
context.stateIds.sort();
|
|
628
|
-
}
|
|
629
|
-
context.states[id] = state;
|
|
630
|
-
} else {
|
|
631
|
-
if (oldState) delete context.states[id];
|
|
632
|
-
state = {};
|
|
633
|
-
const pos = context.stateIds.indexOf(id);
|
|
634
|
-
if (pos !== -1) {
|
|
635
|
-
context.stateIds.splice(pos, 1);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
const _eventObj = eventObj.createEventObject(context, id, context.convertBackStringifiedValues(id, state), context.convertBackStringifiedValues(id, oldState));
|
|
639
|
-
|
|
640
|
-
// if this state matches any subscriptions
|
|
641
|
-
for (let i = 0, l = context.subscriptions.length; i < l; i++) {
|
|
642
|
-
const sub = context.subscriptions[i];
|
|
643
|
-
if (sub && patternMatching(_eventObj, sub.patternCompareFunctions)) {
|
|
644
|
-
try {
|
|
645
|
-
sub.callback(_eventObj);
|
|
646
|
-
} catch (err) {
|
|
647
|
-
adapter.log.error(`Error in callback: ${err}`);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
},
|
|
652
|
-
|
|
653
|
-
fileChange: (id, fileName, size) => {
|
|
654
|
-
// if this file matches any subscriptions
|
|
655
|
-
for (let i = 0, l = context.subscriptionsFile.length; i < l; i++) {
|
|
656
|
-
const sub = context.subscriptionsFile[i];
|
|
657
|
-
if (sub && fileMatching(sub, id, fileName)) {
|
|
658
|
-
try {
|
|
659
|
-
sub.callback(id, fileName, size, sub.withFile);
|
|
660
|
-
} catch (err) {
|
|
661
|
-
adapter.log.error(`Error in callback: ${err}`);
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
},
|
|
666
|
-
|
|
667
|
-
unload: callback => {
|
|
668
|
-
debugStop()
|
|
669
|
-
.then(() => {
|
|
670
|
-
stopTimeSchedules();
|
|
671
|
-
setStateCountCheckInterval && clearInterval(setStateCountCheckInterval);
|
|
672
|
-
stopAllScripts(callback);
|
|
673
|
-
});
|
|
674
|
-
},
|
|
675
|
-
|
|
676
|
-
ready: () => {
|
|
677
|
-
adapter.config.maxSetStatePerMinute = parseInt(adapter.config.maxSetStatePerMinute, 10) || 1000;
|
|
678
|
-
adapter.config.maxTriggersPerScript = parseInt(adapter.config.maxTriggersPerScript, 10) || 100;
|
|
679
|
-
|
|
680
|
-
if (adapter.supportsFeature && adapter.supportsFeature('PLUGINS')) {
|
|
681
|
-
const sentryInstance = adapter.getPluginInstance('sentry');
|
|
682
|
-
if (sentryInstance) {
|
|
683
|
-
const Sentry = sentryInstance.getSentryObject();
|
|
684
|
-
if (Sentry) {
|
|
685
|
-
Sentry.configureScope(scope => {
|
|
686
|
-
scope.addEventProcessor((event, _hint) => {
|
|
687
|
-
if (event.exception && event.exception.values && event.exception.values[0]) {
|
|
688
|
-
const eventData = event.exception.values[0];
|
|
689
|
-
if (eventData.stacktrace && eventData.stacktrace.frames && Array.isArray(eventData.stacktrace.frames) && eventData.stacktrace.frames.length) {
|
|
690
|
-
// Exclude event if script Marker is included
|
|
691
|
-
if (eventData.stacktrace.frames.find(frame => frame.filename && frame.filename.includes(SCRIPT_CODE_MARKER))) {
|
|
692
|
-
return null;
|
|
693
|
-
}
|
|
694
|
-
//Exclude event if own directory is included but not inside own node_modules
|
|
695
|
-
const ownNodeModulesDir = nodePath.join(__dirname, 'node_modules');
|
|
696
|
-
if (!eventData.stacktrace.frames.find(frame => frame.filename && frame.filename.includes(__dirname) && !frame.filename.includes(ownNodeModulesDir))) {
|
|
697
|
-
return null;
|
|
698
|
-
}
|
|
699
|
-
// We have exception data and do not sorted it out, so report it
|
|
700
|
-
return event;
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// No exception in it ... do not report
|
|
705
|
-
return null;
|
|
706
|
-
});
|
|
707
|
-
main();
|
|
708
|
-
});
|
|
709
|
-
} else {
|
|
710
|
-
main();
|
|
711
|
-
}
|
|
712
|
-
} else {
|
|
713
|
-
main();
|
|
714
|
-
}
|
|
715
|
-
} else {
|
|
716
|
-
main();
|
|
717
|
-
}
|
|
718
|
-
},
|
|
719
|
-
|
|
720
|
-
message: obj => {
|
|
721
|
-
if (obj) {
|
|
722
|
-
switch (obj.command) {
|
|
723
|
-
// process messageTo commands
|
|
724
|
-
case 'toScript':
|
|
725
|
-
case 'jsMessageBus':
|
|
726
|
-
if (obj.message && (
|
|
727
|
-
obj.message.instance === null ||
|
|
728
|
-
obj.message.instance === undefined ||
|
|
729
|
-
('javascript.' + obj.message.instance === adapter.namespace) ||
|
|
730
|
-
(obj.message.instance === adapter.namespace)
|
|
731
|
-
)) {
|
|
732
|
-
Object.keys(context.messageBusHandlers).forEach(name => {
|
|
733
|
-
// script name could be script.js.xxx or only xxx
|
|
734
|
-
if ((!obj.message.script || obj.message.script === name) && context.messageBusHandlers[name][obj.message.message]) {
|
|
735
|
-
context.messageBusHandlers[name][obj.message.message].forEach(handler => {
|
|
736
|
-
const sandbox = handler.sandbox;
|
|
737
|
-
|
|
738
|
-
sandbox.verbose && sandbox.log(`onMessage: ${JSON.stringify(obj.message)}`, 'info');
|
|
739
|
-
|
|
740
|
-
try {
|
|
741
|
-
if (obj.callback) {
|
|
742
|
-
handler.cb.call(sandbox, obj.message.data, result => {
|
|
743
|
-
sandbox.verbose && sandbox.log(`onMessage result: ${JSON.stringify(result)}`, 'info');
|
|
744
|
-
|
|
745
|
-
adapter.sendTo(obj.from, obj.command, result, obj.callback);
|
|
746
|
-
});
|
|
747
|
-
} else {
|
|
748
|
-
handler.cb.call(sandbox, obj.message.data, result => {
|
|
749
|
-
sandbox.verbose && sandbox.log(`onMessage result: ${JSON.stringify(result)}`, 'info');
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
} catch (e) {
|
|
753
|
-
adapter.setState('scriptProblem.' + name.substring(SCRIPT_CODE_MARKER.length), true, true);
|
|
754
|
-
context.logError('Error in callback', e);
|
|
755
|
-
}
|
|
756
|
-
});
|
|
757
|
-
}
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
break;
|
|
761
|
-
|
|
762
|
-
case 'loadTypings': { // Load typings for the editor
|
|
763
|
-
const typings = {};
|
|
764
|
-
|
|
765
|
-
// try to load TypeScript lib files from disk
|
|
766
|
-
try {
|
|
767
|
-
const typescriptLibs = resolveTypescriptLibs(targetTsLib);
|
|
768
|
-
Object.assign(typings, typescriptLibs);
|
|
769
|
-
} catch (e) { /* ok, no lib then */
|
|
770
|
-
}
|
|
771
|
-
|
|
772
|
-
// provide the already-loaded ioBroker typings and global script declarations
|
|
773
|
-
Object.assign(typings, tsAmbient);
|
|
774
|
-
|
|
775
|
-
// also provide the known global declarations for each global script
|
|
776
|
-
for (const globalScriptPaths of Object.keys(knownGlobalDeclarationsByScript)) {
|
|
777
|
-
typings[`${globalScriptPaths}.d.ts`] = knownGlobalDeclarationsByScript[globalScriptPaths];
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
if (obj.callback) {
|
|
781
|
-
adapter.sendTo(obj.from, obj.command, {typings}, obj.callback);
|
|
782
|
-
}
|
|
783
|
-
break;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
case 'calcAstroAll': {
|
|
787
|
-
if (obj.message) {
|
|
788
|
-
const sunriseOffset = parseInt(obj.message.sunriseOffset === undefined ? adapter.config.sunriseOffset : obj.message.sunriseOffset, 10) || 0;
|
|
789
|
-
const sunsetOffset = parseInt(obj.message.sunsetOffset === undefined ? adapter.config.sunsetOffset : obj.message.sunsetOffset, 10) || 0;
|
|
790
|
-
const longitude = parseFloat(obj.message.longitude === undefined ? adapter.config.longitude : obj.message.longitude) || 0;
|
|
791
|
-
const latitude = parseFloat(obj.message.latitude === undefined ? adapter.config.latitude : obj.message.latitude) || 0;
|
|
792
|
-
const today = getAstroStartOfDay();
|
|
793
|
-
let astroEvents = {};
|
|
794
|
-
try {
|
|
795
|
-
astroEvents = mods.suncalc.getTimes(today, latitude, longitude);
|
|
796
|
-
} catch (e) {
|
|
797
|
-
adapter.log.error(`Cannot calculate astro data: ${e}`);
|
|
798
|
-
}
|
|
799
|
-
if (astroEvents) {
|
|
800
|
-
try {
|
|
801
|
-
astroEvents.nextSunrise = getAstroEvent(
|
|
802
|
-
today,
|
|
803
|
-
obj.message.sunriseEvent || adapter.config.sunriseEvent,
|
|
804
|
-
obj.message.sunriseLimitStart || adapter.config.sunriseLimitStart,
|
|
805
|
-
obj.message.sunriseLimitEnd || adapter.config.sunriseLimitEnd,
|
|
806
|
-
sunriseOffset,
|
|
807
|
-
false,
|
|
808
|
-
latitude,
|
|
809
|
-
longitude,
|
|
810
|
-
true
|
|
811
|
-
);
|
|
812
|
-
astroEvents.nextSunset = getAstroEvent(
|
|
813
|
-
today,
|
|
814
|
-
obj.message.sunsetEvent || adapter.config.sunsetEvent,
|
|
815
|
-
obj.message.sunsetLimitStart || adapter.config.sunsetLimitStart,
|
|
816
|
-
obj.message.sunsetLimitEnd || adapter.config.sunsetLimitEnd,
|
|
817
|
-
sunsetOffset,
|
|
818
|
-
true,
|
|
819
|
-
latitude,
|
|
820
|
-
longitude,
|
|
821
|
-
true
|
|
822
|
-
);
|
|
823
|
-
} catch (e) {
|
|
824
|
-
adapter.log.error(`Cannot calculate astro data: ${e}`);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
const result = {};
|
|
829
|
-
const keys = Object.keys(astroEvents).sort((a, b) => astroEvents[a] - astroEvents[b]);
|
|
830
|
-
keys.forEach(key => {
|
|
831
|
-
const validDate = astroEvents[key] !== null && !isNaN(astroEvents[key].getTime());
|
|
832
|
-
|
|
833
|
-
result[key] = {
|
|
834
|
-
isValidDate: validDate,
|
|
835
|
-
serverTime: validDate ? formatHoursMinutesSeconds(astroEvents[key]) : 'n/a',
|
|
836
|
-
date: validDate ? astroEvents[key].toISOString() : 'n/a',
|
|
837
|
-
};
|
|
838
|
-
});
|
|
839
|
-
|
|
840
|
-
obj.callback && adapter.sendTo(obj.from, obj.command, result, obj.callback);
|
|
841
|
-
}
|
|
842
|
-
break;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
case 'calcAstro': {
|
|
846
|
-
if (obj.message) {
|
|
847
|
-
const longitude = parseFloat(obj.message.longitude === undefined ? adapter.config.longitude : obj.message.longitude) || 0;
|
|
848
|
-
const latitude = parseFloat(obj.message.latitude === undefined ? adapter.config.latitude : obj.message.latitude) || 0;
|
|
849
|
-
const today = getAstroStartOfDay();
|
|
850
|
-
|
|
851
|
-
const sunriseEvent = obj.message?.sunriseEvent || adapter.config.sunriseEvent;
|
|
852
|
-
const sunriseLimitStart = obj.message?.sunriseLimitStart || adapter.config.sunriseLimitStart;
|
|
853
|
-
const sunriseLimitEnd = obj.message?.sunriseLimitEnd || adapter.config.sunriseLimitEnd;
|
|
854
|
-
const sunriseOffset = parseInt(obj.message.sunriseOffset === undefined ? adapter.config.sunriseOffset : obj.message.sunriseOffset, 10) || 0;
|
|
855
|
-
const nextSunrise = getAstroEvent(
|
|
856
|
-
today,
|
|
857
|
-
sunriseEvent,
|
|
858
|
-
sunriseLimitStart,
|
|
859
|
-
sunriseLimitEnd,
|
|
860
|
-
sunriseOffset,
|
|
861
|
-
false,
|
|
862
|
-
latitude,
|
|
863
|
-
longitude,
|
|
864
|
-
true
|
|
865
|
-
);
|
|
866
|
-
|
|
867
|
-
const sunsetEvent = obj.message?.sunsetEvent || adapter.config.sunsetEvent;
|
|
868
|
-
const sunsetLimitStart = obj.message?.sunsetLimitStart || adapter.config.sunsetLimitStart;
|
|
869
|
-
const sunsetLimitEnd = obj.message?.sunsetLimitEnd || adapter.config.sunsetLimitEnd;
|
|
870
|
-
const sunsetOffset = parseInt(obj.message.sunsetOffset === undefined ? adapter.config.sunsetOffset : obj.message.sunsetOffset, 10) || 0;
|
|
871
|
-
const nextSunset = getAstroEvent(
|
|
872
|
-
today,
|
|
873
|
-
sunsetEvent,
|
|
874
|
-
sunsetLimitStart,
|
|
875
|
-
sunsetLimitEnd,
|
|
876
|
-
sunsetOffset,
|
|
877
|
-
true,
|
|
878
|
-
latitude,
|
|
879
|
-
longitude,
|
|
880
|
-
true
|
|
881
|
-
);
|
|
882
|
-
|
|
883
|
-
const validDateSunrise = nextSunrise !== null && !isNaN(nextSunrise.getTime());
|
|
884
|
-
const validDateSunset = nextSunset !== null && !isNaN(nextSunset.getTime());
|
|
885
|
-
|
|
886
|
-
adapter.log.debug(`calcAstro sunrise: ${sunriseEvent} -> start ${sunriseLimitStart}, end: ${sunriseLimitEnd}, offset: ${sunriseOffset} - ${validDateSunrise ? nextSunrise.toISOString() : 'n/a'}`);
|
|
887
|
-
adapter.log.debug(`calcAstro sunset: ${sunsetEvent} -> start ${sunsetLimitStart}, end: ${sunsetLimitEnd}, offset: ${sunsetOffset} - ${validDateSunset ? nextSunset.toISOString() : 'n/a'}`);
|
|
888
|
-
|
|
889
|
-
obj.callback && adapter.sendTo(obj.from, obj.command, {
|
|
890
|
-
nextSunrise: {
|
|
891
|
-
isValidDate: validDateSunrise,
|
|
892
|
-
serverTime: validDateSunrise ? formatHoursMinutesSeconds(nextSunrise) : 'n/a',
|
|
893
|
-
date: nextSunrise.toISOString(),
|
|
894
|
-
},
|
|
895
|
-
nextSunset: {
|
|
896
|
-
isValidDate: validDateSunset,
|
|
897
|
-
serverTime: validDateSunset ? formatHoursMinutesSeconds(nextSunset) : 'n/a',
|
|
898
|
-
date: nextSunset.toISOString(),
|
|
899
|
-
}
|
|
900
|
-
}, obj.callback);
|
|
901
|
-
}
|
|
902
|
-
break;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
case 'debug': {
|
|
906
|
-
!debugMode && debugStart(obj.message);
|
|
907
|
-
break;
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
case 'debugStop': {
|
|
911
|
-
!debugMode && debugStop()
|
|
912
|
-
.then(() => console.log('stopped'));
|
|
913
|
-
break;
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
case 'rulesOn': {
|
|
917
|
-
context.rulesOpened = obj.message;
|
|
918
|
-
console.log('Enable messaging for ' + context.rulesOpened);
|
|
919
|
-
break;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
case 'rulesOff': {
|
|
923
|
-
// may be if (context.rulesOpened === obj.message)
|
|
924
|
-
console.log('Disable messaging for ' + context.rulesOpened);
|
|
925
|
-
context.rulesOpened = null;
|
|
926
|
-
break;
|
|
927
|
-
}
|
|
928
|
-
|
|
929
|
-
case 'getIoBrokerDataDir': {
|
|
930
|
-
obj.callback && adapter.sendTo(obj.from, obj.command, {
|
|
931
|
-
dataDir: utils.getAbsoluteDefaultDataDir(),
|
|
932
|
-
sep: nodePath.sep
|
|
933
|
-
}, obj.callback);
|
|
934
|
-
break;
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
},
|
|
939
|
-
|
|
940
|
-
/**
|
|
941
|
-
* If the JS-Controller catches an unhandled error, this will be called
|
|
942
|
-
* so we have a chance to handle it ourself.
|
|
943
|
-
* @param {Error} err
|
|
944
|
-
*/
|
|
945
|
-
error: err => {
|
|
946
|
-
// Identify unhandled errors originating from callbacks in scripts
|
|
947
|
-
// These are not caught by wrapping the execution code in try-catch
|
|
948
|
-
if (err && typeof err.stack === 'string') {
|
|
949
|
-
const scriptCodeMarkerIndex = err.stack.indexOf(SCRIPT_CODE_MARKER);
|
|
950
|
-
if (scriptCodeMarkerIndex > -1) {
|
|
951
|
-
// This is a script error
|
|
952
|
-
let scriptName = err.stack.substr(scriptCodeMarkerIndex);
|
|
953
|
-
scriptName = scriptName.substr(0, scriptName.indexOf(':'));
|
|
954
|
-
context.logError(scriptName, err);
|
|
955
|
-
|
|
956
|
-
// Leave the script running for now
|
|
957
|
-
// signal to the JS-Controller that we handled the error ourselves
|
|
958
|
-
return true;
|
|
959
|
-
}
|
|
960
|
-
// check if a path contains adaptername but not own node_module
|
|
961
|
-
// this regex matched "iobroker.javascript/" if NOT followed by "node_modules"
|
|
962
|
-
if (!err.stack.match(/iobroker\.javascript[/\\](?!.*node_modules).*/g)) {
|
|
963
|
-
// This is an error without any info on origin (mostly async errors like connection errors)
|
|
964
|
-
// also consider it as being from a script
|
|
965
|
-
adapter.log.error('An error happened which is most likely from one of your scripts, but the originating script could not be detected.');
|
|
966
|
-
adapter.log.error('Error: ' + err.message);
|
|
967
|
-
adapter.log.error(err.stack);
|
|
968
|
-
|
|
969
|
-
// signal to the JS-Controller that we handled the error ourselves
|
|
970
|
-
return true;
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
}
|
|
974
|
-
});
|
|
975
|
-
|
|
976
|
-
adapter = new utils.Adapter(options);
|
|
977
|
-
|
|
978
|
-
// handler for logs
|
|
979
|
-
adapter.on('log', msg =>
|
|
980
|
-
Object.keys(context.logSubscriptions).forEach(name =>
|
|
981
|
-
context.logSubscriptions[name].forEach(handler => {
|
|
982
|
-
if (typeof handler.cb === 'function' && (handler.severity === '*' || handler.severity === msg.severity)) {
|
|
983
|
-
handler.sandbox.logHandler = handler.severity || '*';
|
|
984
|
-
handler.cb.call(handler.sandbox, msg);
|
|
985
|
-
handler.sandbox.logHandler = null;
|
|
986
|
-
}
|
|
987
|
-
})));
|
|
988
|
-
|
|
989
|
-
context.adapter = adapter;
|
|
990
|
-
|
|
991
|
-
return adapter;
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
function updateObjectContext(id, obj) {
|
|
995
|
-
if (obj) {
|
|
996
|
-
// add state to state ID's list
|
|
997
|
-
if (obj.type === 'state') {
|
|
998
|
-
if (!context.stateIds.includes(id)) {
|
|
999
|
-
context.stateIds.push(id);
|
|
1000
|
-
context.stateIds.sort();
|
|
1001
|
-
}
|
|
1002
|
-
if (context.devices && context.channels) {
|
|
1003
|
-
const parts = id.split('.');
|
|
1004
|
-
parts.pop();
|
|
1005
|
-
const chn = parts.join('.');
|
|
1006
|
-
context.channels[chn] = context.channels[chn] || [];
|
|
1007
|
-
context.channels[chn].push(id);
|
|
1008
|
-
|
|
1009
|
-
parts.pop();
|
|
1010
|
-
const dev = parts.join('.');
|
|
1011
|
-
context.devices[dev] = context.devices[dev] || [];
|
|
1012
|
-
context.devices[dev].push(id);
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
} else {
|
|
1016
|
-
// delete object from state ID's list
|
|
1017
|
-
const pos = context.stateIds.indexOf(id);
|
|
1018
|
-
pos !== -1 && context.stateIds.splice(pos, 1);
|
|
1019
|
-
if (context.devices && context.channels) {
|
|
1020
|
-
const parts = id.split('.');
|
|
1021
|
-
parts.pop();
|
|
1022
|
-
const chn = parts.join('.');
|
|
1023
|
-
if (context.channels[chn]) {
|
|
1024
|
-
const posChn = context.channels[chn].indexOf(id);
|
|
1025
|
-
posChn !== -1 && context.channels[chn].splice(posChn, 1);
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
parts.pop();
|
|
1029
|
-
const dev = parts.join('.');
|
|
1030
|
-
if (context.devices[dev]) {
|
|
1031
|
-
const posDev = context.devices[dev].indexOf(id);
|
|
1032
|
-
posDev !== -1 && context.devices[dev].splice(posDev, 1);
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
|
|
1036
|
-
delete context.folderCreationVerifiedObjects[id];
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
if (!obj && context.objects[id]) {
|
|
1040
|
-
// objects was deleted
|
|
1041
|
-
removeFromNames(id);
|
|
1042
|
-
delete context.objects[id];
|
|
1043
|
-
} else if (obj && !context.objects[id]) {
|
|
1044
|
-
// object was added
|
|
1045
|
-
context.objects[id] = obj;
|
|
1046
|
-
addToNames(obj);
|
|
1047
|
-
} else if (obj && context.objects[id].common) {
|
|
1048
|
-
// Object just changed
|
|
1049
|
-
context.objects[id] = obj;
|
|
1050
|
-
|
|
1051
|
-
const n = getName(id);
|
|
1052
|
-
let nn = context.objects[id].common ? context.objects[id].common.name : '';
|
|
1053
|
-
|
|
1054
|
-
if (nn && typeof nn === 'object') {
|
|
1055
|
-
nn = nn[words.getLanguage()] || nn.en;
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
if (n !== nn) {
|
|
1059
|
-
if (n) {
|
|
1060
|
-
removeFromNames(id);
|
|
1061
|
-
}
|
|
1062
|
-
if (nn) {
|
|
1063
|
-
addToNames(obj);
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
function main() {
|
|
1070
|
-
!debugMode && patchFont()
|
|
1071
|
-
.then(patched => patched && adapter.log.debug('Font patched'));
|
|
1072
|
-
|
|
1073
|
-
adapter.log.debug(`config.subscribe (Do not subscribe all states on start): ${adapter.config.subscribe}`);
|
|
1074
|
-
|
|
1075
|
-
// correct jsonConfig for admin
|
|
1076
|
-
adapter.getForeignObject(`system.adapter.${adapter.namespace}`, (err, obj) => {
|
|
1077
|
-
if (obj && obj.common) {
|
|
1078
|
-
if (obj.common.adminUI?.config !== 'json') {
|
|
1079
|
-
obj.common.adminUI = obj.common.adminUI || {};
|
|
1080
|
-
obj.common.adminUI.config = 'json';
|
|
1081
|
-
adapter.setForeignObject(obj._id, obj);
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
});
|
|
1085
|
-
|
|
1086
|
-
// todo
|
|
1087
|
-
context.errorLogFunction = webstormDebug ? console : adapter.log;
|
|
1088
|
-
activeStr = `${adapter.namespace}.scriptEnabled.`;
|
|
1089
|
-
|
|
1090
|
-
mods.fs = new require('./lib/protectFs')(adapter.log, utils.getAbsoluteDefaultDataDir());
|
|
1091
|
-
mods['fs/promises'] = mods.fs.promises; // to avoid require('fs/promises');
|
|
1092
|
-
|
|
1093
|
-
// try to read TS declarations
|
|
1094
|
-
try {
|
|
1095
|
-
tsAmbient = {
|
|
1096
|
-
'javascript.d.ts': nodeFS.readFileSync(mods.path.join(__dirname, 'lib/javascript.d.ts'), 'utf8')
|
|
1097
|
-
};
|
|
1098
|
-
tsServer.provideAmbientDeclarations(tsAmbient);
|
|
1099
|
-
jsDeclarationServer.provideAmbientDeclarations(tsAmbient);
|
|
1100
|
-
} catch (e) {
|
|
1101
|
-
adapter.log.warn(`Could not read TypeScript ambient declarations: ${e.message}`);
|
|
1102
|
-
// This should not happen, so send a error report to Sentry
|
|
1103
|
-
if (adapter.supportsFeature && adapter.supportsFeature('PLUGINS')) {
|
|
1104
|
-
const sentryInstance = adapter.getPluginInstance('sentry');
|
|
1105
|
-
if (sentryInstance) {
|
|
1106
|
-
const sentryObject = sentryInstance.getSentryObject();
|
|
1107
|
-
if (sentryObject) sentryObject.captureException(e);
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
// Keep the adapter from crashing when the included typings cannot be read
|
|
1111
|
-
tsAmbient = {};
|
|
1112
|
-
}
|
|
1113
|
-
|
|
1114
|
-
context.logWithLineInfo = function (level, msg) {
|
|
1115
|
-
if (msg === undefined) {
|
|
1116
|
-
return context.logWithLineInfo('info', msg);
|
|
1117
|
-
}
|
|
1118
|
-
|
|
1119
|
-
context.errorLogFunction && context.errorLogFunction[level](msg);
|
|
1120
|
-
|
|
1121
|
-
const stack = (new Error().stack).split('\n');
|
|
1122
|
-
|
|
1123
|
-
for (let i = 3; i < stack.length; i++) {
|
|
1124
|
-
if (!stack[i]) {
|
|
1125
|
-
continue;
|
|
1126
|
-
}
|
|
1127
|
-
if (stack[i].match(/runInContext|runInNewContext|javascript\.js:/)) {
|
|
1128
|
-
break;
|
|
1129
|
-
}
|
|
1130
|
-
context.errorLogFunction && context.errorLogFunction[level](fixLineNo(stack[i]));
|
|
1131
|
-
}
|
|
1132
|
-
};
|
|
1133
|
-
|
|
1134
|
-
context.logWithLineInfo.warn = context.logWithLineInfo.bind(1, 'warn');
|
|
1135
|
-
context.logWithLineInfo.error = context.logWithLineInfo.bind(1, 'error');
|
|
1136
|
-
context.logWithLineInfo.info = context.logWithLineInfo.bind(1, 'info');
|
|
1137
|
-
|
|
1138
|
-
installLibraries().then(() => {
|
|
1139
|
-
|
|
1140
|
-
// Load the TS declarations for Node.js and all 3rd party modules
|
|
1141
|
-
loadTypeScriptDeclarations();
|
|
1142
|
-
|
|
1143
|
-
getData(() => {
|
|
1144
|
-
context.scheduler = new Scheduler(adapter.log, Date, mods.suncalc, adapter.config.latitude, adapter.config.longitude);
|
|
1145
|
-
dayTimeSchedules(adapter, context);
|
|
1146
|
-
sunTimeSchedules(adapter, context);
|
|
1147
|
-
timeSchedule(adapter, context);
|
|
1148
|
-
|
|
1149
|
-
// Warning. It could have a side-effect in compact mode, so all adapters will accept self signed certificates
|
|
1150
|
-
if (adapter.config.allowSelfSignedCerts) {
|
|
1151
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
adapter.getObjectView('script', 'javascript', {}, async (err, doc) => {
|
|
1155
|
-
globalScript = '';
|
|
1156
|
-
globalDeclarations = '';
|
|
1157
|
-
knownGlobalDeclarationsByScript = {};
|
|
1158
|
-
if (doc && doc.rows && doc.rows.length) {
|
|
1159
|
-
// assemble global script
|
|
1160
|
-
for (let g = 0; g < doc.rows.length; g++) {
|
|
1161
|
-
const obj = doc.rows[g].value;
|
|
1162
|
-
if (checkIsGlobal(obj)) {
|
|
1163
|
-
if (obj && obj.common) {
|
|
1164
|
-
const engineType = (obj.common.engineType || '').toLowerCase();
|
|
1165
|
-
|
|
1166
|
-
if (obj.common.enabled) {
|
|
1167
|
-
if (engineType.startsWith('typescript')) {
|
|
1168
|
-
// TypeScript
|
|
1169
|
-
adapter.log.info(`${obj._id}: compiling TypeScript source...`);
|
|
1170
|
-
// In order to compile global TypeScript, we need to do some transformations
|
|
1171
|
-
// 1. For top-level-await, some statements must be wrapped in an immediately-invoked async function
|
|
1172
|
-
// 2. If any global script uses `import`, the declarations are no longer visible if they are not exported with `declare global`
|
|
1173
|
-
const transformedSource = transformScriptBeforeCompilation(obj.common.source, true);
|
|
1174
|
-
// The source code must be transformed in order to support top level await
|
|
1175
|
-
// Global scripts must not be treated as a module, otherwise their methods
|
|
1176
|
-
// cannot be found by the normal scripts
|
|
1177
|
-
// We need to hash both global declarations that are known until now
|
|
1178
|
-
// AND the script source, because changing either can change the compilation output
|
|
1179
|
-
const sourceHash = hashSource(tsSourceHashBase + globalDeclarations + transformedSource);
|
|
1180
|
-
|
|
1181
|
-
/** @type {string | undefined} */
|
|
1182
|
-
let compiled;
|
|
1183
|
-
/** @type {string | undefined} */
|
|
1184
|
-
let declarations;
|
|
1185
|
-
// If we already stored the compiled source code and the original source hash,
|
|
1186
|
-
// use the hash to check whether we can rely on the compiled source code or
|
|
1187
|
-
// if we need to compile it again
|
|
1188
|
-
if (
|
|
1189
|
-
typeof obj.common.compiled === 'string'
|
|
1190
|
-
&& typeof obj.common.sourceHash === 'string'
|
|
1191
|
-
&& sourceHash === obj.common.sourceHash
|
|
1192
|
-
) {
|
|
1193
|
-
// We can reuse the stored source
|
|
1194
|
-
compiled = obj.common.compiled;
|
|
1195
|
-
declarations = obj.common.declarations;
|
|
1196
|
-
adapter.log.info(`${obj._id}: source code did not change, using cached compilation result...`);
|
|
1197
|
-
} else {
|
|
1198
|
-
// We don't have a hashed source code or the original source changed, compile it
|
|
1199
|
-
const filename = scriptIdToTSFilename(obj._id);
|
|
1200
|
-
let tsCompiled;
|
|
1201
|
-
try {
|
|
1202
|
-
tsCompiled = tsServer.compile(filename, transformedSource);
|
|
1203
|
-
} catch (e) {
|
|
1204
|
-
adapter.log.error(`${obj._id}: TypeScript compilation failed:\n${e}`);
|
|
1205
|
-
continue;
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
const errors = tsCompiled.diagnostics.map(diag => diag.annotatedSource + '\n').join('\n');
|
|
1209
|
-
|
|
1210
|
-
if (tsCompiled.success) {
|
|
1211
|
-
if (errors.length > 0) {
|
|
1212
|
-
adapter.log.warn(`${obj._id}: TypeScript compilation completed with errors:\n${errors}`);
|
|
1213
|
-
} else {
|
|
1214
|
-
adapter.log.info(`${obj._id}: TypeScript compilation successful`);
|
|
1215
|
-
}
|
|
1216
|
-
compiled = tsCompiled.result;
|
|
1217
|
-
// Global scripts that have been transformed to support `import` need to have their declarations transformed aswell
|
|
1218
|
-
declarations = transformGlobalDeclarations(tsCompiled.declarations || '');
|
|
1219
|
-
|
|
1220
|
-
const newCommon = {
|
|
1221
|
-
sourceHash,
|
|
1222
|
-
compiled,
|
|
1223
|
-
};
|
|
1224
|
-
if (declarations) newCommon.declarations = declarations;
|
|
1225
|
-
|
|
1226
|
-
// Store the compiled source and the original source hash, so we don't need to do the work again next time
|
|
1227
|
-
ignoreObjectChange.add(obj._id); // ignore the next change and don't restart scripts
|
|
1228
|
-
adapter.extendForeignObject(obj._id, {
|
|
1229
|
-
common: newCommon
|
|
1230
|
-
});
|
|
1231
|
-
} else {
|
|
1232
|
-
adapter.log.error(`${obj._id}: TypeScript compilation failed:\n${errors}`);
|
|
1233
|
-
continue;
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
globalScript += compiled + '\n';
|
|
1237
|
-
// if declarations were generated, remember them
|
|
1238
|
-
if (declarations != null) {
|
|
1239
|
-
provideDeclarationsForGlobalScript(obj._id, declarations);
|
|
1240
|
-
}
|
|
1241
|
-
} else { // javascript
|
|
1242
|
-
const sourceCode = obj.common.source;
|
|
1243
|
-
globalScript += sourceCode + '\n';
|
|
1244
|
-
|
|
1245
|
-
// try to compile the declarations so TypeScripts can use
|
|
1246
|
-
// functions defined in global JavaScripts
|
|
1247
|
-
const filename = scriptIdToTSFilename(obj._id);
|
|
1248
|
-
let tsCompiled;
|
|
1249
|
-
try {
|
|
1250
|
-
tsCompiled = jsDeclarationServer.compile(filename, sourceCode);
|
|
1251
|
-
} catch (e) {
|
|
1252
|
-
adapter.log.warn(`${obj._id}: Error while generating type declarations, skipping:\n${e}`);
|
|
1253
|
-
continue;
|
|
1254
|
-
}
|
|
1255
|
-
// if declarations were generated, remember them
|
|
1256
|
-
if (tsCompiled.success && tsCompiled.declarations != null) {
|
|
1257
|
-
provideDeclarationsForGlobalScript(obj._id, tsCompiled.declarations);
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
}
|
|
1262
|
-
}
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
globalScript = globalScript.replace(/\r\n/g, '\n');
|
|
1268
|
-
globalScriptLines = globalScript.split(/\n/g).length - 1;
|
|
1269
|
-
|
|
1270
|
-
if (doc && doc.rows && doc.rows.length) {
|
|
1271
|
-
// load all scripts
|
|
1272
|
-
for (let i = 0; i < doc.rows.length; i++) {
|
|
1273
|
-
if (!checkIsGlobal(doc.rows[i].value)) {
|
|
1274
|
-
load(doc.rows[i].value);
|
|
1275
|
-
}
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
if (adapter.config.mirrorPath) {
|
|
1280
|
-
adapter.config.mirrorInstance = parseInt(adapter.config.mirrorInstance, 10) || 0;
|
|
1281
|
-
if (adapter.instance === adapter.config.mirrorInstance) {
|
|
1282
|
-
const ioBDataDir = utils.getAbsoluteDefaultDataDir() + nodePath.sep;
|
|
1283
|
-
adapter.config.mirrorPath = nodePath.normalize(adapter.config.mirrorPath);
|
|
1284
|
-
let mirrorForbidden = false;
|
|
1285
|
-
for (let dir of forbiddenMirrorLocations) {
|
|
1286
|
-
dir = nodePath.join(ioBDataDir, dir) + nodePath.sep;
|
|
1287
|
-
if (dir.includes(adapter.config.mirrorPath) || adapter.config.mirrorPath.startsWith(dir)) {
|
|
1288
|
-
adapter.log.error(`The Mirror directory is not allowed to be a central ioBroker directory!`);
|
|
1289
|
-
adapter.log.error(`Directory ${adapter.config.mirrorPath} is not allowed to mirror files!`);
|
|
1290
|
-
mirrorForbidden = true;
|
|
1291
|
-
break;
|
|
1292
|
-
}
|
|
1293
|
-
}
|
|
1294
|
-
if (!mirrorForbidden) {
|
|
1295
|
-
mirror = new Mirror({
|
|
1296
|
-
adapter,
|
|
1297
|
-
log: adapter.log,
|
|
1298
|
-
diskRoot: adapter.config.mirrorPath
|
|
1299
|
-
});
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
// CHeck setState counter per minute and stop script if too high
|
|
1305
|
-
setStateCountCheckInterval = setInterval(() => {
|
|
1306
|
-
Object.keys(context.scripts).forEach(id => {
|
|
1307
|
-
if (!context.scripts[id]) return;
|
|
1308
|
-
const currentSetStatePerMinuteCounter = context.scripts[id].setStatePerMinuteCounter;
|
|
1309
|
-
context.scripts[id].setStatePerMinuteCounter = 0;
|
|
1310
|
-
if (currentSetStatePerMinuteCounter > adapter.config.maxSetStatePerMinute) {
|
|
1311
|
-
context.scripts[id].setStatePerMinuteProblemCounter++;
|
|
1312
|
-
adapter.log.debug(`Script ${id} has reached the maximum of ${adapter.config.maxSetStatePerMinute} setState calls per minute in ${context.scripts[id].setStatePerMinuteProblemCounter} consecutive minutes`);
|
|
1313
|
-
// Allow "too high counters" for 1 minute for script starts or such and only
|
|
1314
|
-
// stop the script when lasts longer
|
|
1315
|
-
if (context.scripts[id].setStatePerMinuteProblemCounter > 1) {
|
|
1316
|
-
adapter.log.error(`Script ${id} is calling setState more than ${adapter.config.maxSetStatePerMinute} times per minute! Stopping Script now! Please check your script!`);
|
|
1317
|
-
stop(id);
|
|
1318
|
-
}
|
|
1319
|
-
} else if (context.scripts[id].setStatePerMinuteProblemCounter > 0) {
|
|
1320
|
-
context.scripts[id].setStatePerMinuteProblemCounter--;
|
|
1321
|
-
adapter.log.debug(`Script ${id} has NOT reached the maximum of ${adapter.config.maxSetStatePerMinute} setState calls per minute. Decrease problem counter to ${context.scripts[id].setStatePerMinuteProblemCounter}`);
|
|
1322
|
-
}
|
|
1323
|
-
});
|
|
1324
|
-
}, 60000);
|
|
1325
|
-
|
|
1326
|
-
});
|
|
1327
|
-
});
|
|
1328
|
-
});
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
function stopAllScripts(cb) {
|
|
1332
|
-
Object.keys(context.scripts).forEach(id => stop(id));
|
|
1333
|
-
setTimeout(() => cb(), 0);
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
let globalScript = '';
|
|
1337
|
-
/** Generated declarations for global TypeScripts */
|
|
1338
|
-
let globalDeclarations = '';
|
|
1339
|
-
// Remember which definitions the global scripts
|
|
1340
|
-
// have access to, because it depends on the compile order
|
|
1341
|
-
let knownGlobalDeclarationsByScript = {};
|
|
1342
|
-
let globalScriptLines = 0;
|
|
1343
|
-
// let activeRegEx = null;
|
|
1344
|
-
let activeStr = ''; // enabled state prefix
|
|
1345
|
-
let dayScheduleTimer = null; // schedule for astrological day
|
|
1346
|
-
let sunScheduleTimer = null; // schedule for sun moment times
|
|
1347
|
-
let timeScheduleTimer = null; // schedule for astrological day
|
|
1348
|
-
|
|
1349
|
-
function getNextTimeEvent(time, useNextDay) {
|
|
1350
|
-
const now = getAstroStartOfDay();
|
|
1351
|
-
let [timeHours, timeMinutes] = time.split(':');
|
|
1352
|
-
timeHours = parseInt(timeHours, 10);
|
|
1353
|
-
timeMinutes = parseInt(timeMinutes, 10);
|
|
1354
|
-
if (useNextDay && (now.getHours() > timeHours || (now.getHours() === timeHours && now.getMinutes() > timeMinutes))) {
|
|
1355
|
-
now.setDate(now.getDate() + 1);
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
now.setHours(timeHours);
|
|
1359
|
-
now.setMinutes(timeMinutes);
|
|
1360
|
-
|
|
1361
|
-
return now;
|
|
1362
|
-
}
|
|
1363
|
-
|
|
1364
|
-
function getAstroEvent(date, astroEvent, start, end, offsetMinutes, isDayEnd, latitude, longitude, useNextDay) {
|
|
1365
|
-
let ts = mods.suncalc.getTimes(date, latitude, longitude)[astroEvent];
|
|
1366
|
-
if (!ts || ts.getTime().toString() === 'NaN') {
|
|
1367
|
-
ts = isDayEnd ? getNextTimeEvent(end, useNextDay) : getNextTimeEvent(start, useNextDay);
|
|
1368
|
-
}
|
|
1369
|
-
ts.setMilliseconds(0);
|
|
1370
|
-
ts.setMinutes(ts.getMinutes() + (parseInt(offsetMinutes, 10) || 0));
|
|
1371
|
-
|
|
1372
|
-
let [timeHoursStart, timeMinutesStart] = start.split(':');
|
|
1373
|
-
timeHoursStart = parseInt(timeHoursStart, 10);
|
|
1374
|
-
timeMinutesStart = parseInt(timeMinutesStart, 10) || 0;
|
|
1375
|
-
|
|
1376
|
-
if (ts.getHours() < timeHoursStart || (ts.getHours() === timeHoursStart && ts.getMinutes() < timeMinutesStart)) {
|
|
1377
|
-
ts = getNextTimeEvent(start, useNextDay);
|
|
1378
|
-
ts.setSeconds(0);
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
let [timeHoursEnd, timeMinutesEnd] = end.split(':');
|
|
1382
|
-
timeHoursEnd = parseInt(timeHoursEnd, 10);
|
|
1383
|
-
timeMinutesEnd = parseInt(timeMinutesEnd, 10) || 0;
|
|
1384
|
-
|
|
1385
|
-
if (ts.getHours() > timeHoursEnd || (ts.getHours() === timeHoursEnd && ts.getMinutes() > timeMinutesEnd)) {
|
|
1386
|
-
ts = getNextTimeEvent(end, useNextDay);
|
|
1387
|
-
ts.setSeconds(0);
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
// if event in the past
|
|
1391
|
-
if (date > ts && useNextDay) {
|
|
1392
|
-
// take the next day
|
|
1393
|
-
ts.setDate(ts.getDate() + 1);
|
|
1394
|
-
}
|
|
1395
|
-
return ts;
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
function timeSchedule(adapter, context) {
|
|
1399
|
-
const now = new Date();
|
|
1400
|
-
let hours = now.getHours();
|
|
1401
|
-
const minutes = now.getMinutes();
|
|
1402
|
-
if (context.timeSettings.format12) {
|
|
1403
|
-
if (hours > 12) {
|
|
1404
|
-
hours -= 12;
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
if (context.timeSettings.leadingZeros) {
|
|
1408
|
-
hours = hours.toString().padStart(2, '0');
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
adapter.setState('variables.dayTime', {val: `${hours}:${minutes.toString().padStart(2, '0')}`, ack: true});
|
|
1412
|
-
|
|
1413
|
-
now.setMinutes(now.getMinutes() + 1);
|
|
1414
|
-
now.setSeconds(0);
|
|
1415
|
-
now.setMilliseconds(0);
|
|
1416
|
-
const interval = now.getTime() - Date.now();
|
|
1417
|
-
timeScheduleTimer = setTimeout(timeSchedule, interval, adapter, context);
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
function dayTimeSchedules(adapter, context) {
|
|
1421
|
-
// get astrological event
|
|
1422
|
-
if (adapter.config.latitude === undefined || adapter.config.longitude === undefined ||
|
|
1423
|
-
adapter.config.latitude === '' || adapter.config.longitude === '' ||
|
|
1424
|
-
adapter.config.latitude === null || adapter.config.longitude === null) {
|
|
1425
|
-
adapter.log.error('Longitude or latitude does not set. Cannot use astro.');
|
|
1426
|
-
return;
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
// Calculate next event today
|
|
1430
|
-
const todayDate = getAstroStartOfDay();
|
|
1431
|
-
const nowDate = new Date();
|
|
1432
|
-
|
|
1433
|
-
const todaySunrise = getAstroEvent(todayDate, adapter.config.sunriseEvent, adapter.config.sunriseLimitStart, adapter.config.sunriseLimitEnd, adapter.config.sunriseOffset, false, adapter.config.latitude, adapter.config.longitude);
|
|
1434
|
-
const todaySunset = getAstroEvent(todayDate, adapter.config.sunsetEvent, adapter.config.sunsetLimitStart, adapter.config.sunsetLimitEnd, adapter.config.sunsetOffset, true, adapter.config.latitude, adapter.config.longitude);
|
|
1435
|
-
|
|
1436
|
-
// Sunrise
|
|
1437
|
-
let sunriseTimeout = todaySunrise.getTime() - nowDate.getTime();
|
|
1438
|
-
if (sunriseTimeout < 0 || sunriseTimeout > 3600000) {
|
|
1439
|
-
sunriseTimeout = 3600000;
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
// Sunset
|
|
1443
|
-
let sunsetTimeout = todaySunset.getTime() - nowDate.getTime();
|
|
1444
|
-
if (sunsetTimeout < 0 || sunsetTimeout > 3600000) {
|
|
1445
|
-
sunsetTimeout = 3600000;
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
adapter.getState('variables.isDayTime', (err, state) => {
|
|
1449
|
-
let isDay;
|
|
1450
|
-
if (sunriseTimeout < 5000) {
|
|
1451
|
-
isDay = true;
|
|
1452
|
-
} else if (sunsetTimeout < 5000) {
|
|
1453
|
-
isDay = false;
|
|
1454
|
-
} else {
|
|
1455
|
-
// check if in between
|
|
1456
|
-
isDay = nowDate.getTime() > (todaySunrise.getTime() - 60000) && nowDate <= todaySunset;
|
|
1457
|
-
}
|
|
1458
|
-
|
|
1459
|
-
const val = state ? !!state.val : false;
|
|
1460
|
-
if (val !== isDay || state === null) {
|
|
1461
|
-
adapter.setState('variables.isDayTime', {val: isDay, ack: true});
|
|
1462
|
-
}
|
|
1463
|
-
});
|
|
1464
|
-
|
|
1465
|
-
adapter.getState('variables.isDaylightSaving', (err, state) => {
|
|
1466
|
-
const isDayLightSaving = dstOffsetAtDate(nowDate) !== 0;
|
|
1467
|
-
const val = state ? !!state.val : false;
|
|
1468
|
-
|
|
1469
|
-
if (val !== isDayLightSaving || state === null) {
|
|
1470
|
-
adapter.setState('variables.isDaylightSaving', {val: isDayLightSaving, ack: true});
|
|
1471
|
-
}
|
|
1472
|
-
});
|
|
1473
|
-
|
|
1474
|
-
let nextTimeout = sunriseTimeout;
|
|
1475
|
-
if (sunriseTimeout > sunsetTimeout) {
|
|
1476
|
-
nextTimeout = sunsetTimeout;
|
|
1477
|
-
}
|
|
1478
|
-
nextTimeout = nextTimeout - 3000;
|
|
1479
|
-
if (nextTimeout < 3000) {
|
|
1480
|
-
nextTimeout = 3000;
|
|
1481
|
-
}
|
|
1482
|
-
|
|
1483
|
-
dayScheduleTimer = setTimeout(dayTimeSchedules, nextTimeout, adapter, context);
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
function getAstroStartOfDay() {
|
|
1487
|
-
const d = new Date();
|
|
1488
|
-
d.setMinutes(0);
|
|
1489
|
-
d.setSeconds(0);
|
|
1490
|
-
d.setMilliseconds(0);
|
|
1491
|
-
d.setTime(d.getTime() - (d.getTimezoneOffset() * 60 * 1000));
|
|
1492
|
-
d.setUTCHours(0);
|
|
1493
|
-
|
|
1494
|
-
return d;
|
|
1495
|
-
}
|
|
1496
|
-
|
|
1497
|
-
function formatHoursMinutesSeconds(date) {
|
|
1498
|
-
const h = String(date.getHours());
|
|
1499
|
-
const m = String(date.getMinutes());
|
|
1500
|
-
const s = String(date.getSeconds());
|
|
1501
|
-
|
|
1502
|
-
return `${h.padStart(2, '0')}:${m.padStart(2, '0')}:${s.padStart(2, '0')}`;
|
|
1503
|
-
}
|
|
1504
|
-
|
|
1505
|
-
async function sunTimeSchedules(adapter, context) {
|
|
1506
|
-
if (adapter.config.createAstroStates) {
|
|
1507
|
-
if (!isNaN(adapter.config.longitude) && !isNaN(adapter.config.longitude)) {
|
|
1508
|
-
const calcDate = getAstroStartOfDay();
|
|
1509
|
-
|
|
1510
|
-
const times = mods.suncalc.getTimes(calcDate, adapter.config.latitude, adapter.config.longitude);
|
|
1511
|
-
|
|
1512
|
-
adapter.log.debug(`[sunTimeSchedules] Times: ${JSON.stringify(times)}`);
|
|
1513
|
-
|
|
1514
|
-
for (const t in times) {
|
|
1515
|
-
try {
|
|
1516
|
-
const objId = `variables.astro.${t}`;
|
|
1517
|
-
|
|
1518
|
-
await adapter.setObjectNotExistsAsync(objId, {
|
|
1519
|
-
type: 'state',
|
|
1520
|
-
common: {
|
|
1521
|
-
name: `Astro ${t}`,
|
|
1522
|
-
type: 'string',
|
|
1523
|
-
role: 'value',
|
|
1524
|
-
read: true,
|
|
1525
|
-
write: false,
|
|
1526
|
-
},
|
|
1527
|
-
native: {},
|
|
1528
|
-
});
|
|
1529
|
-
|
|
1530
|
-
if (times[t] !== null && !isNaN(times[t].getTime())) {
|
|
1531
|
-
const timeFormatted = formatHoursMinutesSeconds(times[t]);
|
|
1532
|
-
await adapter.setStateAsync(objId, { val: timeFormatted, c: times[t].toISOString(), ack: true });
|
|
1533
|
-
} else {
|
|
1534
|
-
await adapter.setStateAsync(objId, { val: null, c: 'n/a', ack: true, q: 0x01 });
|
|
1535
|
-
}
|
|
1536
|
-
} catch (err) {
|
|
1537
|
-
adapter.log.error(`[sunTimeSchedules] Unable to set state for astro time "${t}" (${times[t].getTime()}): ${err}`);
|
|
1538
|
-
}
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1541
|
-
const todayDate = new Date();
|
|
1542
|
-
todayDate.setHours(0);
|
|
1543
|
-
todayDate.setMinutes(0);
|
|
1544
|
-
todayDate.setSeconds(1);
|
|
1545
|
-
todayDate.setMilliseconds(0);
|
|
1546
|
-
todayDate.setDate(todayDate.getDate() + 1);
|
|
1547
|
-
|
|
1548
|
-
adapter.log.debug(`[sunTimeSchedules] Next: ${todayDate.toISOString()}`);
|
|
1549
|
-
sunScheduleTimer = setTimeout(sunTimeSchedules, todayDate.getTime() - Date.now(), adapter, context);
|
|
1550
|
-
}
|
|
1551
|
-
} else {
|
|
1552
|
-
// remove astro states if disabled
|
|
1553
|
-
adapter.delObject('variables.astro', { recursive: true });
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
function stopTimeSchedules() {
|
|
1558
|
-
dayScheduleTimer && clearTimeout(dayScheduleTimer);
|
|
1559
|
-
sunScheduleTimer && clearTimeout(sunScheduleTimer);
|
|
1560
|
-
timeScheduleTimer && clearTimeout(timeScheduleTimer);
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
/**
|
|
1564
|
-
* Redirects the virtual-tsc log output to the ioBroker log
|
|
1565
|
-
* @param {string} msg message
|
|
1566
|
-
* @param {string} sev severity (info, silly, debug, warn, error)
|
|
1567
|
-
*/
|
|
1568
|
-
function tsLog(msg, sev) {
|
|
1569
|
-
// shift the severities around, we don't care about the small details
|
|
1570
|
-
if (sev == null || sev === 'info') {
|
|
1571
|
-
sev = 'debug';
|
|
1572
|
-
} else if (sev === 'debug') {
|
|
1573
|
-
// Don't spam build logs on Travis
|
|
1574
|
-
if (isCI) return;
|
|
1575
|
-
sev = 'silly';
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
if (adapter && adapter.log) {
|
|
1579
|
-
adapter.log[sev](msg);
|
|
1580
|
-
} else {
|
|
1581
|
-
console.log(`[${sev.toUpperCase()}] ${msg}`);
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
// Due to a npm bug, virtual-tsc may be hoisted to the top level node_modules but
|
|
1585
|
-
// typescript may still be in the adapter level (https://npm.community/t/packages-with-peerdependencies-are-incorrectly-hoisted/4794),
|
|
1586
|
-
// so we need to tell virtual-tsc where typescript is
|
|
1587
|
-
tsc.setTypeScriptResolveOptions({
|
|
1588
|
-
paths: [require.resolve('typescript')],
|
|
1589
|
-
});
|
|
1590
|
-
// compiler instance for typescript
|
|
1591
|
-
/** @type {tsc.Server} */
|
|
1592
|
-
const tsServer = new tsc.Server(tsCompilerOptions, tsLog);
|
|
1593
|
-
|
|
1594
|
-
// compiler instance for global JS declarations
|
|
1595
|
-
/** @type {tsc.Server} */
|
|
1596
|
-
const jsDeclarationServer = new tsc.Server(
|
|
1597
|
-
jsDeclarationCompilerOptions,
|
|
1598
|
-
isCI ? false : undefined
|
|
1599
|
-
);
|
|
1600
|
-
|
|
1601
|
-
function addGetProperty(object) {
|
|
1602
|
-
try {
|
|
1603
|
-
Object.defineProperty(object, 'get', {
|
|
1604
|
-
value: function (id) {
|
|
1605
|
-
return this[id] || this[adapter.namespace + '.' + id];
|
|
1606
|
-
},
|
|
1607
|
-
enumerable: false
|
|
1608
|
-
});
|
|
1609
|
-
} catch (e) {
|
|
1610
|
-
console.error('Cannot install get property');
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
|
|
1614
|
-
function fixLineNo(line) {
|
|
1615
|
-
if (line.includes('javascript.js:')) {
|
|
1616
|
-
return line;
|
|
1617
|
-
}
|
|
1618
|
-
if (!/script[s]?\.js[.\\/]/.test(line)) {
|
|
1619
|
-
return line;
|
|
1620
|
-
}
|
|
1621
|
-
if (/:([\d]+):/.test(line)) {
|
|
1622
|
-
line = line.replace(/:([\d]+):/, ($0, $1) =>
|
|
1623
|
-
':' + ($1 > globalScriptLines + 1 ? $1 - globalScriptLines - 1 : $1) + ':'); // one line for 'async function ()'
|
|
1624
|
-
} else {
|
|
1625
|
-
line = line.replace(/:([\d]+)$/, ($0, $1) =>
|
|
1626
|
-
':' + ($1 > globalScriptLines + 1 ? $1 - globalScriptLines - 1 : $1)); // one line for 'async function ()'
|
|
1627
|
-
}
|
|
1628
|
-
return line;
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
context.logError = function (msg, e, offs) {
|
|
1632
|
-
const stack = e.stack ? e.stack.toString().split('\n') : (e ? e.toString() : '');
|
|
1633
|
-
if (!msg.includes('\n')) {
|
|
1634
|
-
msg = msg.replace(/[: ]*$/, ': ');
|
|
1635
|
-
}
|
|
1636
|
-
|
|
1637
|
-
//errorLogFunction.error(msg + stack[0]);
|
|
1638
|
-
context.errorLogFunction.error(msg + fixLineNo(stack[0]));
|
|
1639
|
-
for (let i = offs || 1; i < stack.length; i++) {
|
|
1640
|
-
if (!stack[i]) {
|
|
1641
|
-
continue;
|
|
1642
|
-
}
|
|
1643
|
-
if (stack[i].match(/runInNewContext|javascript\.js:/)) {
|
|
1644
|
-
break;
|
|
1645
|
-
}
|
|
1646
|
-
//adapter.log.error(fixLineNo(stack[i]));
|
|
1647
|
-
context.errorLogFunction.error(fixLineNo(stack[i]));
|
|
1648
|
-
}
|
|
1649
|
-
};
|
|
1650
|
-
|
|
1651
|
-
function createActiveObject(id, enabled, cb) {
|
|
1652
|
-
const idActive = `${adapter.namespace}.scriptEnabled.${id.substring(SCRIPT_CODE_MARKER.length)}`;
|
|
1653
|
-
|
|
1654
|
-
if (!context.objects[idActive]) {
|
|
1655
|
-
context.objects[idActive] = {
|
|
1656
|
-
_id: idActive,
|
|
1657
|
-
common: {
|
|
1658
|
-
name: `scriptEnabled.${id.substring(SCRIPT_CODE_MARKER.length)}`,
|
|
1659
|
-
desc: 'controls script activity',
|
|
1660
|
-
type: 'boolean',
|
|
1661
|
-
write: true,
|
|
1662
|
-
read: true,
|
|
1663
|
-
role: 'switch.active'
|
|
1664
|
-
},
|
|
1665
|
-
native: {
|
|
1666
|
-
script: id
|
|
1667
|
-
},
|
|
1668
|
-
type: 'state'
|
|
1669
|
-
};
|
|
1670
|
-
adapter.setForeignObject(idActive, context.objects[idActive], err => {
|
|
1671
|
-
if (!err) {
|
|
1672
|
-
const intermediateStateValue = prepareStateObject(idActive, !!enabled, true);
|
|
1673
|
-
adapter.setForeignState(idActive, !!enabled, true, () => {
|
|
1674
|
-
if (enabled && !adapter.config.subscribe) {
|
|
1675
|
-
context.interimStateValues[idActive] = intermediateStateValue;
|
|
1676
|
-
}
|
|
1677
|
-
cb && cb();
|
|
1678
|
-
});
|
|
1679
|
-
} else if (cb) {
|
|
1680
|
-
cb();
|
|
1681
|
-
}
|
|
1682
|
-
});
|
|
1683
|
-
} else {
|
|
1684
|
-
adapter.getForeignState(idActive, (err, state) => {
|
|
1685
|
-
if (state && state.val !== enabled) {
|
|
1686
|
-
const intermediateStateValue = prepareStateObject(idActive, !!enabled, true);
|
|
1687
|
-
adapter.setForeignState(idActive, !!enabled, true, () => {
|
|
1688
|
-
if (enabled && !adapter.config.subscribe) {
|
|
1689
|
-
context.interimStateValues[id] = intermediateStateValue;
|
|
1690
|
-
}
|
|
1691
|
-
cb && cb();
|
|
1692
|
-
});
|
|
1693
|
-
} else if (cb) {
|
|
1694
|
-
cb();
|
|
1695
|
-
}
|
|
1696
|
-
});
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
function createProblemObject(id, cb) {
|
|
1701
|
-
const idProblem = adapter.namespace + '.scriptProblem.' + id.substring(SCRIPT_CODE_MARKER.length);
|
|
1702
|
-
|
|
1703
|
-
if (!context.objects[idProblem]) {
|
|
1704
|
-
context.objects[idProblem] = {
|
|
1705
|
-
_id: idProblem,
|
|
1706
|
-
common: {
|
|
1707
|
-
name: 'scriptProblem.' + id.substring(SCRIPT_CODE_MARKER.length),
|
|
1708
|
-
desc: 'Script has a problem',
|
|
1709
|
-
type: 'boolean',
|
|
1710
|
-
expert: true,
|
|
1711
|
-
write: false,
|
|
1712
|
-
read: true,
|
|
1713
|
-
role: 'indicator.error'
|
|
1714
|
-
},
|
|
1715
|
-
native: {
|
|
1716
|
-
script: id
|
|
1717
|
-
},
|
|
1718
|
-
type: 'state'
|
|
1719
|
-
};
|
|
1720
|
-
adapter.setForeignObject(idProblem, context.objects[idProblem], err => {
|
|
1721
|
-
if (!err) {
|
|
1722
|
-
adapter.setForeignState(idProblem, false, true, cb);
|
|
1723
|
-
} else if (cb) {
|
|
1724
|
-
cb();
|
|
1725
|
-
}
|
|
1726
|
-
});
|
|
1727
|
-
} else {
|
|
1728
|
-
adapter.getForeignState(idProblem, (err, state) => {
|
|
1729
|
-
if (state && state.val !== false) {
|
|
1730
|
-
adapter.setForeignState(idProblem, false, true, cb);
|
|
1731
|
-
} else if (cb) {
|
|
1732
|
-
cb();
|
|
1733
|
-
}
|
|
1734
|
-
});
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
|
|
1738
|
-
function addToNames(obj) {
|
|
1739
|
-
const id = obj._id;
|
|
1740
|
-
|
|
1741
|
-
if (obj.common && obj.common.name) {
|
|
1742
|
-
let name = obj.common.name;
|
|
1743
|
-
if (name && typeof name === 'object') {
|
|
1744
|
-
name = name[words.getLanguage()] || name.en;
|
|
1745
|
-
}
|
|
1746
|
-
if (!name || typeof name !== 'string') { // TODO, take name in current language
|
|
1747
|
-
return;
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
if (!context.names[name]) {
|
|
1751
|
-
context.names[name] = id;
|
|
1752
|
-
} else {
|
|
1753
|
-
// convert to array
|
|
1754
|
-
if (!Array.isArray(context.names[name])) {
|
|
1755
|
-
context.names[name] = [context.names[name]];
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1758
|
-
context.names[name].push(id);
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
}
|
|
1762
|
-
|
|
1763
|
-
function removeFromNames(id) {
|
|
1764
|
-
const n = getName(id);
|
|
1765
|
-
|
|
1766
|
-
if (n) {
|
|
1767
|
-
if (Array.isArray(context.names[n])) {
|
|
1768
|
-
const pos = context.names[n].indexOf(id);
|
|
1769
|
-
if (pos > -1) {
|
|
1770
|
-
context.names[n].splice(pos, 1);
|
|
1771
|
-
|
|
1772
|
-
if (context.names[n].length === 1) {
|
|
1773
|
-
context.names[n] = context.names[n][0];
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
|
-
} else {
|
|
1777
|
-
delete context.names[n];
|
|
1778
|
-
}
|
|
1779
|
-
}
|
|
1780
|
-
}
|
|
1781
|
-
|
|
1782
|
-
function getName(id) {
|
|
1783
|
-
for (const n in context.names) {
|
|
1784
|
-
if (context.names[n] && Array.isArray(context.names[n])) {
|
|
1785
|
-
if (context.names[n].includes(id)) {
|
|
1786
|
-
return n;
|
|
1787
|
-
}
|
|
1788
|
-
} else if (context.names[n] === id) {
|
|
1789
|
-
return n;
|
|
1790
|
-
}
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
return null;
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
|
-
async function installNpm(npmLib) {
|
|
1797
|
-
return new Promise((resolve, reject) => {
|
|
1798
|
-
const path = __dirname;
|
|
1799
|
-
|
|
1800
|
-
// Also, set the working directory (cwd) of the process instead of using --prefix
|
|
1801
|
-
// because that has ugly bugs on Windows
|
|
1802
|
-
const cmd = `npm install ${npmLib} --omit=dev`;
|
|
1803
|
-
adapter.log.info(`Installing ${npmLib} into ${__dirname} - cmd: ${cmd}`);
|
|
1804
|
-
|
|
1805
|
-
// System call used for update of js-controller itself,
|
|
1806
|
-
// because during installation npm packet will be deleted too, but some files must be loaded even during the installation process.
|
|
1807
|
-
const child = mods['child_process'].exec(cmd, {
|
|
1808
|
-
windowsHide: true,
|
|
1809
|
-
cwd: path,
|
|
1810
|
-
});
|
|
1811
|
-
|
|
1812
|
-
child.stdout && child.stdout.on('data', buf =>
|
|
1813
|
-
adapter.log.info(buf.toString('utf8')));
|
|
1814
|
-
|
|
1815
|
-
child.stderr && child.stderr.on('data', buf =>
|
|
1816
|
-
adapter.log.error(buf.toString('utf8')));
|
|
1817
|
-
|
|
1818
|
-
child.on('err', err => {
|
|
1819
|
-
adapter.log.error(`Cannot install ${npmLib}: ${err}`);
|
|
1820
|
-
reject(npmLib);
|
|
1821
|
-
});
|
|
1822
|
-
child.on('error', err => {
|
|
1823
|
-
adapter.log.error(`Cannot install ${npmLib}: ${err}`);
|
|
1824
|
-
reject(npmLib);
|
|
1825
|
-
});
|
|
1826
|
-
|
|
1827
|
-
child.on('exit', (code /* , signal */) => {
|
|
1828
|
-
if (code) {
|
|
1829
|
-
adapter.log.error(`Cannot install ${npmLib}: ${code}`);
|
|
1830
|
-
reject(code);
|
|
1831
|
-
}
|
|
1832
|
-
// command succeeded
|
|
1833
|
-
resolve(code);
|
|
1834
|
-
});
|
|
1835
|
-
});
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
|
-
async function installLibraries() {
|
|
1839
|
-
if (typeof adapter.config?.libraries !== 'string') {
|
|
1840
|
-
adapter.config.libraries = '';
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
const libraries = adapter.config.libraries.split(/[,;\s]+/).filter(d => d.length > 0);
|
|
1844
|
-
|
|
1845
|
-
adapter.log.debug(`Custom libraries in config: "${adapter.config.libraries}": ${JSON.stringify(libraries)}`);
|
|
1846
|
-
|
|
1847
|
-
let installedNodeModules = [];
|
|
1848
|
-
const keepModules = [];
|
|
1849
|
-
|
|
1850
|
-
// js-controller >= 6.x
|
|
1851
|
-
if (typeof adapter.listInstalledNodeModules === 'function') {
|
|
1852
|
-
installedNodeModules = await adapter.listInstalledNodeModules();
|
|
1853
|
-
|
|
1854
|
-
adapter.log.debug(`Found installed libraries: ${JSON.stringify(installedNodeModules)}`);
|
|
1855
|
-
}
|
|
1856
|
-
|
|
1857
|
-
for (const lib of libraries) {
|
|
1858
|
-
let depName = lib;
|
|
1859
|
-
let version = 'latest';
|
|
1860
|
-
|
|
1861
|
-
if (depName.includes('@') && depName.lastIndexOf('@') > 0) {
|
|
1862
|
-
const parts = depName.split('@');
|
|
1863
|
-
version = parts.pop() ?? 'latest';
|
|
1864
|
-
depName = parts.join('@');
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
/** The real module name, because the dependency can be an url too */
|
|
1868
|
-
let moduleName = depName;
|
|
1869
|
-
|
|
1870
|
-
if (URL.canParse(depName)) {
|
|
1871
|
-
moduleName = await requestModuleNameByUrl(depName);
|
|
1872
|
-
|
|
1873
|
-
adapter.log.debug(`Found custom library in config: "${moduleName}@${version}" (from ${depName})`);
|
|
1874
|
-
} else {
|
|
1875
|
-
adapter.log.debug(`Found custom library in config: "${moduleName}@${version}"`);
|
|
1876
|
-
}
|
|
1877
|
-
|
|
1878
|
-
keepModules.push(moduleName);
|
|
1879
|
-
|
|
1880
|
-
// js-controller >= 6.x
|
|
1881
|
-
if (typeof adapter.installNodeModule === 'function') {
|
|
1882
|
-
try {
|
|
1883
|
-
const result = await adapter.installNodeModule(depName, { version });
|
|
1884
|
-
if (result.success) {
|
|
1885
|
-
adapter.log.debug(`Installed custom library: "${moduleName}@${version}"`);
|
|
1886
|
-
|
|
1887
|
-
const importedModule = await adapter.importNodeModule(moduleName);
|
|
1888
|
-
context.mods[moduleName] = importedModule.default ?? importedModule;
|
|
1889
|
-
} else {
|
|
1890
|
-
adapter.log.warn(`Cannot install custom npm package "${moduleName}@${version}"`);
|
|
1891
|
-
}
|
|
1892
|
-
} catch (e) {
|
|
1893
|
-
adapter.log.warn(`Cannot install custom npm package "${moduleName}@${version}": ${e.message}`);
|
|
1894
|
-
}
|
|
1895
|
-
} else if (!nodeFS.existsSync(`${__dirname}/node_modules/${depName}/package.json`)) {
|
|
1896
|
-
// js-controller < 6.x
|
|
1897
|
-
adapter.log.info(`Installing custom library (legacy mode): "${lib}"`);
|
|
1898
|
-
|
|
1899
|
-
try {
|
|
1900
|
-
await installNpm(lib);
|
|
1901
|
-
adapter.log.info(`Installed custom npm package (legacy mode): "${libraries[lib]}"`);
|
|
1902
|
-
} catch (err) {
|
|
1903
|
-
adapter.log.warn(`Cannot install custom npm package "${libraries[lib]}" (legacy mode): ${err}`);
|
|
1904
|
-
}
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
|
|
1908
|
-
// js-controller >= 6.x
|
|
1909
|
-
if (typeof adapter.uninstallNodeModule === 'function') {
|
|
1910
|
-
for (const installedNodeModule of installedNodeModules) {
|
|
1911
|
-
if (!keepModules.includes(installedNodeModule)) {
|
|
1912
|
-
try {
|
|
1913
|
-
await adapter.uninstallNodeModule(installedNodeModule);
|
|
1914
|
-
|
|
1915
|
-
adapter.log.info(`Removed custom npm package: "${installedNodeModule}"`);
|
|
1916
|
-
} catch (err) {
|
|
1917
|
-
adapter.log.warn(`Cannot remove custom npm package ${installedNodeModule}: ${err}`);
|
|
1918
|
-
}
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
}
|
|
1922
|
-
}
|
|
1923
|
-
|
|
1924
|
-
function createVM(source, name, wrapAsync) {
|
|
1925
|
-
if (debugMode && name !== debugMode) {
|
|
1926
|
-
return false;
|
|
1927
|
-
}
|
|
1928
|
-
|
|
1929
|
-
if (!debugMode) {
|
|
1930
|
-
const logSubscriptionsText = "\n;\nlog(`registered ${__engine.__subscriptions} subscription${__engine.__subscriptions === 1 ? '' : 's'}," +
|
|
1931
|
-
" ${__engine.__schedules} schedule${__engine.__schedules === 1 ? '' : 's'}," +
|
|
1932
|
-
" ${__engine.__subscriptionsMessage} message${__engine.__subscriptionsMessage === 1 ? '' : 's'}," +
|
|
1933
|
-
" ${__engine.__subscriptionsLog} log${__engine.__subscriptionsLog === 1 ? '' : 's'}" +
|
|
1934
|
-
" and ${__engine.__subscriptionsFile} file subscription${__engine.__subscriptionsFile === 1 ? '' : 's'}`);\n";
|
|
1935
|
-
|
|
1936
|
-
if (wrapAsync) {
|
|
1937
|
-
source = `(async () => {\n${source}\n${logSubscriptionsText}\n})();`;
|
|
1938
|
-
} else {
|
|
1939
|
-
source = `${source}\n${logSubscriptionsText}`;
|
|
1940
|
-
}
|
|
1941
|
-
} else {
|
|
1942
|
-
if (wrapAsync) {
|
|
1943
|
-
source = `(async () => {debugger;\n${source}\n})();`;
|
|
1944
|
-
} else {
|
|
1945
|
-
source = `debugger;${source}`;
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
|
-
|
|
1949
|
-
try {
|
|
1950
|
-
const options = {
|
|
1951
|
-
filename: name,
|
|
1952
|
-
displayErrors: true
|
|
1953
|
-
// lineOffset: globalScriptLines
|
|
1954
|
-
};
|
|
1955
|
-
return {
|
|
1956
|
-
script: new vm.Script(source, options),
|
|
1957
|
-
};
|
|
1958
|
-
} catch (e) {
|
|
1959
|
-
context.logError(`${name} compile failed:\r\nat `, e);
|
|
1960
|
-
return false;
|
|
1961
|
-
}
|
|
1962
|
-
}
|
|
1963
|
-
|
|
1964
|
-
function execute(script, name, engineType, verbose, debug) {
|
|
1965
|
-
script.intervals = [];
|
|
1966
|
-
script.timeouts = [];
|
|
1967
|
-
script.schedules = [];
|
|
1968
|
-
script.wizards = [];
|
|
1969
|
-
script.name = name;
|
|
1970
|
-
script.engineType = engineType;
|
|
1971
|
-
script._id = Math.floor(Math.random() * 0xFFFFFFFF);
|
|
1972
|
-
script.subscribes = {};
|
|
1973
|
-
script.subscribesFile = {};
|
|
1974
|
-
script.setStatePerMinuteCounter = 0;
|
|
1975
|
-
script.setStatePerMinuteProblemCounter = 0;
|
|
1976
|
-
adapter.setState(`scriptProblem.${name.substring(SCRIPT_CODE_MARKER.length)}`, { val: false, ack: true, expire: 1000 });
|
|
1977
|
-
|
|
1978
|
-
const sandbox = sandBox(script, name, verbose, debug, context);
|
|
1979
|
-
|
|
1980
|
-
try {
|
|
1981
|
-
script.script.runInNewContext(sandbox, {
|
|
1982
|
-
filename: name,
|
|
1983
|
-
displayErrors: true
|
|
1984
|
-
// lineOffset: globalScriptLines
|
|
1985
|
-
});
|
|
1986
|
-
} catch (e) {
|
|
1987
|
-
adapter.setState(`scriptProblem.${name.substring(SCRIPT_CODE_MARKER.length)}`, { val: true, ack: true, c: 'execute' });
|
|
1988
|
-
context.logError(name, e);
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
|
-
|
|
1992
|
-
function unsubscribe(id) {
|
|
1993
|
-
if (!id) {
|
|
1994
|
-
adapter.log.warn('unsubscribe: empty name');
|
|
1995
|
-
return;
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
|
-
if (id.constructor && id.constructor.name === 'RegExp') {
|
|
1999
|
-
//adapter.log.warn('unsubscribe: todo - process regexp');
|
|
2000
|
-
return;
|
|
2001
|
-
}
|
|
2002
|
-
|
|
2003
|
-
if (typeof id !== 'string') {
|
|
2004
|
-
adapter.log.error(`unsubscribe: invalid type of id - ${typeof id}`);
|
|
2005
|
-
return;
|
|
2006
|
-
}
|
|
2007
|
-
const parts = id.split('.');
|
|
2008
|
-
const _adapter = `system.adapter.${parts[0]}.${parts[1]}`;
|
|
2009
|
-
if (context.objects[_adapter] && context.objects[_adapter].common && context.objects[_adapter].common.subscribable) {
|
|
2010
|
-
const a = parts[0] + '.' + parts[1];
|
|
2011
|
-
const alive = `system.adapter.${a}.alive`;
|
|
2012
|
-
if (context.adapterSubs[alive]) {
|
|
2013
|
-
const pos = context.adapterSubs[alive].indexOf(id);
|
|
2014
|
-
pos !== -1 && context.adapterSubs[alive].splice(pos, 1);
|
|
2015
|
-
if (!context.adapterSubs[alive].length) {
|
|
2016
|
-
delete context.adapterSubs[alive];
|
|
2017
|
-
}
|
|
2018
|
-
}
|
|
2019
|
-
adapter.sendTo(a, 'unsubscribe', id);
|
|
2020
|
-
}
|
|
2021
|
-
}
|
|
2022
|
-
|
|
2023
|
-
// Analyse if logs are still required or not
|
|
2024
|
-
function updateLogSubscriptions() {
|
|
2025
|
-
let found = false;
|
|
2026
|
-
// go through all scripts and check if some one script still require logs
|
|
2027
|
-
Object.keys(context.logSubscriptions).forEach(scriptName => {
|
|
2028
|
-
if (!context.logSubscriptions?.[scriptName] || !context.logSubscriptions[scriptName].length) {
|
|
2029
|
-
delete context.logSubscriptions[scriptName];
|
|
2030
|
-
} else {
|
|
2031
|
-
found = true;
|
|
2032
|
-
}
|
|
2033
|
-
});
|
|
2034
|
-
|
|
2035
|
-
if (found && !logSubscribed) {
|
|
2036
|
-
logSubscribed = true;
|
|
2037
|
-
adapter.requireLog(logSubscribed);
|
|
2038
|
-
adapter.log.info(`Subscribed to log messages (found logSubscriptions)`);
|
|
2039
|
-
} else if (!found && logSubscribed) {
|
|
2040
|
-
logSubscribed = false;
|
|
2041
|
-
adapter.requireLog(logSubscribed);
|
|
2042
|
-
adapter.log.info(`Unsubscribed from log messages (not found logSubscriptions)`);
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
|
|
2046
|
-
function stop(name, callback) {
|
|
2047
|
-
adapter.log.info(`Stopping script ${name}`);
|
|
2048
|
-
|
|
2049
|
-
adapter.setState('scriptEnabled.' + name.substring(SCRIPT_CODE_MARKER.length), false, true);
|
|
2050
|
-
|
|
2051
|
-
if (context.messageBusHandlers[name]) {
|
|
2052
|
-
delete context.messageBusHandlers[name];
|
|
2053
|
-
}
|
|
2054
|
-
|
|
2055
|
-
if (context.tempDirectories[name]) {
|
|
2056
|
-
try {
|
|
2057
|
-
mods.fs.rmSync(context.tempDirectories[name], { recursive: true });
|
|
2058
|
-
|
|
2059
|
-
adapter.log.debug(`Removed temp directory of ${name}: ${context.tempDirectories[name]}`);
|
|
2060
|
-
} catch (err) {
|
|
2061
|
-
adapter.log.warn(`Unable to remove temp directory of ${name}: ${context.tempDirectories[name]}`);
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
delete context.tempDirectories[name];
|
|
2065
|
-
}
|
|
2066
|
-
|
|
2067
|
-
if (context.logSubscriptions[name]) {
|
|
2068
|
-
delete context.logSubscriptions[name];
|
|
2069
|
-
updateLogSubscriptions();
|
|
2070
|
-
}
|
|
2071
|
-
|
|
2072
|
-
if (context.scripts[name]) {
|
|
2073
|
-
// Remove from subscriptions
|
|
2074
|
-
context.isEnums = false;
|
|
2075
|
-
if (adapter.config.subscribe) {
|
|
2076
|
-
// check all subscribed IDs
|
|
2077
|
-
Object.keys(context.scripts[name].subscribes).forEach(id => {
|
|
2078
|
-
if (context.subscribedPatterns[id]) {
|
|
2079
|
-
context.subscribedPatterns[id] -= context.scripts[name].subscribes[id];
|
|
2080
|
-
if (context.subscribedPatterns[id] <= 0) {
|
|
2081
|
-
adapter.unsubscribeForeignStates(id);
|
|
2082
|
-
delete context.subscribedPatterns[id];
|
|
2083
|
-
if (context.states[id]) {
|
|
2084
|
-
delete context.states[id];
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
});
|
|
2089
|
-
}
|
|
2090
|
-
|
|
2091
|
-
for (let i = context.subscriptions.length - 1; i >= 0; i--) {
|
|
2092
|
-
if (context.subscriptions[i].name === name) {
|
|
2093
|
-
const sub = context.subscriptions.splice(i, 1)[0];
|
|
2094
|
-
sub && unsubscribe(sub.pattern.id);
|
|
2095
|
-
} else {
|
|
2096
|
-
if (!context.isEnums && context.subscriptions[i].pattern.enumName || context.subscriptions[i].pattern.enumId) {
|
|
2097
|
-
context.isEnums = true;
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
}
|
|
2101
|
-
|
|
2102
|
-
// check all subscribed files
|
|
2103
|
-
Object.keys(context.scripts[name].subscribesFile).forEach(key => {
|
|
2104
|
-
if (context.subscribedPatternsFile[key]) {
|
|
2105
|
-
context.subscribedPatternsFile[key] -= context.scripts[name].subscribesFile[key];
|
|
2106
|
-
if (context.subscribedPatternsFile[key] <= 0) {
|
|
2107
|
-
const [id, file] = key.split('$%$');
|
|
2108
|
-
adapter.unsubscribeForeignFiles(id, file);
|
|
2109
|
-
delete context.subscribedPatternsFile[key];
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
});
|
|
2113
|
-
for (let i = context.subscriptionsFile.length - 1; i >= 0; i--) {
|
|
2114
|
-
if (context.subscriptionsFile[i].name === name) {
|
|
2115
|
-
context.subscriptionsFile.splice(i, 1)[0];
|
|
2116
|
-
}
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
for (let i = context.subscriptionsObject.length - 1; i >= 0; i--) {
|
|
2120
|
-
if (context.subscriptionsObject[i].name === name) {
|
|
2121
|
-
const sub = context.subscriptionsObject.splice(i, 1)[0];
|
|
2122
|
-
sub && adapter.unsubscribeForeignObjects(sub.pattern);
|
|
2123
|
-
}
|
|
2124
|
-
}
|
|
2125
|
-
|
|
2126
|
-
// Stop all timeouts
|
|
2127
|
-
for (let i = 0; i < context.scripts[name].timeouts.length; i++) {
|
|
2128
|
-
clearTimeout(context.scripts[name].timeouts[i]);
|
|
2129
|
-
}
|
|
2130
|
-
// Stop all intervals
|
|
2131
|
-
for (let i = 0; i < context.scripts[name].intervals.length; i++) {
|
|
2132
|
-
clearInterval(context.scripts[name].intervals[i]);
|
|
2133
|
-
}
|
|
2134
|
-
// Stop all scheduled jobs
|
|
2135
|
-
for (let i = 0; i < context.scripts[name].schedules.length; i++) {
|
|
2136
|
-
if (context.scripts[name].schedules[i]) {
|
|
2137
|
-
const _name = context.scripts[name].schedules[i].name;
|
|
2138
|
-
if (!mods.nodeSchedule.cancelJob(context.scripts[name].schedules[i])) {
|
|
2139
|
-
adapter.log.error(`Error by canceling scheduled job "${_name}"`);
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
|
|
2144
|
-
// Stop all time wizards jobs
|
|
2145
|
-
for (let i = 0; i < context.scripts[name].wizards.length; i++) {
|
|
2146
|
-
if (context.scripts[name].wizards[i]) {
|
|
2147
|
-
context.scheduler && context.scheduler.remove(context.scripts[name].wizards[i]);
|
|
2148
|
-
}
|
|
2149
|
-
}
|
|
2150
|
-
|
|
2151
|
-
// if callback for on stop
|
|
2152
|
-
if (typeof context.scripts[name].onStopCb === 'function') {
|
|
2153
|
-
context.scripts[name].onStopTimeout = parseInt(context.scripts[name].onStopTimeout, 10) || 1000;
|
|
2154
|
-
|
|
2155
|
-
let timeout = setTimeout(() => {
|
|
2156
|
-
if (timeout) {
|
|
2157
|
-
timeout = null;
|
|
2158
|
-
delete context.scripts[name];
|
|
2159
|
-
typeof callback === 'function' && callback(true, name);
|
|
2160
|
-
}
|
|
2161
|
-
}, context.scripts[name].onStopTimeout);
|
|
2162
|
-
|
|
2163
|
-
try {
|
|
2164
|
-
context.scripts[name].onStopCb(() => {
|
|
2165
|
-
if (timeout) {
|
|
2166
|
-
clearTimeout(timeout);
|
|
2167
|
-
timeout = null;
|
|
2168
|
-
delete context.scripts[name];
|
|
2169
|
-
typeof callback === 'function' && callback(true, name);
|
|
2170
|
-
}
|
|
2171
|
-
});
|
|
2172
|
-
} catch (e) {
|
|
2173
|
-
adapter.log.error('error in onStop callback: ' + e);
|
|
2174
|
-
}
|
|
2175
|
-
|
|
2176
|
-
} else {
|
|
2177
|
-
delete context.scripts[name];
|
|
2178
|
-
typeof callback === 'function' && callback(true, name);
|
|
2179
|
-
}
|
|
2180
|
-
} else {
|
|
2181
|
-
typeof callback === 'function' && callback(false, name);
|
|
2182
|
-
}
|
|
2183
|
-
}
|
|
2184
|
-
|
|
2185
|
-
function prepareScript(obj, callback) {
|
|
2186
|
-
if (obj && obj.common && obj.common.enabled && debugState.scriptName === obj._id) {
|
|
2187
|
-
const id = obj._id;
|
|
2188
|
-
return debugStop()
|
|
2189
|
-
.then(() => {
|
|
2190
|
-
adapter.log.info(`Debugging of ${id} was stopped, because started in normal mode`);
|
|
2191
|
-
prepareScript(obj, callback);
|
|
2192
|
-
});
|
|
2193
|
-
}
|
|
2194
|
-
|
|
2195
|
-
if (obj && obj.common &&
|
|
2196
|
-
(obj.common.enabled || debugMode === obj._id) &&
|
|
2197
|
-
obj.common.engine === `system.adapter.${adapter.namespace}` &&
|
|
2198
|
-
obj.common.source
|
|
2199
|
-
) {
|
|
2200
|
-
const name = obj._id;
|
|
2201
|
-
|
|
2202
|
-
const nameId = name.substring(SCRIPT_CODE_MARKER.length);
|
|
2203
|
-
if (!nameId.length || nameId.endsWith('.')) {
|
|
2204
|
-
adapter.log.error(`Script name ${name} is invalid!`);
|
|
2205
|
-
typeof callback === 'function' && callback(false, name);
|
|
2206
|
-
return;
|
|
2207
|
-
}
|
|
2208
|
-
const idActive = `scriptEnabled.${nameId}`;
|
|
2209
|
-
if (!adapter.config.subscribe) {
|
|
2210
|
-
context.interimStateValues[idActive] = prepareStateObject(`${adapter.namespace}.${idActive}`, true, true);
|
|
2211
|
-
}
|
|
2212
|
-
adapter.setState(idActive, true, true);
|
|
2213
|
-
obj.common.engineType = obj.common.engineType || '';
|
|
2214
|
-
|
|
2215
|
-
if ((obj.common.engineType.toLowerCase().startsWith('javascript') || obj.common.engineType === 'Blockly' || obj.common.engineType === 'Rules')) {
|
|
2216
|
-
// Javascript
|
|
2217
|
-
adapter.log.info(`Start JavaScript ${name} (${obj.common.engineType})`);
|
|
2218
|
-
|
|
2219
|
-
let sourceFn = name;
|
|
2220
|
-
if (webstormDebug) {
|
|
2221
|
-
const fn = name.replace(/^script.js./, '').replace(/\./g, '/');
|
|
2222
|
-
sourceFn = mods.path.join(webstormDebug, `${fn}.js`);
|
|
2223
|
-
}
|
|
2224
|
-
context.scripts[name] = createVM(globalScript + '\n' + obj.common.source, sourceFn, true);
|
|
2225
|
-
if (!context.scripts[name]) {
|
|
2226
|
-
delete context.scripts[name];
|
|
2227
|
-
typeof callback === 'function' && callback(false, name);
|
|
2228
|
-
return;
|
|
2229
|
-
}
|
|
2230
|
-
execute(context.scripts[name], sourceFn, obj.common.engineType, obj.common.verbose, obj.common.debug);
|
|
2231
|
-
typeof callback === 'function' && callback(true, name);
|
|
2232
|
-
} else if (obj.common.engineType.toLowerCase().startsWith('typescript')) {
|
|
2233
|
-
// TypeScript
|
|
2234
|
-
adapter.log.info(`Compiling TypeScript source ${name}`);
|
|
2235
|
-
// The source code must be transformed in order to support top level await
|
|
2236
|
-
// and to force TypeScript to compile the code as a module
|
|
2237
|
-
const transformedSource = transformScriptBeforeCompilation(obj.common.source, false);
|
|
2238
|
-
// We need to hash both global declarations that are known until now
|
|
2239
|
-
// AND the script source, because changing either can change the compilation output
|
|
2240
|
-
const sourceHash = hashSource(tsSourceHashBase + globalDeclarations + transformedSource);
|
|
2241
|
-
|
|
2242
|
-
let compiled;
|
|
2243
|
-
// If we already stored the compiled source code and the original source hash,
|
|
2244
|
-
// use the hash to check whether we can rely on the compiled source code or
|
|
2245
|
-
// if we need to compile it again
|
|
2246
|
-
if (
|
|
2247
|
-
typeof obj.common.compiled === 'string'
|
|
2248
|
-
&& typeof obj.common.sourceHash === 'string'
|
|
2249
|
-
&& sourceHash === obj.common.sourceHash
|
|
2250
|
-
) {
|
|
2251
|
-
// We can reuse the stored source
|
|
2252
|
-
compiled = obj.common.compiled;
|
|
2253
|
-
adapter.log.info(`${name}: source code did not change, using cached compilation result...`);
|
|
2254
|
-
} else {
|
|
2255
|
-
// We don't have a hashed source code, or the original source changed, compile it
|
|
2256
|
-
const filename = scriptIdToTSFilename(name);
|
|
2257
|
-
let tsCompiled;
|
|
2258
|
-
try {
|
|
2259
|
-
tsCompiled = tsServer.compile(filename, transformedSource);
|
|
2260
|
-
} catch (e) {
|
|
2261
|
-
adapter.log.error(`${obj._id}: TypeScript compilation failed:\n${e}`);
|
|
2262
|
-
typeof callback === 'function' && callback(false, name);
|
|
2263
|
-
return;
|
|
2264
|
-
}
|
|
2265
|
-
|
|
2266
|
-
const errors = tsCompiled.diagnostics.map(diag => diag.annotatedSource + '\n').join('\n');
|
|
2267
|
-
|
|
2268
|
-
if (tsCompiled.success) {
|
|
2269
|
-
if (errors.length > 0) {
|
|
2270
|
-
adapter.log.warn(`${name}: TypeScript compilation had errors:\n${errors}`);
|
|
2271
|
-
} else {
|
|
2272
|
-
adapter.log.info(`${name}: TypeScript compilation successful`);
|
|
2273
|
-
}
|
|
2274
|
-
compiled = tsCompiled.result;
|
|
2275
|
-
|
|
2276
|
-
// Store the compiled source and the original source hash, so we don't need to do the work again next time
|
|
2277
|
-
ignoreObjectChange.add(name); // ignore the next change and don't restart scripts
|
|
2278
|
-
adapter.extendForeignObject(name, {
|
|
2279
|
-
common: {
|
|
2280
|
-
sourceHash,
|
|
2281
|
-
compiled,
|
|
2282
|
-
}
|
|
2283
|
-
});
|
|
2284
|
-
} else {
|
|
2285
|
-
adapter.log.error(`${name}: TypeScript compilation failed:\n${errors}`);
|
|
2286
|
-
typeof callback === 'function' && callback(false, name);
|
|
2287
|
-
return;
|
|
2288
|
-
}
|
|
2289
|
-
}
|
|
2290
|
-
context.scripts[name] = createVM(globalScript + '\n' + compiled, name, false);
|
|
2291
|
-
if (!context.scripts[name]) {
|
|
2292
|
-
delete context.scripts[name];
|
|
2293
|
-
typeof callback === 'function' && callback(false, name);
|
|
2294
|
-
return;
|
|
2295
|
-
}
|
|
2296
|
-
execute(context.scripts[name], name, obj.common.engineType, obj.common.verbose, obj.common.debug);
|
|
2297
|
-
typeof callback === 'function' && callback(true, name);
|
|
2298
|
-
}
|
|
2299
|
-
} else {
|
|
2300
|
-
let _name;
|
|
2301
|
-
if (obj && obj._id) {
|
|
2302
|
-
_name = obj._id;
|
|
2303
|
-
const scriptIdName = _name.substring(SCRIPT_CODE_MARKER.length);
|
|
2304
|
-
|
|
2305
|
-
if (!scriptIdName.length || scriptIdName.endsWith('.')) {
|
|
2306
|
-
adapter.log.error(`Script name ${_name} is invalid!`);
|
|
2307
|
-
typeof callback === 'function' && callback(false, _name);
|
|
2308
|
-
return;
|
|
2309
|
-
}
|
|
2310
|
-
adapter.setState(`scriptEnabled.${scriptIdName}`, false, true);
|
|
2311
|
-
}
|
|
2312
|
-
!obj && adapter.log.error('Invalid script');
|
|
2313
|
-
typeof callback === 'function' && callback(false, _name);
|
|
2314
|
-
}
|
|
2315
|
-
}
|
|
2316
|
-
|
|
2317
|
-
function load(nameOrObject, callback) {
|
|
2318
|
-
if (typeof nameOrObject === 'object') {
|
|
2319
|
-
// create states for scripts
|
|
2320
|
-
createActiveObject(nameOrObject._id, nameOrObject && nameOrObject.common && nameOrObject.common.enabled, () =>
|
|
2321
|
-
createProblemObject(nameOrObject._id, () =>
|
|
2322
|
-
prepareScript(nameOrObject, callback)));
|
|
2323
|
-
|
|
2324
|
-
} else {
|
|
2325
|
-
adapter.getForeignObject(nameOrObject, (err, obj) => {
|
|
2326
|
-
if (!obj || err) {
|
|
2327
|
-
err && adapter.log.error(`Invalid script "${nameOrObject}": ${err}`);
|
|
2328
|
-
typeof callback === 'function' && callback(false, nameOrObject);
|
|
2329
|
-
} else {
|
|
2330
|
-
return load(obj, callback);
|
|
2331
|
-
}
|
|
2332
|
-
});
|
|
2333
|
-
}
|
|
2334
|
-
}
|
|
2335
|
-
|
|
2336
|
-
function patternMatching(event, patternFunctions) {
|
|
2337
|
-
let matched = false;
|
|
2338
|
-
for (let i = 0, len = patternFunctions.length; i < len; i++) {
|
|
2339
|
-
if (patternFunctions[i](event)) {
|
|
2340
|
-
if (patternFunctions.logic === 'or') {
|
|
2341
|
-
return true;
|
|
2342
|
-
}
|
|
2343
|
-
matched = true;
|
|
2344
|
-
} else if (patternFunctions.logic === 'and') {
|
|
2345
|
-
return false;
|
|
2346
|
-
}
|
|
2347
|
-
}
|
|
2348
|
-
return matched;
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
|
-
async function getData(callback) {
|
|
2352
|
-
await adapter.subscribeForeignObjectsAsync('*');
|
|
2353
|
-
|
|
2354
|
-
if (!adapter.config.subscribe) {
|
|
2355
|
-
await adapter.subscribeForeignStatesAsync('*');
|
|
2356
|
-
} else {
|
|
2357
|
-
await adapter.subscribeStatesAsync('debug.to');
|
|
2358
|
-
await adapter.subscribeStatesAsync('scriptEnabled.*');
|
|
2359
|
-
}
|
|
2360
|
-
|
|
2361
|
-
adapter.log.info('requesting all states');
|
|
2362
|
-
adapter.getForeignStates('*', (err, res) => {
|
|
2363
|
-
if (!adapter.config.subscribe) {
|
|
2364
|
-
if (err || !res) {
|
|
2365
|
-
adapter.log.error(`Could not initialize states: ${err ? err.message : 'no result'}`);
|
|
2366
|
-
adapter.terminate(utils.EXIT_CODES.START_IMMEDIATELY_AFTER_STOP);
|
|
2367
|
-
return;
|
|
2368
|
-
}
|
|
2369
|
-
context.states = Object.assign(res, context.states);
|
|
2370
|
-
|
|
2371
|
-
addGetProperty(context.states);
|
|
2372
|
-
}
|
|
2373
|
-
|
|
2374
|
-
// remember all IDs
|
|
2375
|
-
for (const id in res) {
|
|
2376
|
-
if (Object.prototype.hasOwnProperty.call(res, id)) {
|
|
2377
|
-
context.stateIds.push(id);
|
|
2378
|
-
}
|
|
2379
|
-
}
|
|
2380
|
-
statesInitDone = true;
|
|
2381
|
-
adapter.log.info('received all states');
|
|
2382
|
-
objectsInitDone && typeof callback === 'function' && callback();
|
|
2383
|
-
});
|
|
2384
|
-
|
|
2385
|
-
adapter.log.info('requesting all objects');
|
|
2386
|
-
|
|
2387
|
-
adapter.getObjectList({ include_docs: true }, (err, res) => {
|
|
2388
|
-
if (err || !res || !res.rows) {
|
|
2389
|
-
adapter.log.error(`Could not initialize objects: ${err ? err.message : 'no result'}`);
|
|
2390
|
-
adapter.terminate(utils.EXIT_CODES.START_IMMEDIATELY_AFTER_STOP);
|
|
2391
|
-
return;
|
|
2392
|
-
}
|
|
2393
|
-
context.objects = {};
|
|
2394
|
-
for (let i = 0; i < res.rows.length; i++) {
|
|
2395
|
-
if (!res.rows[i].doc) {
|
|
2396
|
-
adapter.log.debug(`Got empty object for index ${i} (${res.rows[i].id})`);
|
|
2397
|
-
continue;
|
|
2398
|
-
}
|
|
2399
|
-
if (context.objects[res.rows[i].doc._id] === undefined) { // If was already there ignore
|
|
2400
|
-
context.objects[res.rows[i].doc._id] = res.rows[i].doc;
|
|
2401
|
-
}
|
|
2402
|
-
context.objects[res.rows[i].doc._id].type === 'enum' && context.enums.push(res.rows[i].doc._id);
|
|
2403
|
-
|
|
2404
|
-
// Collect all names
|
|
2405
|
-
addToNames(context.objects[res.rows[i].doc._id]);
|
|
2406
|
-
}
|
|
2407
|
-
addGetProperty(context.objects);
|
|
2408
|
-
|
|
2409
|
-
const systemConfig = context.objects['system.config'];
|
|
2410
|
-
|
|
2411
|
-
// set language for debug messages
|
|
2412
|
-
if (systemConfig && systemConfig.common && systemConfig.common.language) {
|
|
2413
|
-
words.setLanguage(systemConfig.common.language);
|
|
2414
|
-
} else if (adapter.language) {
|
|
2415
|
-
words.setLanguage(adapter.language);
|
|
2416
|
-
}
|
|
2417
|
-
|
|
2418
|
-
// try to use system coordinates
|
|
2419
|
-
if (adapter.config.useSystemGPS) {
|
|
2420
|
-
if (systemConfig && systemConfig.common && systemConfig.common.latitude) {
|
|
2421
|
-
adapter.config.latitude = systemConfig.common.latitude;
|
|
2422
|
-
adapter.config.longitude = systemConfig.common.longitude;
|
|
2423
|
-
} else if (adapter.latitude) {
|
|
2424
|
-
adapter.config.latitude = adapter.latitude;
|
|
2425
|
-
adapter.config.longitude = adapter.longitude;
|
|
2426
|
-
}
|
|
2427
|
-
}
|
|
2428
|
-
adapter.config.latitude = parseFloat(adapter.config.latitude);
|
|
2429
|
-
adapter.config.longitude = parseFloat(adapter.config.longitude);
|
|
2430
|
-
|
|
2431
|
-
if (isNaN(adapter.config.latitude)) {
|
|
2432
|
-
adapter.log.warn(`Configured latitude is not a number - check (instance/system) configuration`);
|
|
2433
|
-
} else if (adapter.config.latitude < -90 || adapter.config.latitude > 90) {
|
|
2434
|
-
adapter.log.warn(`Configured latitude "${adapter.config.latitude}" is invalid - check (instance/system) configuration`);
|
|
2435
|
-
}
|
|
2436
|
-
|
|
2437
|
-
if (isNaN(adapter.config.longitude)) {
|
|
2438
|
-
adapter.log.warn(`Configured longitude is not a number - check (instance/system) configuration`);
|
|
2439
|
-
} else if (adapter.config.longitude < -180 || adapter.config.longitude > 180) {
|
|
2440
|
-
adapter.log.warn(`Configured longitude "${adapter.config.longitude}" is invalid - check (instance/system) configuration`);
|
|
2441
|
-
}
|
|
2442
|
-
|
|
2443
|
-
adapter.config.sunriseEvent = adapter.config.sunriseEvent || 'nightEnd';
|
|
2444
|
-
adapter.config.sunriseOffset = adapter.config.sunriseOffset || 0;
|
|
2445
|
-
adapter.config.sunriseLimitStart = adapter.config.sunriseLimitStart || '06:00';
|
|
2446
|
-
adapter.config.sunriseLimitEnd = adapter.config.sunriseLimitEnd || '12:00';
|
|
2447
|
-
|
|
2448
|
-
adapter.config.sunsetEvent = adapter.config.sunsetEvent || 'dusk';
|
|
2449
|
-
adapter.config.sunsetOffset = adapter.config.sunsetOffset || 0;
|
|
2450
|
-
adapter.config.sunsetLimitStart = adapter.config.sunsetLimitStart || '18:00';
|
|
2451
|
-
adapter.config.sunsetLimitEnd = adapter.config.sunsetLimitEnd || '23:00';
|
|
2452
|
-
|
|
2453
|
-
objectsInitDone = true;
|
|
2454
|
-
adapter.log.info('received all objects');
|
|
2455
|
-
statesInitDone && typeof callback === 'function' && callback();
|
|
2456
|
-
});
|
|
2457
|
-
}
|
|
2458
|
-
|
|
2459
|
-
const debugState = {
|
|
2460
|
-
scriptName: '',
|
|
2461
|
-
child: null,
|
|
2462
|
-
promiseOnEnd: null,
|
|
2463
|
-
paused: false,
|
|
2464
|
-
started: 0,
|
|
2465
|
-
};
|
|
2466
|
-
|
|
2467
|
-
function debugStop() {
|
|
2468
|
-
if (debugState.child) {
|
|
2469
|
-
debugSendToInspector({cmd: 'end'});
|
|
2470
|
-
debugState.endTimeout = setTimeout(() => {
|
|
2471
|
-
debugState.endTimeout = null;
|
|
2472
|
-
debugState.child && debugState.child.kill('SIGTERM');
|
|
2473
|
-
}, 500);
|
|
2474
|
-
} else {
|
|
2475
|
-
debugState.promiseOnEnd = Promise.resolve();
|
|
2476
|
-
}
|
|
2477
|
-
|
|
2478
|
-
return debugState.promiseOnEnd
|
|
2479
|
-
.then(() => {
|
|
2480
|
-
debugState.child = null;
|
|
2481
|
-
debugState.running = false;
|
|
2482
|
-
debugState.scriptName = '';
|
|
2483
|
-
debugState.endTimeout && clearTimeout(debugState.endTimeout);
|
|
2484
|
-
debugState.endTimeout = null;
|
|
2485
|
-
});
|
|
2486
|
-
}
|
|
2487
|
-
|
|
2488
|
-
function debugDisableScript(id) {
|
|
2489
|
-
const obj = context.objects[id];
|
|
2490
|
-
if (obj && obj.common && obj.common.enabled) {
|
|
2491
|
-
return adapter.extendForeignObjectAsync(obj._id, {common: {enabled: false}});
|
|
2492
|
-
} else {
|
|
2493
|
-
return Promise.resolve();
|
|
2494
|
-
}
|
|
2495
|
-
}
|
|
2496
|
-
|
|
2497
|
-
function debugSendToInspector(message) {
|
|
2498
|
-
if (debugState.child) {
|
|
2499
|
-
try {
|
|
2500
|
-
adapter.log.info(`send to debugger: ${message}`);
|
|
2501
|
-
debugState.child.send(message);
|
|
2502
|
-
} catch (e) {
|
|
2503
|
-
debugStop()
|
|
2504
|
-
.then(() => adapter.log.info(`Debugging of "${debugState.scriptName}" was stopped, because started in normal mode`));
|
|
2505
|
-
}
|
|
2506
|
-
} else {
|
|
2507
|
-
adapter.log.error(`Cannot send command to terminated inspector`);
|
|
2508
|
-
return adapter.setState('debug.from', JSON.stringify({cmd: 'error', error: `Cannot send command to terminated inspector`, id: 1}), true);
|
|
2509
|
-
}
|
|
2510
|
-
}
|
|
2511
|
-
|
|
2512
|
-
function debugStart(data) {
|
|
2513
|
-
if (Date.now() - debugState.started < 1000) {
|
|
2514
|
-
console.log('Start ignored');
|
|
2515
|
-
return;
|
|
2516
|
-
}
|
|
2517
|
-
|
|
2518
|
-
debugState.started = Date.now();
|
|
2519
|
-
// stop the script if it's running
|
|
2520
|
-
debugDisableScript(data.scriptName)
|
|
2521
|
-
.then(() => debugStop())
|
|
2522
|
-
.then(() => {
|
|
2523
|
-
if (data.adapter) {
|
|
2524
|
-
debugState.adapterInstance = data.adapter;
|
|
2525
|
-
debugState.scriptName = '';
|
|
2526
|
-
} else {
|
|
2527
|
-
debugState.adapterInstance = '';
|
|
2528
|
-
debugState.scriptName = data.scriptName;
|
|
2529
|
-
}
|
|
2530
|
-
|
|
2531
|
-
debugState.breakOnStart = data.breakOnStart;
|
|
2532
|
-
|
|
2533
|
-
debugState.promiseOnEnd = new Promise(resolve => {
|
|
2534
|
-
const options = {
|
|
2535
|
-
stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
|
|
2536
|
-
//stdio: ['pipe', 'pipe', 'pipe', 'ipc']
|
|
2537
|
-
};
|
|
2538
|
-
const args = [];
|
|
2539
|
-
if (debugState.adapterInstance) {
|
|
2540
|
-
args.push('--breakOnStart');
|
|
2541
|
-
}
|
|
2542
|
-
|
|
2543
|
-
debugState.child = fork(`${__dirname}/lib/inspect.js`, args, options);
|
|
2544
|
-
|
|
2545
|
-
/*debugState.child.stdout.setEncoding('utf8');
|
|
2546
|
-
debugState.child.stderr.setEncoding('utf8');
|
|
2547
|
-
debugState.child.stdout.on('data', childPrint);
|
|
2548
|
-
debugState.child.stderr.on('data', childPrint);*/
|
|
2549
|
-
|
|
2550
|
-
debugState.child && debugState.child.on('message', message => {
|
|
2551
|
-
if (typeof message === 'string') {
|
|
2552
|
-
try {
|
|
2553
|
-
message = JSON.parse(message);
|
|
2554
|
-
} catch (e) {
|
|
2555
|
-
return adapter.log.error(`Cannot parse message from inspector: ${message}`);
|
|
2556
|
-
}
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
|
-
message.cmd !== 'ready' && adapter.setState('debug.from', JSON.stringify(message), true);
|
|
2560
|
-
|
|
2561
|
-
switch (message.cmd) {
|
|
2562
|
-
case 'ready': {
|
|
2563
|
-
debugSendToInspector({cmd: 'start', scriptName: debugState.scriptName, adapterInstance: debugState.adapterInstance, instance: adapter.instance});
|
|
2564
|
-
break;
|
|
2565
|
-
}
|
|
2566
|
-
|
|
2567
|
-
case 'watched': {
|
|
2568
|
-
//console.log(`WATCHED: ${JSON.stringify(message)}`);
|
|
2569
|
-
break;
|
|
2570
|
-
}
|
|
2571
|
-
|
|
2572
|
-
case 'paused': {
|
|
2573
|
-
debugState.paused = true;
|
|
2574
|
-
console.log(`host: PAUSED`);
|
|
2575
|
-
break;
|
|
2576
|
-
}
|
|
2577
|
-
|
|
2578
|
-
case 'resumed' : {
|
|
2579
|
-
debugState.paused = false;
|
|
2580
|
-
//console.log(`STARTED`);
|
|
2581
|
-
break;
|
|
2582
|
-
}
|
|
2583
|
-
|
|
2584
|
-
case 'log' : {
|
|
2585
|
-
console.log(`[${message.severity}] ${message.text}`);
|
|
2586
|
-
break;
|
|
2587
|
-
}
|
|
2588
|
-
|
|
2589
|
-
case 'readyToDebug': {
|
|
2590
|
-
console.log(`host: readyToDebug (set breakpoints): [${message.scriptId}] ${message.script}`);
|
|
2591
|
-
break;
|
|
2592
|
-
}
|
|
2593
|
-
}
|
|
2594
|
-
});
|
|
2595
|
-
debugState.child && debugState.child.on('error', error => {
|
|
2596
|
-
adapter.log.error(`Cannot start inspector: ${error}`);
|
|
2597
|
-
adapter.setState('debug.from', JSON.stringify({cmd: 'error', error}), true);
|
|
2598
|
-
});
|
|
2599
|
-
|
|
2600
|
-
debugState.child && debugState.child.on('exit', code => {
|
|
2601
|
-
if (code) {
|
|
2602
|
-
adapter.setState('debug.from', JSON.stringify({cmd: 'error', error: `invalid response code: ${code}`}), true);
|
|
2603
|
-
}
|
|
2604
|
-
adapter.setState('debug.from', JSON.stringify({cmd: 'debugStopped', code}), true);
|
|
2605
|
-
debugState.child = null;
|
|
2606
|
-
resolve(code);
|
|
2607
|
-
});
|
|
2608
|
-
});
|
|
2609
|
-
});
|
|
2610
|
-
}
|
|
2611
|
-
|
|
2612
|
-
async function patchFont() {
|
|
2613
|
-
let stat;
|
|
2614
|
-
let dbFile;
|
|
2615
|
-
try {
|
|
2616
|
-
stat = nodeFS.statSync(`${__dirname}/admin/vs/base/browser/ui/codicons/codicon/codicon.ttf`);
|
|
2617
|
-
dbFile = await adapter.readFileAsync('javascript.admin', `vs/base/browser/ui/codicons/codicon/codicon.ttf`);
|
|
2618
|
-
} catch (error) {
|
|
2619
|
-
// ignore
|
|
2620
|
-
}
|
|
2621
|
-
if (dbFile && dbFile.file) {
|
|
2622
|
-
dbFile = dbFile.file;
|
|
2623
|
-
}
|
|
2624
|
-
|
|
2625
|
-
if (!stat || stat.size !== 73452 || !dbFile || dbFile.byteLength !== 73452) {
|
|
2626
|
-
try {
|
|
2627
|
-
const buffer = Buffer.from(JSON.parse(nodeFS.readFileSync(`${__dirname}/admin/vsFont/codicon.json`)), 'base64');
|
|
2628
|
-
|
|
2629
|
-
const zip = await require('jszip').loadAsync(buffer);
|
|
2630
|
-
const data = await zip.file('codicon.ttf').async('arraybuffer');
|
|
2631
|
-
if (data.byteLength !== 73452) {
|
|
2632
|
-
throw new Error('invalid font file!');
|
|
2633
|
-
}
|
|
2634
|
-
nodeFS.writeFileSync(`${__dirname}/admin/vs/base/browser/ui/codicons/codicon/codicon.ttf`, Buffer.from(data));
|
|
2635
|
-
// upload this file
|
|
2636
|
-
await adapter.writeFileAsync('javascript.admin', 'vs/base/browser/ui/codicons/codicon/codicon.ttf', Buffer.from(data));
|
|
2637
|
-
return true;
|
|
2638
|
-
} catch (error) {
|
|
2639
|
-
adapter.log.error(`Cannot patch font: ${error}`);
|
|
2640
|
-
return false;
|
|
2641
|
-
}
|
|
2642
|
-
} else {
|
|
2643
|
-
return false;
|
|
2644
|
-
}
|
|
2645
|
-
}
|
|
2646
|
-
|
|
2647
|
-
// If started as allInOne mode => return function to create instance
|
|
2648
|
-
if (module.parent) {
|
|
2649
|
-
module.exports = startAdapter;
|
|
2650
|
-
} else {
|
|
2651
|
-
// or start the instance directly
|
|
2652
|
-
startAdapter();
|
|
2653
|
-
}
|