@iobroker/gui-components 8.0.2 → 10.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.
Files changed (160) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +834 -543
  3. package/build/AdminConnection.js.map +1 -1
  4. package/build/Components/404.js +13 -13
  5. package/build/Components/404.js.map +1 -1
  6. package/build/Components/ColorPicker.js.map +1 -1
  7. package/build/Components/ComplexCron.js +2 -2
  8. package/build/Components/ComplexCron.js.map +1 -1
  9. package/build/Components/CopyToClipboard.js.map +1 -1
  10. package/build/Components/CustomModal.js +1 -1
  11. package/build/Components/CustomModal.js.map +1 -1
  12. package/build/Components/DeviceType/DeviceTypeIcon.js +1 -0
  13. package/build/Components/DeviceType/DeviceTypeIcon.js.map +1 -1
  14. package/build/Components/DeviceType/DeviceTypeSelector.js +2 -2
  15. package/build/Components/DeviceType/DeviceTypeSelector.js.map +1 -1
  16. package/build/Components/DeviceType/i18n/de.json +1 -0
  17. package/build/Components/DeviceType/i18n/en.json +1 -0
  18. package/build/Components/DeviceType/i18n/fr.json +1 -0
  19. package/build/Components/DeviceType/i18n/it.json +1 -0
  20. package/build/Components/DeviceType/i18n/nl.json +1 -0
  21. package/build/Components/DeviceType/i18n/pl.json +1 -0
  22. package/build/Components/DeviceType/i18n/pt.json +1 -0
  23. package/build/Components/DeviceType/i18n/ru.json +1 -0
  24. package/build/Components/DeviceType/i18n/uk.json +1 -0
  25. package/build/Components/DeviceType/i18n/zh-cn.json +1 -0
  26. package/build/Components/FileBrowser.d.ts +39 -4
  27. package/build/Components/FileBrowser.js +104 -11
  28. package/build/Components/FileBrowser.js.map +1 -1
  29. package/build/Components/FileViewer.js +2 -4
  30. package/build/Components/FileViewer.js.map +1 -1
  31. package/build/Components/Icon.d.ts +1 -3
  32. package/build/Components/Icon.js +11 -11
  33. package/build/Components/Icon.js.map +1 -1
  34. package/build/Components/Image.js +8 -4
  35. package/build/Components/Image.js.map +1 -1
  36. package/build/Components/InfoBox.js +1 -1
  37. package/build/Components/InfoBox.js.map +1 -1
  38. package/build/Components/IobUri.js +5 -5
  39. package/build/Components/IobUri.js.map +1 -1
  40. package/build/Components/Loader.d.ts +2 -3
  41. package/build/Components/Loader.js +25 -257
  42. package/build/Components/Loader.js.map +1 -1
  43. package/build/Components/Loaders/Community.d.ts +31 -0
  44. package/build/Components/Loaders/Community.js +265 -0
  45. package/build/Components/Loaders/Community.js.map +1 -0
  46. package/build/Components/Loaders/HA.d.ts +17 -0
  47. package/build/Components/Loaders/HA.js +99 -0
  48. package/build/Components/Loaders/HA.js.map +1 -0
  49. package/build/Components/Loaders/MV.js.map +1 -1
  50. package/build/Components/Loaders/NW.d.ts +17 -0
  51. package/build/Components/Loaders/NW.js +70 -0
  52. package/build/Components/Loaders/NW.js.map +1 -0
  53. package/build/Components/Loaders/PT.js +103 -103
  54. package/build/Components/Loaders/PT.js.map +1 -1
  55. package/build/Components/Loaders/Vendor.js +7 -7
  56. package/build/Components/Loaders/Vendor.js.map +1 -1
  57. package/build/Components/MDUtils.js.map +1 -1
  58. package/build/Components/ObjectBrowser.d.ts +25 -406
  59. package/build/Components/ObjectBrowser.js +460 -1543
  60. package/build/Components/ObjectBrowser.js.map +1 -1
  61. package/build/Components/Router.js.map +1 -1
  62. package/build/Components/SaveCloseButtons.js.map +1 -1
  63. package/build/Components/Schedule.d.ts +27 -1
  64. package/build/Components/Schedule.js +60 -50
  65. package/build/Components/Schedule.js.map +1 -1
  66. package/build/Components/SelectWithIcon.js +1 -1
  67. package/build/Components/SelectWithIcon.js.map +1 -1
  68. package/build/Components/SimpleCron/cronText.js.map +1 -1
  69. package/build/Components/SimpleCron/index.js +3 -3
  70. package/build/Components/SimpleCron/index.js.map +1 -1
  71. package/build/Components/TabContainer.js +7 -2
  72. package/build/Components/TabContainer.js.map +1 -1
  73. package/build/Components/TabContent.d.ts +1 -1
  74. package/build/Components/TabContent.js +5 -5
  75. package/build/Components/TabContent.js.map +1 -1
  76. package/build/Components/TabHeader.js +2 -2
  77. package/build/Components/TabHeader.js.map +1 -1
  78. package/build/Components/TableResize.js.map +1 -1
  79. package/build/Components/TextWithIcon.js.map +1 -1
  80. package/build/Components/TreeTable.d.ts +1 -0
  81. package/build/Components/TreeTable.js +16 -6
  82. package/build/Components/TreeTable.js.map +1 -1
  83. package/build/Components/UploadImage.js +305 -305
  84. package/build/Components/UploadImage.js.map +1 -1
  85. package/build/Components/Utils.d.ts +17 -3
  86. package/build/Components/Utils.js +167 -9
  87. package/build/Components/Utils.js.map +1 -1
  88. package/build/Components/objectBrowser.types.d.ts +496 -0
  89. package/build/Components/objectBrowserUtils.d.ts +170 -0
  90. package/build/Components/objectBrowserUtils.js +1375 -0
  91. package/build/Components/objectBrowserUtils.js.map +1 -0
  92. package/build/Connection.js.map +1 -1
  93. package/build/Dialogs/ComplexCron.js.map +1 -1
  94. package/build/Dialogs/Confirm.js.map +1 -1
  95. package/build/Dialogs/Cron.js.map +1 -1
  96. package/build/Dialogs/Error.js.map +1 -1
  97. package/build/Dialogs/Message.js.map +1 -1
  98. package/build/Dialogs/SelectFile.d.ts +1 -1
  99. package/build/Dialogs/SelectFile.js +1 -1
  100. package/build/Dialogs/SelectFile.js.map +1 -1
  101. package/build/Dialogs/SelectID.d.ts +1 -1
  102. package/build/Dialogs/SelectID.js +1 -1
  103. package/build/Dialogs/SelectID.js.map +1 -1
  104. package/build/Dialogs/SimpleCron.js.map +1 -1
  105. package/build/Dialogs/TextInput.js +1 -1
  106. package/build/Dialogs/TextInput.js.map +1 -1
  107. package/build/GenericApp.d.ts +6 -4
  108. package/build/GenericApp.js +22 -16
  109. package/build/GenericApp.js.map +1 -1
  110. package/build/Prompt.js +7 -7
  111. package/build/Prompt.js.map +1 -1
  112. package/build/Theme.js +57 -11
  113. package/build/Theme.js.map +1 -1
  114. package/build/assets/devices/parseNames.js +1 -0
  115. package/build/assets/devices/parseNames.js.map +1 -1
  116. package/build/assets/rooms/parseNames.js +1 -0
  117. package/build/assets/rooms/parseNames.js.map +1 -1
  118. package/build/dictionary.js.map +1 -1
  119. package/build/globals.d.ts +2 -0
  120. package/build/i18n/de.json +5 -66
  121. package/build/i18n/en.json +5 -66
  122. package/build/i18n/es.json +5 -66
  123. package/build/i18n/fr.json +5 -66
  124. package/build/i18n/it.json +5 -61
  125. package/build/i18n/nl.json +5 -61
  126. package/build/i18n/pl.json +5 -61
  127. package/build/i18n/pt.json +5 -61
  128. package/build/i18n/ru.json +5 -61
  129. package/build/i18n/uk.json +5 -61
  130. package/build/i18n/zh-cn.json +5 -61
  131. package/build/i18n.js +12 -15
  132. package/build/i18n.js.map +1 -1
  133. package/build/index.css +56 -56
  134. package/build/index.d.ts +9 -4
  135. package/build/index.js +5 -2
  136. package/build/index.js.map +1 -1
  137. package/build/modulefederation.admin.config.d.ts +1 -0
  138. package/build/modulefederation.admin.config.js +1 -1
  139. package/build/modulefederation.admin.config.js.map +1 -1
  140. package/build/types.d.ts +4 -84
  141. package/i18n/de.json +5 -66
  142. package/i18n/en.json +5 -66
  143. package/i18n/es.json +5 -66
  144. package/i18n/fr.json +5 -66
  145. package/i18n/it.json +5 -61
  146. package/i18n/nl.json +5 -61
  147. package/i18n/pl.json +5 -61
  148. package/i18n/pt.json +5 -61
  149. package/i18n/ru.json +5 -61
  150. package/i18n/uk.json +5 -61
  151. package/i18n/zh-cn.json +5 -61
  152. package/index.css +56 -56
  153. package/modulefederation.admin.config.d.ts +1 -0
  154. package/modulefederation.admin.config.js +1 -2
  155. package/package.json +50 -35
  156. package/tasksExample.ts +93 -0
  157. package/build/LegacyConnection.d.ts +0 -938
  158. package/build/LegacyConnection.js +0 -2849
  159. package/build/LegacyConnection.js.map +0 -1
  160. package/tasksExample.js +0 -91
@@ -1,2849 +0,0 @@
1
- /** Possible progress states. */
2
- export const PROGRESS = {
3
- /** The socket is connecting. */
4
- CONNECTING: 0,
5
- /** The socket is successfully connected. */
6
- CONNECTED: 1,
7
- /** All objects are loaded. */
8
- OBJECTS_LOADED: 2,
9
- /** All states are loaded. */
10
- STATES_LOADED: 3,
11
- /** The socket is ready for use. */
12
- READY: 4,
13
- };
14
- const PERMISSION_ERROR = 'permissionError';
15
- const NOT_CONNECTED = 'notConnectedError';
16
- export const ERRORS = {
17
- PERMISSION_ERROR,
18
- NOT_CONNECTED,
19
- };
20
- /** Converts ioB pattern into regex */
21
- export function pattern2RegEx(pattern) {
22
- pattern = (pattern || '').toString();
23
- const startsWithWildcard = pattern[0] === '*';
24
- const endsWithWildcard = pattern[pattern.length - 1] === '*';
25
- pattern = pattern.replace(/[-/\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*');
26
- return (startsWithWildcard ? '' : '^') + pattern + (endsWithWildcard ? '' : '$');
27
- }
28
- export class LegacyConnection {
29
- // Do not define it as null, else we must check for null everywhere
30
- _socket;
31
- _authTimer;
32
- systemLang = 'en';
33
- _waitForFirstConnection;
34
- _waitForFirstConnectionResolve = null;
35
- _promises = {};
36
- _instanceSubscriptions;
37
- props;
38
- doNotLoadAllObjects;
39
- doNotLoadACL;
40
- states = {};
41
- objects = null;
42
- scriptLoadCounter;
43
- acl = null;
44
- firstConnect = true;
45
- waitForRestart = false;
46
- connected = false;
47
- statesSubscribes = {};
48
- objectsSubscribes = {};
49
- filesSubscribes = {};
50
- onConnectionHandlers = [];
51
- onLogHandlers = [];
52
- onProgress;
53
- onError;
54
- loaded = false;
55
- loadTimer = null;
56
- loadCounter = 0;
57
- ignoreState = '';
58
- simStates = {};
59
- autoSubscribes;
60
- autoSubscribeLog;
61
- subscribed;
62
- isSecure;
63
- onCmdStdoutHandler;
64
- onCmdStderrHandler;
65
- onCmdExitHandler;
66
- systemConfig = null;
67
- objectViewCached;
68
- constructor(props) {
69
- props ||= { protocol: window.location.protocol, host: window.location.hostname };
70
- this.props = props;
71
- this.autoSubscribes = this.props.autoSubscribes || [];
72
- this.autoSubscribeLog = this.props.autoSubscribeLog || false;
73
- this.props.protocol ||= window.location.protocol;
74
- this.props.host ||= window.location.hostname;
75
- this.props.port ||=
76
- window.location.port === '3000' ? (LegacyConnection.isWeb() ? 8082 : 8081) : window.location.port;
77
- this.props.ioTimeout = Math.max(this.props.ioTimeout || 20000, 20000);
78
- this.props.cmdTimeout = Math.max(this.props.cmdTimeout || 5000, 5000);
79
- this._instanceSubscriptions = {};
80
- // breaking change. Do not load all objects by default is true
81
- this.doNotLoadAllObjects = this.props.doNotLoadAllObjects === undefined ? true : this.props.doNotLoadAllObjects;
82
- this.doNotLoadACL = this.props.doNotLoadACL === undefined ? true : this.props.doNotLoadACL;
83
- this.states = {};
84
- this._waitForFirstConnection = new Promise(resolve => {
85
- this._waitForFirstConnectionResolve = resolve;
86
- });
87
- this.onProgress = this.props.onProgress || (() => { });
88
- this.onError =
89
- this.props.onError ||
90
- ((err) => console.error(err));
91
- this.startSocket();
92
- }
93
- /**
94
- * Checks if this connection is running in a web adapter and not in an admin.
95
- *
96
- * @returns True if running in a web adapter or in a socketio adapter.
97
- */
98
- static isWeb() {
99
- const adapterName = window.adapterName;
100
- return (adapterName === 'material' ||
101
- adapterName === 'vis' ||
102
- adapterName?.startsWith('vis-') ||
103
- adapterName === 'echarts-show' ||
104
- window.socketUrl !== undefined);
105
- }
106
- /**
107
- * Starts the socket.io connection.
108
- */
109
- startSocket() {
110
- // if socket io is not yet loaded
111
- if (typeof window.io === 'undefined' && typeof window.iob === 'undefined') {
112
- // if in index.html the onLoad function not defined
113
- if (typeof window.registerSocketOnLoad !== 'function') {
114
- // poll if loaded
115
- this.scriptLoadCounter ||= 0;
116
- this.scriptLoadCounter++;
117
- if (this.scriptLoadCounter < 30) {
118
- // wait till the script loaded
119
- setTimeout(() => this.startSocket(), 100);
120
- return;
121
- }
122
- window.alert('Cannot load socket.io.js!');
123
- }
124
- else {
125
- // register on load
126
- window.registerSocketOnLoad(() => this.startSocket());
127
- }
128
- return;
129
- }
130
- if (this._socket) {
131
- // socket was initialized, do not repeat
132
- return;
133
- }
134
- let host = this.props.host;
135
- let port = this.props.port;
136
- let protocol = this.props.protocol.replace(':', '');
137
- let path = window.location.pathname;
138
- if (window.location.hostname === 'iobroker.net' || window.location.hostname === 'iobroker.pro') {
139
- path = '';
140
- }
141
- else {
142
- // if web adapter, socket io could be on another port or even host
143
- if (window.socketUrl) {
144
- const parsed = new URL(window.socketUrl);
145
- host = parsed.hostname;
146
- port = parsed.port;
147
- protocol = parsed.protocol.replace(':', '');
148
- }
149
- // get a current path
150
- const pos = path.lastIndexOf('/');
151
- if (pos !== -1) {
152
- path = path.substring(0, pos + 1);
153
- }
154
- if (LegacyConnection.isWeb()) {
155
- // remove one level, like echarts, vis, .... We have here: '/echarts/'
156
- const parts = path.split('/');
157
- if (parts.length > 2) {
158
- parts.pop();
159
- // if it is a version, like in material, so remove it too
160
- if (parts[parts.length - 1].match(/\d+\.\d+\.\d+/)) {
161
- parts.pop();
162
- }
163
- parts.pop();
164
- path = parts.join('/');
165
- if (!path.endsWith('/')) {
166
- path += '/';
167
- }
168
- }
169
- }
170
- }
171
- const url = port ? `${protocol}://${host}:${port}${path}` : `${protocol}://${host}${path}`;
172
- this._socket = (window.io || window.iob).connect(url, {
173
- path: path.endsWith('/') ? `${path}socket.io` : `${path}/socket.io`,
174
- query: 'ws=true',
175
- name: this.props.name,
176
- timeout: this.props.ioTimeout,
177
- uuid: this.props.uuid,
178
- });
179
- this._socket.on('connect', (noTimeout) => {
180
- // If the user is not admin, it takes some time to install the handlers, because all rights must be checked
181
- if (noTimeout !== true) {
182
- setTimeout(() => this.getVersion().then(info => {
183
- const [major, minor, patch] = info.version.split('.');
184
- const v = parseInt(major, 10) * 10000 + parseInt(minor, 10) * 100 + parseInt(patch, 10);
185
- if (v < 40102) {
186
- this._authTimer = null;
187
- // possible this is an old version of admin
188
- this.onPreConnect(false, false);
189
- }
190
- else {
191
- this._socket.emit('authenticate', (isOk, isSecure) => this.onPreConnect(isOk, isSecure));
192
- }
193
- }), 500);
194
- }
195
- else {
196
- // iobroker websocket waits, till all handlers are installed
197
- this._socket.emit('authenticate', (isOk, isSecure) => this.onPreConnect(isOk, isSecure));
198
- }
199
- });
200
- this._socket.on('reconnect', () => {
201
- this.onProgress(PROGRESS.READY);
202
- this.connected = true;
203
- if (this.waitForRestart) {
204
- window.location.reload();
205
- }
206
- else {
207
- this._subscribe(true);
208
- this.onConnectionHandlers.forEach(cb => cb(true));
209
- }
210
- });
211
- this._socket.on('disconnect', () => {
212
- this.connected = false;
213
- this.subscribed = false;
214
- this.onProgress(PROGRESS.CONNECTING);
215
- this.onConnectionHandlers.forEach(cb => cb(false));
216
- });
217
- this._socket.on('reauthenticate', () => LegacyConnection.authenticate());
218
- this._socket.on('log', message => {
219
- this.props.onLog?.(message);
220
- this.onLogHandlers.forEach(cb => cb(message));
221
- });
222
- this._socket.on('error', (err) => {
223
- let _err = err || '';
224
- if (typeof _err.toString !== 'function') {
225
- _err = JSON.stringify(_err);
226
- console.error(`Received strange error: ${_err}`);
227
- }
228
- _err = _err.toString();
229
- if (_err.includes('User not authorized')) {
230
- LegacyConnection.authenticate();
231
- }
232
- else {
233
- window.alert(`Socket Error: ${err}`);
234
- }
235
- });
236
- this._socket.on('connect_error', (err) => console.error(`Connect error: ${err}`));
237
- this._socket.on('permissionError', (err) => this.onError({
238
- message: 'no permission',
239
- operation: err.operation,
240
- type: err.type,
241
- id: err.id || '',
242
- }));
243
- this._socket.on('objectChange', (id, obj) => setTimeout(() => this.objectChange(id, obj), 0));
244
- this._socket.on('stateChange', (id, state) => setTimeout(() => this.stateChange(id, state), 0));
245
- this._socket.on('im', (messageType, from, data) => setTimeout(() => this.instanceMessage(messageType, from, data), 0));
246
- this._socket.on('fileChange', (id, fileName, size) => setTimeout(() => this.fileChange(id, fileName, size), 0));
247
- this._socket.on('cmdStdout', (id, text) => this.onCmdStdoutHandler?.(id, text));
248
- this._socket.on('cmdStderr', (id, text) => this.onCmdStderrHandler?.(id, text));
249
- this._socket.on('cmdExit', (id, exitCode) => this.onCmdExitHandler?.(id, exitCode));
250
- }
251
- /**
252
- * Called internally.
253
- */
254
- onPreConnect(_isOk, isSecure) {
255
- if (this._authTimer) {
256
- clearTimeout(this._authTimer);
257
- this._authTimer = null;
258
- }
259
- this.connected = true;
260
- this.isSecure = isSecure;
261
- if (this.waitForRestart) {
262
- window.location.reload();
263
- }
264
- else {
265
- if (this.firstConnect) {
266
- // retry strategy
267
- this.loadTimer = setTimeout(() => {
268
- this.loadTimer = null;
269
- this.loadCounter++;
270
- if (this.loadCounter < 10) {
271
- void this.onConnect().catch(e => this.onError(e));
272
- }
273
- }, 1000);
274
- if (!this.loaded) {
275
- void this.onConnect().catch(e => this.onError(e));
276
- }
277
- }
278
- else {
279
- this.onProgress(PROGRESS.READY);
280
- }
281
- this._subscribe(true);
282
- this.onConnectionHandlers.forEach(cb => cb(true));
283
- }
284
- if (this._waitForFirstConnectionResolve) {
285
- this._waitForFirstConnectionResolve();
286
- this._waitForFirstConnectionResolve = null;
287
- }
288
- }
289
- /**
290
- * Checks if running in ioBroker cloud
291
- */
292
- static isCloud() {
293
- if (window.location.hostname.includes('amazonaws.com') || window.location.hostname.includes('iobroker.in')) {
294
- return true;
295
- }
296
- if (typeof window.socketUrl === 'undefined') {
297
- return false;
298
- }
299
- return window.socketUrl.includes('iobroker.in') || window.socketUrl.includes('amazonaws');
300
- }
301
- /**
302
- * Checks if the socket is connected.
303
- */
304
- isConnected() {
305
- return this.connected;
306
- }
307
- /**
308
- * Checks if the socket is connected.
309
- * Promise resolves if once connected.
310
- */
311
- waitForFirstConnection() {
312
- return this._waitForFirstConnection;
313
- }
314
- /**
315
- * Called internally.
316
- */
317
- async _getUserPermissions() {
318
- if (this.doNotLoadACL) {
319
- return null;
320
- }
321
- return new Promise((resolve, reject) => {
322
- this._socket.emit('getUserPermissions', (err, acl) => err ? reject(new Error(err)) : resolve(acl));
323
- });
324
- }
325
- /**
326
- * Called internally.
327
- */
328
- async onConnect() {
329
- let acl;
330
- try {
331
- acl = await this._getUserPermissions();
332
- }
333
- catch (e) {
334
- const knownError = e;
335
- this.onError(`Cannot read user permissions: ${knownError.message}`);
336
- return;
337
- }
338
- if (!this.doNotLoadACL) {
339
- if (this.loaded) {
340
- return;
341
- }
342
- this.loaded = true;
343
- if (this.loadTimer) {
344
- clearTimeout(this.loadTimer);
345
- this.loadTimer = null;
346
- }
347
- this.onProgress(PROGRESS.CONNECTED);
348
- this.firstConnect = false;
349
- this.acl = acl;
350
- }
351
- // Read system configuration
352
- let systemConfig;
353
- try {
354
- systemConfig = await this.getSystemConfig();
355
- if (this.doNotLoadACL) {
356
- if (this.loaded) {
357
- return;
358
- }
359
- this.loaded = true;
360
- if (this.loadTimer) {
361
- clearTimeout(this.loadTimer);
362
- this.loadTimer = null;
363
- }
364
- this.onProgress(PROGRESS.CONNECTED);
365
- this.firstConnect = false;
366
- }
367
- this.systemConfig = systemConfig;
368
- if (this.systemConfig?.common) {
369
- this.systemLang = this.systemConfig.common.language;
370
- }
371
- else {
372
- // @ts-expect-error userLanguage is not standard
373
- this.systemLang = window.navigator.userLanguage || window.navigator.language;
374
- if (/^(en|de|ru|pt|nl|fr|it|es|pl|uk)-?/.test(this.systemLang)) {
375
- this.systemLang = this.systemLang.substr(0, 2);
376
- }
377
- else if (!/^(en|de|ru|pt|nl|fr|it|es|pl|uk|zh-cn)$/.test(this.systemLang)) {
378
- this.systemLang = 'en';
379
- }
380
- }
381
- this.props.onLanguage?.(this.systemLang);
382
- if (!this.doNotLoadAllObjects) {
383
- await this.getObjects();
384
- this.onProgress(PROGRESS.READY);
385
- if (this.props.onReady && this.objects) {
386
- this.props.onReady(this.objects);
387
- }
388
- }
389
- else {
390
- this.objects = { 'system.config': systemConfig };
391
- this.onProgress(PROGRESS.READY);
392
- this.props.onReady?.(this.objects);
393
- }
394
- }
395
- catch (e) {
396
- this.onError(`Cannot read system config: ${e}`);
397
- }
398
- }
399
- /**
400
- * Called internally.
401
- */
402
- static authenticate() {
403
- if (window.location.search.includes('&href=')) {
404
- window.location.href = `${window.location.protocol}//${window.location.host}${window.location.pathname}${window.location.search}${window.location.hash}`;
405
- }
406
- else {
407
- window.location.href = `${window.location.protocol}//${window.location.host}${window.location.pathname}?login&href=${window.location.search}${window.location.hash}`;
408
- }
409
- }
410
- /**
411
- * Subscribe to changes of the given state.
412
- *
413
- * @param id The ioBroker state ID or array of states
414
- * @param binary Set to true if the given state is binary and requires Base64 decoding
415
- * @param cb The callback
416
- */
417
- async subscribeState(id, binary, cb) {
418
- if (typeof binary === 'function') {
419
- cb = binary;
420
- binary = false;
421
- }
422
- let ids;
423
- if (!Array.isArray(id)) {
424
- ids = [id];
425
- }
426
- else {
427
- ids = id;
428
- }
429
- if (!cb) {
430
- console.error('No callback found for subscribeState');
431
- return Promise.reject(new Error('No callback found for subscribeState'));
432
- }
433
- const toSubscribe = [];
434
- for (let i = 0; i < ids.length; i++) {
435
- const _id = ids[i];
436
- if (!this.statesSubscribes[_id]) {
437
- let reg = _id
438
- .replace(/\./g, '\\.')
439
- .replace(/\*/g, '.*')
440
- .replace(/\(/g, '\\(')
441
- .replace(/\)/g, '\\)')
442
- .replace(/\+/g, '\\+')
443
- .replace(/\[/g, '\\[');
444
- if (!reg.includes('*')) {
445
- reg += '$';
446
- }
447
- this.statesSubscribes[_id] = { reg: new RegExp(reg), cbs: [cb] };
448
- if (_id !== this.ignoreState) {
449
- toSubscribe.push(_id);
450
- }
451
- }
452
- else {
453
- !this.statesSubscribes[_id].cbs.includes(cb) && this.statesSubscribes[_id].cbs.push(cb);
454
- }
455
- }
456
- if (!this.connected) {
457
- return;
458
- }
459
- if (toSubscribe.length) {
460
- // no answer from server required
461
- this._socket.emit('subscribe', toSubscribe);
462
- }
463
- if (binary) {
464
- let base64;
465
- for (let i = 0; i < ids.length; i++) {
466
- try {
467
- // deprecated, but we still support it
468
- base64 = await this.getBinaryState(ids[i]);
469
- }
470
- catch (e) {
471
- console.error(`Cannot getBinaryState "${ids[i]}": ${JSON.stringify(e)}`);
472
- base64 = undefined;
473
- }
474
- if (base64 !== undefined && cb) {
475
- cb(ids[i], base64);
476
- }
477
- }
478
- }
479
- else {
480
- return new Promise((resolve, reject) => {
481
- this._socket.emit(LegacyConnection.isWeb() ? 'getStates' : 'getForeignStates', ids, (err, states) => {
482
- if (err) {
483
- console.error(`Cannot getForeignStates "${id}": ${JSON.stringify(err)}`);
484
- reject(new Error(err));
485
- }
486
- else {
487
- if (states) {
488
- Object.keys(states).forEach(_id => cb(_id, states[_id]));
489
- }
490
- resolve();
491
- }
492
- });
493
- });
494
- }
495
- }
496
- /**
497
- * Subscribe to changes of the given state.
498
- */
499
- subscribeStateAsync(
500
- /** The ioBroker state ID or array of states */
501
- id,
502
- /** The callback. */
503
- cb) {
504
- let ids;
505
- if (!Array.isArray(id)) {
506
- ids = [id];
507
- }
508
- else {
509
- ids = id;
510
- }
511
- const toSubscribe = [];
512
- for (let i = 0; i < ids.length; i++) {
513
- const _id = ids[i];
514
- if (!this.statesSubscribes[_id]) {
515
- let reg = _id
516
- .replace(/\./g, '\\.')
517
- .replace(/\*/g, '.*')
518
- .replace(/\(/g, '\\(')
519
- .replace(/\)/g, '\\)')
520
- .replace(/\+/g, '\\+')
521
- .replace(/\[/g, '\\[');
522
- if (!reg.includes('*')) {
523
- reg += '$';
524
- }
525
- this.statesSubscribes[_id] = { reg: new RegExp(reg), cbs: [] };
526
- this.statesSubscribes[_id].cbs.push(cb);
527
- if (_id !== this.ignoreState) {
528
- // no answer from server required
529
- toSubscribe.push(_id);
530
- }
531
- }
532
- else {
533
- !this.statesSubscribes[_id].cbs.includes(cb) && this.statesSubscribes[_id].cbs.push(cb);
534
- }
535
- }
536
- if (toSubscribe.length && this.connected) {
537
- // no answer from server required
538
- this._socket.emit('subscribe', toSubscribe);
539
- }
540
- return new Promise((resolve, reject) => {
541
- if (typeof cb === 'function' && this.connected) {
542
- this._socket.emit(LegacyConnection.isWeb() ? 'getStates' : 'getForeignStates', id, (err, states) => {
543
- err && console.error(`Cannot getForeignStates "${id}": ${JSON.stringify(err)}`);
544
- states && Object.keys(states).forEach(_id => cb(_id, states[_id]));
545
- states
546
- ? resolve()
547
- : reject(new Error(`Cannot getForeignStates "${id}": ${JSON.stringify(err)}`));
548
- });
549
- }
550
- else {
551
- this.connected ? reject(new Error('callback is not a function')) : reject(new Error('not connected'));
552
- }
553
- });
554
- }
555
- /**
556
- * Unsubscribes all or the given callback from changes of the given state.
557
- */
558
- unsubscribeState(
559
- /** The ioBroker state ID or array of states */
560
- id,
561
- /** The callback. */
562
- cb) {
563
- let ids;
564
- if (!Array.isArray(id)) {
565
- ids = [id];
566
- }
567
- else {
568
- ids = id;
569
- }
570
- const toUnsubscribe = [];
571
- for (let i = 0; i < ids.length; i++) {
572
- const _id = ids[i];
573
- if (this.statesSubscribes[_id]) {
574
- if (cb) {
575
- const pos = this.statesSubscribes[_id].cbs.indexOf(cb);
576
- if (pos !== -1) {
577
- this.statesSubscribes[_id].cbs.splice(pos, 1);
578
- }
579
- }
580
- else {
581
- this.statesSubscribes[_id].cbs = [];
582
- }
583
- if (!this.statesSubscribes[_id].cbs || !this.statesSubscribes[_id].cbs.length) {
584
- delete this.statesSubscribes[_id];
585
- if (_id !== this.ignoreState) {
586
- toUnsubscribe.push(_id);
587
- }
588
- }
589
- }
590
- }
591
- if (toUnsubscribe.length && this.connected) {
592
- // no answer from server required
593
- this._socket.emit('unsubscribe', toUnsubscribe);
594
- }
595
- }
596
- /**
597
- * Subscribe to changes of the given object.
598
- *
599
- * @param id The ioBroker object ID or array of objects
600
- * @param cb The callback
601
- */
602
- subscribeObject(id, cb) {
603
- let ids;
604
- if (!Array.isArray(id)) {
605
- ids = [id];
606
- }
607
- else {
608
- ids = id;
609
- }
610
- const toSubscribe = [];
611
- for (let i = 0; i < ids.length; i++) {
612
- const _id = ids[i];
613
- if (!this.objectsSubscribes[_id]) {
614
- let reg = _id.replace(/\./g, '\\.').replace(/\*/g, '.*');
615
- if (!reg.includes('*')) {
616
- reg += '$';
617
- }
618
- this.objectsSubscribes[_id] = { reg: new RegExp(reg), cbs: [cb] };
619
- toSubscribe.push(_id);
620
- }
621
- else {
622
- !this.objectsSubscribes[_id].cbs.includes(cb) && this.objectsSubscribes[_id].cbs.push(cb);
623
- }
624
- }
625
- if (this.connected && toSubscribe.length) {
626
- this._socket.emit('subscribeObjects', toSubscribe);
627
- }
628
- return Promise.resolve();
629
- }
630
- /**
631
- * Unsubscribes all or the given callback from changes of the given object.
632
- *
633
- * @param id The ioBroker object ID or array of objects
634
- * @param cb The callback
635
- */
636
- unsubscribeObject(id, cb) {
637
- let ids;
638
- if (!Array.isArray(id)) {
639
- ids = [id];
640
- }
641
- else {
642
- ids = id;
643
- }
644
- const toUnsubscribe = [];
645
- for (let i = 0; i < ids.length; i++) {
646
- const _id = ids[i];
647
- if (this.objectsSubscribes[_id]) {
648
- if (cb) {
649
- const pos = this.objectsSubscribes[_id].cbs.indexOf(cb);
650
- pos !== -1 && this.objectsSubscribes[_id].cbs.splice(pos, 1);
651
- }
652
- else {
653
- this.objectsSubscribes[_id].cbs = [];
654
- }
655
- if (this.connected && (!this.objectsSubscribes[_id].cbs || !this.objectsSubscribes[_id].cbs.length)) {
656
- delete this.objectsSubscribes[_id];
657
- toUnsubscribe.push(_id);
658
- }
659
- }
660
- }
661
- if (this.connected && toUnsubscribe.length) {
662
- this._socket.emit('unsubscribeObjects', toUnsubscribe);
663
- }
664
- return Promise.resolve();
665
- }
666
- /**
667
- * Called internally.
668
- */
669
- fileChange(id, fileName, size) {
670
- for (const sub of Object.values(this.filesSubscribes)) {
671
- if (sub.regId.test(id) && sub.regFilePattern.test(fileName)) {
672
- for (const cb of sub.cbs) {
673
- try {
674
- cb(id, fileName, size);
675
- }
676
- catch (e) {
677
- console.error(`Error by callback of fileChange: ${e}`);
678
- }
679
- }
680
- }
681
- }
682
- }
683
- /**
684
- * Subscribe to changes of the files.
685
- *
686
- * @param id The ioBroker state ID for meta-object. Could be a pattern
687
- * @param filePattern Pattern or file name, like 'main/*' or 'main/visViews.json`
688
- * @param cb The callback.
689
- */
690
- async subscribeFiles(
691
- /** The ioBroker state ID for meta-object. Could be a pattern */
692
- id,
693
- /** Pattern or file name, like 'main/*' or 'main/visViews.json` */
694
- filePattern,
695
- /** The callback. */
696
- cb) {
697
- if (typeof cb !== 'function') {
698
- throw new Error('The state change handler must be a function!');
699
- }
700
- let filePatterns;
701
- if (Array.isArray(filePattern)) {
702
- filePatterns = filePattern;
703
- }
704
- else {
705
- filePatterns = [filePattern];
706
- }
707
- const toSubscribe = [];
708
- for (let f = 0; f < filePatterns.length; f++) {
709
- const pattern = filePatterns[f];
710
- const key = `${id}$%$${pattern}`;
711
- if (!this.filesSubscribes[key]) {
712
- this.filesSubscribes[key] = {
713
- regId: new RegExp(pattern2RegEx(id)),
714
- regFilePattern: new RegExp(pattern2RegEx(pattern)),
715
- cbs: [cb],
716
- };
717
- toSubscribe.push(pattern);
718
- }
719
- else {
720
- !this.filesSubscribes[key].cbs.includes(cb) && this.filesSubscribes[key].cbs.push(cb);
721
- }
722
- }
723
- if (this.connected && toSubscribe.length) {
724
- this._socket.emit('subscribeFiles', id, toSubscribe);
725
- }
726
- return Promise.resolve();
727
- }
728
- /**
729
- * Unsubscribes the given callback from changes of files.
730
- *
731
- * @param id The ioBroker state ID.
732
- * @param filePattern Pattern or file name, like 'main/*' or 'main/visViews.json`
733
- * @param cb The callback.
734
- */
735
- unsubscribeFiles(id, filePattern, cb) {
736
- let filePatterns;
737
- if (Array.isArray(filePattern)) {
738
- filePatterns = filePattern;
739
- }
740
- else {
741
- filePatterns = [filePattern];
742
- }
743
- const toUnsubscribe = [];
744
- for (let f = 0; f < filePatterns.length; f++) {
745
- const pattern = filePatterns[f];
746
- const key = `${id}$%$${pattern}`;
747
- if (this.filesSubscribes[key]) {
748
- const sub = this.filesSubscribes[key];
749
- if (cb) {
750
- const pos = sub.cbs.indexOf(cb);
751
- pos !== -1 && sub.cbs.splice(pos, 1);
752
- }
753
- else {
754
- sub.cbs = [];
755
- }
756
- if (!sub.cbs?.length) {
757
- delete this.filesSubscribes[key];
758
- if (this.connected) {
759
- toUnsubscribe.push(pattern);
760
- }
761
- }
762
- }
763
- }
764
- if (this.connected && toUnsubscribe.length) {
765
- this._socket.emit('unsubscribeFiles', id, toUnsubscribe);
766
- }
767
- }
768
- /**
769
- * Called internally.
770
- */
771
- objectChange(id, obj) {
772
- // update main.objects cache
773
- if (!this.objects) {
774
- return;
775
- }
776
- let oldObj;
777
- let changed = false;
778
- if (obj) {
779
- if (this.objects[id]) {
780
- // @ts-expect-error fix later
781
- oldObj = { _id: id, type: this.objects[id].type };
782
- }
783
- if (!this.objects[id] || JSON.stringify(this.objects[id]) !== JSON.stringify(obj)) {
784
- this.objects[id] = obj;
785
- changed = true;
786
- }
787
- }
788
- else if (this.objects[id]) {
789
- // @ts-expect-error fix later
790
- oldObj = { _id: id, type: this.objects[id].type };
791
- delete this.objects[id];
792
- changed = true;
793
- }
794
- Object.keys(this.objectsSubscribes).forEach(_id => {
795
- if (_id === id || this.objectsSubscribes[_id].reg.test(id)) {
796
- this.objectsSubscribes[_id].cbs.forEach(cb => {
797
- try {
798
- cb(id, obj, oldObj);
799
- }
800
- catch (e) {
801
- console.error(`Error by callback of objectChange: ${e}`);
802
- }
803
- });
804
- }
805
- });
806
- if (changed && this.props.onObjectChange) {
807
- void this.props.onObjectChange(id, obj);
808
- }
809
- }
810
- /**
811
- * Called internally.
812
- */
813
- stateChange(id, state) {
814
- for (const task in this.statesSubscribes) {
815
- if (Object.prototype.hasOwnProperty.call(this.statesSubscribes, task) &&
816
- this.statesSubscribes[task].reg.test(id)) {
817
- this.statesSubscribes[task].cbs.forEach(cb => {
818
- try {
819
- void cb(id, state);
820
- }
821
- catch (e) {
822
- const knownError = e;
823
- console.error(`Error by callback of stateChange: ${knownError?.message}`);
824
- }
825
- });
826
- }
827
- }
828
- }
829
- /**
830
- * Called internally.
831
- *
832
- * @param messageType The message type
833
- * @param sourceInstance The source instance
834
- * @param data Payload
835
- */
836
- instanceMessage(messageType, sourceInstance, data) {
837
- if (this._instanceSubscriptions[sourceInstance]) {
838
- this._instanceSubscriptions[sourceInstance].forEach(sub => {
839
- if (sub.messageType === messageType) {
840
- sub.callback(data, sourceInstance, messageType);
841
- }
842
- });
843
- }
844
- }
845
- /**
846
- * Gets all states.
847
- *
848
- * @param pattern The pattern to filter states
849
- * @param disableProgressUpdate Don't call onProgress() when done
850
- */
851
- getStates(pattern, disableProgressUpdate) {
852
- if (!this.connected) {
853
- return Promise.reject(new Error(NOT_CONNECTED));
854
- }
855
- if (typeof pattern === 'boolean') {
856
- disableProgressUpdate = pattern;
857
- pattern = undefined;
858
- }
859
- return new Promise((resolve, reject) => {
860
- this._socket.emit('getStates', pattern, (err, res) => {
861
- this.states = res;
862
- !disableProgressUpdate && this.onProgress(PROGRESS.STATES_LOADED);
863
- err ? reject(new Error(err)) : resolve(this.states);
864
- });
865
- });
866
- }
867
- /**
868
- * Gets the given state.
869
- *
870
- * @param id The state ID
871
- */
872
- getState(id) {
873
- if (!this.connected) {
874
- return Promise.reject(new Error(NOT_CONNECTED));
875
- }
876
- if (id && id === this.ignoreState) {
877
- return Promise.resolve(this.simStates[id] || { val: null, ack: true });
878
- }
879
- return new Promise((resolve, reject) => {
880
- this._socket.emit('getState', id, (err, state) => err ? reject(new Error(err)) : resolve(state));
881
- });
882
- }
883
- /**
884
- * Get the given binary state.
885
- *
886
- * @deprecated since js-controller 5.0. Use files instead.
887
- * @param id The state ID.
888
- */
889
- getBinaryState(id) {
890
- if (!this.connected) {
891
- return Promise.reject(new Error(NOT_CONNECTED));
892
- }
893
- // the data will come in base64
894
- return new Promise((resolve, reject) => {
895
- this._socket.emit('getBinaryState', id, (err, base64) => err ? reject(new Error(err)) : resolve(base64));
896
- });
897
- }
898
- /**
899
- * Set the given binary state.
900
- *
901
- * @deprecated since js-controller 5.0. Use files instead.
902
- * @param id The state ID.
903
- * @param base64 The Base64 encoded binary data.
904
- */
905
- setBinaryState(id, base64) {
906
- if (!this.connected) {
907
- return Promise.reject(new Error(NOT_CONNECTED));
908
- }
909
- // the data will come in base64
910
- return new Promise((resolve, reject) => {
911
- this._socket.emit('setBinaryState', id, base64, (err) => err ? reject(new Error(err)) : resolve());
912
- });
913
- }
914
- /**
915
- * Sets the given state value.
916
- *
917
- * @param id The state ID
918
- * @param val The state value
919
- * @param ack The acknowledgment flag
920
- */
921
- setState(id, val, ack) {
922
- if (!this.connected) {
923
- return Promise.reject(new Error(NOT_CONNECTED));
924
- }
925
- // extra handling for "nothing_selected" state for vis
926
- if (id && id === this.ignoreState) {
927
- let state;
928
- if (typeof ack === 'boolean') {
929
- state = val;
930
- }
931
- else if (typeof val === 'object' && val.val !== undefined) {
932
- state = val;
933
- }
934
- else {
935
- state = {
936
- val: val,
937
- ack: false,
938
- ts: Date.now(),
939
- lc: Date.now(),
940
- from: 'system.adapter.vis.0',
941
- };
942
- }
943
- this.simStates[id] = state;
944
- // inform subscribers about changes
945
- if (this.statesSubscribes[id]) {
946
- for (const cb of this.statesSubscribes[id].cbs) {
947
- try {
948
- void cb(id, state);
949
- }
950
- catch (e) {
951
- console.error(`Error by callback of stateChanged: ${e}`);
952
- }
953
- }
954
- }
955
- return Promise.resolve();
956
- }
957
- return new Promise((resolve, reject) => {
958
- this._socket.emit('setState', id, val, (err) => (err ? reject(new Error(err)) : resolve()));
959
- });
960
- }
961
- /**
962
- * Gets all objects.
963
- *
964
- * @param update Set to true to retrieve all objects from the server (instead of using the local cache)
965
- * @param disableProgressUpdate Don't call onProgress() when done
966
- */
967
- getObjects(update, disableProgressUpdate) {
968
- if (!this.connected) {
969
- return Promise.reject(new Error(NOT_CONNECTED));
970
- }
971
- return new Promise((resolve, reject) => {
972
- if (!update && this.objects) {
973
- resolve(this.objects);
974
- }
975
- else {
976
- this._socket.emit(LegacyConnection.isWeb() ? 'getObjects' : 'getAllObjects', (err, res) => {
977
- this.objects = res;
978
- disableProgressUpdate && this.onProgress(PROGRESS.OBJECTS_LOADED);
979
- err ? reject(new Error(err)) : resolve(this.objects);
980
- });
981
- }
982
- });
983
- }
984
- /**
985
- * Gets objects by list of IDs.
986
- *
987
- * @param list Array of object IDs to retrieve
988
- */
989
- getObjectsById(list) {
990
- if (!this.connected) {
991
- return Promise.reject(new Error(NOT_CONNECTED));
992
- }
993
- return new Promise((resolve, reject) => {
994
- this._socket.emit('getObjects', list, (err, res) => err ? reject(new Error(err)) : resolve(res));
995
- });
996
- }
997
- /**
998
- * Called internally.
999
- */
1000
- _subscribe(isEnable) {
1001
- if (isEnable && !this.subscribed) {
1002
- this.subscribed = true;
1003
- this.autoSubscribes.forEach(id => this._socket.emit('subscribeObjects', id));
1004
- // re-subscribe objects
1005
- Object.keys(this.objectsSubscribes).forEach(id => this._socket.emit('subscribeObjects', id));
1006
- // re-subscribe logs
1007
- this.autoSubscribeLog && this._socket.emit('requireLog', true);
1008
- // re-subscribe states
1009
- const ids = Object.keys(this.statesSubscribes);
1010
- ids.forEach(id => this._socket.emit('subscribe', id));
1011
- ids.length &&
1012
- this._socket.emit(LegacyConnection.isWeb() ? 'getStates' : 'getForeignStates', ids, (err, states) => {
1013
- err && console.error(`Cannot getForeignStates: ${JSON.stringify(err)}`);
1014
- // inform about states
1015
- states && Object.keys(states).forEach(id => this.stateChange(id, states[id]));
1016
- });
1017
- }
1018
- else if (!isEnable && this.subscribed) {
1019
- this.subscribed = false;
1020
- // un-subscribe objects
1021
- this.autoSubscribes.forEach(id => this._socket.emit('unsubscribeObjects', id));
1022
- Object.keys(this.objectsSubscribes).forEach(id => this._socket.emit('unsubscribeObjects', id));
1023
- // un-subscribe logs
1024
- this.autoSubscribeLog && this._socket.emit('requireLog', false);
1025
- // un-subscribe states
1026
- Object.keys(this.statesSubscribes).forEach(id => this._socket.emit('unsubscribe', id));
1027
- }
1028
- }
1029
- /**
1030
- * Requests log updates.
1031
- *
1032
- * @param isEnabled Set to true to get logs
1033
- */
1034
- requireLog(isEnabled) {
1035
- if (!this.connected) {
1036
- return Promise.reject(new Error(NOT_CONNECTED));
1037
- }
1038
- return new Promise((resolve, reject) => {
1039
- this._socket.emit('requireLog', isEnabled, (err) => err ? reject(new Error(err)) : resolve());
1040
- });
1041
- }
1042
- /**
1043
- * Deletes the given object.
1044
- *
1045
- * @param id The object ID
1046
- * @param maintenance Force deletion of non-conform IDs
1047
- */
1048
- delObject(id, maintenance) {
1049
- if (!this.connected) {
1050
- return Promise.reject(new Error(NOT_CONNECTED));
1051
- }
1052
- return new Promise((resolve, reject) => {
1053
- this._socket.emit('delObject', id, { maintenance: !!maintenance }, (err) => err ? reject(new Error(err)) : resolve());
1054
- });
1055
- }
1056
- /**
1057
- * Deletes the given object and all its children.
1058
- *
1059
- * @param id The object ID
1060
- * @param maintenance Force deletion of non-conform IDs
1061
- */
1062
- delObjects(id, maintenance) {
1063
- if (!this.connected) {
1064
- return Promise.reject(new Error(NOT_CONNECTED));
1065
- }
1066
- return new Promise((resolve, reject) => {
1067
- this._socket.emit('delObjects', id, { maintenance: !!maintenance }, (err) => err ? reject(new Error(err)) : resolve());
1068
- });
1069
- }
1070
- /**
1071
- * Sets the object.
1072
- */
1073
- setObject(id, obj) {
1074
- if (!this.connected) {
1075
- return Promise.reject(new Error(NOT_CONNECTED));
1076
- }
1077
- if (!obj) {
1078
- return Promise.reject(new Error('Null object is not allowed'));
1079
- }
1080
- obj = JSON.parse(JSON.stringify(obj));
1081
- if (Object.prototype.hasOwnProperty.call(obj, 'from')) {
1082
- delete obj.from;
1083
- }
1084
- if (Object.prototype.hasOwnProperty.call(obj, 'user')) {
1085
- delete obj.user;
1086
- }
1087
- if (Object.prototype.hasOwnProperty.call(obj, 'ts')) {
1088
- delete obj.ts;
1089
- }
1090
- return new Promise((resolve, reject) => {
1091
- this._socket.emit('setObject', id, obj, (err) => (err ? reject(new Error(err)) : resolve()));
1092
- });
1093
- }
1094
- /**
1095
- * Gets the object with the given id from the server.
1096
- */
1097
- getObject(id) {
1098
- if (!this.connected) {
1099
- return Promise.reject(new Error(NOT_CONNECTED));
1100
- }
1101
- if (id && id === this.ignoreState) {
1102
- return Promise.resolve({
1103
- _id: this.ignoreState,
1104
- type: 'state',
1105
- common: {
1106
- name: 'ignored state',
1107
- type: 'mixed',
1108
- read: true,
1109
- write: true,
1110
- role: 'state',
1111
- },
1112
- native: {},
1113
- });
1114
- }
1115
- return new Promise((resolve, reject) => {
1116
- this._socket.emit('getObject', id, (err, obj) => err ? reject(new Error(err)) : resolve(obj));
1117
- });
1118
- }
1119
- /**
1120
- * Get all instances of the given adapter or all instances of all adapters.
1121
- *
1122
- * @param adapter The name of the adapter
1123
- * @param update Force update
1124
- */
1125
- getAdapterInstances(adapter, update) {
1126
- if (typeof adapter === 'boolean') {
1127
- update = adapter;
1128
- adapter = '';
1129
- }
1130
- adapter ||= '';
1131
- if (!update && this._promises[`instances_${adapter}`] instanceof Promise) {
1132
- return this._promises[`instances_${adapter}`];
1133
- }
1134
- if (!this.connected) {
1135
- return Promise.reject(new Error(NOT_CONNECTED));
1136
- }
1137
- this._promises[`instances_${adapter}`] = new Promise((resolve, reject) => {
1138
- this._socket.emit('getAdapterInstances', adapter, (err, instances) => err ? reject(new Error(err)) : resolve(instances));
1139
- });
1140
- return this._promises[`instances_${adapter}`];
1141
- }
1142
- /**
1143
- * Get adapters with the given name or all adapters.
1144
- *
1145
- * @param adapter The name of the adapter
1146
- * @param update Force update
1147
- */
1148
- getAdapters(adapter, update) {
1149
- if (LegacyConnection.isWeb()) {
1150
- return Promise.reject(new Error('Allowed only in admin'));
1151
- }
1152
- if (typeof adapter === 'boolean') {
1153
- update = adapter;
1154
- adapter = '';
1155
- }
1156
- adapter ||= '';
1157
- if (!update && this._promises[`adapter_${adapter}`] instanceof Promise) {
1158
- return this._promises[`adapter_${adapter}`];
1159
- }
1160
- if (!this.connected) {
1161
- return Promise.reject(new Error(NOT_CONNECTED));
1162
- }
1163
- this._promises[`adapter_${adapter}`] = new Promise((resolve, reject) => {
1164
- this._socket.emit('getAdapters', adapter, (err, adapters) => {
1165
- err ? reject(new Error(err)) : resolve(adapters);
1166
- });
1167
- });
1168
- return this._promises[`adapter_${adapter}`];
1169
- }
1170
- /**
1171
- * Called internally.
1172
- */
1173
- _renameGroups(objs, cb) {
1174
- if (!objs?.length) {
1175
- cb?.(null);
1176
- }
1177
- else {
1178
- const obj = objs.pop();
1179
- if (!obj) {
1180
- setTimeout(() => this._renameGroups(objs, cb), 0);
1181
- return;
1182
- }
1183
- const oldId = obj._id;
1184
- obj._id = obj.newId;
1185
- delete obj.newId;
1186
- this.setObject(obj._id, obj)
1187
- .then(() => this.delObject(oldId))
1188
- .then(() => setTimeout(() => this._renameGroups(objs, cb), 0))
1189
- .catch((err) => cb?.(err));
1190
- }
1191
- }
1192
- /**
1193
- * Rename a group.
1194
- *
1195
- * @param id The id.
1196
- * @param newId The new id.
1197
- * @param newName The new name.
1198
- */
1199
- async renameGroup(id, newId, newName) {
1200
- if (LegacyConnection.isWeb()) {
1201
- return Promise.reject(new Error('Allowed only in admin'));
1202
- }
1203
- const groups = await this.getGroups(true);
1204
- if (groups.length) {
1205
- // find all elements
1206
- const groupsToRename = groups.filter(group => group._id.startsWith(`${id}.`));
1207
- groupsToRename.forEach(group => {
1208
- group.newId = (newId + group._id.substring(id.length));
1209
- });
1210
- await new Promise((resolve, reject) => {
1211
- this._renameGroups(groupsToRename, (err) => err ? reject(new Error(err)) : resolve(null));
1212
- });
1213
- const obj = groups.find(group => group._id === id);
1214
- if (obj) {
1215
- obj._id = newId;
1216
- if (newName !== undefined) {
1217
- obj.common ||= {};
1218
- obj.common.name = newName;
1219
- }
1220
- return this.setObject(obj._id, obj).then(() => this.delObject(id));
1221
- }
1222
- }
1223
- return Promise.resolve();
1224
- }
1225
- /**
1226
- * Sends a message to a specific instance or all instances of some specific adapter.
1227
- *
1228
- * @param instance The instance to send this message to.
1229
- * @param command Command name of the target instance.
1230
- * @param data The message data to send.
1231
- */
1232
- sendTo(instance, command, data) {
1233
- if (!this.connected) {
1234
- return Promise.reject(new Error(NOT_CONNECTED));
1235
- }
1236
- return new Promise(resolve => {
1237
- this._socket.emit('sendTo', instance, command, data, (result) => resolve(result));
1238
- });
1239
- }
1240
- /**
1241
- * Extend an object and create it if it might not exist.
1242
- *
1243
- * @param id The id.
1244
- * @param obj The object.
1245
- */
1246
- extendObject(id, obj) {
1247
- if (!this.connected) {
1248
- return Promise.reject(new Error(NOT_CONNECTED));
1249
- }
1250
- obj = JSON.parse(JSON.stringify(obj));
1251
- if (Object.prototype.hasOwnProperty.call(obj, 'from')) {
1252
- delete obj.from;
1253
- }
1254
- if (Object.prototype.hasOwnProperty.call(obj, 'user')) {
1255
- delete obj.user;
1256
- }
1257
- if (Object.prototype.hasOwnProperty.call(obj, 'ts')) {
1258
- delete obj.ts;
1259
- }
1260
- return new Promise((resolve, reject) => {
1261
- this._socket.emit('extendObject', id, obj, (err) => err ? reject(new Error(err)) : resolve());
1262
- });
1263
- }
1264
- /**
1265
- * Register a handler for log messages.
1266
- */
1267
- registerLogHandler(handler) {
1268
- !this.onLogHandlers.includes(handler) && this.onLogHandlers.push(handler);
1269
- }
1270
- /**
1271
- * Unregister a handler for log messages.
1272
- */
1273
- unregisterLogHandler(handler) {
1274
- const pos = this.onLogHandlers.indexOf(handler);
1275
- pos !== -1 && this.onLogHandlers.splice(pos, 1);
1276
- }
1277
- /**
1278
- * Register a handler for the connection state.
1279
- */
1280
- registerConnectionHandler(handler) {
1281
- !this.onConnectionHandlers.includes(handler) && this.onConnectionHandlers.push(handler);
1282
- }
1283
- /**
1284
- * Unregister a handler for the connection state.
1285
- */
1286
- unregisterConnectionHandler(handler) {
1287
- const pos = this.onConnectionHandlers.indexOf(handler);
1288
- pos !== -1 && this.onConnectionHandlers.splice(pos, 1);
1289
- }
1290
- /**
1291
- * Set the handler for standard output of a command.
1292
- *
1293
- * @param handler The handler.
1294
- */
1295
- registerCmdStdoutHandler(handler) {
1296
- this.onCmdStdoutHandler = handler;
1297
- }
1298
- /**
1299
- * Unset the handler for standard output of a command.
1300
- */
1301
- unregisterCmdStdoutHandler( /* handler */) {
1302
- this.onCmdStdoutHandler = undefined;
1303
- }
1304
- /**
1305
- * Set the handler for standard error of a command.
1306
- *
1307
- * @param handler The handler.
1308
- */
1309
- registerCmdStderrHandler(handler) {
1310
- this.onCmdStderrHandler = handler;
1311
- }
1312
- /**
1313
- * Unset the handler for standard error of a command.
1314
- */
1315
- unregisterCmdStderrHandler() {
1316
- this.onCmdStderrHandler = undefined;
1317
- }
1318
- /**
1319
- * Set the handler for exit of a command.
1320
- */
1321
- registerCmdExitHandler(handler) {
1322
- this.onCmdExitHandler = handler;
1323
- }
1324
- /**
1325
- * Unset the handler for exit of a command.
1326
- */
1327
- unregisterCmdExitHandler() {
1328
- this.onCmdExitHandler = undefined;
1329
- }
1330
- /**
1331
- * Get all enums with the given name.
1332
- */
1333
- getEnums(
1334
- /** The name of the enum. */
1335
- _enum,
1336
- /** Force update. */
1337
- update) {
1338
- if (!update && this._promises[`enums_${_enum || 'all'}`] instanceof Promise) {
1339
- return this._promises[`enums_${_enum || 'all'}`];
1340
- }
1341
- if (!this.connected) {
1342
- return Promise.reject(new Error(NOT_CONNECTED));
1343
- }
1344
- this._promises[`enums_${_enum || 'all'}`] = new Promise((resolve, reject) => {
1345
- this._socket.emit('getObjectView', 'system', 'enum', { startkey: `enum.${_enum || ''}`, endkey: `enum.${_enum ? `${_enum}.` : ''}\u9999` }, (err, res) => {
1346
- if (!err && res) {
1347
- const _res = {};
1348
- for (let i = 0; i < res.rows.length; i++) {
1349
- if (_enum && res.rows[i].id === `enum.${_enum}`) {
1350
- continue;
1351
- }
1352
- _res[res.rows[i].id] = res.rows[i].value;
1353
- }
1354
- resolve(_res);
1355
- }
1356
- else if (err) {
1357
- reject(new Error(err));
1358
- }
1359
- else {
1360
- reject(new Error('Invalid response while getting enums'));
1361
- }
1362
- });
1363
- });
1364
- return this._promises[`enums_${_enum || 'all'}`];
1365
- }
1366
- /**
1367
- * Query a predefined object view.
1368
- *
1369
- * @param design design - 'system' or other designs like `custom`.
1370
- * @param type The type of object.
1371
- * @param start The start ID.
1372
- * @param end The end ID.
1373
- */
1374
- getObjectViewCustom(
1375
- /** The design: 'system' or other designs like `custom`. */
1376
- design,
1377
- /** The type of object. */
1378
- type,
1379
- /** The start ID. */
1380
- start,
1381
- /** The end ID. */
1382
- end) {
1383
- return new Promise((resolve, reject) => {
1384
- this._socket.emit('getObjectView', design, type, { startkey: start, endkey: end }, (err, res) => {
1385
- if (!err) {
1386
- const _res = {};
1387
- if (res && res.rows) {
1388
- for (let i = 0; i < res.rows.length; i++) {
1389
- _res[res.rows[i].id] = res.rows[i].value;
1390
- }
1391
- }
1392
- resolve(_res);
1393
- }
1394
- else {
1395
- reject(new Error(err));
1396
- }
1397
- });
1398
- });
1399
- }
1400
- /**
1401
- * Query a predefined object view.
1402
- *
1403
- * @param type The type of object.
1404
- * @param start The start ID.
1405
- * @param end The end ID.
1406
- */
1407
- async getObjectViewSystem(type, start, end) {
1408
- const key = `${type}_${start || ''}_${end || ''}`;
1409
- const result = await this.getObjectViewCustom('system', type, start, end);
1410
- if (this.objectViewCached?.[key]) {
1411
- // update cached value
1412
- this.objectViewCached[key] = result;
1413
- }
1414
- return result;
1415
- }
1416
- /**
1417
- * Query a predefined object view.
1418
- *
1419
- * @param type The type of object.
1420
- * @param start The start ID.
1421
- * @param [end] The end ID.
1422
- */
1423
- async getObjectViewSystemCached(type, start, end) {
1424
- const key = `${type}_${start || ''}_${end || ''}`;
1425
- if (this.objectViewCached?.[key]) {
1426
- return Promise.resolve(this.objectViewCached[key]);
1427
- }
1428
- const result = await this.getObjectViewCustom('system', type, start, end);
1429
- this.objectViewCached ||= {};
1430
- this.objectViewCached[key] = result;
1431
- return result;
1432
- }
1433
- /**
1434
- * @deprecated since version 1.1.15, cause parameter order does not match backend
1435
- *
1436
- * Query a predefined object view.
1437
- * @param start The start ID.
1438
- * @param end The end ID.
1439
- * @param type The type of object.
1440
- */
1441
- getObjectView(start, end, type) {
1442
- if (!this.connected) {
1443
- return Promise.reject(new Error(NOT_CONNECTED));
1444
- }
1445
- start ||= '';
1446
- end ||= '\u9999';
1447
- return this.getObjectViewCustom('system', type, start, end);
1448
- }
1449
- /**
1450
- * Get the stored certificates.
1451
- *
1452
- * @param update Force update.
1453
- */
1454
- getCertificates(update) {
1455
- if (LegacyConnection.isWeb()) {
1456
- return Promise.reject(new Error('Allowed only in admin'));
1457
- }
1458
- if (this._promises.cert instanceof Promise && !update) {
1459
- return this._promises.cert;
1460
- }
1461
- if (!this.connected) {
1462
- return Promise.reject(new Error(NOT_CONNECTED));
1463
- }
1464
- this._promises.cert = this.getObject('system.certificates').then(res => {
1465
- const certs = [];
1466
- if (res && res.native && res.native.certificates) {
1467
- Object.keys(res.native.certificates).forEach(c => {
1468
- const cert = res.native.certificates[c];
1469
- if (!cert) {
1470
- return;
1471
- }
1472
- const _cert = {
1473
- name: c,
1474
- type: '',
1475
- };
1476
- // If it is a filename, it could be everything
1477
- if (cert.length < 700 && (cert.includes('/') || cert.includes('\\'))) {
1478
- if (c.toLowerCase().includes('private')) {
1479
- _cert.type = 'private';
1480
- }
1481
- else if (cert.toLowerCase().includes('private')) {
1482
- _cert.type = 'private';
1483
- }
1484
- else if (c.toLowerCase().includes('public')) {
1485
- _cert.type = 'public';
1486
- }
1487
- else if (cert.toLowerCase().includes('public')) {
1488
- _cert.type = 'public';
1489
- }
1490
- certs.push(_cert);
1491
- }
1492
- else {
1493
- _cert.type =
1494
- cert.substring(0, '-----BEGIN RSA PRIVATE KEY'.length) === '-----BEGIN RSA PRIVATE KEY' ||
1495
- cert.substring(0, '-----BEGIN PRIVATE KEY'.length) === '-----BEGIN PRIVATE KEY'
1496
- ? 'private'
1497
- : 'public';
1498
- if (_cert.type === 'public') {
1499
- const m = cert.split('-----END CERTIFICATE-----');
1500
- if (m.filter((t) => t.replace(/\r\n|\r|\n/, '').trim()).length > 1) {
1501
- _cert.type = 'chained';
1502
- }
1503
- }
1504
- certs.push(_cert);
1505
- }
1506
- });
1507
- }
1508
- return certs;
1509
- });
1510
- return this._promises.cert;
1511
- }
1512
- /**
1513
- * Get the logs from a host (only for admin connection).
1514
- */
1515
- getLogs(host, linesNumber) {
1516
- if (LegacyConnection.isWeb()) {
1517
- return Promise.reject(new Error('Allowed only in admin'));
1518
- }
1519
- if (!this.connected) {
1520
- return Promise.reject(new Error(NOT_CONNECTED));
1521
- }
1522
- return new Promise(resolve => {
1523
- this._socket.emit('sendToHost', host, 'getLogs', linesNumber || 200, (lines) => resolve(lines));
1524
- });
1525
- }
1526
- /**
1527
- * Get the log files (only for admin connection).
1528
- */
1529
- getLogsFiles(host) {
1530
- if (LegacyConnection.isWeb()) {
1531
- return Promise.reject(new Error('Allowed only in admin'));
1532
- }
1533
- if (!this.connected) {
1534
- return Promise.reject(new Error(NOT_CONNECTED));
1535
- }
1536
- return new Promise((resolve, reject) => {
1537
- this._socket.emit('readLogs', host, (err, files) => err ? reject(new Error(err)) : resolve(files));
1538
- });
1539
- }
1540
- /**
1541
- * Delete the logs from a host (only for admin connection).
1542
- */
1543
- delLogs(host) {
1544
- if (LegacyConnection.isWeb()) {
1545
- return Promise.reject(new Error('Allowed only in admin'));
1546
- }
1547
- if (!this.connected) {
1548
- return Promise.reject(new Error(NOT_CONNECTED));
1549
- }
1550
- return new Promise((resolve, reject) => {
1551
- this._socket.emit('sendToHost', host, 'delLogs', null, (error) => error ? reject(new Error(error)) : resolve());
1552
- });
1553
- }
1554
- /**
1555
- * Read the meta items.
1556
- */
1557
- readMetaItems() {
1558
- if (!this.connected) {
1559
- return Promise.reject(new Error(NOT_CONNECTED));
1560
- }
1561
- return new Promise((resolve, reject) => {
1562
- this._socket.emit('getObjectView', 'system', 'meta', { startkey: '', endkey: '\u9999' }, (err, objs) => err
1563
- ? reject(new Error(err))
1564
- : resolve(objs.rows &&
1565
- objs.rows.map((obj) => obj.value)));
1566
- });
1567
- }
1568
- /**
1569
- * Read the directory of an adapter.
1570
- *
1571
- * @param adapter The adapter name.
1572
- * @param fileName The directory name.
1573
- */
1574
- readDir(adapter, fileName) {
1575
- if (!this.connected) {
1576
- return Promise.reject(new Error(NOT_CONNECTED));
1577
- }
1578
- return new Promise((resolve, reject) => {
1579
- this._socket.emit('readDir', adapter, fileName, (err, files) => err ? reject(new Error(err)) : resolve(files));
1580
- });
1581
- }
1582
- /**
1583
- * Read a file of an adapter.
1584
- *
1585
- * @param adapter The adapter name.
1586
- * @param fileName The file name.
1587
- * @param base64 If it must be a base64 format.
1588
- */
1589
- readFile(adapter, fileName, base64) {
1590
- if (!this.connected) {
1591
- return Promise.reject(new Error(NOT_CONNECTED));
1592
- }
1593
- return new Promise((resolve, reject) => {
1594
- if (!base64) {
1595
- this._socket.emit('readFile', adapter, fileName, (err, data, type) => {
1596
- err ? reject(new Error(err)) : resolve({ data, type });
1597
- });
1598
- }
1599
- else {
1600
- this._socket.emit('readFile64', adapter, fileName, base64, (err, data) => err ? reject(new Error(err)) : resolve(data));
1601
- }
1602
- });
1603
- }
1604
- /**
1605
- * Write a file of an adapter.
1606
- *
1607
- * @param adapter The adapter name.
1608
- * @param fileName The file name.
1609
- * @param data The data (if it's a Buffer, it will be converted to Base64)
1610
- */
1611
- writeFile64(adapter, fileName, data) {
1612
- if (!this.connected) {
1613
- return Promise.reject(new Error(NOT_CONNECTED));
1614
- }
1615
- return new Promise((resolve, reject) => {
1616
- if (typeof data === 'string') {
1617
- this._socket.emit('writeFile', adapter, fileName, data, (err) => err ? reject(new Error(err)) : resolve());
1618
- }
1619
- else {
1620
- const base64 = btoa(new Uint8Array(data).reduce((_data, byte) => _data + String.fromCharCode(byte), ''));
1621
- this._socket.emit('writeFile64', adapter, fileName, base64, (err) => err ? reject(new Error(err)) : resolve());
1622
- }
1623
- });
1624
- }
1625
- /**
1626
- * Delete a file of an adapter.
1627
- *
1628
- * @param adapter The adapter name.
1629
- * @param fileName The file name.
1630
- */
1631
- deleteFile(adapter, fileName) {
1632
- if (!this.connected) {
1633
- return Promise.reject(new Error(NOT_CONNECTED));
1634
- }
1635
- return new Promise((resolve, reject) => {
1636
- this._socket.emit('unlink', adapter, fileName, (err) => err ? reject(new Error(err)) : resolve());
1637
- });
1638
- }
1639
- /**
1640
- * Delete a folder of an adapter.
1641
- * All files in folder will be deleted.
1642
- *
1643
- * @param adapter The adapter name.
1644
- * @param folderName The folder name.
1645
- */
1646
- deleteFolder(adapter, folderName) {
1647
- if (!this.connected) {
1648
- return Promise.reject(new Error(NOT_CONNECTED));
1649
- }
1650
- return new Promise((resolve, reject) => {
1651
- this._socket.emit('deleteFolder', adapter, folderName, (err) => err ? reject(new Error(err)) : resolve());
1652
- });
1653
- }
1654
- /**
1655
- * Get the list of all hosts.
1656
- *
1657
- * @param update Force update.
1658
- */
1659
- getHosts(update) {
1660
- if (LegacyConnection.isWeb()) {
1661
- return Promise.reject(new Error('Allowed only in admin'));
1662
- }
1663
- if (!update && this._promises.hosts instanceof Promise) {
1664
- return this._promises.hosts;
1665
- }
1666
- if (!this.connected) {
1667
- return Promise.reject(new Error(NOT_CONNECTED));
1668
- }
1669
- this._promises.hosts = new Promise((resolve, reject) => {
1670
- this._socket.emit('getObjectView', 'system', 'host', { startkey: 'system.host.', endkey: 'system.host.\u9999' }, (err, doc) => {
1671
- if (err) {
1672
- reject(new Error(err));
1673
- }
1674
- else {
1675
- resolve(doc.rows.map(item => item.value));
1676
- }
1677
- });
1678
- });
1679
- return this._promises.hosts;
1680
- }
1681
- /**
1682
- * Get the list of all users.
1683
- *
1684
- * @param update Force update.
1685
- */
1686
- getUsers(update) {
1687
- if (LegacyConnection.isWeb()) {
1688
- return Promise.reject(new Error('Allowed only in admin'));
1689
- }
1690
- if (!update && this._promises.users instanceof Promise) {
1691
- return this._promises.users;
1692
- }
1693
- if (!this.connected) {
1694
- return Promise.reject(new Error(NOT_CONNECTED));
1695
- }
1696
- this._promises.users = new Promise((resolve, reject) => {
1697
- this._socket.emit('getObjectView', 'system', 'user', { startkey: 'system.user.', endkey: 'system.user.\u9999' }, (err, doc) => {
1698
- if (err) {
1699
- reject(new Error(err));
1700
- }
1701
- else {
1702
- resolve(doc.rows.map(item => item.value));
1703
- }
1704
- });
1705
- });
1706
- return this._promises.users;
1707
- }
1708
- /**
1709
- * Get the list of all groups.
1710
- *
1711
- * @param update Force update.
1712
- */
1713
- getGroups(update) {
1714
- if (!update && this._promises.groups instanceof Promise) {
1715
- return this._promises.groups;
1716
- }
1717
- if (!this.connected) {
1718
- return Promise.reject(new Error(NOT_CONNECTED));
1719
- }
1720
- this._promises.groups = new Promise((resolve, reject) => {
1721
- this._socket.emit('getObjectView', 'system', 'group', { startkey: 'system.group.', endkey: 'system.group.\u9999' }, (err, doc) => {
1722
- if (err) {
1723
- reject(new Error(err));
1724
- }
1725
- else {
1726
- resolve(doc.rows.map(item => item.value));
1727
- }
1728
- });
1729
- });
1730
- return this._promises.groups;
1731
- }
1732
- /**
1733
- * Get the host information.
1734
- *
1735
- * @param host The host name.
1736
- * @param update Force update.
1737
- * @param timeoutMs Optional read timeout.
1738
- */
1739
- getHostInfo(host, update, timeoutMs) {
1740
- if (LegacyConnection.isWeb()) {
1741
- return Promise.reject(new Error('Allowed only in admin'));
1742
- }
1743
- if (!host.startsWith('system.host.')) {
1744
- host += `system.host.${host}`;
1745
- }
1746
- if (!update && this._promises[`hostInfo_${host}`] instanceof Promise) {
1747
- return this._promises[`hostInfo_${host}`];
1748
- }
1749
- if (!this.connected) {
1750
- return Promise.reject(new Error(NOT_CONNECTED));
1751
- }
1752
- this._promises[`hostInfo_${host}`] = new Promise((resolve, reject) => {
1753
- let timeout = setTimeout(() => {
1754
- if (timeout) {
1755
- timeout = null;
1756
- reject(new Error('getHostInfo timeout'));
1757
- }
1758
- }, timeoutMs || this.props.cmdTimeout);
1759
- this._socket.emit('sendToHost', host, 'getHostInfo', null, (data) => {
1760
- if (timeout) {
1761
- clearTimeout(timeout);
1762
- timeout = null;
1763
- if (data === PERMISSION_ERROR) {
1764
- reject(new Error('May not read "getHostInfo"'));
1765
- }
1766
- else if (!data || typeof data !== 'object') {
1767
- reject(new Error('Cannot read "getHostInfo"'));
1768
- }
1769
- else {
1770
- resolve(data);
1771
- }
1772
- }
1773
- });
1774
- });
1775
- return this._promises[`hostInfo_${host}`];
1776
- }
1777
- /**
1778
- * Get the host information (short version).
1779
- *
1780
- * @param host The host name.
1781
- * @param update Force update.
1782
- * @param timeoutMs Optional read timeout.
1783
- */
1784
- getHostInfoShort(host, update, timeoutMs) {
1785
- if (LegacyConnection.isWeb()) {
1786
- return Promise.reject(new Error('Allowed only in admin'));
1787
- }
1788
- if (!host.startsWith('system.host.')) {
1789
- host += `system.host.${host}`;
1790
- }
1791
- if (!update && this._promises[`hostInfoShort_${host}`] instanceof Promise) {
1792
- return this._promises[`hostInfoShort_${host}`];
1793
- }
1794
- if (!this.connected) {
1795
- return Promise.reject(new Error(NOT_CONNECTED));
1796
- }
1797
- this._promises[`hostInfoShort_${host}`] = new Promise((resolve, reject) => {
1798
- let timeout = setTimeout(() => {
1799
- if (timeout) {
1800
- timeout = null;
1801
- reject(new Error('hostInfoShort timeout'));
1802
- }
1803
- }, timeoutMs || this.props.cmdTimeout);
1804
- this._socket.emit('sendToHost', host, 'getHostInfoShort', null, (data) => {
1805
- if (timeout) {
1806
- clearTimeout(timeout);
1807
- timeout = null;
1808
- if (data === PERMISSION_ERROR) {
1809
- reject(new Error('May not read "getHostInfoShort"'));
1810
- }
1811
- else if (!data || typeof data !== 'object') {
1812
- reject(new Error('Cannot read "getHostInfoShort"'));
1813
- }
1814
- else {
1815
- resolve(data);
1816
- }
1817
- }
1818
- });
1819
- });
1820
- return this._promises[`hostInfoShort_${host}`];
1821
- }
1822
- /**
1823
- * Get the repository.
1824
- *
1825
- * @param host The host name.
1826
- * @param options Options.
1827
- * @param update Force update.
1828
- * @param timeoutMs Timeout in ms.
1829
- */
1830
- getRepository(host, options, update, timeoutMs) {
1831
- if (LegacyConnection.isWeb()) {
1832
- return Promise.reject(new Error('Allowed only in admin'));
1833
- }
1834
- if (!update && this._promises.repo instanceof Promise) {
1835
- return this._promises.repo;
1836
- }
1837
- if (!this.connected) {
1838
- return Promise.reject(new Error(NOT_CONNECTED));
1839
- }
1840
- if (!host.startsWith('system.host.')) {
1841
- host += `system.host.${host}`;
1842
- }
1843
- this._promises.repo = new Promise((resolve, reject) => {
1844
- let timeout = setTimeout(() => {
1845
- if (timeout) {
1846
- timeout = null;
1847
- reject(new Error('getRepository timeout'));
1848
- }
1849
- }, timeoutMs || this.props.cmdTimeout);
1850
- this._socket.emit('sendToHost', host, 'getRepository', options, (data) => {
1851
- if (timeout) {
1852
- clearTimeout(timeout);
1853
- timeout = null;
1854
- if (data === PERMISSION_ERROR) {
1855
- reject(new Error('May not read "getRepository"'));
1856
- }
1857
- else if (!data || typeof data !== 'object') {
1858
- reject(new Error('Cannot read "getRepository"'));
1859
- }
1860
- else {
1861
- resolve(data);
1862
- }
1863
- }
1864
- });
1865
- });
1866
- return this._promises.repo;
1867
- }
1868
- /**
1869
- * Get the installed.
1870
- *
1871
- * @param host The host name.
1872
- * @param update Force update.
1873
- * @param cmdTimeout Timeout in ms.
1874
- */
1875
- getInstalled(host, update, cmdTimeout) {
1876
- if (LegacyConnection.isWeb()) {
1877
- return Promise.reject(new Error('Allowed only in admin'));
1878
- }
1879
- this._promises.installed = this._promises.installed || {};
1880
- if (!update && this._promises.installed[host] instanceof Promise) {
1881
- return this._promises.installed[host];
1882
- }
1883
- if (!this.connected) {
1884
- return Promise.reject(new Error(NOT_CONNECTED));
1885
- }
1886
- if (!host.startsWith('system.host.')) {
1887
- host += `system.host.${host}`;
1888
- }
1889
- this._promises.installed[host] = new Promise((resolve, reject) => {
1890
- let timeout = setTimeout(() => {
1891
- if (timeout) {
1892
- timeout = null;
1893
- reject(new Error('getInstalled timeout'));
1894
- }
1895
- }, cmdTimeout || this.props.cmdTimeout);
1896
- this._socket.emit('sendToHost', host, 'getInstalled', null, (data) => {
1897
- if (timeout) {
1898
- clearTimeout(timeout);
1899
- timeout = null;
1900
- if (data === PERMISSION_ERROR) {
1901
- reject(new Error('May not read "getInstalled"'));
1902
- }
1903
- else if (!data || typeof data !== 'object') {
1904
- reject(new Error('Cannot read "getInstalled"'));
1905
- }
1906
- else {
1907
- resolve(data);
1908
- }
1909
- }
1910
- });
1911
- });
1912
- return this._promises.installed[host];
1913
- }
1914
- /**
1915
- * Rename file or folder in ioBroker DB
1916
- *
1917
- * @param adapter Instance name, like `vis-2.0`.
1918
- * @param oldName The current file name, e.g., main/vis-views.json
1919
- * @param newName The new file name, e.g., main/vis-views-new.json
1920
- */
1921
- rename(adapter, oldName, newName) {
1922
- if (!this.connected) {
1923
- return Promise.reject(new Error(NOT_CONNECTED));
1924
- }
1925
- return new Promise((resolve, reject) => {
1926
- this._socket.emit('rename', adapter, oldName, newName, (err) => err ? reject(new Error(err)) : resolve());
1927
- });
1928
- }
1929
- /**
1930
- * Rename file in ioBroker DB
1931
- */
1932
- renameFile(
1933
- /** instance name */
1934
- adapter,
1935
- /** current file name, e.g., main/vis-views.json */
1936
- oldName,
1937
- /** new file name, e.g., main/vis-views-new.json */
1938
- newName) {
1939
- if (!this.connected) {
1940
- return Promise.reject(new Error(NOT_CONNECTED));
1941
- }
1942
- return new Promise((resolve, reject) => {
1943
- this._socket.emit('renameFile', adapter, oldName, newName, (err) => err ? reject(new Error(err)) : resolve());
1944
- });
1945
- }
1946
- /**
1947
- * Execute a command on a host.
1948
- */
1949
- cmdExec(
1950
- /** The host name. */
1951
- host,
1952
- /** The command. */
1953
- cmd,
1954
- /** The command ID. */
1955
- cmdId,
1956
- /** Timeout of command in ms */
1957
- cmdTimeout) {
1958
- if (LegacyConnection.isWeb()) {
1959
- return Promise.reject(new Error('Allowed only in admin'));
1960
- }
1961
- if (!this.connected) {
1962
- return Promise.reject(new Error(NOT_CONNECTED));
1963
- }
1964
- if (!host.startsWith(host)) {
1965
- host += `system.host.${host}`;
1966
- }
1967
- return new Promise((resolve, reject) => {
1968
- let timeout = cmdTimeout
1969
- ? setTimeout(() => {
1970
- if (timeout) {
1971
- timeout = null;
1972
- reject(new Error('cmdExec timeout'));
1973
- }
1974
- }, cmdTimeout)
1975
- : null;
1976
- this._socket.emit('cmdExec', host, cmdId, cmd, null, (err) => {
1977
- if (!cmdTimeout || timeout) {
1978
- timeout && clearTimeout(timeout);
1979
- timeout = null;
1980
- if (err) {
1981
- reject(new Error(err));
1982
- }
1983
- else {
1984
- resolve();
1985
- }
1986
- }
1987
- });
1988
- });
1989
- }
1990
- /**
1991
- * Checks if a given feature is supported.
1992
- */
1993
- checkFeatureSupported(
1994
- /** The feature to check. */
1995
- feature,
1996
- /** Force update. */
1997
- update) {
1998
- if (!update && this._promises[`supportedFeatures_${feature}`] instanceof Promise) {
1999
- return this._promises[`supportedFeatures_${feature}`];
2000
- }
2001
- if (!this.connected) {
2002
- return Promise.reject(new Error(NOT_CONNECTED));
2003
- }
2004
- this._promises[`supportedFeatures_${feature}`] = new Promise((resolve, reject) => {
2005
- this._socket.emit('checkFeatureSupported', feature, (err, supported) => err ? reject(new Error(err)) : resolve(supported));
2006
- });
2007
- return this._promises[`supportedFeatures_${feature}`];
2008
- }
2009
- /**
2010
- * Read the base settings of a given host.
2011
- */
2012
- async readBaseSettings(host) {
2013
- if (LegacyConnection.isWeb()) {
2014
- return Promise.reject(new Error('Allowed only in admin'));
2015
- }
2016
- const result = await this.checkFeatureSupported('CONTROLLER_READWRITE_BASE_SETTINGS');
2017
- if (result) {
2018
- if (!this.connected) {
2019
- return Promise.reject(new Error(NOT_CONNECTED));
2020
- }
2021
- return new Promise((resolve, reject) => {
2022
- let timeout = setTimeout(() => {
2023
- if (timeout) {
2024
- timeout = null;
2025
- reject(new Error('readBaseSettings timeout'));
2026
- }
2027
- }, this.props.cmdTimeout);
2028
- if (host.startsWith('system.host.')) {
2029
- host = host.replace(/^system\.host\./, '');
2030
- }
2031
- this._socket.emit('sendToHost', host, 'readBaseSettings', null, (data) => {
2032
- if (timeout) {
2033
- clearTimeout(timeout);
2034
- timeout = null;
2035
- if (data === PERMISSION_ERROR) {
2036
- reject(new Error('May not read "BaseSettings"'));
2037
- }
2038
- else if (!data || typeof data !== 'object') {
2039
- reject(new Error('Cannot read "BaseSettings"'));
2040
- }
2041
- else {
2042
- resolve(data);
2043
- }
2044
- }
2045
- });
2046
- });
2047
- }
2048
- return Promise.reject(new Error('Not supported'));
2049
- }
2050
- /**
2051
- * Write the base settings of a given host.
2052
- *
2053
- * @param host The host name.
2054
- * @param config The new base settings.
2055
- */
2056
- writeBaseSettings(host, config) {
2057
- if (LegacyConnection.isWeb()) {
2058
- return Promise.reject(new Error('Allowed only in admin'));
2059
- }
2060
- return this.checkFeatureSupported('CONTROLLER_READWRITE_BASE_SETTINGS').then(result => {
2061
- if (result) {
2062
- if (!this.connected) {
2063
- return Promise.reject(new Error(NOT_CONNECTED));
2064
- }
2065
- return new Promise((resolve, reject) => {
2066
- let timeout = setTimeout(() => {
2067
- if (timeout) {
2068
- timeout = null;
2069
- reject(new Error('writeBaseSettings timeout'));
2070
- }
2071
- }, this.props.cmdTimeout);
2072
- this._socket.emit('sendToHost', host, 'writeBaseSettings', config, (data) => {
2073
- if (timeout) {
2074
- clearTimeout(timeout);
2075
- timeout = null;
2076
- if (data === PERMISSION_ERROR) {
2077
- reject(new Error('May not write "BaseSettings"'));
2078
- }
2079
- else if (!data) {
2080
- reject(new Error('Cannot write "BaseSettings"'));
2081
- }
2082
- else {
2083
- resolve(data);
2084
- }
2085
- }
2086
- });
2087
- });
2088
- }
2089
- return Promise.reject(new Error('Not supported'));
2090
- });
2091
- }
2092
- /**
2093
- * Send command to restart the iobroker on host
2094
- */
2095
- restartController(host) {
2096
- if (LegacyConnection.isWeb()) {
2097
- return Promise.reject(new Error('Allowed only in admin'));
2098
- }
2099
- return new Promise((resolve, reject) => {
2100
- this._socket.emit('sendToHost', host, 'restartController', null, (error) => {
2101
- error ? reject(new Error(error)) : resolve(true);
2102
- });
2103
- });
2104
- }
2105
- /**
2106
- * Read statistics information from host
2107
- *
2108
- * @param host Host name
2109
- * @param typeOfDiag one of none, normal, no-city, extended
2110
- */
2111
- getDiagData(host, typeOfDiag) {
2112
- if (LegacyConnection.isWeb()) {
2113
- return Promise.reject(new Error('Allowed only in admin'));
2114
- }
2115
- return new Promise(resolve => {
2116
- this._socket.emit('sendToHost', host, 'getDiagData', typeOfDiag, (result) => resolve(result));
2117
- });
2118
- }
2119
- /**
2120
- * Read all states (which might not belong to this adapter) which match the given pattern.
2121
- */
2122
- getForeignStates(pattern) {
2123
- if (!this.connected) {
2124
- return Promise.reject(new Error(NOT_CONNECTED));
2125
- }
2126
- if (LegacyConnection.isWeb()) {
2127
- return new Promise((resolve, reject) => {
2128
- this._socket.emit('getStates', pattern || '*', (err, states) => err ? reject(new Error(err)) : resolve(states));
2129
- });
2130
- }
2131
- return new Promise((resolve, reject) => {
2132
- this._socket.emit('getForeignStates', pattern || '*', (err, states) => err ? reject(new Error(err)) : resolve(states));
2133
- });
2134
- }
2135
- /**
2136
- * Get foreign objects by pattern, by specific type and resolve their enums. (Only admin)
2137
- */
2138
- getForeignObjects(pattern, type) {
2139
- if (LegacyConnection.isWeb()) {
2140
- return Promise.reject(new Error('Allowed only in admin'));
2141
- }
2142
- if (!this.connected) {
2143
- return Promise.reject(new Error(NOT_CONNECTED));
2144
- }
2145
- return new Promise((resolve, reject) => {
2146
- this._socket.emit('getForeignObjects', pattern || '*', type, (err, states) => err ? reject(new Error(err)) : resolve(states));
2147
- });
2148
- }
2149
- /**
2150
- * Gets the system configuration.
2151
- *
2152
- * @param update Force update.
2153
- */
2154
- getSystemConfig(update) {
2155
- if (!update && this._promises.systemConfig instanceof Promise) {
2156
- return this._promises.systemConfig;
2157
- }
2158
- if (!this.connected) {
2159
- return Promise.reject(new Error(NOT_CONNECTED));
2160
- }
2161
- this._promises.systemConfig = this.getObject('system.config').then(obj => {
2162
- const systemConfig = (obj || {});
2163
- systemConfig.common ||= {};
2164
- systemConfig.native ||= {};
2165
- return systemConfig;
2166
- });
2167
- return this._promises.systemConfig;
2168
- }
2169
- /**
2170
- * Sets the system configuration.
2171
- */
2172
- setSystemConfig(obj) {
2173
- return this.setObject('system.config', obj).then(() => (this._promises.systemConfig = Promise.resolve(obj)));
2174
- }
2175
- /**
2176
- * Get the raw socket.io socket.
2177
- */
2178
- getRawSocket() {
2179
- return this._socket;
2180
- }
2181
- /**
2182
- * Get the history of a given state.
2183
- */
2184
- getHistory(id, options) {
2185
- if (!this.connected) {
2186
- return Promise.reject(new Error(NOT_CONNECTED));
2187
- }
2188
- return new Promise((resolve, reject) => {
2189
- this._socket.emit('getHistory', id, options, (err, values) => err ? reject(new Error(err)) : resolve(values));
2190
- });
2191
- }
2192
- /**
2193
- * Get the history of a given state.
2194
- */
2195
- getHistoryEx(id, options) {
2196
- if (!this.connected) {
2197
- return Promise.reject(new Error(NOT_CONNECTED));
2198
- }
2199
- return new Promise((resolve, reject) => {
2200
- this._socket.emit('getHistory', id, options, (err, values, step, sessionId) => err ? reject(new Error(err)) : resolve({ values, sessionId, step }));
2201
- });
2202
- }
2203
- /**
2204
- * Change the password of the given user.
2205
- */
2206
- changePassword(user, password) {
2207
- if (LegacyConnection.isWeb()) {
2208
- return Promise.reject(new Error('Allowed only in admin'));
2209
- }
2210
- return new Promise((resolve, reject) => {
2211
- this._socket.emit('changePassword', user, password, (err) => err ? reject(new Error(err)) : resolve());
2212
- });
2213
- }
2214
- /**
2215
- * Get the IP addresses of the given host.
2216
- */
2217
- getIpAddresses(host,
2218
- /** Force update. */
2219
- update) {
2220
- if (LegacyConnection.isWeb()) {
2221
- return Promise.reject(new Error('Allowed only in admin'));
2222
- }
2223
- if (!host.startsWith('system.host.')) {
2224
- host = `system.host.${host}`;
2225
- }
2226
- if (!update && this._promises[`IPs_${host}`] instanceof Promise) {
2227
- return this._promises[`IPs_${host}`];
2228
- }
2229
- this._promises[`IPs_${host}`] = this.getObject(host).then(obj => (obj?.common ? obj.common.address || [] : []));
2230
- return this._promises[`IPs_${host}`];
2231
- }
2232
- /**
2233
- * Get the IP addresses with interface names of the given host or find host by IP.
2234
- */
2235
- getHostByIp(ipOrHostName,
2236
- /** Force update. */
2237
- update) {
2238
- if (LegacyConnection.isWeb()) {
2239
- return Promise.reject(new Error('Allowed only in admin'));
2240
- }
2241
- if (ipOrHostName.startsWith('system.host.')) {
2242
- ipOrHostName = ipOrHostName.replace(/^system\.host\./, '');
2243
- }
2244
- if (!update && this._promises[`rIPs_${ipOrHostName}`] instanceof Promise) {
2245
- return this._promises[`rIPs_${ipOrHostName}`];
2246
- }
2247
- this._promises[`rIPs_${ipOrHostName}`] = new Promise(resolve => {
2248
- this._socket.emit('getHostByIp', ipOrHostName, (_ip, host) => {
2249
- const IPs4 = [{ name: '[IPv4] 0.0.0.0 - Listen on all IPs', address: '0.0.0.0', family: 'ipv4' }];
2250
- const IPs6 = [{ name: '[IPv6] :: - Listen on all IPs', address: '::', family: 'ipv6' }];
2251
- if (host?.native?.hardware?.networkInterfaces) {
2252
- for (const eth in host.native.hardware.networkInterfaces) {
2253
- if (!Object.prototype.hasOwnProperty.call(host.native.hardware.networkInterfaces, eth)) {
2254
- continue;
2255
- }
2256
- for (let num = 0; num < host.native.hardware.networkInterfaces[eth].length; num++) {
2257
- if (host.native.hardware.networkInterfaces[eth][num].family !== 'IPv6') {
2258
- IPs4.push({
2259
- name: `[${host.native.hardware.networkInterfaces[eth][num].family}] ${host.native.hardware.networkInterfaces[eth][num].address} - ${eth}`,
2260
- address: host.native.hardware.networkInterfaces[eth][num].address,
2261
- family: 'ipv4',
2262
- });
2263
- }
2264
- else {
2265
- IPs6.push({
2266
- name: `[${host.native.hardware.networkInterfaces[eth][num].family}] ${host.native.hardware.networkInterfaces[eth][num].address} - ${eth}`,
2267
- address: host.native.hardware.networkInterfaces[eth][num].address,
2268
- family: 'ipv6',
2269
- });
2270
- }
2271
- }
2272
- }
2273
- }
2274
- for (let i = 0; i < IPs6.length; i++) {
2275
- IPs4.push(IPs6[i]);
2276
- }
2277
- resolve(IPs4);
2278
- });
2279
- });
2280
- return this._promises[`rIPs_${ipOrHostName}`];
2281
- }
2282
- /**
2283
- * Encrypt a text
2284
- */
2285
- encrypt(text) {
2286
- if (LegacyConnection.isWeb()) {
2287
- return Promise.reject(new Error('Allowed only in admin'));
2288
- }
2289
- return new Promise((resolve, reject) => {
2290
- this._socket.emit('encrypt', text, (err, _text) => err ? reject(new Error(err)) : resolve(_text));
2291
- });
2292
- }
2293
- /**
2294
- * Decrypt a text
2295
- */
2296
- decrypt(encryptedText) {
2297
- if (LegacyConnection.isWeb()) {
2298
- return Promise.reject(new Error('Allowed only in admin'));
2299
- }
2300
- return new Promise((resolve, reject) => {
2301
- this._socket.emit('decrypt', encryptedText, (err, text) => err ? reject(new Error(err)) : resolve(text));
2302
- });
2303
- }
2304
- /**
2305
- * Gets the version.
2306
- */
2307
- getVersion(update) {
2308
- if (!update && this._promises.version instanceof Promise) {
2309
- return this._promises.version;
2310
- }
2311
- this._promises.version = new Promise((resolve, reject) => {
2312
- this._socket.emit('getVersion', (err, version, serverName) => {
2313
- // support of old socket.io
2314
- if (err && !version && typeof err === 'string' && err.match(/\d+\.\d+\.\d+/)) {
2315
- resolve({ version: err, serverName: 'socketio' });
2316
- }
2317
- else {
2318
- err ? reject(new Error(err)) : resolve({ version, serverName });
2319
- }
2320
- });
2321
- });
2322
- return this._promises.version;
2323
- }
2324
- /**
2325
- * Gets the web server name.
2326
- */
2327
- getWebServerName() {
2328
- if (this._promises.webName instanceof Promise) {
2329
- return this._promises.webName;
2330
- }
2331
- this._promises.webName = new Promise((resolve, reject) => {
2332
- this._socket.emit('getAdapterName', (err, name) => err ? reject(new Error(err)) : resolve(name));
2333
- });
2334
- return this._promises.webName;
2335
- }
2336
- /**
2337
- * Gets the admin version.
2338
- *
2339
- * @deprecated use getVersion()
2340
- */
2341
- getAdminVersion() {
2342
- console.log('Deprecated: use getVersion');
2343
- return this.getVersion();
2344
- }
2345
- /**
2346
- * Change access rights for a file
2347
- *
2348
- * @param adapter The adapter name.
2349
- * @param fileName file name with a full path. It could be like vis.0/*
2350
- * @param options like {mode: 0x644}
2351
- * @param options.mode Access rights. Default is 0x644
2352
- */
2353
- chmodFile(adapter, fileName, options) {
2354
- if (LegacyConnection.isWeb()) {
2355
- return Promise.reject(new Error('Allowed only in admin'));
2356
- }
2357
- if (!this.connected) {
2358
- return Promise.reject(new Error(NOT_CONNECTED));
2359
- }
2360
- return new Promise((resolve, reject) => {
2361
- this._socket.emit('chmodFile', adapter, fileName, options, (err, entries, id) => err ? reject(new Error(err)) : resolve({ entries, id }));
2362
- });
2363
- }
2364
- /**
2365
- * Change an owner or/and owner group for a file
2366
- *
2367
- * @param adapter The adapter name.
2368
- * @param fileName file name with a full path. It could be like vis.0/*
2369
- * @param options like {owner: 'user', ownerGroup: 'group'}
2370
- * @param options.owner User name
2371
- * @param options.ownerGroup Group name
2372
- */
2373
- chownFile(adapter, fileName, options) {
2374
- if (LegacyConnection.isWeb()) {
2375
- return Promise.reject(new Error('Allowed only in admin'));
2376
- }
2377
- if (!this.connected) {
2378
- return Promise.reject(new Error(NOT_CONNECTED));
2379
- }
2380
- return new Promise((resolve, reject) => {
2381
- this._socket.emit('chownFile', adapter, fileName, options, (err, entries, id) => err ? reject(new Error(err)) : resolve({ entries, id }));
2382
- });
2383
- }
2384
- /**
2385
- * Check if the file exists
2386
- *
2387
- * @param adapter The adapter name.
2388
- * @param fileName file name with a full path. It could be like vis.0/*
2389
- */
2390
- fileExists(adapter, fileName) {
2391
- if (!this.connected) {
2392
- return Promise.reject(new Error(NOT_CONNECTED));
2393
- }
2394
- return new Promise((resolve, reject) => {
2395
- this._socket.emit('fileExists', adapter, fileName, (err, exists) => err ? reject(new Error(err)) : resolve(exists));
2396
- });
2397
- }
2398
- /**
2399
- * Get the alarm notifications from a host (only for admin connection).
2400
- */
2401
- getNotifications(host, category) {
2402
- if (LegacyConnection.isWeb()) {
2403
- return Promise.reject(new Error('Allowed only in admin'));
2404
- }
2405
- if (!this.connected) {
2406
- return Promise.reject(new Error(NOT_CONNECTED));
2407
- }
2408
- return new Promise(resolve => {
2409
- this._socket.emit('sendToHost', host, 'getNotifications', { category }, (notifications) => resolve(notifications));
2410
- });
2411
- }
2412
- /**
2413
- * Clear the alarm notifications on a host (only for admin connection).
2414
- *
2415
- * @param host The host name.
2416
- * @param category optional
2417
- */
2418
- clearNotifications(host, category) {
2419
- if (LegacyConnection.isWeb()) {
2420
- return Promise.reject(new Error('Allowed only in admin'));
2421
- }
2422
- if (!this.connected) {
2423
- return Promise.reject(new Error(NOT_CONNECTED));
2424
- }
2425
- return new Promise(resolve => {
2426
- this._socket.emit('sendToHost', host, 'clearNotifications', { category }, (result) => resolve(result));
2427
- });
2428
- }
2429
- /**
2430
- * Read if only easy mode is allowed (only for admin connection).
2431
- */
2432
- getIsEasyModeStrict() {
2433
- if (LegacyConnection.isWeb()) {
2434
- return Promise.reject(new Error('Allowed only in admin'));
2435
- }
2436
- if (!this.connected) {
2437
- return Promise.reject(new Error(NOT_CONNECTED));
2438
- }
2439
- return new Promise((resolve, reject) => {
2440
- this._socket.emit('getIsEasyModeStrict', (error, isStrict) => error ? reject(new Error(error)) : resolve(isStrict));
2441
- });
2442
- }
2443
- /**
2444
- * Read easy mode configuration (only for admin connection).
2445
- */
2446
- getEasyMode() {
2447
- if (LegacyConnection.isWeb()) {
2448
- return Promise.reject(new Error('Allowed only in admin'));
2449
- }
2450
- if (!this.connected) {
2451
- return Promise.reject(new Error(NOT_CONNECTED));
2452
- }
2453
- return new Promise((resolve, reject) => {
2454
- this._socket.emit('getEasyMode', (error, config) => error ? reject(new Error(error)) : resolve(config));
2455
- });
2456
- }
2457
- /**
2458
- * Read current user
2459
- */
2460
- getCurrentUser() {
2461
- if (!this.connected) {
2462
- return Promise.reject(new Error(NOT_CONNECTED));
2463
- }
2464
- return new Promise(resolve => {
2465
- this._socket.emit('authEnabled', (_isSecure, user) => resolve(user));
2466
- });
2467
- }
2468
- getCurrentSession(cmdTimeout) {
2469
- if (!this.connected) {
2470
- return Promise.reject(new Error(NOT_CONNECTED));
2471
- }
2472
- return new Promise((resolve, reject) => {
2473
- const controller = new AbortController();
2474
- let timeout = setTimeout(() => {
2475
- if (timeout) {
2476
- timeout = null;
2477
- controller.abort();
2478
- reject(new Error('getCurrentSession timeout'));
2479
- }
2480
- }, cmdTimeout || 5000);
2481
- fetch('./session', { signal: controller.signal })
2482
- .then(res => res.json())
2483
- .then(json => {
2484
- if (timeout) {
2485
- clearTimeout(timeout);
2486
- timeout = null;
2487
- resolve(json);
2488
- }
2489
- })
2490
- .catch(e => reject(new Error(`getCurrentSession: ${e}`)));
2491
- });
2492
- }
2493
- /**
2494
- * Read adapter ratings
2495
- */
2496
- getRatings(update) {
2497
- if (LegacyConnection.isWeb()) {
2498
- return Promise.reject(new Error('Allowed only in admin'));
2499
- }
2500
- if (!this.connected) {
2501
- return Promise.reject(new Error(NOT_CONNECTED));
2502
- }
2503
- return new Promise((resolve, reject) => {
2504
- this._socket.emit('getRatings', update, (err, ratings) => err ? reject(new Error(err)) : resolve(ratings));
2505
- });
2506
- }
2507
- /**
2508
- * Read current web, socketio or admin namespace, like admin.0
2509
- */
2510
- getCurrentInstance() {
2511
- if (!this.connected) {
2512
- return Promise.reject(new Error(NOT_CONNECTED));
2513
- }
2514
- if (this._promises.currentInstance instanceof Promise) {
2515
- return this._promises.currentInstance;
2516
- }
2517
- this._promises.currentInstance = new Promise((resolve, reject) => {
2518
- this._socket.emit('getCurrentInstance', (err, namespace) => err ? reject(new Error(err)) : resolve(namespace));
2519
- });
2520
- return this._promises.currentInstance;
2521
- }
2522
- // returns very optimized information for adapters to minimize a connection load
2523
- getCompactAdapters(update) {
2524
- if (LegacyConnection.isWeb()) {
2525
- return Promise.reject(new Error('Allowed only in admin'));
2526
- }
2527
- if (!update && this._promises.compactAdapters instanceof Promise) {
2528
- return this._promises.compactAdapters;
2529
- }
2530
- if (!this.connected) {
2531
- return Promise.reject(new Error(NOT_CONNECTED));
2532
- }
2533
- this._promises.compactAdapters = new Promise((resolve, reject) => {
2534
- this._socket.emit('getCompactAdapters', (err, adapters) => err ? reject(new Error(err)) : resolve(adapters));
2535
- });
2536
- return this._promises.compactAdapters;
2537
- }
2538
- getAdaptersResetCache(adapter) {
2539
- adapter ||= '';
2540
- delete this._promises.compactAdapters;
2541
- delete this._promises[`adapter_${adapter}`];
2542
- }
2543
- // returns very optimized information for adapters to minimize a connection load
2544
- getCompactInstances(update) {
2545
- if (LegacyConnection.isWeb()) {
2546
- return Promise.reject(new Error('Allowed only in admin'));
2547
- }
2548
- if (!update && this._promises.compactInstances instanceof Promise) {
2549
- return this._promises.compactInstances;
2550
- }
2551
- if (!this.connected) {
2552
- return Promise.reject(new Error(NOT_CONNECTED));
2553
- }
2554
- this._promises.compactInstances = new Promise((resolve, reject) => {
2555
- this._socket.emit('getCompactInstances', (err, instances) => err ? reject(new Error(err)) : resolve(instances));
2556
- });
2557
- return this._promises.compactInstances;
2558
- }
2559
- getAdapternInstancesResetCache(adapter) {
2560
- adapter ||= '';
2561
- delete this._promises.compactInstances;
2562
- delete this._promises[`instances_${adapter}`];
2563
- }
2564
- /**
2565
- * Returns very optimized information for adapters to minimize a connection load.
2566
- * Reads only version of installed adapter
2567
- */
2568
- getCompactInstalled(host, update, cmdTimeout) {
2569
- if (LegacyConnection.isWeb()) {
2570
- return Promise.reject(new Error('Allowed only in admin'));
2571
- }
2572
- this._promises.installedCompact ||= {};
2573
- if (!update && this._promises.installedCompact[host] instanceof Promise) {
2574
- return this._promises.installedCompact[host];
2575
- }
2576
- if (!this.connected) {
2577
- return Promise.reject(new Error(NOT_CONNECTED));
2578
- }
2579
- if (!host.startsWith('system.host.')) {
2580
- host += `system.host.${host}`;
2581
- }
2582
- this._promises.installedCompact[host] = new Promise((resolve, reject) => {
2583
- let timeout = setTimeout(() => {
2584
- if (timeout) {
2585
- timeout = null;
2586
- reject(new Error('getCompactInstalled timeout'));
2587
- }
2588
- }, cmdTimeout || this.props.cmdTimeout);
2589
- this._socket.emit('getCompactInstalled', host, (data) => {
2590
- if (timeout) {
2591
- clearTimeout(timeout);
2592
- timeout = null;
2593
- if (data === PERMISSION_ERROR) {
2594
- reject(new Error('May not read "getCompactInstalled"'));
2595
- }
2596
- else if (!data || typeof data !== 'object') {
2597
- reject(new Error('Cannot read "getCompactInstalled"'));
2598
- }
2599
- else {
2600
- resolve(data);
2601
- }
2602
- }
2603
- });
2604
- });
2605
- return this._promises.installedCompact[host];
2606
- }
2607
- // returns very optimized information for adapters to minimize a connection load.
2608
- // reads only version of installed adapter
2609
- getCompactSystemRepositories(update, cmdTimeout) {
2610
- if (LegacyConnection.isWeb()) {
2611
- return Promise.reject(new Error('Allowed only in admin'));
2612
- }
2613
- if (!update && this._promises.getCompactSystemRepositories instanceof Promise) {
2614
- return this._promises.getCompactSystemRepositories;
2615
- }
2616
- if (!this.connected) {
2617
- return Promise.reject(new Error(NOT_CONNECTED));
2618
- }
2619
- this._promises.getCompactSystemRepositories = new Promise((resolve, reject) => {
2620
- let timeout = setTimeout(() => {
2621
- if (timeout) {
2622
- timeout = null;
2623
- reject(new Error('getCompactSystemRepositories timeout'));
2624
- }
2625
- }, cmdTimeout || this.props.cmdTimeout);
2626
- this._socket.emit('getCompactSystemRepositories', (data) => {
2627
- if (timeout) {
2628
- clearTimeout(timeout);
2629
- timeout = null;
2630
- if (data === PERMISSION_ERROR) {
2631
- reject(new Error('May not read "getCompactSystemRepositories"'));
2632
- }
2633
- else if (!data || typeof data !== 'object') {
2634
- reject(new Error('Cannot read "getCompactSystemRepositories"'));
2635
- }
2636
- else {
2637
- resolve(data);
2638
- }
2639
- }
2640
- });
2641
- });
2642
- return this._promises.getCompactSystemRepositories;
2643
- }
2644
- // returns very optimized information for adapters to minimize a connection load
2645
- getCompactSystemConfig(update) {
2646
- if (!update && this._promises.systemConfigPromise instanceof Promise) {
2647
- return this._promises.systemConfigPromise;
2648
- }
2649
- if (!this.connected) {
2650
- return Promise.reject(new Error(NOT_CONNECTED));
2651
- }
2652
- this._promises.systemConfigPromise = new Promise((resolve, reject) => {
2653
- this._socket.emit('getCompactSystemConfig', (err, systemConfig) => err ? reject(new Error(err)) : resolve(systemConfig));
2654
- });
2655
- return this._promises.systemConfigPromise;
2656
- }
2657
- /**
2658
- * Get the repository in compact form (only version and icon).
2659
- *
2660
- * @param host The host name.
2661
- * @param update Force update.
2662
- * @param timeoutMs timeout in ms.
2663
- */
2664
- getCompactRepository(host, update, timeoutMs) {
2665
- if (LegacyConnection.isWeb()) {
2666
- return Promise.reject(new Error('Allowed only in admin'));
2667
- }
2668
- if (!update && this._promises.repoCompact instanceof Promise) {
2669
- return this._promises.repoCompact;
2670
- }
2671
- if (!this.connected) {
2672
- return Promise.reject(new Error(NOT_CONNECTED));
2673
- }
2674
- if (!host.startsWith('system.host.')) {
2675
- host += `system.host.${host}`;
2676
- }
2677
- this._promises.repoCompact = new Promise((resolve, reject) => {
2678
- let timeout = setTimeout(() => {
2679
- if (timeout) {
2680
- timeout = null;
2681
- reject(new Error('getCompactRepository timeout'));
2682
- }
2683
- }, timeoutMs || this.props.cmdTimeout);
2684
- this._socket.emit('getCompactRepository', host, (data) => {
2685
- if (timeout) {
2686
- clearTimeout(timeout);
2687
- timeout = null;
2688
- if (data === PERMISSION_ERROR) {
2689
- reject(new Error('May not read "getCompactRepository"'));
2690
- }
2691
- else if (!data) {
2692
- reject(new Error('Cannot read "getCompactRepository"'));
2693
- }
2694
- else {
2695
- resolve(data);
2696
- }
2697
- }
2698
- });
2699
- });
2700
- return this._promises.repoCompact;
2701
- }
2702
- getInstalledResetCache() {
2703
- delete this._promises.repoCompact;
2704
- delete this._promises.repo;
2705
- }
2706
- /**
2707
- * Get the list of all hosts in compact form (only _id, common.name, common.icon, common.color, native.hardware.networkInterfaces)
2708
- */
2709
- getCompactHosts(update) {
2710
- if (LegacyConnection.isWeb()) {
2711
- return Promise.reject(new Error('Allowed only in admin'));
2712
- }
2713
- if (!update && this._promises.hostsCompact instanceof Promise) {
2714
- return this._promises.hostsCompact;
2715
- }
2716
- if (!this.connected) {
2717
- return Promise.reject(new Error(NOT_CONNECTED));
2718
- }
2719
- this._promises.hostsCompact = new Promise((resolve, reject) => {
2720
- this._socket.emit('getCompactHosts', (err, hosts) => err ? reject(new Error(err)) : resolve(hosts));
2721
- });
2722
- return this._promises.hostsCompact;
2723
- }
2724
- /**
2725
- * Get uuid
2726
- */
2727
- getUuid() {
2728
- if (this._promises.uuid instanceof Promise) {
2729
- return this._promises.uuid;
2730
- }
2731
- if (!this.connected) {
2732
- return Promise.reject(new Error(NOT_CONNECTED));
2733
- }
2734
- this._promises.uuid = this.getObject('system.meta.uuid').then(obj => obj?.native?.uuid);
2735
- return this._promises.uuid;
2736
- }
2737
- /**
2738
- * Subscribe on instance message
2739
- *
2740
- * @param targetInstance instance, like 'cameras.0'
2741
- * @param messageType message type like 'startCamera/cam3'
2742
- * @param data optional data object
2743
- * @param callback message handler
2744
- */
2745
- subscribeOnInstance(targetInstance, messageType, data, callback) {
2746
- if (!this.connected) {
2747
- return Promise.reject(new Error(NOT_CONNECTED));
2748
- }
2749
- return new Promise((resolve, reject) => {
2750
- this._socket.emit('clientSubscribe', targetInstance, messageType, data, (err, result) => {
2751
- if (err) {
2752
- reject(new Error(err));
2753
- }
2754
- else if (result?.error) {
2755
- reject(new Error(result.error));
2756
- }
2757
- else {
2758
- if (!targetInstance.startsWith('system.adapter.')) {
2759
- targetInstance = `system.adapter.${targetInstance}`;
2760
- }
2761
- // save callback
2762
- this._instanceSubscriptions[targetInstance] ||= [];
2763
- if (!this._instanceSubscriptions[targetInstance].find(sub => sub.messageType === messageType && sub.callback === callback)) {
2764
- this._instanceSubscriptions[targetInstance].push({
2765
- messageType,
2766
- callback,
2767
- });
2768
- }
2769
- resolve(result);
2770
- }
2771
- });
2772
- });
2773
- }
2774
- /**
2775
- * Unsubscribe from instance message
2776
- *
2777
- * @param targetInstance instance, like 'cameras.0'
2778
- * @param messageType message type like 'startCamera/cam3'
2779
- * @param callback message handler. Could be null if all callbacks for this messageType should be unsubscribed
2780
- */
2781
- unsubscribeFromInstance(targetInstance, messageType, callback) {
2782
- if (!targetInstance.startsWith('system.adapter.')) {
2783
- targetInstance = `system.adapter.${targetInstance}`;
2784
- }
2785
- let deleted;
2786
- const promiseResults = [];
2787
- do {
2788
- deleted = false;
2789
- const index = this._instanceSubscriptions[targetInstance]?.findIndex(sub => (!messageType || sub.messageType === messageType) && (!callback || sub.callback === callback));
2790
- if (index !== undefined && index !== null && index !== -1) {
2791
- deleted = true;
2792
- // remember messageType
2793
- const _messageType = this._instanceSubscriptions[targetInstance][index].messageType;
2794
- this._instanceSubscriptions[targetInstance].splice(index, 1);
2795
- if (!this._instanceSubscriptions[targetInstance].length) {
2796
- delete this._instanceSubscriptions[targetInstance];
2797
- }
2798
- // try to find another subscription for this instance and messageType
2799
- const found = this._instanceSubscriptions[targetInstance] &&
2800
- this._instanceSubscriptions[targetInstance].find(sub => sub.messageType === _messageType);
2801
- if (!found) {
2802
- promiseResults.push(new Promise((resolve, reject) => {
2803
- this._socket.emit('clientUnsubscribe', targetInstance, messageType, (err, wasSubscribed) => {
2804
- if (err) {
2805
- reject(new Error(err));
2806
- }
2807
- else {
2808
- resolve(wasSubscribed);
2809
- }
2810
- });
2811
- }));
2812
- }
2813
- }
2814
- } while (deleted && (!callback || !messageType));
2815
- if (promiseResults.length) {
2816
- return Promise.all(promiseResults).then((results) => results.find(result => result) || false);
2817
- }
2818
- return Promise.resolve(false);
2819
- }
2820
- /**
2821
- * Send log to ioBroker log
2822
- */
2823
- log(text, level) {
2824
- if (text) {
2825
- this._socket.emit('log', text, level || 'debug');
2826
- }
2827
- }
2828
- /**
2829
- * Logout current user
2830
- */
2831
- logout() {
2832
- if (!this.connected) {
2833
- return Promise.reject(new Error(NOT_CONNECTED));
2834
- }
2835
- return new Promise((resolve, reject) => {
2836
- this._socket.emit('logout', (err) => (err ? reject(new Error(err)) : resolve()));
2837
- });
2838
- }
2839
- /**
2840
- * This is a special method for vis.
2841
- * It is used to not send to server the changes about "nothing_selected" state
2842
- *
2843
- * @param id The state that has to be ignored by communication
2844
- */
2845
- setStateToIgnore(id) {
2846
- this.ignoreState = id || '';
2847
- }
2848
- }
2849
- //# sourceMappingURL=LegacyConnection.js.map