@iobroker/adapter-react-v5 7.2.4 → 7.3.0

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 (375) hide show
  1. package/README.md +7 -15
  2. package/build/AdminConnection.d.ts +1 -0
  3. package/build/AdminConnection.js +2 -0
  4. package/build/AdminConnection.js.map +1 -0
  5. package/{src/Components/404.tsx → build/Components/404.js} +14 -39
  6. package/build/Components/404.js.map +1 -0
  7. package/{Components → build/Components}/ColorPicker.d.ts +2 -2
  8. package/{Components → build/Components}/ColorPicker.js +50 -65
  9. package/build/Components/ColorPicker.js.map +1 -0
  10. package/{Components → build/Components}/ComplexCron.d.ts +2 -2
  11. package/{Components → build/Components}/ComplexCron.js +43 -71
  12. package/build/Components/ComplexCron.js.map +1 -0
  13. package/{Components → build/Components}/CopyToClipboard.d.ts +1 -2
  14. package/{src/Components/CopyToClipboard.tsx → build/Components/CopyToClipboard.js} +20 -38
  15. package/build/Components/CopyToClipboard.js.map +1 -0
  16. package/{Components → build/Components}/CustomModal.d.ts +3 -3
  17. package/build/Components/CustomModal.js +60 -0
  18. package/build/Components/CustomModal.js.map +1 -0
  19. package/{Components → build/Components}/FileBrowser.d.ts +5 -3
  20. package/{Components → build/Components}/FileBrowser.js +230 -236
  21. package/build/Components/FileBrowser.js.map +1 -0
  22. package/build/Components/FileViewer.d.ts +49 -0
  23. package/build/Components/FileViewer.js +247 -0
  24. package/build/Components/FileViewer.js.map +1 -0
  25. package/{Components → build/Components}/Icon.d.ts +1 -1
  26. package/build/Components/Icon.js +140 -0
  27. package/build/Components/Icon.js.map +1 -0
  28. package/{Components → build/Components}/IconPicker.d.ts +2 -2
  29. package/build/Components/IconPicker.js +73 -0
  30. package/build/Components/IconPicker.js.map +1 -0
  31. package/{Components → build/Components}/IconSelector.d.ts +3 -3
  32. package/{Components → build/Components}/IconSelector.js +29 -57
  33. package/build/Components/IconSelector.js.map +1 -0
  34. package/{Components → build/Components}/Image.d.ts +2 -2
  35. package/{Components → build/Components}/Image.js +16 -22
  36. package/build/Components/Image.js.map +1 -0
  37. package/{Components → build/Components}/Loader.d.ts +2 -2
  38. package/{Components → build/Components}/Loader.js +15 -40
  39. package/build/Components/Loader.js.map +1 -0
  40. package/{Components → build/Components}/Loaders/MV.d.ts +2 -2
  41. package/build/Components/Loaders/MV.js +61 -0
  42. package/build/Components/Loaders/MV.js.map +1 -0
  43. package/{Components → build/Components}/Loaders/PT.d.ts +2 -2
  44. package/{Components → build/Components}/Loaders/PT.js +10 -35
  45. package/build/Components/Loaders/PT.js.map +1 -0
  46. package/{Components → build/Components}/Loaders/Vendor.d.ts +2 -2
  47. package/build/Components/Loaders/Vendor.js +52 -0
  48. package/build/Components/Loaders/Vendor.js.map +1 -0
  49. package/{Components → build/Components}/Logo.d.ts +2 -2
  50. package/build/Components/Logo.js +108 -0
  51. package/build/Components/Logo.js.map +1 -0
  52. package/{Components → build/Components}/MDUtils.d.ts +1 -2
  53. package/{Components → build/Components}/MDUtils.js +4 -9
  54. package/build/Components/MDUtils.js.map +1 -0
  55. package/{Components → build/Components}/ObjectBrowser.d.ts +4 -4
  56. package/{Components → build/Components}/ObjectBrowser.js +1159 -1122
  57. package/build/Components/ObjectBrowser.js.map +1 -0
  58. package/{Components → build/Components}/Router.d.ts +1 -2
  59. package/{Components → build/Components}/Router.js +6 -7
  60. package/build/Components/Router.js.map +1 -0
  61. package/{Components → build/Components}/SaveCloseButtons.d.ts +2 -2
  62. package/build/Components/SaveCloseButtons.js +65 -0
  63. package/build/Components/SaveCloseButtons.js.map +1 -0
  64. package/{Components → build/Components}/Schedule.d.ts +2 -2
  65. package/{Components → build/Components}/Schedule.js +242 -257
  66. package/build/Components/Schedule.js.map +1 -0
  67. package/{Components → build/Components}/SelectWithIcon.d.ts +2 -2
  68. package/build/Components/SelectWithIcon.js +135 -0
  69. package/build/Components/SelectWithIcon.js.map +1 -0
  70. package/build/Components/SimpleCron/cronText.js +15 -0
  71. package/build/Components/SimpleCron/cronText.js.map +1 -0
  72. package/{Components → build/Components}/SimpleCron/index.d.ts +2 -2
  73. package/{Components → build/Components}/SimpleCron/index.js +55 -58
  74. package/build/Components/SimpleCron/index.js.map +1 -0
  75. package/{Components → build/Components}/TabContainer.d.ts +2 -2
  76. package/build/Components/TabContainer.js +23 -0
  77. package/build/Components/TabContainer.js.map +1 -0
  78. package/{Components → build/Components}/TabContent.d.ts +3 -2
  79. package/build/Components/TabContent.js +20 -0
  80. package/build/Components/TabContent.js.map +1 -0
  81. package/build/Components/TabHeader.d.ts +6 -0
  82. package/build/Components/TabHeader.js +6 -0
  83. package/build/Components/TabHeader.js.map +1 -0
  84. package/{Components → build/Components}/TableResize.d.ts +2 -2
  85. package/{src/Components/TableResize.tsx → build/Components/TableResize.js} +64 -134
  86. package/build/Components/TableResize.js.map +1 -0
  87. package/{Components → build/Components}/TextWithIcon.d.ts +2 -2
  88. package/{src/Components/TextWithIcon.tsx → build/Components/TextWithIcon.js} +30 -75
  89. package/build/Components/TextWithIcon.js.map +1 -0
  90. package/{Components → build/Components}/ToggleThemeMenu.d.ts +1 -1
  91. package/build/Components/ToggleThemeMenu.js +13 -0
  92. package/build/Components/ToggleThemeMenu.js.map +1 -0
  93. package/{Components → build/Components}/TreeTable.d.ts +3 -3
  94. package/{Components → build/Components}/TreeTable.js +87 -99
  95. package/build/Components/TreeTable.js.map +1 -0
  96. package/{Components → build/Components}/UploadImage.d.ts +2 -2
  97. package/{Components → build/Components}/UploadImage.js +45 -69
  98. package/build/Components/UploadImage.js.map +1 -0
  99. package/{Components → build/Components}/Utils.d.ts +2 -2
  100. package/{Components → build/Components}/Utils.js +47 -60
  101. package/build/Components/Utils.js.map +1 -0
  102. package/build/Components/withWidth.d.ts +2 -0
  103. package/build/Components/withWidth.js +22 -0
  104. package/build/Components/withWidth.js.map +1 -0
  105. package/build/Connection.d.ts +1 -0
  106. package/build/Connection.js +2 -0
  107. package/build/Connection.js.map +1 -0
  108. package/{Dialogs → build/Dialogs}/ComplexCron.d.ts +2 -2
  109. package/build/Dialogs/ComplexCron.js +85 -0
  110. package/build/Dialogs/ComplexCron.js.map +1 -0
  111. package/{Dialogs → build/Dialogs}/Confirm.d.ts +2 -2
  112. package/build/Dialogs/Confirm.js +83 -0
  113. package/build/Dialogs/Confirm.js.map +1 -0
  114. package/{Dialogs → build/Dialogs}/Cron.d.ts +2 -2
  115. package/build/Dialogs/Cron.js +72 -0
  116. package/build/Dialogs/Cron.js.map +1 -0
  117. package/{Dialogs → build/Dialogs}/Error.d.ts +2 -2
  118. package/build/Dialogs/Error.js +27 -0
  119. package/build/Dialogs/Error.js.map +1 -0
  120. package/{Dialogs → build/Dialogs}/Message.d.ts +2 -2
  121. package/build/Dialogs/Message.js +29 -0
  122. package/build/Dialogs/Message.js.map +1 -0
  123. package/{Dialogs → build/Dialogs}/SelectFile.d.ts +2 -2
  124. package/build/Dialogs/SelectFile.js +116 -0
  125. package/build/Dialogs/SelectFile.js.map +1 -0
  126. package/{Dialogs → build/Dialogs}/SelectID.d.ts +3 -3
  127. package/{Dialogs → build/Dialogs}/SelectID.js +28 -53
  128. package/build/Dialogs/SelectID.js.map +1 -0
  129. package/{Dialogs → build/Dialogs}/SimpleCron.d.ts +2 -2
  130. package/build/Dialogs/SimpleCron.js +46 -0
  131. package/build/Dialogs/SimpleCron.js.map +1 -0
  132. package/build/Dialogs/TextInput.d.ts +2 -0
  133. package/build/Dialogs/TextInput.js +31 -0
  134. package/build/Dialogs/TextInput.js.map +1 -0
  135. package/{GenericApp.d.ts → build/GenericApp.d.ts} +2 -3
  136. package/{GenericApp.js → build/GenericApp.js} +162 -176
  137. package/build/GenericApp.js.map +1 -0
  138. package/{LegacyConnection.d.ts → build/LegacyConnection.d.ts} +69 -4
  139. package/{LegacyConnection.js → build/LegacyConnection.js} +106 -99
  140. package/build/LegacyConnection.js.map +1 -0
  141. package/{Prompt.d.ts → build/Prompt.d.ts} +1 -1
  142. package/{Prompt.js → build/Prompt.js} +3 -4
  143. package/build/Prompt.js.map +1 -0
  144. package/build/Theme.d.ts +5 -0
  145. package/{Theme.js → build/Theme.js} +36 -32
  146. package/build/Theme.js.map +1 -0
  147. package/build/assets/devices/parseNames.d.ts +0 -0
  148. package/build/assets/devices/parseNames.js +35 -0
  149. package/build/assets/devices/parseNames.js.map +1 -0
  150. package/build/assets/rooms/parseNames.d.ts +0 -0
  151. package/build/assets/rooms/parseNames.js +35 -0
  152. package/build/assets/rooms/parseNames.js.map +1 -0
  153. package/build/dictionary.d.ts +1 -0
  154. package/build/dictionary.js +25 -0
  155. package/build/dictionary.js.map +1 -0
  156. package/build/i18n/de.json +449 -0
  157. package/build/i18n/en.json +449 -0
  158. package/build/i18n/es.json +449 -0
  159. package/build/i18n/fr.json +449 -0
  160. package/build/i18n/it.json +449 -0
  161. package/build/i18n/nl.json +449 -0
  162. package/build/i18n/pl.json +449 -0
  163. package/build/i18n/pt.json +449 -0
  164. package/build/i18n/ru.json +449 -0
  165. package/build/i18n/uk.json +449 -0
  166. package/build/i18n/zh-cn.json +449 -0
  167. package/{i18n.d.ts → build/i18n.d.ts} +2 -2
  168. package/{i18n.js → build/i18n.js} +9 -11
  169. package/build/i18n.js.map +1 -0
  170. package/build/icons/IconAdapter.d.ts +3 -0
  171. package/build/icons/IconAdapter.js +5 -0
  172. package/build/icons/IconAdapter.js.map +1 -0
  173. package/build/icons/IconAlias.d.ts +3 -0
  174. package/build/icons/IconAlias.js +5 -0
  175. package/build/icons/IconAlias.js.map +1 -0
  176. package/build/icons/IconChannel.d.ts +3 -0
  177. package/build/icons/IconChannel.js +8 -0
  178. package/build/icons/IconChannel.js.map +1 -0
  179. package/build/icons/IconClearFilter.d.ts +3 -0
  180. package/build/icons/IconClearFilter.js +6 -0
  181. package/build/icons/IconClearFilter.js.map +1 -0
  182. package/build/icons/IconClosed.d.ts +3 -0
  183. package/build/icons/IconClosed.js +5 -0
  184. package/build/icons/IconClosed.js.map +1 -0
  185. package/build/icons/IconCopy.d.ts +3 -0
  186. package/build/icons/IconCopy.js +4 -0
  187. package/build/icons/IconCopy.js.map +1 -0
  188. package/build/icons/IconDevice.d.ts +3 -0
  189. package/build/icons/IconDevice.js +14 -0
  190. package/build/icons/IconDevice.js.map +1 -0
  191. package/build/icons/IconDocument.d.ts +3 -0
  192. package/build/icons/IconDocument.js +5 -0
  193. package/build/icons/IconDocument.js.map +1 -0
  194. package/build/icons/IconDocumentReadOnly.d.ts +3 -0
  195. package/build/icons/IconDocumentReadOnly.js +6 -0
  196. package/build/icons/IconDocumentReadOnly.js.map +1 -0
  197. package/build/icons/IconExpert.d.ts +3 -0
  198. package/build/icons/IconExpert.js +5 -0
  199. package/build/icons/IconExpert.js.map +1 -0
  200. package/build/icons/IconFx.d.ts +3 -0
  201. package/build/icons/IconFx.js +4 -0
  202. package/build/icons/IconFx.js.map +1 -0
  203. package/build/icons/IconInstance.d.ts +3 -0
  204. package/build/icons/IconInstance.js +5 -0
  205. package/build/icons/IconInstance.js.map +1 -0
  206. package/build/icons/IconLogout.d.ts +3 -0
  207. package/build/icons/IconLogout.js +5 -0
  208. package/build/icons/IconLogout.js.map +1 -0
  209. package/build/icons/IconNoIcon.d.ts +3 -0
  210. package/build/icons/IconNoIcon.js +4 -0
  211. package/build/icons/IconNoIcon.js.map +1 -0
  212. package/build/icons/IconOpen.d.ts +3 -0
  213. package/build/icons/IconOpen.js +5 -0
  214. package/build/icons/IconOpen.js.map +1 -0
  215. package/{icons → build/icons}/IconProps.d.ts +1 -1
  216. package/build/icons/IconProps.js +2 -0
  217. package/build/icons/IconProps.js.map +1 -0
  218. package/build/icons/IconState.d.ts +3 -0
  219. package/build/icons/IconState.js +5 -0
  220. package/build/icons/IconState.js.map +1 -0
  221. package/build/index.d.ts +76 -0
  222. package/build/index.js +75 -0
  223. package/build/index.js.map +1 -0
  224. package/{types.d.ts → build/types.d.ts} +1 -1
  225. package/package.json +84 -48
  226. package/AdminConnection.d.ts +0 -2
  227. package/AdminConnection.js +0 -4
  228. package/Components/404.js +0 -101
  229. package/Components/CopyToClipboard.js +0 -163
  230. package/Components/CustomModal.js +0 -88
  231. package/Components/FileViewer.d.ts +0 -10
  232. package/Components/FileViewer.js +0 -305
  233. package/Components/Icon.js +0 -148
  234. package/Components/IconPicker.js +0 -98
  235. package/Components/Loaders/MV.js +0 -66
  236. package/Components/Loaders/Vendor.js +0 -77
  237. package/Components/Logo.js +0 -117
  238. package/Components/SaveCloseButtons.js +0 -69
  239. package/Components/SelectWithIcon.js +0 -168
  240. package/Components/SimpleCron/cronText.js +0 -19
  241. package/Components/TabContainer.js +0 -25
  242. package/Components/TabContent.js +0 -21
  243. package/Components/TabHeader.d.ts +0 -6
  244. package/Components/TabHeader.js +0 -11
  245. package/Components/TableResize.js +0 -226
  246. package/Components/TextWithIcon.js +0 -119
  247. package/Components/ToggleThemeMenu.js +0 -18
  248. package/Components/withWidth.d.ts +0 -3
  249. package/Components/withWidth.js +0 -27
  250. package/Connection.d.ts +0 -3
  251. package/Connection.js +0 -8
  252. package/Dialogs/ComplexCron.js +0 -90
  253. package/Dialogs/Confirm.js +0 -111
  254. package/Dialogs/Cron.js +0 -100
  255. package/Dialogs/Error.js +0 -55
  256. package/Dialogs/Message.js +0 -57
  257. package/Dialogs/SelectFile.js +0 -119
  258. package/Dialogs/SimpleCron.js +0 -51
  259. package/Dialogs/TextInput.d.ts +0 -3
  260. package/Dialogs/TextInput.js +0 -35
  261. package/Theme.d.ts +0 -6
  262. package/i18n/de.json +0 -449
  263. package/i18n/en.json +0 -449
  264. package/i18n/es.json +0 -449
  265. package/i18n/fr.json +0 -449
  266. package/i18n/it.json +0 -449
  267. package/i18n/nl.json +0 -449
  268. package/i18n/pl.json +0 -449
  269. package/i18n/pt.json +0 -449
  270. package/i18n/ru.json +0 -449
  271. package/i18n/uk.json +0 -449
  272. package/i18n/zh-cn.json +0 -449
  273. package/icons/IconAdapter.d.ts +0 -4
  274. package/icons/IconAdapter.js +0 -10
  275. package/icons/IconAlias.d.ts +0 -4
  276. package/icons/IconAlias.js +0 -10
  277. package/icons/IconChannel.d.ts +0 -4
  278. package/icons/IconChannel.js +0 -13
  279. package/icons/IconClearFilter.d.ts +0 -4
  280. package/icons/IconClearFilter.js +0 -11
  281. package/icons/IconClosed.d.ts +0 -4
  282. package/icons/IconClosed.js +0 -10
  283. package/icons/IconCopy.d.ts +0 -4
  284. package/icons/IconCopy.js +0 -9
  285. package/icons/IconDevice.d.ts +0 -4
  286. package/icons/IconDevice.js +0 -19
  287. package/icons/IconDocument.d.ts +0 -4
  288. package/icons/IconDocument.js +0 -10
  289. package/icons/IconDocumentReadOnly.d.ts +0 -4
  290. package/icons/IconDocumentReadOnly.js +0 -11
  291. package/icons/IconExpert.d.ts +0 -4
  292. package/icons/IconExpert.js +0 -10
  293. package/icons/IconFx.d.ts +0 -4
  294. package/icons/IconFx.js +0 -9
  295. package/icons/IconInstance.d.ts +0 -4
  296. package/icons/IconInstance.js +0 -10
  297. package/icons/IconLogout.d.ts +0 -4
  298. package/icons/IconLogout.js +0 -10
  299. package/icons/IconNoIcon.d.ts +0 -4
  300. package/icons/IconNoIcon.js +0 -9
  301. package/icons/IconOpen.d.ts +0 -4
  302. package/icons/IconOpen.js +0 -10
  303. package/icons/IconProps.js +0 -2
  304. package/icons/IconState.d.ts +0 -4
  305. package/icons/IconState.js +0 -10
  306. package/index.d.ts +0 -128
  307. package/index.js +0 -215
  308. package/src/AdminConnection.tsx +0 -3
  309. package/src/Components/ColorPicker.tsx +0 -343
  310. package/src/Components/ComplexCron.tsx +0 -561
  311. package/src/Components/CustomModal.tsx +0 -170
  312. package/src/Components/FileBrowser.tsx +0 -2560
  313. package/src/Components/FileViewer.tsx +0 -412
  314. package/src/Components/Icon.tsx +0 -238
  315. package/src/Components/IconPicker.tsx +0 -165
  316. package/src/Components/IconSelector.tsx +0 -2220
  317. package/src/Components/Image.tsx +0 -193
  318. package/src/Components/Loader.tsx +0 -328
  319. package/src/Components/Logo.tsx +0 -176
  320. package/src/Components/MDUtils.tsx +0 -104
  321. package/src/Components/ObjectBrowser.tsx +0 -8947
  322. package/src/Components/Router.tsx +0 -90
  323. package/src/Components/SaveCloseButtons.tsx +0 -117
  324. package/src/Components/Schedule.tsx +0 -1998
  325. package/src/Components/SelectWithIcon.tsx +0 -239
  326. package/src/Components/TabContainer.tsx +0 -57
  327. package/src/Components/TabContent.tsx +0 -38
  328. package/src/Components/TabHeader.tsx +0 -20
  329. package/src/Components/ToggleThemeMenu.tsx +0 -52
  330. package/src/Components/TreeTable.tsx +0 -1002
  331. package/src/Components/UploadImage.tsx +0 -643
  332. package/src/Components/Utils.tsx +0 -1802
  333. package/src/Components/loader.css +0 -231
  334. package/src/Components/withWidth.tsx +0 -32
  335. package/src/Connection.tsx +0 -5
  336. package/src/Dialogs/ComplexCron.tsx +0 -163
  337. package/src/Dialogs/Confirm.tsx +0 -185
  338. package/src/Dialogs/Cron.tsx +0 -192
  339. package/src/Dialogs/Error.tsx +0 -67
  340. package/src/Dialogs/Message.tsx +0 -73
  341. package/src/Dialogs/SelectFile.tsx +0 -280
  342. package/src/Dialogs/SelectID.tsx +0 -310
  343. package/src/Dialogs/SimpleCron.tsx +0 -101
  344. package/src/Dialogs/TextInput.tsx +0 -99
  345. package/src/GenericApp.tsx +0 -1076
  346. package/src/LegacyConnection.tsx +0 -3720
  347. package/src/Prompt.tsx +0 -22
  348. package/src/Theme.tsx +0 -472
  349. package/src/icons/IconAdapter.tsx +0 -22
  350. package/src/icons/IconAlias.tsx +0 -22
  351. package/src/icons/IconChannel.tsx +0 -60
  352. package/src/icons/IconClearFilter.tsx +0 -24
  353. package/src/icons/IconClosed.tsx +0 -22
  354. package/src/icons/IconCopy.tsx +0 -21
  355. package/src/icons/IconDevice.tsx +0 -126
  356. package/src/icons/IconDocument.tsx +0 -22
  357. package/src/icons/IconDocumentReadOnly.tsx +0 -27
  358. package/src/icons/IconExpert.tsx +0 -26
  359. package/src/icons/IconFx.tsx +0 -38
  360. package/src/icons/IconInstance.tsx +0 -22
  361. package/src/icons/IconLogout.tsx +0 -32
  362. package/src/icons/IconNoIcon.tsx +0 -21
  363. package/src/icons/IconOpen.tsx +0 -22
  364. package/src/icons/IconProps.tsx +0 -16
  365. package/src/icons/IconState.tsx +0 -38
  366. package/src/index.css +0 -56
  367. /package/{Components → build/Components}/404.d.ts +0 -0
  368. /package/{Components → build/Components}/SimpleCron/cronText.d.ts +0 -0
  369. /package/{assets → build/assets}/devices.json +0 -0
  370. /package/{assets → build/assets}/lamp_ceiling.svg +0 -0
  371. /package/{assets → build/assets}/lamp_table.svg +0 -0
  372. /package/{assets → build/assets}/no_icon.svg +0 -0
  373. /package/{assets → build/assets}/rooms.json +0 -0
  374. /package/{index.css → build/index.css} +0 -0
  375. /package/{tasks.js → tasksExample.js} +0 -0
@@ -1,3720 +0,0 @@
1
- /**
2
- * Copyright 2020-2024, Denis Haev (bluefox) <dogafox@gmail.com>
3
- *
4
- * MIT License
5
- *
6
- */
7
-
8
- import { type HostInfo } from '@iobroker/js-controller-common-db/build/esm/lib/common/tools';
9
- import { type FilteredNotificationInformation } from '@iobroker/js-controller-common/build/esm/lib/common/notificationHandler';
10
- import type { IoBJson } from '@iobroker/types/build/config';
11
-
12
- declare global {
13
- interface Window {
14
- adapterName: undefined | string;
15
- socketUrl: undefined | string;
16
- registerSocketOnLoad: (func: () => void) => void;
17
- vendorPrefix: undefined | string;
18
- io: any;
19
- iob: any;
20
- }
21
- }
22
-
23
- export type CompactSystemRepositoryEntry = {
24
- link: string;
25
- hash?: string;
26
- stable?: boolean;
27
- json:
28
- | {
29
- _repoInfo: {
30
- stable?: boolean;
31
- name?: ioBroker.StringOrTranslated;
32
- };
33
- }
34
- | null
35
- | undefined;
36
- };
37
-
38
- export type CompactSystemRepository = {
39
- _id: ioBroker.HostObject['_id'];
40
- common: {
41
- name: ioBroker.HostCommon['name'];
42
- dontDelete: boolean;
43
- };
44
- native: {
45
- repositories: Record<string, CompactSystemRepositoryEntry>;
46
- };
47
- };
48
-
49
- /** Possible progress states. */
50
- export const PROGRESS = {
51
- /** The socket is connecting. */
52
- CONNECTING: 0,
53
- /** The socket is successfully connected. */
54
- CONNECTED: 1,
55
- /** All objects are loaded. */
56
- OBJECTS_LOADED: 2,
57
- /** All states are loaded. */
58
- STATES_LOADED: 3,
59
- /** The socket is ready for use. */
60
- READY: 4,
61
- };
62
-
63
- const PERMISSION_ERROR = 'permissionError';
64
- const NOT_CONNECTED = 'notConnectedError';
65
- const TIMEOUT_FOR_ADMIN4 = 1300;
66
-
67
- export const ERRORS = {
68
- PERMISSION_ERROR,
69
- NOT_CONNECTED,
70
- };
71
-
72
- export type BinaryStateChangeHandler = (id: string, base64: string | null) => void;
73
-
74
- function fixAdminUI(obj: ioBroker.AdapterObject): ioBroker.AdapterObject {
75
- // @ts-expect-error it is deprecated, but still could appear
76
- if (obj?.common && !obj.common.adminUI) {
77
- if (obj.common.noConfig) {
78
- // @ts-expect-error it is deprecated, but still could appear
79
- obj.common.adminUI = obj.common.adminUI || {};
80
- // @ts-expect-error it is deprecated, but still could appear
81
- obj.common.adminUI.config = 'none';
82
- // @ts-expect-error it is deprecated, but still could appear
83
- } else if (obj.common.jsonConfig) {
84
- // @ts-expect-error it is deprecated, but still could appear
85
- obj.common.adminUI = obj.common.adminUI || {};
86
- // @ts-expect-error it is deprecated, but still could appear
87
- obj.common.adminUI.config = 'json';
88
- } else if (obj.common.materialize) {
89
- // @ts-expect-error it is deprecated, but still could appear
90
- obj.common.adminUI = obj.common.adminUI || {};
91
- // @ts-expect-error it is deprecated, but still could appear
92
- obj.common.adminUI.config = 'materialize';
93
- } else {
94
- // @ts-expect-error it is deprecated, but still could appear
95
- obj.common.adminUI = obj.common.adminUI || {};
96
- // @ts-expect-error it is deprecated, but still could appear
97
- obj.common.adminUI.config = 'html';
98
- }
99
-
100
- // @ts-expect-error it is deprecated, but still could appear
101
- if (obj.common.jsonCustom) {
102
- // @ts-expect-error it is deprecated, but still could appear
103
- obj.common.adminUI = obj.common.adminUI || {};
104
- // @ts-expect-error it is deprecated, but still could appear
105
- obj.common.adminUI.custom = 'json';
106
- } else if (obj.common.supportCustoms) {
107
- // @ts-expect-error it is deprecated, but still could appear
108
- obj.common.adminUI = obj.common.adminUI || {};
109
- // @ts-expect-error it is deprecated, but still could appear
110
- obj.common.adminUI.custom = 'json';
111
- }
112
-
113
- if (obj.common.materializeTab && obj.common.adminTab) {
114
- // @ts-expect-error it is deprecated, but still could appear
115
- obj.common.adminUI = obj.common.adminUI || {};
116
- // @ts-expect-error it is deprecated, but still could appear
117
- obj.common.adminUI.tab = 'materialize';
118
- } else if (obj.common.adminTab) {
119
- // @ts-expect-error it is deprecated, but still could appear
120
- obj.common.adminUI = obj.common.adminUI || {};
121
- // @ts-expect-error it is deprecated, but still could appear
122
- obj.common.adminUI.tab = 'html';
123
- }
124
-
125
- // @ts-expect-error it is deprecated, but still could appear
126
- if (obj.common.adminUI) {
127
- console.debug(
128
- // @ts-expect-error it is deprecated, but still could appear
129
- `Please add to "${obj._id.replace(/\.\d+$/, '')}" common.adminUI=${JSON.stringify(obj.common.adminUI)}`,
130
- );
131
- }
132
- }
133
- return obj;
134
- }
135
-
136
- /** Converts ioB pattern into regex */
137
- export function pattern2RegEx(pattern: string): string {
138
- pattern = (pattern || '').toString();
139
-
140
- const startsWithWildcard = pattern[0] === '*';
141
- const endsWithWildcard = pattern[pattern.length - 1] === '*';
142
-
143
- pattern = pattern.replace(/[-/\\^$+?.()|[\]{}]/g, '\\$&').replace(/\*/g, '.*');
144
-
145
- return (startsWithWildcard ? '' : '^') + pattern + (endsWithWildcard ? '' : '$');
146
- }
147
-
148
- interface ConnectionProps {
149
- /** The socket name. */
150
- name?: string;
151
- /** State IDs to always automatically subscribe to. */
152
- autoSubscribes?: string[];
153
- /** Automatically subscribe to logging. */
154
- autoSubscribeLog?: boolean;
155
- /** The protocol to use for the socket.io connection. */
156
- protocol: string;
157
- /** The host name to use for the socket.io connection. */
158
- host: string;
159
- /** The port to use for the socket.io connection. */
160
- port?: string | number;
161
- /** The socket.io connection timeout. */
162
- ioTimeout?: number;
163
- /** The socket.io command timeout. */
164
- cmdTimeout?: number;
165
- /** Flag to indicate if all objects should be loaded or not. Default true (not loaded) */
166
- doNotLoadAllObjects?: boolean;
167
- /** Flag to indicate if AccessControlList for current user will be loaded or not. Default true (not loaded) */
168
- doNotLoadACL?: boolean;
169
- /** Progress callback. */
170
- onProgress?: (progress: number) => void;
171
- /** Ready callback. */
172
- onReady?: (objects: Record<string, ioBroker.Object>) => void;
173
- /** Log callback. */
174
- onLog?: (text: string) => void;
175
- /** Error callback. */
176
- onError?: (error: any) => void;
177
- /** Object change callback. */
178
- onObjectChange?: ioBroker.ObjectChangeHandler;
179
- /** Gets called when the system language is determined */
180
- onLanguage?: (lang: ioBroker.Languages) => void;
181
- /** Forces the use of the Compact Methods, wich only exists in admin 5 UI. */
182
- admin5only?: boolean;
183
- /** The device UUID with which the communication must be established */
184
- uuid?: string;
185
- /** Authentication token (used only in cloud) */
186
- token?: string;
187
- }
188
-
189
- export interface ConnectOptions {
190
- path?: string;
191
- query?: string;
192
- name?: string;
193
- timeout?: number;
194
- uuid?: string;
195
- }
196
-
197
- export interface SocketClient {
198
- connect(url?: string, options?: ConnectOptions): void;
199
- close(): void;
200
- destroy(): void;
201
-
202
- readonly connected: boolean;
203
-
204
- on(event: string, callback: (...args: any) => void): void;
205
- off(event: string, callback: (...args: any) => void): void;
206
- emit(event: string, ...args: any): boolean;
207
- }
208
-
209
- interface RenameGroupObject extends ioBroker.GroupObject {
210
- newId?: ioBroker.ObjectIDs.Group;
211
- }
212
-
213
- interface Promises {
214
- installedCompact?: {
215
- [host: string]: Promise<Record<string, ioBroker.AdapterObject>> | null;
216
- } | null;
217
- installed?: {
218
- [host: string]: Promise<Record<string, ioBroker.AdapterObject>> | null;
219
- } | null;
220
- systemConfig?: Promise<ioBroker.SystemConfigObject> | null;
221
- hosts?: Promise<ioBroker.HostObject[]> | null;
222
- users?: Promise<ioBroker.UserObject[]> | null;
223
- compactAdapters?: Promise<Record<string, ioBroker.AdapterObject>> | null;
224
- repoCompact?: Promise<any> | null;
225
- version?: Promise<{ version: string; serverName: string }> | null;
226
- groups?: Promise<ioBroker.GroupObject[]> | null;
227
- repo?: Promise<Record<string, ioBroker.AdapterObject>> | null;
228
- cert?: Promise<{ name: string; type: 'public' | 'private' | 'chained' | '' }[]> | null;
229
- webName?: Promise<string> | null;
230
- compactInstances?: Promise<Record<string, ioBroker.InstanceObject>> | null;
231
- getCompactSystemRepositories?: Promise<CompactSystemRepository> | null;
232
- systemConfigPromise?: Promise<ioBroker.SystemConfigObject> | null;
233
- hostsCompact?: Promise<ioBroker.HostObject[]> | null;
234
- uuid?: Promise<string | undefined>;
235
- [feature: `supportedFeatures_${string}`]: Promise<boolean> | null;
236
- [type: `instances_${string}`]: Promise<any> | null;
237
- [_enum: `enums_${string}`]: Promise<any> | null;
238
- [adapter: `adapter_${string}`]: Promise<any> | null;
239
- [host: `IPs_${string}`]: Promise<string[]> | null;
240
- [host: `hostInfo_${string}`]: Promise<HostInfo> | null;
241
- [host: `hostInfoShort_${string}`]: Promise<HostInfo> | null;
242
- [host: `rIPs_${string}`]: Promise<{ name: string; address: string; family: 'ipv4' | 'ipv6' }[]> | null;
243
- currentInstance?: Promise<string> | null;
244
- }
245
-
246
- class Connection {
247
- // Do not define it as null, else we must check for null everywhere
248
- private _socket: SocketClient;
249
-
250
- private _authTimer: ReturnType<typeof setTimeout> | null | undefined;
251
-
252
- private systemLang: ioBroker.Languages = 'en';
253
-
254
- private readonly _waitForFirstConnection: Promise<void>;
255
-
256
- private _waitForFirstConnectionResolve: (() => void) | null = null;
257
-
258
- private _promises: Promises = {};
259
-
260
- private readonly _instanceSubscriptions: Record<
261
- string,
262
- {
263
- messageType: string;
264
- callback: (data: Record<string, any>, sourceInstance: string, messageType: string) => void;
265
- }[]
266
- >;
267
-
268
- private props: ConnectionProps;
269
-
270
- private doNotLoadAllObjects: boolean;
271
-
272
- private readonly doNotLoadACL: boolean;
273
-
274
- private states: Record<string, ioBroker.State> = {};
275
-
276
- private objects: Record<string, ioBroker.Object> | null = null;
277
-
278
- private scriptLoadCounter: number | undefined;
279
-
280
- private acl: Record<string, any> | null = null;
281
-
282
- private firstConnect: boolean = true;
283
-
284
- private readonly waitForRestart: boolean = false;
285
-
286
- private connected: boolean = false;
287
-
288
- private readonly statesSubscribes: Record<
289
- string,
290
- { reg: RegExp; cbs: (ioBroker.StateChangeHandler | BinaryStateChangeHandler)[] }
291
- > = {};
292
-
293
- private readonly objectsSubscribes: Record<
294
- string,
295
- {
296
- reg: RegExp;
297
- cbs: ((id: string, obj: ioBroker.Object | null | undefined, oldObj?: ioBroker.Object | null) => void)[];
298
- }
299
- > = {};
300
-
301
- private readonly filesSubscribes: Record<
302
- string,
303
- { regId: RegExp; cbs: ioBroker.FileChangeHandler[]; regFilePattern: RegExp }
304
- > = {};
305
-
306
- private onConnectionHandlers: ((connected: boolean) => void)[] = [];
307
-
308
- private onLogHandlers: ((message: string) => void)[] = [];
309
-
310
- private readonly onProgress: (progress: number) => void;
311
-
312
- private readonly onError: (
313
- err:
314
- | string
315
- | {
316
- message: string;
317
- operation: string;
318
- type: string;
319
- id: string;
320
- },
321
- ) => void;
322
-
323
- private loaded: boolean = false;
324
-
325
- private loadTimer: ReturnType<typeof setTimeout> | null = null;
326
-
327
- private loadCounter: number = 0;
328
-
329
- private admin5only: boolean;
330
-
331
- private ignoreState: string = '';
332
-
333
- private readonly simStates: Record<string, ioBroker.State> = {};
334
-
335
- private autoSubscribes: string[];
336
-
337
- private readonly autoSubscribeLog: boolean;
338
-
339
- private subscribed: boolean | undefined;
340
-
341
- public isSecure: boolean | undefined;
342
-
343
- private onCmdStdoutHandler: ((id: string, text: string) => void) | undefined;
344
-
345
- private onCmdStderrHandler: ((id: string, text: string) => void) | undefined;
346
-
347
- private onCmdExitHandler: ((id: string, exitCode: number) => void) | undefined;
348
-
349
- public systemConfig: ioBroker.SystemConfigObject | null = null;
350
-
351
- constructor(props: ConnectionProps) {
352
- props = props || { protocol: window.location.protocol, host: window.location.hostname };
353
- this.props = props;
354
-
355
- this.autoSubscribes = this.props.autoSubscribes || [];
356
- this.autoSubscribeLog = this.props.autoSubscribeLog || false;
357
-
358
- this.props.protocol = this.props.protocol || window.location.protocol;
359
- this.props.host = this.props.host || window.location.hostname;
360
- this.props.port =
361
- this.props.port ||
362
- (window.location.port === '3000' ? (Connection.isWeb() ? 8082 : 8081) : window.location.port);
363
- this.props.ioTimeout = Math.max(this.props.ioTimeout || 20000, 20000);
364
- this.props.cmdTimeout = Math.max(this.props.cmdTimeout || 5000, 5000);
365
- this._instanceSubscriptions = {};
366
-
367
- // breaking change. Do not load all objects by default is true
368
- this.doNotLoadAllObjects = this.props.doNotLoadAllObjects === undefined ? true : this.props.doNotLoadAllObjects;
369
- this.doNotLoadACL = this.props.doNotLoadACL === undefined ? true : this.props.doNotLoadACL;
370
-
371
- this.states = {};
372
- this._waitForFirstConnection = new Promise(resolve => {
373
- this._waitForFirstConnectionResolve = resolve;
374
- });
375
- this.onProgress = this.props.onProgress || (() => {});
376
- this.onError =
377
- this.props.onError ||
378
- ((
379
- err:
380
- | string
381
- | {
382
- message: string;
383
- operation: string;
384
- type: string;
385
- id: string;
386
- },
387
- ) => console.error(err));
388
- this.admin5only = this.props.admin5only || false;
389
-
390
- this.startSocket();
391
- }
392
-
393
- /**
394
- * Checks if this connection is running in a web adapter and not in an admin.
395
- *
396
- * @returns True if running in a web adapter or in a socketio adapter.
397
- */
398
- static isWeb(): boolean {
399
- const adapterName: string | undefined = window.adapterName;
400
- return (
401
- adapterName === 'material' ||
402
- adapterName === 'vis' ||
403
- adapterName?.startsWith('vis-') ||
404
- adapterName === 'echarts-show' ||
405
- window.socketUrl !== undefined
406
- );
407
- }
408
-
409
- /**
410
- * Starts the socket.io connection.
411
- */
412
- startSocket(): void {
413
- // if socket io is not yet loaded
414
- if (typeof window.io === 'undefined' && typeof window.iob === 'undefined') {
415
- // if in index.html the onLoad function not defined
416
- if (typeof window.registerSocketOnLoad !== 'function') {
417
- // poll if loaded
418
- this.scriptLoadCounter = this.scriptLoadCounter || 0;
419
- this.scriptLoadCounter++;
420
-
421
- if (this.scriptLoadCounter < 30) {
422
- // wait till the script loaded
423
- setTimeout(() => this.startSocket(), 100);
424
- return;
425
- }
426
- window.alert('Cannot load socket.io.js!');
427
- } else {
428
- // register on load
429
- window.registerSocketOnLoad(() => this.startSocket());
430
- }
431
- return;
432
- }
433
- if (this._socket) {
434
- // socket was initialized, do not repeat
435
- return;
436
- }
437
-
438
- let host = this.props.host;
439
- let port = this.props.port;
440
- let protocol = this.props.protocol.replace(':', '');
441
- let path = window.location.pathname;
442
-
443
- if (window.location.hostname === 'iobroker.net' || window.location.hostname === 'iobroker.pro') {
444
- path = '';
445
- } else {
446
- // if web adapter, socket io could be on another port or even host
447
- if (window.socketUrl) {
448
- const parsed = new URL((window as any).socketUrl as string);
449
- host = parsed.hostname;
450
- port = parsed.port;
451
- protocol = parsed.protocol.replace(':', '');
452
- }
453
- // get a current path
454
- const pos = path.lastIndexOf('/');
455
- if (pos !== -1) {
456
- path = path.substring(0, pos + 1);
457
- }
458
-
459
- if (Connection.isWeb()) {
460
- // remove one level, like echarts, vis, .... We have here: '/echarts/'
461
- const parts = path.split('/');
462
- if (parts.length > 2) {
463
- parts.pop();
464
- // if it is a version, like in material, so remove it too
465
- if (parts[parts.length - 1].match(/\d+\.\d+\.\d+/)) {
466
- parts.pop();
467
- }
468
- parts.pop();
469
- path = parts.join('/');
470
- if (!path.endsWith('/')) {
471
- path += '/';
472
- }
473
- }
474
- }
475
- }
476
-
477
- const url = port ? `${protocol}://${host}:${port}${path}` : `${protocol}://${host}${path}`;
478
-
479
- this._socket = (window.io || window.iob).connect(url, {
480
- path: path.endsWith('/') ? `${path}socket.io` : `${path}/socket.io`,
481
- query: 'ws=true',
482
- name: this.props.name,
483
- timeout: this.props.ioTimeout,
484
- uuid: this.props.uuid,
485
- });
486
-
487
- this._socket.on('connect', (noTimeout: boolean | undefined) => {
488
- // If the user is not admin, it takes some time to install the handlers, because all rights must be checked
489
- if (noTimeout !== true) {
490
- setTimeout(
491
- () =>
492
- this.getVersion().then(info => {
493
- const [major, minor, patch] = info.version.split('.');
494
- const v = parseInt(major, 10) * 10000 + parseInt(minor, 10) * 100 + parseInt(patch, 10);
495
- if (v < 40102) {
496
- this._authTimer = null;
497
- // possible this is an old version of admin
498
- this.onPreConnect(false, false);
499
- } else {
500
- this._socket.emit('authenticate', (isOk: boolean, isSecure: boolean) =>
501
- this.onPreConnect(isOk, isSecure),
502
- );
503
- }
504
- }),
505
- 500,
506
- );
507
- } else {
508
- // iobroker websocket waits, till all handlers are installed
509
- this._socket.emit('authenticate', (isOk: boolean, isSecure: boolean) =>
510
- this.onPreConnect(isOk, isSecure),
511
- );
512
- }
513
- });
514
-
515
- this._socket.on('reconnect', () => {
516
- this.onProgress(PROGRESS.READY);
517
- this.connected = true;
518
-
519
- if (this.waitForRestart) {
520
- window.location.reload();
521
- } else {
522
- this._subscribe(true);
523
- this.onConnectionHandlers.forEach(cb => cb(true));
524
- }
525
- });
526
-
527
- this._socket.on('disconnect', () => {
528
- this.connected = false;
529
- this.subscribed = false;
530
- this.onProgress(PROGRESS.CONNECTING);
531
- this.onConnectionHandlers.forEach(cb => cb(false));
532
- });
533
-
534
- this._socket.on('reauthenticate', () => Connection.authenticate());
535
-
536
- this._socket.on('log', message => {
537
- this.props.onLog && this.props.onLog(message);
538
- this.onLogHandlers.forEach(cb => cb(message));
539
- });
540
-
541
- this._socket.on('error', (err: string | null) => {
542
- let _err = err || '';
543
- if (typeof _err.toString !== 'function') {
544
- _err = JSON.stringify(_err);
545
- console.error(`Received strange error: ${_err}`);
546
- }
547
- _err = _err.toString();
548
- if (_err.includes('User not authorized')) {
549
- Connection.authenticate();
550
- } else {
551
- window.alert(`Socket Error: ${err}`);
552
- }
553
- });
554
-
555
- this._socket.on('connect_error', (err: string) => console.error(`Connect error: ${err}`));
556
-
557
- this._socket.on('permissionError', (err: { operation: string; type: string; id?: string }) =>
558
- this.onError({
559
- message: 'no permission',
560
- operation: err.operation,
561
- type: err.type,
562
- id: err.id || '',
563
- }),
564
- );
565
-
566
- this._socket.on('objectChange', (id: string, obj: ioBroker.Object | null) =>
567
- setTimeout(() => this.objectChange(id, obj), 0),
568
- );
569
-
570
- this._socket.on('stateChange', (id: string, state) => setTimeout(() => this.stateChange(id, state), 0));
571
-
572
- this._socket.on('im', (messageType: string, from: string, data) =>
573
- setTimeout(() => this.instanceMessage(messageType, from, data), 0),
574
- );
575
-
576
- this._socket.on('fileChange', (id: string, fileName: string, size: number | null) =>
577
- setTimeout(() => this.fileChange(id, fileName, size), 0),
578
- );
579
-
580
- this._socket.on(
581
- 'cmdStdout',
582
- (id: string, text: string) => this.onCmdStdoutHandler && this.onCmdStdoutHandler(id, text),
583
- );
584
-
585
- this._socket.on(
586
- 'cmdStderr',
587
- (id: string, text: string) => this.onCmdStderrHandler && this.onCmdStderrHandler(id, text),
588
- );
589
-
590
- this._socket.on(
591
- 'cmdExit',
592
- (id: string, exitCode: number) => this.onCmdExitHandler && this.onCmdExitHandler(id, exitCode),
593
- );
594
- }
595
-
596
- /**
597
- * Called internally.
598
- */
599
- private onPreConnect(_isOk: boolean, isSecure: boolean): void {
600
- if (this._authTimer) {
601
- clearTimeout(this._authTimer);
602
- this._authTimer = null;
603
- }
604
-
605
- this.connected = true;
606
- this.isSecure = isSecure;
607
-
608
- if (this.waitForRestart) {
609
- window.location.reload();
610
- } else {
611
- if (this.firstConnect) {
612
- // retry strategy
613
- this.loadTimer = setTimeout(() => {
614
- this.loadTimer = null;
615
- this.loadCounter++;
616
- if (this.loadCounter < 10) {
617
- void this.onConnect().catch(e => this.onError(e));
618
- }
619
- }, 1000);
620
-
621
- if (!this.loaded) {
622
- void this.onConnect().catch(e => this.onError(e));
623
- }
624
- } else {
625
- this.onProgress(PROGRESS.READY);
626
- }
627
-
628
- this._subscribe(true);
629
- this.onConnectionHandlers.forEach(cb => cb(true));
630
- }
631
-
632
- if (this._waitForFirstConnectionResolve) {
633
- this._waitForFirstConnectionResolve();
634
- this._waitForFirstConnectionResolve = null;
635
- }
636
- }
637
-
638
- /**
639
- * Checks if running in ioBroker cloud
640
- */
641
- static isCloud(): boolean {
642
- if (window.location.hostname.includes('amazonaws.com') || window.location.hostname.includes('iobroker.in')) {
643
- return true;
644
- }
645
- if (typeof window.socketUrl === 'undefined') {
646
- return false;
647
- }
648
- return window.socketUrl.includes('iobroker.in') || window.socketUrl.includes('amazonaws');
649
- }
650
-
651
- /**
652
- * Checks if the socket is connected.
653
- */
654
- isConnected(): boolean {
655
- return this.connected;
656
- }
657
-
658
- /**
659
- * Checks if the socket is connected.
660
- * Promise resolves if once connected.
661
- */
662
- waitForFirstConnection(): Promise<void> {
663
- return this._waitForFirstConnection;
664
- }
665
-
666
- /**
667
- * Called internally.
668
- */
669
- private async _getUserPermissions(): Promise<Record<string, any> | null> {
670
- if (this.doNotLoadACL) {
671
- return null;
672
- }
673
- return new Promise((resolve, reject) => {
674
- this._socket.emit('getUserPermissions', (err: string | null, acl: Record<string, any> | null) =>
675
- err ? reject(new Error(err)) : resolve(acl),
676
- );
677
- });
678
- }
679
-
680
- /**
681
- * Called internally.
682
- */
683
- private async onConnect(): Promise<void> {
684
- let acl: Record<string, any> | null | undefined;
685
- try {
686
- acl = await this._getUserPermissions();
687
- } catch (e) {
688
- const knownError = e as Error;
689
- this.onError(`Cannot read user permissions: ${knownError.message}`);
690
- return;
691
- }
692
- if (!this.doNotLoadACL) {
693
- if (this.loaded) {
694
- return;
695
- }
696
- this.loaded = true;
697
- this.loadTimer && clearTimeout(this.loadTimer);
698
- this.loadTimer = null;
699
-
700
- this.onProgress(PROGRESS.CONNECTED);
701
- this.firstConnect = false;
702
-
703
- this.acl = acl;
704
- }
705
-
706
- // Read system configuration
707
- let data: ioBroker.SystemConfigObject | null;
708
- try {
709
- if (this.admin5only && !window.vendorPrefix) {
710
- data = await this.getCompactSystemConfig();
711
- } else {
712
- data = await this.getSystemConfig();
713
- }
714
- if (this.doNotLoadACL) {
715
- if (this.loaded) {
716
- return;
717
- }
718
- this.loaded = true;
719
- this.loadTimer && clearTimeout(this.loadTimer);
720
- this.loadTimer = null;
721
-
722
- this.onProgress(PROGRESS.CONNECTED);
723
- this.firstConnect = false;
724
- }
725
-
726
- this.systemConfig = data;
727
- if (this.systemConfig && this.systemConfig.common) {
728
- this.systemLang = this.systemConfig.common.language;
729
- } else {
730
- // @ts-expect-error userLanguage is not standard
731
- this.systemLang = window.navigator.userLanguage || window.navigator.language;
732
-
733
- if (/^(en|de|ru|pt|nl|fr|it|es|pl|uk)-?/.test(this.systemLang)) {
734
- this.systemLang = this.systemLang.substr(0, 2) as ioBroker.Languages;
735
- } else if (!/^(en|de|ru|pt|nl|fr|it|es|pl|uk|zh-cn)$/.test(this.systemLang)) {
736
- this.systemLang = 'en';
737
- }
738
- }
739
-
740
- this.props.onLanguage && this.props.onLanguage(this.systemLang);
741
-
742
- if (!this.doNotLoadAllObjects) {
743
- await this.getObjects();
744
- this.onProgress(PROGRESS.READY);
745
- this.props.onReady && this.objects && this.props.onReady(this.objects);
746
- } else {
747
- this.objects = this.admin5only ? {} : { 'system.config': data };
748
- this.onProgress(PROGRESS.READY);
749
- this.props.onReady && this.props.onReady(this.objects);
750
- }
751
- } catch (e) {
752
- this.onError(`Cannot read system config: ${e}`);
753
- }
754
- }
755
-
756
- /**
757
- * Called internally.
758
- */
759
- private static authenticate(): void {
760
- if (window.location.search.includes('&href=')) {
761
- window.location.href = `${window.location.protocol}//${window.location.host}${window.location.pathname}${window.location.search}${window.location.hash}`;
762
- } else {
763
- window.location.href = `${window.location.protocol}//${window.location.host}${window.location.pathname}?login&href=${window.location.search}${window.location.hash}`;
764
- }
765
- }
766
-
767
- /**
768
- * Subscribe to changes of the given state.
769
- *
770
- * @param id The ioBroker state ID or array of states
771
- * @param binary Set to true if the given state is binary and requires Base64 decoding
772
- * @param cb The callback
773
- */
774
- subscribeState(
775
- id: string | string[],
776
- binary: boolean | ioBroker.StateChangeHandler | BinaryStateChangeHandler,
777
- cb?: ioBroker.StateChangeHandler | BinaryStateChangeHandler,
778
- ): void {
779
- if (typeof binary === 'function') {
780
- cb = binary;
781
- binary = false;
782
- }
783
-
784
- let ids: string[];
785
- if (!Array.isArray(id)) {
786
- ids = [id];
787
- } else {
788
- ids = id;
789
- }
790
- if (!cb) {
791
- console.error('No callback found for subscribeState');
792
- return;
793
- }
794
- const toSubscribe = [];
795
- for (let i = 0; i < ids.length; i++) {
796
- const _id = ids[i];
797
- if (!this.statesSubscribes[_id]) {
798
- let reg = _id
799
- .replace(/\./g, '\\.')
800
- .replace(/\*/g, '.*')
801
- .replace(/\(/g, '\\(')
802
- .replace(/\)/g, '\\)')
803
- .replace(/\+/g, '\\+')
804
- .replace(/\[/g, '\\[');
805
-
806
- if (!reg.includes('*')) {
807
- reg += '$';
808
- }
809
- this.statesSubscribes[_id] = { reg: new RegExp(reg), cbs: [cb] };
810
- if (_id !== this.ignoreState) {
811
- toSubscribe.push(_id);
812
- }
813
- } else {
814
- !this.statesSubscribes[_id].cbs.includes(cb) && this.statesSubscribes[_id].cbs.push(cb);
815
- }
816
- }
817
-
818
- if (!this.connected) {
819
- return;
820
- }
821
-
822
- if (toSubscribe.length) {
823
- // no answer from server required
824
- this._socket.emit('subscribe', toSubscribe);
825
- }
826
-
827
- if (binary) {
828
- for (let i = 0; i < ids.length; i++) {
829
- this.getBinaryState(ids[i])
830
- .then((base64: string) => cb && (cb as BinaryStateChangeHandler)(ids[i], base64))
831
- .catch(e => console.error(`Cannot getBinaryState "${ids[i]}": ${JSON.stringify(e)}`));
832
- }
833
- } else {
834
- this._socket.emit(
835
- Connection.isWeb() ? 'getStates' : 'getForeignStates',
836
- id,
837
- (err: string | null, states: Record<string, ioBroker.State>) => {
838
- err && console.error(`Cannot getForeignStates "${id}": ${JSON.stringify(err)}`);
839
- states && Object.keys(states).forEach(_id => (cb as ioBroker.StateChangeHandler)(_id, states[_id]));
840
- },
841
- );
842
- }
843
- }
844
-
845
- /**
846
- * Subscribe to changes of the given state.
847
- */
848
- subscribeStateAsync(
849
- /** The ioBroker state ID or array of states */
850
- id: string | string[],
851
- /** The callback. */
852
- cb: ioBroker.StateChangeHandler,
853
- ): Promise<void> {
854
- let ids: string[];
855
- if (!Array.isArray(id)) {
856
- ids = [id];
857
- } else {
858
- ids = id;
859
- }
860
- const toSubscribe = [];
861
- for (let i = 0; i < ids.length; i++) {
862
- const _id = ids[i];
863
- if (!this.statesSubscribes[_id]) {
864
- let reg = _id
865
- .replace(/\./g, '\\.')
866
- .replace(/\*/g, '.*')
867
- .replace(/\(/g, '\\(')
868
- .replace(/\)/g, '\\)')
869
- .replace(/\+/g, '\\+')
870
- .replace(/\[/g, '\\[');
871
-
872
- if (!reg.includes('*')) {
873
- reg += '$';
874
- }
875
- this.statesSubscribes[_id] = { reg: new RegExp(reg), cbs: [] };
876
- this.statesSubscribes[_id].cbs.push(cb);
877
- if (_id !== this.ignoreState) {
878
- // no answer from server required
879
- toSubscribe.push(_id);
880
- }
881
- } else {
882
- !this.statesSubscribes[_id].cbs.includes(cb) && this.statesSubscribes[_id].cbs.push(cb);
883
- }
884
- }
885
-
886
- if (toSubscribe.length && this.connected) {
887
- // no answer from server required
888
- this._socket.emit('subscribe', toSubscribe);
889
- }
890
-
891
- return new Promise((resolve, reject) => {
892
- if (typeof cb === 'function' && this.connected) {
893
- this._socket.emit(
894
- Connection.isWeb() ? 'getStates' : 'getForeignStates',
895
- id,
896
- (err: string | null, states: Record<string, ioBroker.State>) => {
897
- err && console.error(`Cannot getForeignStates "${id}": ${JSON.stringify(err)}`);
898
- states && Object.keys(states).forEach(_id => cb(_id, states[_id]));
899
- states
900
- ? resolve()
901
- : reject(new Error(`Cannot getForeignStates "${id}": ${JSON.stringify(err)}`));
902
- },
903
- );
904
- } else {
905
- this.connected ? reject(new Error('callback is not a function')) : reject(new Error('not connected'));
906
- }
907
- });
908
- }
909
-
910
- /**
911
- * Unsubscribes all or the given callback from changes of the given state.
912
- */
913
- unsubscribeState(
914
- /** The ioBroker state ID or array of states */
915
- id: string | string[],
916
- /** The callback. */
917
- cb?: ioBroker.StateChangeHandler | BinaryStateChangeHandler,
918
- ): void {
919
- let ids: string[];
920
- if (!Array.isArray(id)) {
921
- ids = [id];
922
- } else {
923
- ids = id;
924
- }
925
- const toUnsubscribe = [];
926
- for (let i = 0; i < ids.length; i++) {
927
- const _id = ids[i];
928
-
929
- if (this.statesSubscribes[_id]) {
930
- if (cb) {
931
- const pos = this.statesSubscribes[_id].cbs.indexOf(cb);
932
- pos !== -1 && this.statesSubscribes[_id].cbs.splice(pos, 1);
933
- } else {
934
- this.statesSubscribes[_id].cbs = [];
935
- }
936
-
937
- if (!this.statesSubscribes[_id].cbs || !this.statesSubscribes[_id].cbs.length) {
938
- delete this.statesSubscribes[_id];
939
- if (_id !== this.ignoreState) {
940
- toUnsubscribe.push(_id);
941
- }
942
- }
943
- }
944
- }
945
-
946
- if (toUnsubscribe.length && this.connected) {
947
- // no answer from server required
948
- this._socket.emit('unsubscribe', toUnsubscribe);
949
- }
950
- }
951
-
952
- /**
953
- * Subscribe to changes of the given object.
954
- *
955
- * @param id The ioBroker object ID or array of objects
956
- * @param cb The callback
957
- */
958
- subscribeObject(id: string | string[], cb: ioBroker.ObjectChangeHandler): Promise<void> {
959
- let ids: string[];
960
- if (!Array.isArray(id)) {
961
- ids = [id];
962
- } else {
963
- ids = id;
964
- }
965
- const toSubscribe = [];
966
- for (let i = 0; i < ids.length; i++) {
967
- const _id = ids[i];
968
- if (!this.objectsSubscribes[_id]) {
969
- let reg = _id.replace(/\./g, '\\.').replace(/\*/g, '.*');
970
- if (!reg.includes('*')) {
971
- reg += '$';
972
- }
973
- this.objectsSubscribes[_id] = { reg: new RegExp(reg), cbs: [cb] };
974
- toSubscribe.push(_id);
975
- } else {
976
- !this.objectsSubscribes[_id].cbs.includes(cb) && this.objectsSubscribes[_id].cbs.push(cb);
977
- }
978
- }
979
- if (this.connected && toSubscribe.length) {
980
- this._socket.emit('subscribeObjects', toSubscribe);
981
- }
982
-
983
- return Promise.resolve();
984
- }
985
-
986
- /**
987
- * Unsubscribes all or the given callback from changes of the given object.
988
- *
989
- * @param id The ioBroker object ID or array of objects
990
- * @param cb The callback
991
- */
992
- unsubscribeObject(id: string | string[], cb?: ioBroker.ObjectChangeHandler): Promise<void> {
993
- let ids: string[];
994
- if (!Array.isArray(id)) {
995
- ids = [id];
996
- } else {
997
- ids = id;
998
- }
999
- const toUnsubscribe = [];
1000
- for (let i = 0; i < ids.length; i++) {
1001
- const _id = ids[i];
1002
- if (this.objectsSubscribes[_id]) {
1003
- if (cb) {
1004
- const pos = this.objectsSubscribes[_id].cbs.indexOf(cb);
1005
- pos !== -1 && this.objectsSubscribes[_id].cbs.splice(pos, 1);
1006
- } else {
1007
- this.objectsSubscribes[_id].cbs = [];
1008
- }
1009
-
1010
- if (this.connected && (!this.objectsSubscribes[_id].cbs || !this.objectsSubscribes[_id].cbs.length)) {
1011
- delete this.objectsSubscribes[_id];
1012
- toUnsubscribe.push(_id);
1013
- }
1014
- }
1015
- }
1016
-
1017
- if (this.connected && toUnsubscribe.length) {
1018
- this._socket.emit('unsubscribeObjects', toUnsubscribe);
1019
- }
1020
-
1021
- return Promise.resolve();
1022
- }
1023
-
1024
- /**
1025
- * Called internally.
1026
- */
1027
- private fileChange(id: string, fileName: string, size: number | null): void {
1028
- for (const sub of Object.values(this.filesSubscribes)) {
1029
- if (sub.regId.test(id) && sub.regFilePattern.test(fileName)) {
1030
- for (const cb of sub.cbs) {
1031
- try {
1032
- cb(id, fileName, size);
1033
- } catch (e) {
1034
- console.error(`Error by callback of fileChange: ${e}`);
1035
- }
1036
- }
1037
- }
1038
- }
1039
- }
1040
-
1041
- /**
1042
- * Subscribe to changes of the files.
1043
- *
1044
- * @param id The ioBroker state ID for meta-object. Could be a pattern
1045
- * @param filePattern Pattern or file name, like 'main/*' or 'main/visViews.json`
1046
- * @param cb The callback.
1047
- */
1048
- async subscribeFiles(
1049
- /** The ioBroker state ID for meta-object. Could be a pattern */
1050
- id: string,
1051
- /** Pattern or file name, like 'main/*' or 'main/visViews.json` */
1052
- filePattern: string | string[],
1053
- /** The callback. */
1054
- cb: ioBroker.FileChangeHandler,
1055
- ): Promise<void> {
1056
- if (typeof cb !== 'function') {
1057
- throw new Error('The state change handler must be a function!');
1058
- }
1059
- let filePatterns;
1060
- if (Array.isArray(filePattern)) {
1061
- filePatterns = filePattern;
1062
- } else {
1063
- filePatterns = [filePattern];
1064
- }
1065
- const toSubscribe = [];
1066
- for (let f = 0; f < filePatterns.length; f++) {
1067
- const pattern = filePatterns[f];
1068
- const key = `${id}$%$${pattern}`;
1069
-
1070
- if (!this.filesSubscribes[key]) {
1071
- this.filesSubscribes[key] = {
1072
- regId: new RegExp(pattern2RegEx(id)),
1073
- regFilePattern: new RegExp(pattern2RegEx(pattern)),
1074
- cbs: [cb],
1075
- };
1076
-
1077
- toSubscribe.push(pattern);
1078
- } else {
1079
- !this.filesSubscribes[key].cbs.includes(cb) && this.filesSubscribes[key].cbs.push(cb);
1080
- }
1081
- }
1082
- if (this.connected && toSubscribe.length) {
1083
- this._socket.emit('subscribeFiles', id, toSubscribe);
1084
- }
1085
- return Promise.resolve();
1086
- }
1087
-
1088
- /**
1089
- * Unsubscribes the given callback from changes of files.
1090
- *
1091
- * @param id The ioBroker state ID.
1092
- * @param filePattern Pattern or file name, like 'main/*' or 'main/visViews.json`
1093
- * @param cb The callback.
1094
- */
1095
- unsubscribeFiles(id: string, filePattern: string, cb?: ioBroker.FileChangeHandler): void {
1096
- let filePatterns: string[];
1097
- if (Array.isArray(filePattern)) {
1098
- filePatterns = filePattern;
1099
- } else {
1100
- filePatterns = [filePattern];
1101
- }
1102
- const toUnsubscribe = [];
1103
- for (let f = 0; f < filePatterns.length; f++) {
1104
- const pattern = filePatterns[f];
1105
- const key = `${id}$%$${pattern}`;
1106
- if (this.filesSubscribes[key]) {
1107
- const sub = this.filesSubscribes[key];
1108
- if (cb) {
1109
- const pos = sub.cbs.indexOf(cb);
1110
- pos !== -1 && sub.cbs.splice(pos, 1);
1111
- } else {
1112
- sub.cbs = [];
1113
- }
1114
-
1115
- if (!sub.cbs || !sub.cbs.length) {
1116
- delete this.filesSubscribes[key];
1117
- this.connected && toUnsubscribe.push(pattern);
1118
- }
1119
- }
1120
- }
1121
-
1122
- if (this.connected && toUnsubscribe.length) {
1123
- this._socket.emit('unsubscribeFiles', id, toUnsubscribe);
1124
- }
1125
- }
1126
-
1127
- /**
1128
- * Called internally.
1129
- */
1130
- private objectChange(id: string, obj: ioBroker.Object | null): void {
1131
- // update main.objects cache
1132
- if (!this.objects) {
1133
- return;
1134
- }
1135
-
1136
- let oldObj: Partial<ioBroker.Object> | null;
1137
-
1138
- let changed = false;
1139
- if (obj) {
1140
- if (this.objects[id]) {
1141
- // @ts-expect-error fix later
1142
- oldObj = { _id: id, type: this.objects[id].type };
1143
- }
1144
-
1145
- if (!this.objects[id] || JSON.stringify(this.objects[id]) !== JSON.stringify(obj)) {
1146
- this.objects[id] = obj;
1147
- changed = true;
1148
- }
1149
- } else if (this.objects[id]) {
1150
- // @ts-expect-error fix later
1151
- oldObj = { _id: id, type: this.objects[id].type };
1152
- delete this.objects[id];
1153
- changed = true;
1154
- }
1155
-
1156
- Object.keys(this.objectsSubscribes).forEach(_id => {
1157
- if (_id === id || this.objectsSubscribes[_id].reg.test(id)) {
1158
- this.objectsSubscribes[_id].cbs.forEach(cb => {
1159
- try {
1160
- cb(id, obj, oldObj as ioBroker.Object);
1161
- } catch (e) {
1162
- console.error(`Error by callback of objectChange: ${e}`);
1163
- }
1164
- });
1165
- }
1166
- });
1167
-
1168
- if (changed && this.props.onObjectChange) {
1169
- void this.props.onObjectChange(id, obj);
1170
- }
1171
- }
1172
-
1173
- /**
1174
- * Called internally.
1175
- */
1176
- private stateChange(id: string, state: ioBroker.State | null): void {
1177
- for (const task in this.statesSubscribes) {
1178
- if (
1179
- Object.prototype.hasOwnProperty.call(this.statesSubscribes, task) &&
1180
- this.statesSubscribes[task].reg.test(id)
1181
- ) {
1182
- this.statesSubscribes[task].cbs.forEach(cb => {
1183
- try {
1184
- void (cb as ioBroker.StateChangeHandler)(id, state);
1185
- } catch (e) {
1186
- const knownError = e as Error;
1187
- console.error(`Error by callback of stateChange: ${knownError?.message}`);
1188
- }
1189
- });
1190
- }
1191
- }
1192
- }
1193
-
1194
- /**
1195
- * Called internally.
1196
- *
1197
- * @param messageType The message type
1198
- * @param sourceInstance The source instance
1199
- * @param data Payload
1200
- */
1201
- instanceMessage(messageType: string, sourceInstance: string, data: Record<string, any>): void {
1202
- if (this._instanceSubscriptions[sourceInstance]) {
1203
- this._instanceSubscriptions[sourceInstance].forEach(sub => {
1204
- if (sub.messageType === messageType) {
1205
- sub.callback(data, sourceInstance, messageType);
1206
- }
1207
- });
1208
- }
1209
- }
1210
-
1211
- /**
1212
- * Gets all states.
1213
- *
1214
- * @param pattern The pattern to filter states
1215
- * @param disableProgressUpdate Don't call onProgress() when done
1216
- */
1217
- getStates(pattern?: string | boolean, disableProgressUpdate?: boolean): Promise<Record<string, ioBroker.State>> {
1218
- if (!this.connected) {
1219
- return Promise.reject(new Error(NOT_CONNECTED));
1220
- }
1221
-
1222
- if (typeof pattern === 'boolean') {
1223
- disableProgressUpdate = pattern;
1224
- pattern = undefined;
1225
- }
1226
-
1227
- return new Promise((resolve, reject) => {
1228
- this._socket.emit('getStates', pattern, (err: string | null, res: Record<string, ioBroker.State>) => {
1229
- this.states = res;
1230
- !disableProgressUpdate && this.onProgress(PROGRESS.STATES_LOADED);
1231
- err ? reject(new Error(err)) : resolve(this.states);
1232
- });
1233
- });
1234
- }
1235
-
1236
- /**
1237
- * Gets the given state.
1238
- *
1239
- * @param id The state ID
1240
- */
1241
- getState(id: string): Promise<ioBroker.State | null> {
1242
- if (!this.connected) {
1243
- return Promise.reject(new Error(NOT_CONNECTED));
1244
- }
1245
- if (id && id === this.ignoreState) {
1246
- return Promise.resolve(this.simStates[id] || ({ val: null, ack: true } as ioBroker.State));
1247
- }
1248
- return new Promise((resolve, reject) => {
1249
- this._socket.emit('getState', id, (err: string | null, state: ioBroker.State) =>
1250
- err ? reject(new Error(err)) : resolve(state),
1251
- );
1252
- });
1253
- }
1254
-
1255
- /**
1256
- * Get the given binary state.
1257
- *
1258
- * @deprecated since js-controller 5.0. Use files instead.
1259
- * @param id The state ID.
1260
- */
1261
- getBinaryState(id: string): Promise<string> {
1262
- if (!this.connected) {
1263
- return Promise.reject(new Error(NOT_CONNECTED));
1264
- }
1265
-
1266
- // the data will come in base64
1267
- return new Promise((resolve, reject) => {
1268
- this._socket.emit('getBinaryState', id, (err: string | null, base64: string) =>
1269
- err ? reject(new Error(err)) : resolve(base64),
1270
- );
1271
- });
1272
- }
1273
-
1274
- /**
1275
- * Set the given binary state.
1276
- *
1277
- * @deprecated since js-controller 5.0. Use files instead.
1278
- * @param id The state ID.
1279
- * @param base64 The Base64 encoded binary data.
1280
- */
1281
- setBinaryState(id: string, base64: string): Promise<void> {
1282
- if (!this.connected) {
1283
- return Promise.reject(new Error(NOT_CONNECTED));
1284
- }
1285
-
1286
- // the data will come in base64
1287
- return new Promise((resolve, reject) => {
1288
- this._socket.emit('setBinaryState', id, base64, (err: string | null) =>
1289
- err ? reject(new Error(err)) : resolve(),
1290
- );
1291
- });
1292
- }
1293
-
1294
- /**
1295
- * Sets the given state value.
1296
- *
1297
- * @param id The state ID
1298
- * @param val The state value
1299
- * @param ack The acknowledgment flag
1300
- */
1301
- setState(id: string, val: string | number | boolean | ioBroker.SettableState | null, ack?: boolean): Promise<void> {
1302
- if (!this.connected) {
1303
- return Promise.reject(new Error(NOT_CONNECTED));
1304
- }
1305
-
1306
- // extra handling for "nothing_selected" state for vis
1307
- if (id && id === this.ignoreState) {
1308
- let state: ioBroker.State;
1309
- if (typeof ack === 'boolean') {
1310
- state = val as ioBroker.State;
1311
- } else if (typeof val === 'object' && (val as ioBroker.State).val !== undefined) {
1312
- state = val as ioBroker.State;
1313
- } else {
1314
- state = {
1315
- val: val as string | number | boolean | null,
1316
- ack: false,
1317
- ts: Date.now(),
1318
- lc: Date.now(),
1319
- from: 'system.adapter.vis.0',
1320
- };
1321
- }
1322
-
1323
- this.simStates[id] = state;
1324
-
1325
- // inform subscribers about changes
1326
- if (this.statesSubscribes[id]) {
1327
- for (const cb of this.statesSubscribes[id].cbs) {
1328
- try {
1329
- void (cb as ioBroker.StateChangeHandler)(id, state);
1330
- } catch (e) {
1331
- console.error(`Error by callback of stateChanged: ${e}`);
1332
- }
1333
- }
1334
- }
1335
-
1336
- return Promise.resolve();
1337
- }
1338
-
1339
- return new Promise((resolve, reject) => {
1340
- this._socket.emit('setState', id, val, (err: string | null) => (err ? reject(new Error(err)) : resolve()));
1341
- });
1342
- }
1343
-
1344
- /**
1345
- * Gets all objects.
1346
- *
1347
- * @param update Set to true to retrieve all objects from the server (instead of using the local cache)
1348
- * @param disableProgressUpdate Don't call onProgress() when done
1349
- */
1350
- getObjects(update?: boolean, disableProgressUpdate?: boolean): Promise<Record<string, ioBroker.Object>> {
1351
- if (!this.connected) {
1352
- return Promise.reject(new Error(NOT_CONNECTED));
1353
- }
1354
- return new Promise((resolve, reject) => {
1355
- if (!update && this.objects) {
1356
- resolve(this.objects);
1357
- } else {
1358
- this._socket.emit(
1359
- Connection.isWeb() ? 'getObjects' : 'getAllObjects',
1360
- (err: string | null, res: Record<string, ioBroker.Object>) => {
1361
- this.objects = res;
1362
- disableProgressUpdate && this.onProgress(PROGRESS.OBJECTS_LOADED);
1363
- err ? reject(new Error(err)) : resolve(this.objects);
1364
- },
1365
- );
1366
- }
1367
- });
1368
- }
1369
-
1370
- /**
1371
- * Gets objects by list of IDs.
1372
- *
1373
- * @param list Array of object IDs to retrieve
1374
- */
1375
- getObjectsById(list: string[]): Promise<Record<string, ioBroker.Object>> {
1376
- if (!this.connected) {
1377
- return Promise.reject(new Error(NOT_CONNECTED));
1378
- }
1379
-
1380
- return new Promise((resolve, reject) => {
1381
- this._socket.emit('getObjects', list, (err: string | null, res: Record<string, ioBroker.Object>) =>
1382
- err ? reject(new Error(err)) : resolve(res),
1383
- );
1384
- });
1385
- }
1386
-
1387
- /**
1388
- * Called internally.
1389
- */
1390
- private _subscribe(isEnable: boolean): void {
1391
- if (isEnable && !this.subscribed) {
1392
- this.subscribed = true;
1393
- this.autoSubscribes.forEach(id => this._socket.emit('subscribeObjects', id));
1394
- // re-subscribe objects
1395
- Object.keys(this.objectsSubscribes).forEach(id => this._socket.emit('subscribeObjects', id));
1396
- // re-subscribe logs
1397
- this.autoSubscribeLog && this._socket.emit('requireLog', true);
1398
- // re-subscribe states
1399
- const ids = Object.keys(this.statesSubscribes);
1400
- ids.forEach(id => this._socket.emit('subscribe', id));
1401
- ids.length &&
1402
- this._socket.emit(
1403
- Connection.isWeb() ? 'getStates' : 'getForeignStates',
1404
- ids,
1405
- (err: string | null, states: Record<string, ioBroker.State>) => {
1406
- err && console.error(`Cannot getForeignStates: ${JSON.stringify(err)}`);
1407
- // inform about states
1408
- states && Object.keys(states).forEach(id => this.stateChange(id, states[id]));
1409
- },
1410
- );
1411
- } else if (!isEnable && this.subscribed) {
1412
- this.subscribed = false;
1413
- // un-subscribe objects
1414
- this.autoSubscribes.forEach(id => this._socket.emit('unsubscribeObjects', id));
1415
- Object.keys(this.objectsSubscribes).forEach(id => this._socket.emit('unsubscribeObjects', id));
1416
- // un-subscribe logs
1417
- this.autoSubscribeLog && this._socket.emit('requireLog', false);
1418
-
1419
- // un-subscribe states
1420
- Object.keys(this.statesSubscribes).forEach(id => this._socket.emit('unsubscribe', id));
1421
- }
1422
- }
1423
-
1424
- /**
1425
- * Requests log updates.
1426
- *
1427
- * @param isEnabled Set to true to get logs
1428
- */
1429
- requireLog(isEnabled: boolean): Promise<void> {
1430
- if (!this.connected) {
1431
- return Promise.reject(new Error(NOT_CONNECTED));
1432
- }
1433
- return new Promise((resolve, reject) => {
1434
- this._socket.emit('requireLog', isEnabled, (err: string | null) =>
1435
- err ? reject(new Error(err)) : resolve(),
1436
- );
1437
- });
1438
- }
1439
-
1440
- /**
1441
- * Deletes the given object.
1442
- *
1443
- * @param id The object ID
1444
- * @param maintenance Force deletion of non-conform IDs
1445
- */
1446
- delObject(id: string, maintenance?: boolean): Promise<void> {
1447
- if (!this.connected) {
1448
- return Promise.reject(new Error(NOT_CONNECTED));
1449
- }
1450
- return new Promise((resolve, reject) => {
1451
- this._socket.emit('delObject', id, { maintenance: !!maintenance }, (err: string | null) =>
1452
- err ? reject(new Error(err)) : resolve(),
1453
- );
1454
- });
1455
- }
1456
-
1457
- /**
1458
- * Deletes the given object and all its children.
1459
- *
1460
- * @param id The object ID
1461
- * @param maintenance Force deletion of non-conform IDs
1462
- */
1463
- delObjects(id: string, maintenance?: boolean): Promise<void> {
1464
- if (!this.connected) {
1465
- return Promise.reject(new Error(NOT_CONNECTED));
1466
- }
1467
- return new Promise((resolve, reject) => {
1468
- this._socket.emit('delObjects', id, { maintenance: !!maintenance }, (err: string | null) =>
1469
- err ? reject(new Error(err)) : resolve(),
1470
- );
1471
- });
1472
- }
1473
-
1474
- /**
1475
- * Sets the object.
1476
- */
1477
- setObject(id: string, obj: ioBroker.SettableObject): Promise<void> {
1478
- if (!this.connected) {
1479
- return Promise.reject(new Error(NOT_CONNECTED));
1480
- }
1481
-
1482
- if (!obj) {
1483
- return Promise.reject(new Error('Null object is not allowed'));
1484
- }
1485
-
1486
- obj = JSON.parse(JSON.stringify(obj));
1487
-
1488
- if (Object.prototype.hasOwnProperty.call(obj, 'from')) {
1489
- delete obj.from;
1490
- }
1491
- if (Object.prototype.hasOwnProperty.call(obj, 'user')) {
1492
- delete obj.user;
1493
- }
1494
- if (Object.prototype.hasOwnProperty.call(obj, 'ts')) {
1495
- delete obj.ts;
1496
- }
1497
-
1498
- return new Promise((resolve, reject) => {
1499
- this._socket.emit('setObject', id, obj, (err: string | null) => (err ? reject(new Error(err)) : resolve()));
1500
- });
1501
- }
1502
-
1503
- /**
1504
- * Gets the object with the given id from the server.
1505
- */
1506
- getObject(id: string): Promise<ioBroker.Object> {
1507
- if (!this.connected) {
1508
- return Promise.reject(new Error(NOT_CONNECTED));
1509
- }
1510
- if (id && id === this.ignoreState) {
1511
- return Promise.resolve({
1512
- _id: this.ignoreState,
1513
- type: 'state',
1514
- common: {
1515
- name: 'ignored state',
1516
- type: 'mixed',
1517
- read: true,
1518
- write: true,
1519
- role: 'state',
1520
- },
1521
- native: {},
1522
- });
1523
- }
1524
-
1525
- return new Promise((resolve, reject) => {
1526
- this._socket.emit('getObject', id, (err: string | null, obj: ioBroker.Object) =>
1527
- err ? reject(new Error(err)) : resolve(obj),
1528
- );
1529
- });
1530
- }
1531
-
1532
- /**
1533
- * Get all instances of the given adapter or all instances of all adapters.
1534
- *
1535
- * @param adapter The name of the adapter
1536
- * @param update Force update
1537
- */
1538
- getAdapterInstances(adapter?: string | boolean, update?: boolean): Promise<ioBroker.InstanceObject[]> {
1539
- if (typeof adapter === 'boolean') {
1540
- update = adapter;
1541
- adapter = '';
1542
- }
1543
- adapter = adapter || '';
1544
-
1545
- if (!update && this._promises[`instances_${adapter}`]) {
1546
- return this._promises[`instances_${adapter}`] as Promise<ioBroker.InstanceObject[]>;
1547
- }
1548
-
1549
- if (!this.connected) {
1550
- return Promise.reject(new Error(NOT_CONNECTED));
1551
- }
1552
-
1553
- this._promises[`instances_${adapter}`] = new Promise((resolve, reject) => {
1554
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
1555
- timeout = null;
1556
- this.getObjectView(
1557
- `system.adapter.${adapter ? `${adapter}.` : ''}`,
1558
- `system.adapter.${adapter ? `${adapter}.` : ''}\u9999`,
1559
- 'instance',
1560
- )
1561
- .then(items =>
1562
- resolve(Object.keys(items).map(id => fixAdminUI(items[id] as ioBroker.AdapterObject))),
1563
- )
1564
- .catch(e => reject(new Error(e)));
1565
- }, TIMEOUT_FOR_ADMIN4);
1566
-
1567
- this._socket.emit(
1568
- 'getAdapterInstances',
1569
- adapter,
1570
- (err: string | null, instances: ioBroker.InstanceObject[]) => {
1571
- if (timeout) {
1572
- clearTimeout(timeout);
1573
- timeout = null;
1574
- err ? reject(new Error(err)) : resolve(instances);
1575
- }
1576
- },
1577
- );
1578
- });
1579
-
1580
- return this._promises[`instances_${adapter}`] as Promise<ioBroker.InstanceObject[]>;
1581
- }
1582
-
1583
- /**
1584
- * Get adapters with the given name or all adapters.
1585
- *
1586
- * @param adapter The name of the adapter
1587
- * @param update Force update
1588
- */
1589
- getAdapters(adapter?: string | boolean, update?: boolean): Promise<ioBroker.AdapterObject[]> {
1590
- if (Connection.isWeb()) {
1591
- return Promise.reject(new Error('Allowed only in admin'));
1592
- }
1593
-
1594
- if (typeof adapter === 'boolean') {
1595
- update = adapter;
1596
- adapter = '';
1597
- }
1598
-
1599
- adapter = adapter || '';
1600
-
1601
- if (!update && this._promises[`adapter_${adapter}`]) {
1602
- return this._promises[`adapter_${adapter}`] as Promise<ioBroker.AdapterObject[]>;
1603
- }
1604
-
1605
- if (!this.connected) {
1606
- return Promise.reject(new Error(NOT_CONNECTED));
1607
- }
1608
-
1609
- this._promises[`adapter_${adapter}`] = new Promise((resolve, reject) => {
1610
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
1611
- timeout = null;
1612
- this.getObjectView(`system.adapter.${adapter}.`, `system.adapter.${adapter}.\u9999`, 'adapter')
1613
- .then(items => {
1614
- resolve(Object.keys(items).map(id => fixAdminUI(items[id] as ioBroker.AdapterObject)));
1615
- })
1616
- .catch(e => reject(new Error(e)));
1617
- }, TIMEOUT_FOR_ADMIN4);
1618
-
1619
- this._socket.emit('getAdapters', adapter, (err: string | null, adapters: ioBroker.AdapterObject[]) => {
1620
- if (timeout) {
1621
- clearTimeout(timeout);
1622
- timeout = null;
1623
- err ? reject(new Error(err)) : resolve(adapters);
1624
- }
1625
- });
1626
- });
1627
-
1628
- return this._promises[`adapter_${adapter}`] as Promise<ioBroker.AdapterObject[]>;
1629
- }
1630
-
1631
- /**
1632
- * Called internally.
1633
- */
1634
- private _renameGroups(objs: RenameGroupObject[], cb: (err: string | null) => void): void {
1635
- if (!objs || !objs.length) {
1636
- cb && cb(null);
1637
- } else {
1638
- const obj = objs.pop();
1639
- if (!obj) {
1640
- setTimeout(() => this._renameGroups(objs, cb), 0);
1641
- return;
1642
- }
1643
- const oldId = obj._id;
1644
- obj._id = obj.newId as ioBroker.ObjectIDs.Group;
1645
- delete obj.newId;
1646
-
1647
- this.setObject(obj._id, obj)
1648
- .then(() => this.delObject(oldId))
1649
- .then(() => setTimeout(() => this._renameGroups(objs, cb), 0))
1650
- .catch((err: string | null) => cb && cb(err));
1651
- }
1652
- }
1653
-
1654
- /**
1655
- * Rename a group.
1656
- *
1657
- * @param id The id.
1658
- * @param newId The new id.
1659
- * @param newName The new name.
1660
- */
1661
- async renameGroup(id: string, newId: string, newName: ioBroker.StringOrTranslated): Promise<void> {
1662
- if (Connection.isWeb()) {
1663
- return Promise.reject(new Error('Allowed only in admin'));
1664
- }
1665
-
1666
- const groups = await this.getGroups(true);
1667
- if (groups.length) {
1668
- // find all elements
1669
- const groupsToRename: RenameGroupObject[] = (groups as RenameGroupObject[]).filter(group =>
1670
- group._id.startsWith(`${id}.`),
1671
- );
1672
-
1673
- groupsToRename.forEach(group => {
1674
- group.newId = (newId + group._id.substring(id.length)) as ioBroker.ObjectIDs.Group;
1675
- });
1676
-
1677
- await new Promise((resolve, reject) => {
1678
- this._renameGroups(groupsToRename, (err: string | null) =>
1679
- err ? reject(new Error(err)) : resolve(null),
1680
- );
1681
- });
1682
- const obj = groups.find(group => group._id === id);
1683
-
1684
- if (obj) {
1685
- obj._id = newId as ioBroker.ObjectIDs.Group;
1686
- if (newName !== undefined) {
1687
- obj.common = obj.common || ({} as ioBroker.GroupCommon);
1688
- // @ts-expect-error will be corrected in the next js-controller release
1689
- obj.common.name = newName;
1690
- }
1691
-
1692
- return this.setObject(obj._id, obj).then(() => this.delObject(id));
1693
- }
1694
- }
1695
-
1696
- return Promise.resolve();
1697
- }
1698
-
1699
- /**
1700
- * Sends a message to a specific instance or all instances of some specific adapter.
1701
- *
1702
- * @param instance The instance to send this message to.
1703
- * @param command Command name of the target instance.
1704
- * @param data The message data to send.
1705
- */
1706
- sendTo(instance: string, command: string, data: any): Promise<{ result?: any; error?: string }> {
1707
- if (!this.connected) {
1708
- return Promise.reject(new Error(NOT_CONNECTED));
1709
- }
1710
- return new Promise(resolve => {
1711
- this._socket.emit('sendTo', instance, command, data, (result: { result?: any; error?: string }) =>
1712
- resolve(result),
1713
- );
1714
- });
1715
- }
1716
-
1717
- /**
1718
- * Extend an object and create it if it might not exist.
1719
- *
1720
- * @param id The id.
1721
- * @param obj The object.
1722
- */
1723
- extendObject(id: string, obj: ioBroker.PartialObject): Promise<void> {
1724
- if (!this.connected) {
1725
- return Promise.reject(new Error(NOT_CONNECTED));
1726
- }
1727
-
1728
- obj = JSON.parse(JSON.stringify(obj));
1729
-
1730
- if (Object.prototype.hasOwnProperty.call(obj, 'from')) {
1731
- delete obj.from;
1732
- }
1733
- if (Object.prototype.hasOwnProperty.call(obj, 'user')) {
1734
- delete obj.user;
1735
- }
1736
- if (Object.prototype.hasOwnProperty.call(obj, 'ts')) {
1737
- delete obj.ts;
1738
- }
1739
-
1740
- return new Promise((resolve, reject) => {
1741
- this._socket.emit('extendObject', id, obj, (err: string | null) =>
1742
- err ? reject(new Error(err)) : resolve(),
1743
- );
1744
- });
1745
- }
1746
-
1747
- /**
1748
- * Register a handler for log messages.
1749
- */
1750
- registerLogHandler(handler: (message: string) => void): void {
1751
- !this.onLogHandlers.includes(handler) && this.onLogHandlers.push(handler);
1752
- }
1753
-
1754
- /**
1755
- * Unregister a handler for log messages.
1756
- */
1757
- unregisterLogHandler(handler: (message: string) => void): void {
1758
- const pos = this.onLogHandlers.indexOf(handler);
1759
- pos !== -1 && this.onLogHandlers.splice(pos, 1);
1760
- }
1761
-
1762
- /**
1763
- * Register a handler for the connection state.
1764
- */
1765
- registerConnectionHandler(handler: (connected: boolean) => void): void {
1766
- !this.onConnectionHandlers.includes(handler) && this.onConnectionHandlers.push(handler);
1767
- }
1768
-
1769
- /**
1770
- * Unregister a handler for the connection state.
1771
- */
1772
- unregisterConnectionHandler(handler: (connected: boolean) => void): void {
1773
- const pos = this.onConnectionHandlers.indexOf(handler);
1774
- pos !== -1 && this.onConnectionHandlers.splice(pos, 1);
1775
- }
1776
-
1777
- /**
1778
- * Set the handler for standard output of a command.
1779
- *
1780
- * @param handler The handler.
1781
- */
1782
- registerCmdStdoutHandler(handler: (id: string, text: string) => void): void {
1783
- this.onCmdStdoutHandler = handler;
1784
- }
1785
-
1786
- /**
1787
- * Unset the handler for standard output of a command.
1788
- */
1789
- unregisterCmdStdoutHandler(/* handler */): void {
1790
- this.onCmdStdoutHandler = undefined;
1791
- }
1792
-
1793
- /**
1794
- * Set the handler for standard error of a command.
1795
- *
1796
- * @param handler The handler.
1797
- */
1798
- registerCmdStderrHandler(handler: (id: string, text: string) => void): void {
1799
- this.onCmdStderrHandler = handler;
1800
- }
1801
-
1802
- /**
1803
- * Unset the handler for standard error of a command.
1804
- */
1805
- unregisterCmdStderrHandler(): void {
1806
- this.onCmdStderrHandler = undefined;
1807
- }
1808
-
1809
- /**
1810
- * Set the handler for exit of a command.
1811
- */
1812
- registerCmdExitHandler(handler: (id: string, exitCode: number) => void): void {
1813
- this.onCmdExitHandler = handler;
1814
- }
1815
-
1816
- /**
1817
- * Unset the handler for exit of a command.
1818
- */
1819
- unregisterCmdExitHandler(): void {
1820
- this.onCmdExitHandler = undefined;
1821
- }
1822
-
1823
- /**
1824
- * Get all enums with the given name.
1825
- */
1826
- getEnums(
1827
- /** The name of the enum. */
1828
- _enum?: string,
1829
- /** Force update. */
1830
- update?: boolean,
1831
- ): Promise<Record<string, ioBroker.EnumObject>> {
1832
- if (!update && this._promises[`enums_${_enum || 'all'}`]) {
1833
- return this._promises[`enums_${_enum || 'all'}`] as Promise<Record<string, ioBroker.EnumObject>>;
1834
- }
1835
-
1836
- if (!this.connected) {
1837
- return Promise.reject(new Error(NOT_CONNECTED));
1838
- }
1839
-
1840
- this._promises[`enums_${_enum || 'all'}`] = new Promise((resolve, reject) => {
1841
- this._socket.emit(
1842
- 'getObjectView',
1843
- 'system',
1844
- 'enum',
1845
- { startkey: `enum.${_enum || ''}`, endkey: `enum.${_enum ? `${_enum}.` : ''}\u9999` },
1846
- (err: string | null, res: { rows: { value: ioBroker.EnumObject; id: string }[] }) => {
1847
- if (!err && res) {
1848
- const _res: Record<string, ioBroker.EnumObject> = {};
1849
- for (let i = 0; i < res.rows.length; i++) {
1850
- if (_enum && res.rows[i].id === `enum.${_enum}`) {
1851
- continue;
1852
- }
1853
- _res[res.rows[i].id] = res.rows[i].value;
1854
- }
1855
- resolve(_res);
1856
- } else if (err) {
1857
- reject(new Error(err));
1858
- } else {
1859
- reject(new Error('Invalid response while getting enums'));
1860
- }
1861
- },
1862
- );
1863
- });
1864
-
1865
- return this._promises[`enums_${_enum || 'all'}`] as Promise<Record<string, ioBroker.EnumObject>>;
1866
- }
1867
-
1868
- /**
1869
- * Query a predefined object view.
1870
- *
1871
- * @param design design - 'system' or other designs like `custom`.
1872
- * @param type The type of object.
1873
- * @param start The start ID.
1874
- * @param end The end ID.
1875
- */
1876
- getObjectViewCustom(
1877
- /** The design: 'system' or other designs like `custom`. */
1878
- design: string,
1879
- /** The type of object. */
1880
- type: ioBroker.ObjectType,
1881
- /** The start ID. */
1882
- start: string,
1883
- /** The end ID. */
1884
- end?: string,
1885
- ): Promise<Record<string, ioBroker.Object>> {
1886
- return new Promise((resolve, reject) => {
1887
- this._socket.emit(
1888
- 'getObjectView',
1889
- design,
1890
- type,
1891
- { startkey: start, endkey: end },
1892
- (err: string | null, res: { rows: { value: ioBroker.Object; id: string }[] }) => {
1893
- if (!err) {
1894
- const _res: Record<string, ioBroker.Object> = {};
1895
- if (res && res.rows) {
1896
- for (let i = 0; i < res.rows.length; i++) {
1897
- _res[res.rows[i].id] = res.rows[i].value;
1898
- }
1899
- }
1900
- resolve(_res);
1901
- } else {
1902
- reject(new Error(err));
1903
- }
1904
- },
1905
- );
1906
- });
1907
- }
1908
-
1909
- /**
1910
- * Query a predefined object view.
1911
- *
1912
- * @param type The type of object.
1913
- * @param start The start ID.
1914
- * @param end The end ID.
1915
- */
1916
- getObjectViewSystem(
1917
- type: ioBroker.ObjectType,
1918
- start: string,
1919
- end?: string,
1920
- ): Promise<Record<string, ioBroker.Object>> {
1921
- return this.getObjectViewCustom('system', type, start, end);
1922
- }
1923
-
1924
- /**
1925
- * @deprecated since version 1.1.15, cause parameter order does not match backend
1926
- *
1927
- * Query a predefined object view.
1928
- * @param start The start ID.
1929
- * @param end The end ID.
1930
- * @param type The type of object.
1931
- */
1932
- getObjectView(start: string, end: string, type: ioBroker.ObjectType): Promise<Record<string, ioBroker.Object>> {
1933
- if (!this.connected) {
1934
- return Promise.reject(new Error(NOT_CONNECTED));
1935
- }
1936
-
1937
- start = start || '';
1938
- end = end || '\u9999';
1939
- return this.getObjectViewCustom('system', type, start, end);
1940
- }
1941
-
1942
- /**
1943
- * Get the stored certificates.
1944
- *
1945
- * @param update Force update.
1946
- */
1947
- getCertificates(update?: boolean): Promise<{ name: string; type: 'public' | 'private' | 'chained' | '' }[]> {
1948
- if (Connection.isWeb()) {
1949
- return Promise.reject(new Error('Allowed only in admin'));
1950
- }
1951
-
1952
- if (this._promises.cert && !update) {
1953
- return this._promises.cert;
1954
- }
1955
-
1956
- if (!this.connected) {
1957
- return Promise.reject(new Error(NOT_CONNECTED));
1958
- }
1959
-
1960
- this._promises.cert = this.getObject('system.certificates').then(res => {
1961
- const certs: { name: string; type: 'public' | 'private' | 'chained' | '' }[] = [];
1962
- if (res && res.native && res.native.certificates) {
1963
- Object.keys(res.native.certificates).forEach(c => {
1964
- const cert: string = res.native.certificates[c];
1965
- if (!cert) {
1966
- return;
1967
- }
1968
- const _cert: { name: string; type: 'public' | 'private' | 'chained' | '' } = {
1969
- name: c,
1970
- type: '',
1971
- };
1972
- // If it is a filename, it could be everything
1973
- if (cert.length < 700 && (cert.includes('/') || cert.includes('\\'))) {
1974
- if (c.toLowerCase().includes('private')) {
1975
- _cert.type = 'private';
1976
- } else if (cert.toLowerCase().includes('private')) {
1977
- _cert.type = 'private';
1978
- } else if (c.toLowerCase().includes('public')) {
1979
- _cert.type = 'public';
1980
- } else if (cert.toLowerCase().includes('public')) {
1981
- _cert.type = 'public';
1982
- }
1983
- certs.push(_cert);
1984
- } else {
1985
- _cert.type =
1986
- cert.substring(0, '-----BEGIN RSA PRIVATE KEY'.length) === '-----BEGIN RSA PRIVATE KEY' ||
1987
- cert.substring(0, '-----BEGIN PRIVATE KEY'.length) === '-----BEGIN PRIVATE KEY'
1988
- ? 'private'
1989
- : 'public';
1990
-
1991
- if (_cert.type === 'public') {
1992
- const m = cert.split('-----END CERTIFICATE-----');
1993
- if (m.filter((t: string) => t.replace(/\r\n|\r|\n/, '').trim()).length > 1) {
1994
- _cert.type = 'chained';
1995
- }
1996
- }
1997
-
1998
- certs.push(_cert);
1999
- }
2000
- });
2001
- }
2002
- return certs;
2003
- });
2004
-
2005
- return this._promises.cert;
2006
- }
2007
-
2008
- /**
2009
- * Get the logs from a host (only for admin connection).
2010
- */
2011
- getLogs(host: string, linesNumber?: number): Promise<string[]> {
2012
- if (Connection.isWeb()) {
2013
- return Promise.reject(new Error('Allowed only in admin'));
2014
- }
2015
-
2016
- if (!this.connected) {
2017
- return Promise.reject(new Error(NOT_CONNECTED));
2018
- }
2019
-
2020
- return new Promise(resolve => {
2021
- this._socket.emit('sendToHost', host, 'getLogs', linesNumber || 200, (lines: string[]) => resolve(lines));
2022
- });
2023
- }
2024
-
2025
- /**
2026
- * Get the log files (only for admin connection).
2027
- */
2028
- getLogsFiles(host: string): Promise<string[]> {
2029
- if (Connection.isWeb()) {
2030
- return Promise.reject(new Error('Allowed only in admin'));
2031
- }
2032
- if (!this.connected) {
2033
- return Promise.reject(new Error(NOT_CONNECTED));
2034
- }
2035
- return new Promise((resolve, reject) => {
2036
- this._socket.emit('readLogs', host, (err: string | null, files: string[]) =>
2037
- err ? reject(new Error(err)) : resolve(files),
2038
- );
2039
- });
2040
- }
2041
-
2042
- /**
2043
- * Delete the logs from a host (only for admin connection).
2044
- */
2045
- delLogs(host: string): Promise<void> {
2046
- if (Connection.isWeb()) {
2047
- return Promise.reject(new Error('Allowed only in admin'));
2048
- }
2049
- if (!this.connected) {
2050
- return Promise.reject(new Error(NOT_CONNECTED));
2051
- }
2052
- return new Promise((resolve, reject) => {
2053
- this._socket.emit('sendToHost', host, 'delLogs', null, (error: string | null) =>
2054
- error ? reject(new Error(error)) : resolve(),
2055
- );
2056
- });
2057
- }
2058
-
2059
- /**
2060
- * Read the meta items.
2061
- */
2062
- readMetaItems(): Promise<ioBroker.MetaObject[]> {
2063
- if (!this.connected) {
2064
- return Promise.reject(new Error(NOT_CONNECTED));
2065
- }
2066
- return new Promise((resolve, reject) => {
2067
- this._socket.emit(
2068
- 'getObjectView',
2069
- 'system',
2070
- 'meta',
2071
- { startkey: '', endkey: '\u9999' },
2072
- (err: string | null, objs: { rows: { value: ioBroker.MetaObject; id: string }[] }) =>
2073
- err
2074
- ? reject(new Error(err))
2075
- : resolve(
2076
- objs.rows &&
2077
- objs.rows.map((obj: { value: ioBroker.MetaObject; id: string }) => obj.value),
2078
- ),
2079
- );
2080
- });
2081
- }
2082
-
2083
- /**
2084
- * Read the directory of an adapter.
2085
- *
2086
- * @param adapter The adapter name.
2087
- * @param fileName The directory name.
2088
- */
2089
- readDir(adapter: string, fileName: string): Promise<ioBroker.ReadDirResult[]> {
2090
- if (!this.connected) {
2091
- return Promise.reject(new Error(NOT_CONNECTED));
2092
- }
2093
- return new Promise((resolve, reject) => {
2094
- this._socket.emit('readDir', adapter, fileName, (err: string | null, files: ioBroker.ReadDirResult[]) =>
2095
- err ? reject(new Error(err)) : resolve(files),
2096
- );
2097
- });
2098
- }
2099
-
2100
- /**
2101
- * Read a file of an adapter.
2102
- *
2103
- * @param adapter The adapter name.
2104
- * @param fileName The file name.
2105
- * @param base64 If it must be a base64 format.
2106
- */
2107
- readFile(adapter: string, fileName: string, base64?: boolean): Promise<string | { data: string; type: string }> {
2108
- if (!this.connected) {
2109
- return Promise.reject(new Error(NOT_CONNECTED));
2110
- }
2111
- return new Promise((resolve, reject) => {
2112
- if (!base64) {
2113
- this._socket.emit('readFile', adapter, fileName, (err: string | null, data: string, type: string) => {
2114
- err ? reject(new Error(err)) : resolve({ data, type });
2115
- });
2116
- } else {
2117
- this._socket.emit('readFile64', adapter, fileName, base64, (err: string | null, data: string) =>
2118
- err ? reject(new Error(err)) : resolve(data),
2119
- );
2120
- }
2121
- });
2122
- }
2123
-
2124
- /**
2125
- * Write a file of an adapter.
2126
- *
2127
- * @param adapter The adapter name.
2128
- * @param fileName The file name.
2129
- * @param data The data (if it's a Buffer, it will be converted to Base64)
2130
- */
2131
- writeFile64(adapter: string, fileName: string, data: Buffer | string): Promise<void> {
2132
- if (!this.connected) {
2133
- return Promise.reject(new Error(NOT_CONNECTED));
2134
- }
2135
- return new Promise((resolve, reject) => {
2136
- if (typeof data === 'string') {
2137
- this._socket.emit('writeFile', adapter, fileName, data, (err: string | null) =>
2138
- err ? reject(new Error(err)) : resolve(),
2139
- );
2140
- } else {
2141
- const base64 = btoa(
2142
- new Uint8Array(data).reduce((_data, byte) => _data + String.fromCharCode(byte), ''),
2143
- );
2144
-
2145
- this._socket.emit('writeFile64', adapter, fileName, base64, (err: string | null) =>
2146
- err ? reject(new Error(err)) : resolve(),
2147
- );
2148
- }
2149
- });
2150
- }
2151
-
2152
- /**
2153
- * Delete a file of an adapter.
2154
- *
2155
- * @param adapter The adapter name.
2156
- * @param fileName The file name.
2157
- */
2158
- deleteFile(adapter: string, fileName: string): Promise<void> {
2159
- if (!this.connected) {
2160
- return Promise.reject(new Error(NOT_CONNECTED));
2161
- }
2162
- return new Promise((resolve, reject) => {
2163
- this._socket.emit('unlink', adapter, fileName, (err: string | null) =>
2164
- err ? reject(new Error(err)) : resolve(),
2165
- );
2166
- });
2167
- }
2168
-
2169
- /**
2170
- * Delete a folder of an adapter.
2171
- * All files in folder will be deleted.
2172
- *
2173
- * @param adapter The adapter name.
2174
- * @param folderName The folder name.
2175
- */
2176
- deleteFolder(adapter: string, folderName: string): Promise<void> {
2177
- if (!this.connected) {
2178
- return Promise.reject(new Error(NOT_CONNECTED));
2179
- }
2180
- return new Promise((resolve, reject) => {
2181
- this._socket.emit('deleteFolder', adapter, folderName, (err: string | null) =>
2182
- err ? reject(new Error(err)) : resolve(),
2183
- );
2184
- });
2185
- }
2186
-
2187
- /**
2188
- * Get the list of all hosts.
2189
- *
2190
- * @param update Force update.
2191
- */
2192
- getHosts(update?: boolean): Promise<ioBroker.HostObject[]> {
2193
- if (Connection.isWeb()) {
2194
- return Promise.reject(new Error('Allowed only in admin'));
2195
- }
2196
- if (!update && this._promises.hosts) {
2197
- return this._promises.hosts;
2198
- }
2199
-
2200
- if (!this.connected) {
2201
- return Promise.reject(new Error(NOT_CONNECTED));
2202
- }
2203
-
2204
- this._promises.hosts = new Promise((resolve, reject) => {
2205
- this._socket.emit(
2206
- 'getObjectView',
2207
- 'system',
2208
- 'host',
2209
- { startkey: 'system.host.', endkey: 'system.host.\u9999' },
2210
- (err: string | null, doc: { rows: { value: ioBroker.HostObject; id: string }[] }) => {
2211
- if (err) {
2212
- reject(new Error(err));
2213
- } else {
2214
- resolve(doc.rows.map(item => item.value));
2215
- }
2216
- },
2217
- );
2218
- });
2219
-
2220
- return this._promises.hosts;
2221
- }
2222
-
2223
- /**
2224
- * Get the list of all users.
2225
- *
2226
- * @param update Force update.
2227
- */
2228
- getUsers(update?: boolean): Promise<ioBroker.UserObject[]> {
2229
- if (Connection.isWeb()) {
2230
- return Promise.reject(new Error('Allowed only in admin'));
2231
- }
2232
- if (!update && this._promises.users) {
2233
- return this._promises.users;
2234
- }
2235
- if (!this.connected) {
2236
- return Promise.reject(new Error(NOT_CONNECTED));
2237
- }
2238
-
2239
- this._promises.users = new Promise((resolve, reject) => {
2240
- this._socket.emit(
2241
- 'getObjectView',
2242
- 'system',
2243
- 'user',
2244
- { startkey: 'system.user.', endkey: 'system.user.\u9999' },
2245
- (err: string | null, doc: { rows: { value: ioBroker.UserObject; id: string }[] }) => {
2246
- if (err) {
2247
- reject(new Error(err));
2248
- } else {
2249
- resolve(doc.rows.map(item => item.value));
2250
- }
2251
- },
2252
- );
2253
- });
2254
-
2255
- return this._promises.users;
2256
- }
2257
-
2258
- /**
2259
- * Get the list of all groups.
2260
- *
2261
- * @param update Force update.
2262
- */
2263
- getGroups(update?: boolean): Promise<ioBroker.GroupObject[]> {
2264
- if (!update && this._promises.groups) {
2265
- return this._promises.groups;
2266
- }
2267
- if (!this.connected) {
2268
- return Promise.reject(new Error(NOT_CONNECTED));
2269
- }
2270
-
2271
- this._promises.groups = new Promise((resolve, reject) => {
2272
- this._socket.emit(
2273
- 'getObjectView',
2274
- 'system',
2275
- 'group',
2276
- { startkey: 'system.group.', endkey: 'system.group.\u9999' },
2277
- (err: string | null, doc: { rows: { value: ioBroker.GroupObject; id: string }[] }) => {
2278
- if (err) {
2279
- reject(new Error(err));
2280
- } else {
2281
- resolve(doc.rows.map(item => item.value));
2282
- }
2283
- },
2284
- );
2285
- });
2286
-
2287
- return this._promises.groups;
2288
- }
2289
-
2290
- /**
2291
- * Get the host information.
2292
- *
2293
- * @param host The host name.
2294
- * @param update Force update.
2295
- * @param timeoutMs Optional read timeout.
2296
- */
2297
- getHostInfo(host: string, update?: boolean, timeoutMs?: number): Promise<HostInfo> {
2298
- if (Connection.isWeb()) {
2299
- return Promise.reject(new Error('Allowed only in admin'));
2300
- }
2301
- if (!host.startsWith('system.host.')) {
2302
- host += `system.host.${host}`;
2303
- }
2304
-
2305
- if (!update && this._promises[`hostInfo_${host}`]) {
2306
- return this._promises[`hostInfo_${host}`] as Promise<HostInfo>;
2307
- }
2308
-
2309
- if (!this.connected) {
2310
- return Promise.reject(new Error(NOT_CONNECTED));
2311
- }
2312
-
2313
- this._promises[`hostInfo_${host}`] = new Promise((resolve, reject) => {
2314
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
2315
- if (timeout) {
2316
- timeout = null;
2317
- reject(new Error('getHostInfo timeout'));
2318
- }
2319
- }, timeoutMs || this.props.cmdTimeout);
2320
-
2321
- this._socket.emit('sendToHost', host, 'getHostInfo', null, (data: string | HostInfo) => {
2322
- if (timeout) {
2323
- clearTimeout(timeout);
2324
- timeout = null;
2325
- if (data === PERMISSION_ERROR) {
2326
- reject(new Error('May not read "getHostInfo"'));
2327
- } else if (!data || typeof data !== 'object') {
2328
- reject(new Error('Cannot read "getHostInfo"'));
2329
- } else {
2330
- resolve(data);
2331
- }
2332
- }
2333
- });
2334
- });
2335
-
2336
- return this._promises[`hostInfo_${host}`] as Promise<HostInfo>;
2337
- }
2338
-
2339
- /**
2340
- * Get the host information (short version).
2341
- *
2342
- * @param host The host name.
2343
- * @param update Force update.
2344
- * @param timeoutMs Optional read timeout.
2345
- */
2346
- getHostInfoShort(host: string, update?: boolean, timeoutMs?: number): Promise<HostInfo> {
2347
- if (Connection.isWeb()) {
2348
- return Promise.reject(new Error('Allowed only in admin'));
2349
- }
2350
- if (!host.startsWith('system.host.')) {
2351
- host += `system.host.${host}`;
2352
- }
2353
- if (!update && this._promises[`hostInfoShort_${host}`]) {
2354
- return this._promises[`hostInfoShort_${host}`] as Promise<HostInfo>;
2355
- }
2356
-
2357
- if (!this.connected) {
2358
- return Promise.reject(new Error(NOT_CONNECTED));
2359
- }
2360
-
2361
- this._promises[`hostInfoShort_${host}`] = new Promise((resolve, reject) => {
2362
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
2363
- if (timeout) {
2364
- timeout = null;
2365
- reject(new Error('hostInfoShort timeout'));
2366
- }
2367
- }, timeoutMs || this.props.cmdTimeout);
2368
-
2369
- this._socket.emit('sendToHost', host, 'getHostInfoShort', null, (data: string | HostInfo) => {
2370
- if (timeout) {
2371
- clearTimeout(timeout);
2372
- timeout = null;
2373
- if (data === PERMISSION_ERROR) {
2374
- reject(new Error('May not read "getHostInfoShort"'));
2375
- } else if (!data || typeof data !== 'object') {
2376
- reject(new Error('Cannot read "getHostInfoShort"'));
2377
- } else {
2378
- resolve(data);
2379
- }
2380
- }
2381
- });
2382
- });
2383
-
2384
- return this._promises[`hostInfoShort_${host}`] as Promise<HostInfo>;
2385
- }
2386
-
2387
- /**
2388
- * Get the repository.
2389
- *
2390
- * @param host The host name.
2391
- * @param options Options.
2392
- * @param update Force update.
2393
- * @param timeoutMs Timeout in ms.
2394
- */
2395
- getRepository(
2396
- host: string,
2397
- options?: { update: boolean; repo: string } | string,
2398
- update?: boolean,
2399
- timeoutMs?: number,
2400
- ): Promise<Record<string, ioBroker.AdapterObject>> {
2401
- if (Connection.isWeb()) {
2402
- return Promise.reject(new Error('Allowed only in admin'));
2403
- }
2404
- if (!update && this._promises.repo) {
2405
- return this._promises.repo;
2406
- }
2407
-
2408
- if (!this.connected) {
2409
- return Promise.reject(new Error(NOT_CONNECTED));
2410
- }
2411
-
2412
- if (!host.startsWith('system.host.')) {
2413
- host += `system.host.${host}`;
2414
- }
2415
-
2416
- this._promises.repo = new Promise((resolve, reject) => {
2417
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
2418
- if (timeout) {
2419
- timeout = null;
2420
- reject(new Error('getRepository timeout'));
2421
- }
2422
- }, timeoutMs || this.props.cmdTimeout);
2423
-
2424
- this._socket.emit(
2425
- 'sendToHost',
2426
- host,
2427
- 'getRepository',
2428
- options,
2429
- (data: string | Record<string, ioBroker.AdapterObject>) => {
2430
- if (timeout) {
2431
- clearTimeout(timeout);
2432
- timeout = null;
2433
- if (data === PERMISSION_ERROR) {
2434
- reject(new Error('May not read "getRepository"'));
2435
- } else if (!data || typeof data !== 'object') {
2436
- reject(new Error('Cannot read "getRepository"'));
2437
- } else {
2438
- resolve(data);
2439
- }
2440
- }
2441
- },
2442
- );
2443
- });
2444
-
2445
- return this._promises.repo;
2446
- }
2447
-
2448
- /**
2449
- * Get the installed.
2450
- *
2451
- * @param host The host name.
2452
- * @param update Force update.
2453
- * @param cmdTimeout Timeout in ms.
2454
- */
2455
- getInstalled(host: string, update?: boolean, cmdTimeout?: number): Promise<Record<string, ioBroker.AdapterObject>> {
2456
- if (Connection.isWeb()) {
2457
- return Promise.reject(new Error('Allowed only in admin'));
2458
- }
2459
-
2460
- this._promises.installed = this._promises.installed || {};
2461
-
2462
- if (!update && this._promises.installed[host]) {
2463
- return this._promises.installed[host] as Promise<Record<string, ioBroker.AdapterObject>>;
2464
- }
2465
-
2466
- if (!this.connected) {
2467
- return Promise.reject(new Error(NOT_CONNECTED));
2468
- }
2469
-
2470
- if (!host.startsWith('system.host.')) {
2471
- host += `system.host.${host}`;
2472
- }
2473
-
2474
- this._promises.installed[host] = new Promise((resolve, reject) => {
2475
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
2476
- if (timeout) {
2477
- timeout = null;
2478
- reject(new Error('getInstalled timeout'));
2479
- }
2480
- }, cmdTimeout || this.props.cmdTimeout);
2481
-
2482
- this._socket.emit(
2483
- 'sendToHost',
2484
- host,
2485
- 'getInstalled',
2486
- null,
2487
- (data: string | Record<string, ioBroker.AdapterObject>) => {
2488
- if (timeout) {
2489
- clearTimeout(timeout);
2490
- timeout = null;
2491
- if (data === PERMISSION_ERROR) {
2492
- reject(new Error('May not read "getInstalled"'));
2493
- } else if (!data || typeof data !== 'object') {
2494
- reject(new Error('Cannot read "getInstalled"'));
2495
- } else {
2496
- resolve(data);
2497
- }
2498
- }
2499
- },
2500
- );
2501
- });
2502
-
2503
- return this._promises.installed[host] as Promise<Record<string, ioBroker.AdapterObject>>;
2504
- }
2505
-
2506
- /**
2507
- * Rename file or folder in ioBroker DB
2508
- *
2509
- * @param adapter Instance name, like `vis-2.0`.
2510
- * @param oldName The current file name, e.g., main/vis-views.json
2511
- * @param newName The new file name, e.g., main/vis-views-new.json
2512
- */
2513
- rename(adapter: string, oldName: string, newName: string): Promise<void> {
2514
- if (!this.connected) {
2515
- return Promise.reject(new Error(NOT_CONNECTED));
2516
- }
2517
- return new Promise((resolve, reject) => {
2518
- this._socket.emit('rename', adapter, oldName, newName, (err: string | null) =>
2519
- err ? reject(new Error(err)) : resolve(),
2520
- );
2521
- });
2522
- }
2523
-
2524
- /**
2525
- * Rename file in ioBroker DB
2526
- */
2527
- renameFile(
2528
- /** instance name */
2529
- adapter: string,
2530
- /** current file name, e.g., main/vis-views.json */
2531
- oldName: string,
2532
- /** new file name, e.g., main/vis-views-new.json */
2533
- newName: string,
2534
- ): Promise<void> {
2535
- if (!this.connected) {
2536
- return Promise.reject(new Error(NOT_CONNECTED));
2537
- }
2538
- return new Promise((resolve, reject) => {
2539
- this._socket.emit('renameFile', adapter, oldName, newName, (err: string | null) =>
2540
- err ? reject(new Error(err)) : resolve(),
2541
- );
2542
- });
2543
- }
2544
-
2545
- /**
2546
- * Execute a command on a host.
2547
- */
2548
- cmdExec(
2549
- /** The host name. */
2550
- host: string,
2551
- /** The command. */
2552
- cmd: string,
2553
- /** The command ID. */
2554
- cmdId: string,
2555
- /** Timeout of command in ms */
2556
- cmdTimeout: number,
2557
- ): Promise<void> {
2558
- if (Connection.isWeb()) {
2559
- return Promise.reject(new Error('Allowed only in admin'));
2560
- }
2561
- if (!this.connected) {
2562
- return Promise.reject(new Error(NOT_CONNECTED));
2563
- }
2564
-
2565
- if (!host.startsWith(host)) {
2566
- host += `system.host.${host}`;
2567
- }
2568
-
2569
- return new Promise((resolve, reject) => {
2570
- let timeout: ReturnType<typeof setTimeout> | null = cmdTimeout
2571
- ? setTimeout(() => {
2572
- if (timeout) {
2573
- timeout = null;
2574
- reject(new Error('cmdExec timeout'));
2575
- }
2576
- }, cmdTimeout)
2577
- : null;
2578
-
2579
- this._socket.emit('cmdExec', host, cmdId, cmd, null, (err: string | null) => {
2580
- if (!cmdTimeout || timeout) {
2581
- timeout && clearTimeout(timeout);
2582
- timeout = null;
2583
- if (err) {
2584
- reject(new Error(err));
2585
- } else {
2586
- resolve();
2587
- }
2588
- }
2589
- });
2590
- });
2591
- }
2592
-
2593
- /**
2594
- * Checks if a given feature is supported.
2595
- */
2596
- checkFeatureSupported(
2597
- /** The feature to check. */
2598
- feature: string,
2599
- /** Force update. */
2600
- update?: boolean,
2601
- ): Promise<boolean> {
2602
- if (!update && this._promises[`supportedFeatures_${feature}`]) {
2603
- return this._promises[`supportedFeatures_${feature}`] as Promise<boolean>;
2604
- }
2605
-
2606
- if (!this.connected) {
2607
- return Promise.reject(new Error(NOT_CONNECTED));
2608
- }
2609
-
2610
- this._promises[`supportedFeatures_${feature}`] = new Promise((resolve, reject) => {
2611
- this._socket.emit('checkFeatureSupported', feature, (err: string | null, supported: boolean) =>
2612
- err ? reject(new Error(err)) : resolve(supported),
2613
- );
2614
- });
2615
-
2616
- return this._promises[`supportedFeatures_${feature}`] as Promise<boolean>;
2617
- }
2618
-
2619
- /**
2620
- * Read the base settings of a given host.
2621
- */
2622
- async readBaseSettings(host: string): Promise<Record<string, any>> {
2623
- if (Connection.isWeb()) {
2624
- return Promise.reject(new Error('Allowed only in admin'));
2625
- }
2626
- const result = await this.checkFeatureSupported('CONTROLLER_READWRITE_BASE_SETTINGS');
2627
- if (result) {
2628
- if (!this.connected) {
2629
- return Promise.reject(new Error(NOT_CONNECTED));
2630
- }
2631
- return new Promise((resolve, reject) => {
2632
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
2633
- if (timeout) {
2634
- timeout = null;
2635
- reject(new Error('readBaseSettings timeout'));
2636
- }
2637
- }, this.props.cmdTimeout);
2638
-
2639
- if (host.startsWith('system.host.')) {
2640
- host = host.replace(/^system\.host\./, '');
2641
- }
2642
-
2643
- this._socket.emit(
2644
- 'sendToHost',
2645
- host,
2646
- 'readBaseSettings',
2647
- null,
2648
- (data: Record<string, any> | string) => {
2649
- if (timeout) {
2650
- clearTimeout(timeout);
2651
- timeout = null;
2652
-
2653
- if (data === PERMISSION_ERROR) {
2654
- reject(new Error('May not read "BaseSettings"'));
2655
- } else if (!data || typeof data !== 'object') {
2656
- reject(new Error('Cannot read "BaseSettings"'));
2657
- } else {
2658
- resolve(data);
2659
- }
2660
- }
2661
- },
2662
- );
2663
- });
2664
- }
2665
- return Promise.reject(new Error('Not supported'));
2666
- }
2667
-
2668
- /**
2669
- * Write the base settings of a given host.
2670
- *
2671
- * @param host The host name.
2672
- * @param config The new base settings.
2673
- */
2674
- writeBaseSettings(host: string, config: IoBJson): Promise<{ result?: 'ok'; error?: string }> {
2675
- if (Connection.isWeb()) {
2676
- return Promise.reject(new Error('Allowed only in admin'));
2677
- }
2678
- return this.checkFeatureSupported('CONTROLLER_READWRITE_BASE_SETTINGS').then(result => {
2679
- if (result) {
2680
- if (!this.connected) {
2681
- return Promise.reject(new Error(NOT_CONNECTED));
2682
- }
2683
- return new Promise((resolve, reject) => {
2684
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
2685
- if (timeout) {
2686
- timeout = null;
2687
- reject(new Error('writeBaseSettings timeout'));
2688
- }
2689
- }, this.props.cmdTimeout);
2690
-
2691
- this._socket.emit(
2692
- 'sendToHost',
2693
- host,
2694
- 'writeBaseSettings',
2695
- config,
2696
- (data: { result?: 'ok'; error?: string } | string) => {
2697
- if (timeout) {
2698
- clearTimeout(timeout);
2699
- timeout = null;
2700
-
2701
- if (data === PERMISSION_ERROR) {
2702
- reject(new Error('May not write "BaseSettings"'));
2703
- } else if (!data) {
2704
- reject(new Error('Cannot write "BaseSettings"'));
2705
- } else {
2706
- resolve(data as { result?: 'ok'; error?: string });
2707
- }
2708
- }
2709
- },
2710
- );
2711
- });
2712
- }
2713
-
2714
- return Promise.reject(new Error('Not supported'));
2715
- });
2716
- }
2717
-
2718
- /**
2719
- * Send command to restart the iobroker on host
2720
- */
2721
- restartController(host: string): Promise<boolean> {
2722
- if (Connection.isWeb()) {
2723
- return Promise.reject(new Error('Allowed only in admin'));
2724
- }
2725
- return new Promise((resolve, reject) => {
2726
- this._socket.emit('sendToHost', host, 'restartController', null, (error: string | null) => {
2727
- error ? reject(new Error(error)) : resolve(true);
2728
- });
2729
- });
2730
- }
2731
-
2732
- /**
2733
- * Read statistics information from host
2734
- *
2735
- * @param host Host name
2736
- * @param typeOfDiag one of none, normal, no-city, extended
2737
- */
2738
- getDiagData(host: string, typeOfDiag: 'none' | 'normal' | 'no-city' | 'extended'): Promise<Record<string, any>> {
2739
- if (Connection.isWeb()) {
2740
- return Promise.reject(new Error('Allowed only in admin'));
2741
- }
2742
- return new Promise(resolve => {
2743
- this._socket.emit('sendToHost', host, 'getDiagData', typeOfDiag, (result: Record<string, any>) =>
2744
- resolve(result),
2745
- );
2746
- });
2747
- }
2748
-
2749
- /**
2750
- * Read all states (which might not belong to this adapter) which match the given pattern.
2751
- */
2752
- getForeignStates(pattern?: string): Promise<Record<string, ioBroker.State>> {
2753
- if (!this.connected) {
2754
- return Promise.reject(new Error(NOT_CONNECTED));
2755
- }
2756
- if (Connection.isWeb()) {
2757
- return new Promise((resolve, reject) => {
2758
- this._socket.emit(
2759
- 'getStates',
2760
- pattern || '*',
2761
- (err: string | null, states: Record<string, ioBroker.State>) =>
2762
- err ? reject(new Error(err)) : resolve(states),
2763
- );
2764
- });
2765
- }
2766
-
2767
- return new Promise((resolve, reject) => {
2768
- this._socket.emit(
2769
- 'getForeignStates',
2770
- pattern || '*',
2771
- (err: string | null, states: Record<string, ioBroker.State>) =>
2772
- err ? reject(new Error(err)) : resolve(states),
2773
- );
2774
- });
2775
- }
2776
-
2777
- /**
2778
- * Get foreign objects by pattern, by specific type and resolve their enums. (Only admin)
2779
- */
2780
- getForeignObjects(pattern: string, type?: ioBroker.ObjectType): Promise<Record<string, ioBroker.State>> {
2781
- if (Connection.isWeb()) {
2782
- return Promise.reject(new Error('Allowed only in admin'));
2783
- }
2784
-
2785
- if (!this.connected) {
2786
- return Promise.reject(new Error(NOT_CONNECTED));
2787
- }
2788
- return new Promise((resolve, reject) => {
2789
- this._socket.emit(
2790
- 'getForeignObjects',
2791
- pattern || '*',
2792
- type,
2793
- (err: string | null, states: Record<string, ioBroker.State>) =>
2794
- err ? reject(new Error(err)) : resolve(states),
2795
- );
2796
- });
2797
- }
2798
-
2799
- /**
2800
- * Gets the system configuration.
2801
- *
2802
- * @param update Force update.
2803
- */
2804
- getSystemConfig(update?: boolean): Promise<ioBroker.SystemConfigObject> {
2805
- if (!update && this._promises.systemConfig) {
2806
- return this._promises.systemConfig;
2807
- }
2808
-
2809
- if (!this.connected) {
2810
- return Promise.reject(new Error(NOT_CONNECTED));
2811
- }
2812
-
2813
- this._promises.systemConfig = this.getObject('system.config').then(obj => {
2814
- const systemConfig: ioBroker.SystemConfigObject = (obj || {}) as ioBroker.SystemConfigObject;
2815
- systemConfig.common = systemConfig.common || ({} as ioBroker.SystemConfigCommon);
2816
- systemConfig.native = systemConfig.native || {};
2817
- return systemConfig;
2818
- });
2819
-
2820
- return this._promises.systemConfig;
2821
- }
2822
-
2823
- /**
2824
- * Sets the system configuration.
2825
- */
2826
- setSystemConfig(
2827
- obj: ioBroker.SettableObjectWorker<ioBroker.SystemConfigObject>,
2828
- ): Promise<ioBroker.SystemConfigObject> {
2829
- return this.setObject('system.config', obj).then(
2830
- () => (this._promises.systemConfig = Promise.resolve(obj as ioBroker.SystemConfigObject)),
2831
- );
2832
- }
2833
-
2834
- /**
2835
- * Get the raw socket.io socket.
2836
- */
2837
- getRawSocket(): SocketClient {
2838
- return this._socket;
2839
- }
2840
-
2841
- /**
2842
- * Get the history of a given state.
2843
- */
2844
- getHistory(id: string, options: ioBroker.GetHistoryOptions): Promise<ioBroker.GetHistoryResult> {
2845
- if (!this.connected) {
2846
- return Promise.reject(new Error(NOT_CONNECTED));
2847
- }
2848
-
2849
- return new Promise((resolve, reject) => {
2850
- this._socket.emit('getHistory', id, options, (err: string | null, values: ioBroker.GetHistoryResult) =>
2851
- err ? reject(new Error(err)) : resolve(values),
2852
- );
2853
- });
2854
- }
2855
-
2856
- /**
2857
- * Get the history of a given state.
2858
- */
2859
- getHistoryEx(
2860
- id: string,
2861
- options: ioBroker.GetHistoryOptions,
2862
- ): Promise<{ values: ioBroker.GetHistoryResult; sessionId: string; stepIgnore: number }> {
2863
- if (!this.connected) {
2864
- return Promise.reject(new Error(NOT_CONNECTED));
2865
- }
2866
-
2867
- return new Promise((resolve, reject) => {
2868
- this._socket.emit(
2869
- 'getHistory',
2870
- id,
2871
- options,
2872
- (err: string | null, values: ioBroker.GetHistoryResult, stepIgnore: number, sessionId: string) =>
2873
- err ? reject(new Error(err)) : resolve({ values, sessionId, stepIgnore }),
2874
- );
2875
- });
2876
- }
2877
-
2878
- /**
2879
- * Change the password of the given user.
2880
- */
2881
- changePassword(user: string, password: string): Promise<void> {
2882
- if (Connection.isWeb()) {
2883
- return Promise.reject(new Error('Allowed only in admin'));
2884
- }
2885
- return new Promise((resolve, reject) => {
2886
- this._socket.emit('changePassword', user, password, (err: string | null) =>
2887
- err ? reject(new Error(err)) : resolve(),
2888
- );
2889
- });
2890
- }
2891
-
2892
- /**
2893
- * Get the IP addresses of the given host.
2894
- */
2895
- getIpAddresses(
2896
- host: string,
2897
- /** Force update. */
2898
- update?: boolean,
2899
- ): Promise<string[]> {
2900
- if (Connection.isWeb()) {
2901
- return Promise.reject(new Error('Allowed only in admin'));
2902
- }
2903
- if (!host.startsWith('system.host.')) {
2904
- host = `system.host.${host}`;
2905
- }
2906
-
2907
- if (!update && this._promises[`IPs_${host}`]) {
2908
- return this._promises[`IPs_${host}`] as Promise<string[]>;
2909
- }
2910
- this._promises[`IPs_${host}`] = this.getObject(host).then(obj => (obj?.common ? obj.common.address || [] : []));
2911
-
2912
- return this._promises[`IPs_${host}`] as Promise<string[]>;
2913
- }
2914
-
2915
- /**
2916
- * Get the IP addresses with interface names of the given host or find host by IP.
2917
- */
2918
- getHostByIp(
2919
- ipOrHostName: string,
2920
- /** Force update. */
2921
- update?: boolean,
2922
- ): Promise<{ name: string; address: string; family: 'ipv4' | 'ipv6' }[]> {
2923
- if (Connection.isWeb()) {
2924
- return Promise.reject(new Error('Allowed only in admin'));
2925
- }
2926
- if (ipOrHostName.startsWith('system.host.')) {
2927
- ipOrHostName = ipOrHostName.replace(/^system\.host\./, '');
2928
- }
2929
-
2930
- if (!update && this._promises[`rIPs_${ipOrHostName}`]) {
2931
- return this._promises[`rIPs_${ipOrHostName}`] as Promise<
2932
- { name: string; address: string; family: 'ipv4' | 'ipv6' }[]
2933
- >;
2934
- }
2935
- this._promises[`rIPs_${ipOrHostName}`] = new Promise(resolve => {
2936
- this._socket.emit('getHostByIp', ipOrHostName, (ip: string, host: any) => {
2937
- const IPs4: {
2938
- name: string;
2939
- address: string;
2940
- family: 'ipv4' | 'ipv6';
2941
- }[] = [{ name: '[IPv4] 0.0.0.0 - Listen on all IPs', address: '0.0.0.0', family: 'ipv4' }];
2942
- const IPs6: {
2943
- name: string;
2944
- address: string;
2945
- family: 'ipv4' | 'ipv6';
2946
- }[] = [{ name: '[IPv6] :: - Listen on all IPs', address: '::', family: 'ipv6' }];
2947
- if (host?.native?.hardware?.networkInterfaces) {
2948
- for (const eth in host.native.hardware.networkInterfaces) {
2949
- if (!Object.prototype.hasOwnProperty.call(host.native.hardware.networkInterfaces, eth)) {
2950
- continue;
2951
- }
2952
- for (let num = 0; num < host.native.hardware.networkInterfaces[eth].length; num++) {
2953
- if (host.native.hardware.networkInterfaces[eth][num].family !== 'IPv6') {
2954
- IPs4.push({
2955
- name: `[${host.native.hardware.networkInterfaces[eth][num].family}] ${host.native.hardware.networkInterfaces[eth][num].address} - ${eth}`,
2956
- address: host.native.hardware.networkInterfaces[eth][num].address,
2957
- family: 'ipv4',
2958
- });
2959
- } else {
2960
- IPs6.push({
2961
- name: `[${host.native.hardware.networkInterfaces[eth][num].family}] ${host.native.hardware.networkInterfaces[eth][num].address} - ${eth}`,
2962
- address: host.native.hardware.networkInterfaces[eth][num].address,
2963
- family: 'ipv6',
2964
- });
2965
- }
2966
- }
2967
- }
2968
- }
2969
- for (let i = 0; i < IPs6.length; i++) {
2970
- IPs4.push(IPs6[i]);
2971
- }
2972
- resolve(IPs4);
2973
- });
2974
- });
2975
-
2976
- return this._promises[`rIPs_${ipOrHostName}`] as Promise<
2977
- { name: string; address: string; family: 'ipv4' | 'ipv6' }[]
2978
- >;
2979
- }
2980
-
2981
- /**
2982
- * Encrypt a text
2983
- */
2984
- encrypt(text: string): Promise<string> {
2985
- if (Connection.isWeb()) {
2986
- return Promise.reject(new Error('Allowed only in admin'));
2987
- }
2988
- return new Promise((resolve, reject) => {
2989
- this._socket.emit('encrypt', text, (err: string | null, _text: string) =>
2990
- err ? reject(new Error(err)) : resolve(_text),
2991
- );
2992
- });
2993
- }
2994
-
2995
- /**
2996
- * Decrypt a text
2997
- */
2998
- decrypt(encryptedText: string): Promise<string> {
2999
- if (Connection.isWeb()) {
3000
- return Promise.reject(new Error('Allowed only in admin'));
3001
- }
3002
- return new Promise((resolve, reject) => {
3003
- this._socket.emit('decrypt', encryptedText, (err: string | null, text: string) =>
3004
- err ? reject(new Error(err)) : resolve(text),
3005
- );
3006
- });
3007
- }
3008
-
3009
- /**
3010
- * Gets the version.
3011
- */
3012
- getVersion(update?: boolean): Promise<{ version: string; serverName: string }> {
3013
- if (update && this._promises.version) {
3014
- delete this._promises.version;
3015
- }
3016
-
3017
- this._promises.version =
3018
- this._promises.version ||
3019
- new Promise((resolve, reject) => {
3020
- this._socket.emit('getVersion', (err: string | null, version: string, serverName: string) => {
3021
- // support of old socket.io
3022
- if (err && !version && typeof err === 'string' && err.match(/\d+\.\d+\.\d+/)) {
3023
- resolve({ version: err, serverName: 'socketio' });
3024
- } else {
3025
- err ? reject(new Error(err)) : resolve({ version, serverName });
3026
- }
3027
- });
3028
- });
3029
-
3030
- return this._promises.version;
3031
- }
3032
-
3033
- /**
3034
- * Gets the web server name.
3035
- */
3036
- getWebServerName(): Promise<string> {
3037
- this._promises.webName =
3038
- this._promises.webName ||
3039
- new Promise((resolve, reject) => {
3040
- this._socket.emit('getAdapterName', (err: string | null, name: string) =>
3041
- err ? reject(new Error(err)) : resolve(name),
3042
- );
3043
- });
3044
-
3045
- return this._promises.webName;
3046
- }
3047
-
3048
- /**
3049
- * Gets the admin version.
3050
- *
3051
- * @deprecated use getVersion()
3052
- */
3053
- getAdminVersion(): Promise<{ version: string; serverName: string }> {
3054
- console.log('Deprecated: use getVersion');
3055
- return this.getVersion();
3056
- }
3057
-
3058
- /**
3059
- * Change access rights for a file
3060
- *
3061
- * @param adapter The adapter name.
3062
- * @param fileName file name with a full path. It could be like vis.0/*
3063
- * @param options like {mode: 0x644}
3064
- * @param options.mode Access rights. Default is 0x644
3065
- */
3066
- chmodFile(
3067
- adapter: string,
3068
- fileName: string,
3069
- options?: { mode: number },
3070
- ): Promise<{ entries: ioBroker.ChownFileResult[]; id: string }> {
3071
- if (Connection.isWeb()) {
3072
- return Promise.reject(new Error('Allowed only in admin'));
3073
- }
3074
- if (!this.connected) {
3075
- return Promise.reject(new Error(NOT_CONNECTED));
3076
- }
3077
-
3078
- return new Promise((resolve, reject) => {
3079
- this._socket.emit(
3080
- 'chmodFile',
3081
- adapter,
3082
- fileName,
3083
- options,
3084
- (err: string | null, entries: ioBroker.ChownFileResult[], id: string) =>
3085
- err ? reject(new Error(err)) : resolve({ entries, id }),
3086
- );
3087
- });
3088
- }
3089
-
3090
- /**
3091
- * Change an owner or/and owner group for a file
3092
- *
3093
- * @param adapter The adapter name.
3094
- * @param fileName file name with a full path. It could be like vis.0/*
3095
- * @param options like {owner: 'user', ownerGroup: 'group'}
3096
- * @param options.owner User name
3097
- * @param options.ownerGroup Group name
3098
- */
3099
- chownFile(
3100
- adapter: string,
3101
- fileName: string,
3102
- options: { owner?: string; ownerGroup?: string },
3103
- ): Promise<{ entries: ioBroker.ChownFileResult[]; id: string }> {
3104
- if (Connection.isWeb()) {
3105
- return Promise.reject(new Error('Allowed only in admin'));
3106
- }
3107
- if (!this.connected) {
3108
- return Promise.reject(new Error(NOT_CONNECTED));
3109
- }
3110
-
3111
- return new Promise((resolve, reject) => {
3112
- this._socket.emit(
3113
- 'chownFile',
3114
- adapter,
3115
- fileName,
3116
- options,
3117
- (err: string | null, entries: ioBroker.ChownFileResult[], id: string) =>
3118
- err ? reject(new Error(err)) : resolve({ entries, id }),
3119
- );
3120
- });
3121
- }
3122
-
3123
- /**
3124
- * Check if the file exists
3125
- *
3126
- * @param adapter The adapter name.
3127
- * @param fileName file name with a full path. It could be like vis.0/*
3128
- */
3129
- fileExists(adapter: string, fileName: string): Promise<boolean> {
3130
- if (!this.connected) {
3131
- return Promise.reject(new Error(NOT_CONNECTED));
3132
- }
3133
-
3134
- return new Promise((resolve, reject) => {
3135
- this._socket.emit('fileExists', adapter, fileName, (err: string | null, exists: boolean) =>
3136
- err ? reject(new Error(err)) : resolve(exists),
3137
- );
3138
- });
3139
- }
3140
-
3141
- /**
3142
- * Get the alarm notifications from a host (only for admin connection).
3143
- */
3144
- getNotifications(host: string, category?: string): Promise<FilteredNotificationInformation> {
3145
- if (Connection.isWeb()) {
3146
- return Promise.reject(new Error('Allowed only in admin'));
3147
- }
3148
-
3149
- if (!this.connected) {
3150
- return Promise.reject(new Error(NOT_CONNECTED));
3151
- }
3152
- return new Promise(resolve => {
3153
- this._socket.emit(
3154
- 'sendToHost',
3155
- host,
3156
- 'getNotifications',
3157
- { category },
3158
- (notifications: FilteredNotificationInformation) => resolve(notifications),
3159
- );
3160
- });
3161
- }
3162
-
3163
- /**
3164
- * Clear the alarm notifications on a host (only for admin connection).
3165
- *
3166
- * @param host The host name.
3167
- * @param category optional
3168
- */
3169
- clearNotifications(host: string, category?: string): Promise<{ result: 'ok' }> {
3170
- if (Connection.isWeb()) {
3171
- return Promise.reject(new Error('Allowed only in admin'));
3172
- }
3173
-
3174
- if (!this.connected) {
3175
- return Promise.reject(new Error(NOT_CONNECTED));
3176
- }
3177
- return new Promise(resolve => {
3178
- this._socket.emit('sendToHost', host, 'clearNotifications', { category }, (result: { result: 'ok' }) =>
3179
- resolve(result),
3180
- );
3181
- });
3182
- }
3183
-
3184
- /**
3185
- * Read if only easy mode is allowed (only for admin connection).
3186
- */
3187
- getIsEasyModeStrict(): Promise<boolean> {
3188
- if (Connection.isWeb()) {
3189
- return Promise.reject(new Error('Allowed only in admin'));
3190
- }
3191
- if (!this.connected) {
3192
- return Promise.reject(new Error(NOT_CONNECTED));
3193
- }
3194
- return new Promise((resolve, reject) => {
3195
- this._socket.emit('getIsEasyModeStrict', (error: null | string, isStrict: boolean) =>
3196
- error ? reject(new Error(error)) : resolve(isStrict),
3197
- );
3198
- });
3199
- }
3200
-
3201
- /**
3202
- * Read easy mode configuration (only for admin connection).
3203
- */
3204
- getEasyMode(): Promise<any> {
3205
- if (Connection.isWeb()) {
3206
- return Promise.reject(new Error('Allowed only in admin'));
3207
- }
3208
- if (!this.connected) {
3209
- return Promise.reject(new Error(NOT_CONNECTED));
3210
- }
3211
- return new Promise((resolve, reject) => {
3212
- this._socket.emit('getEasyMode', (error: string | null, config: any) =>
3213
- error ? reject(new Error(error)) : resolve(config),
3214
- );
3215
- });
3216
- }
3217
-
3218
- /**
3219
- * Read current user
3220
- */
3221
- getCurrentUser(): Promise<string> {
3222
- if (!this.connected) {
3223
- return Promise.reject(new Error(NOT_CONNECTED));
3224
- }
3225
-
3226
- return new Promise(resolve => {
3227
- this._socket.emit('authEnabled', (isSecure: boolean, user: string) => resolve(user));
3228
- });
3229
- }
3230
-
3231
- getCurrentSession(cmdTimeout?: number): Promise<{ expireInSec: number }> {
3232
- if (!this.connected) {
3233
- return Promise.reject(new Error(NOT_CONNECTED));
3234
- }
3235
-
3236
- return new Promise((resolve, reject) => {
3237
- const controller = new AbortController();
3238
-
3239
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
3240
- if (timeout) {
3241
- timeout = null;
3242
- controller.abort();
3243
- reject(new Error('getCurrentSession timeout'));
3244
- }
3245
- }, cmdTimeout || 5000);
3246
-
3247
- fetch('./session', { signal: controller.signal })
3248
- .then(res => res.json())
3249
- .then(json => {
3250
- if (timeout) {
3251
- clearTimeout(timeout);
3252
- timeout = null;
3253
- resolve(json);
3254
- }
3255
- })
3256
- .catch(e => reject(new Error(`getCurrentSession: ${e}`)));
3257
- });
3258
- }
3259
-
3260
- /**
3261
- * Read adapter ratings
3262
- */
3263
- getRatings(update?: boolean): Promise<any> {
3264
- if (Connection.isWeb()) {
3265
- return Promise.reject(new Error('Allowed only in admin'));
3266
- }
3267
- if (!this.connected) {
3268
- return Promise.reject(new Error(NOT_CONNECTED));
3269
- }
3270
- return new Promise((resolve, reject) => {
3271
- this._socket.emit('getRatings', update, (err: string | null, ratings: any) =>
3272
- err ? reject(new Error(err)) : resolve(ratings),
3273
- );
3274
- });
3275
- }
3276
-
3277
- /**
3278
- * Read current web, socketio or admin namespace, like admin.0
3279
- */
3280
- getCurrentInstance(): Promise<string> {
3281
- if (!this.connected) {
3282
- return Promise.reject(new Error(NOT_CONNECTED));
3283
- }
3284
-
3285
- this._promises.currentInstance =
3286
- this._promises.currentInstance ||
3287
- new Promise((resolve, reject) => {
3288
- this._socket.emit('getCurrentInstance', (err: string | null, namespace: string) =>
3289
- err ? reject(new Error(err)) : resolve(namespace),
3290
- );
3291
- });
3292
-
3293
- return this._promises.currentInstance;
3294
- }
3295
-
3296
- // returns very optimized information for adapters to minimize a connection load
3297
- getCompactAdapters(update?: boolean): Promise<Record<string, ioBroker.AdapterObject>> {
3298
- if (Connection.isWeb()) {
3299
- return Promise.reject(new Error('Allowed only in admin'));
3300
- }
3301
- if (!update && this._promises.compactAdapters) {
3302
- return this._promises.compactAdapters;
3303
- }
3304
- if (!this.connected) {
3305
- return Promise.reject(new Error(NOT_CONNECTED));
3306
- }
3307
- this._promises.compactAdapters = new Promise((resolve, reject) => {
3308
- this._socket.emit(
3309
- 'getCompactAdapters',
3310
- (err: string | null, adapters: Record<string, ioBroker.AdapterObject>) =>
3311
- err ? reject(new Error(err)) : resolve(adapters),
3312
- );
3313
- });
3314
-
3315
- return this._promises.compactAdapters;
3316
- }
3317
-
3318
- getAdaptersResetCache(adapter?: string): void {
3319
- adapter = adapter || '';
3320
- delete this._promises.compactAdapters;
3321
- delete this._promises[`adapter_${adapter}`];
3322
- }
3323
-
3324
- // returns very optimized information for adapters to minimize a connection load
3325
- getCompactInstances(update?: boolean): Promise<Record<string, ioBroker.InstanceObject>> {
3326
- if (Connection.isWeb()) {
3327
- return Promise.reject(new Error('Allowed only in admin'));
3328
- }
3329
- if (!update && this._promises.compactInstances) {
3330
- return this._promises.compactInstances;
3331
- }
3332
- if (!this.connected) {
3333
- return Promise.reject(new Error(NOT_CONNECTED));
3334
- }
3335
-
3336
- this._promises.compactInstances = new Promise((resolve, reject) => {
3337
- this._socket.emit(
3338
- 'getCompactInstances',
3339
- (err: string | null, instances: Record<string, ioBroker.InstanceObject>) =>
3340
- err ? reject(new Error(err)) : resolve(instances),
3341
- );
3342
- });
3343
-
3344
- return this._promises.compactInstances;
3345
- }
3346
-
3347
- getAdapternInstancesResetCache(adapter?: string): void {
3348
- adapter = adapter || '';
3349
- delete this._promises.compactInstances;
3350
- delete this._promises[`instances_${adapter}`];
3351
- }
3352
-
3353
- /**
3354
- * Returns very optimized information for adapters to minimize a connection load.
3355
- * Reads only version of installed adapter
3356
- */
3357
- getCompactInstalled(
3358
- host: string,
3359
- update?: boolean,
3360
- cmdTimeout?: number,
3361
- ): Promise<Record<string, ioBroker.AdapterObject>> {
3362
- if (Connection.isWeb()) {
3363
- return Promise.reject(new Error('Allowed only in admin'));
3364
- }
3365
-
3366
- this._promises.installedCompact = this._promises.installedCompact || {};
3367
-
3368
- if (!update && this._promises.installedCompact[host]) {
3369
- return this._promises.installedCompact[host] as Promise<Record<string, ioBroker.AdapterObject>>;
3370
- }
3371
-
3372
- if (!this.connected) {
3373
- return Promise.reject(new Error(NOT_CONNECTED));
3374
- }
3375
-
3376
- if (!host.startsWith('system.host.')) {
3377
- host += `system.host.${host}`;
3378
- }
3379
-
3380
- this._promises.installedCompact[host] = new Promise((resolve, reject) => {
3381
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
3382
- if (timeout) {
3383
- timeout = null;
3384
- reject(new Error('getCompactInstalled timeout'));
3385
- }
3386
- }, cmdTimeout || this.props.cmdTimeout);
3387
-
3388
- this._socket.emit('getCompactInstalled', host, (data: Record<string, ioBroker.AdapterObject> | string) => {
3389
- if (timeout) {
3390
- clearTimeout(timeout);
3391
- timeout = null;
3392
- if (data === PERMISSION_ERROR) {
3393
- reject(new Error('May not read "getCompactInstalled"'));
3394
- } else if (!data || typeof data !== 'object') {
3395
- reject(new Error('Cannot read "getCompactInstalled"'));
3396
- } else {
3397
- resolve(data);
3398
- }
3399
- }
3400
- });
3401
- });
3402
-
3403
- return this._promises.installedCompact[host] as Promise<Record<string, ioBroker.AdapterObject>>;
3404
- }
3405
-
3406
- // returns very optimized information for adapters to minimize a connection load.
3407
- // reads only version of installed adapter
3408
- getCompactSystemRepositories(update?: boolean, cmdTimeout?: number): Promise<CompactSystemRepository> {
3409
- if (Connection.isWeb()) {
3410
- return Promise.reject(new Error('Allowed only in admin'));
3411
- }
3412
-
3413
- if (!update && this._promises.getCompactSystemRepositories) {
3414
- return this._promises.getCompactSystemRepositories;
3415
- }
3416
-
3417
- if (!this.connected) {
3418
- return Promise.reject(new Error(NOT_CONNECTED));
3419
- }
3420
-
3421
- this._promises.getCompactSystemRepositories = new Promise((resolve, reject) => {
3422
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
3423
- if (timeout) {
3424
- timeout = null;
3425
- reject(new Error('getCompactSystemRepositories timeout'));
3426
- }
3427
- }, cmdTimeout || this.props.cmdTimeout);
3428
-
3429
- this._socket.emit('getCompactSystemRepositories', (data: CompactSystemRepository | string) => {
3430
- if (timeout) {
3431
- clearTimeout(timeout);
3432
- timeout = null;
3433
- if (data === PERMISSION_ERROR) {
3434
- reject(new Error('May not read "getCompactSystemRepositories"'));
3435
- } else if (!data || typeof data !== 'object') {
3436
- reject(new Error('Cannot read "getCompactSystemRepositories"'));
3437
- } else {
3438
- resolve(data);
3439
- }
3440
- }
3441
- });
3442
- });
3443
-
3444
- return this._promises.getCompactSystemRepositories;
3445
- }
3446
-
3447
- // returns very optimized information for adapters to minimize a connection load
3448
- getCompactSystemConfig(update?: boolean): Promise<ioBroker.SystemConfigObject> {
3449
- if (!update && this._promises.systemConfigPromise) {
3450
- return this._promises.systemConfigPromise;
3451
- }
3452
-
3453
- if (!this.connected) {
3454
- return Promise.reject(new Error(NOT_CONNECTED));
3455
- }
3456
-
3457
- this._promises.systemConfigPromise = new Promise((resolve, reject) => {
3458
- this._socket.emit(
3459
- 'getCompactSystemConfig',
3460
- (err: string | null, systemConfig: ioBroker.SystemConfigObject) =>
3461
- err ? reject(new Error(err)) : resolve(systemConfig),
3462
- );
3463
- });
3464
-
3465
- return this._promises.systemConfigPromise;
3466
- }
3467
-
3468
- /**
3469
- * Get the repository in compact form (only version and icon).
3470
- *
3471
- * @param host The host name.
3472
- * @param update Force update.
3473
- * @param timeoutMs timeout in ms.
3474
- */
3475
- getCompactRepository(
3476
- host: string,
3477
- update?: boolean,
3478
- timeoutMs?: number,
3479
- ): Promise<Record<string, { version: string; icon: string }>> {
3480
- if (Connection.isWeb()) {
3481
- return Promise.reject(new Error('Allowed only in admin'));
3482
- }
3483
-
3484
- if (!update && this._promises.repoCompact) {
3485
- return this._promises.repoCompact;
3486
- }
3487
-
3488
- if (!this.connected) {
3489
- return Promise.reject(new Error(NOT_CONNECTED));
3490
- }
3491
-
3492
- if (!host.startsWith('system.host.')) {
3493
- host += `system.host.${host}`;
3494
- }
3495
-
3496
- this._promises.repoCompact = new Promise((resolve, reject) => {
3497
- let timeout: ReturnType<typeof setTimeout> | null = setTimeout(() => {
3498
- if (timeout) {
3499
- timeout = null;
3500
- reject(new Error('getCompactRepository timeout'));
3501
- }
3502
- }, timeoutMs || this.props.cmdTimeout);
3503
-
3504
- this._socket.emit(
3505
- 'getCompactRepository',
3506
- host,
3507
- (data: Record<string, { version: string; icon: string }> | string) => {
3508
- if (timeout) {
3509
- clearTimeout(timeout);
3510
- timeout = null;
3511
- if (data === PERMISSION_ERROR) {
3512
- reject(new Error('May not read "getCompactRepository"'));
3513
- } else if (!data) {
3514
- reject(new Error('Cannot read "getCompactRepository"'));
3515
- } else {
3516
- resolve(data);
3517
- }
3518
- }
3519
- },
3520
- );
3521
- });
3522
-
3523
- return this._promises.repoCompact;
3524
- }
3525
-
3526
- getInstalledResetCache(): void {
3527
- delete this._promises.repoCompact;
3528
- delete this._promises.repo;
3529
- }
3530
-
3531
- /**
3532
- * Get the list of all hosts in compact form (only _id, common.name, common.icon, common.color, native.hardware.networkInterfaces)
3533
- */
3534
- getCompactHosts(update?: boolean): Promise<ioBroker.HostObject[]> {
3535
- if (Connection.isWeb()) {
3536
- return Promise.reject(new Error('Allowed only in admin'));
3537
- }
3538
- if (!update && this._promises.hostsCompact) {
3539
- return this._promises.hostsCompact;
3540
- }
3541
-
3542
- if (!this.connected) {
3543
- return Promise.reject(new Error(NOT_CONNECTED));
3544
- }
3545
-
3546
- this._promises.hostsCompact = new Promise((resolve, reject) => {
3547
- this._socket.emit('getCompactHosts', (err: string | null, hosts: ioBroker.HostObject[]) =>
3548
- err ? reject(new Error(err)) : resolve(hosts),
3549
- );
3550
- });
3551
-
3552
- return this._promises.hostsCompact;
3553
- }
3554
-
3555
- /**
3556
- * Get uuid
3557
- */
3558
- getUuid(): Promise<string | undefined> {
3559
- if (this._promises.uuid) {
3560
- return this._promises.uuid;
3561
- }
3562
-
3563
- if (!this.connected) {
3564
- return Promise.reject(new Error(NOT_CONNECTED));
3565
- }
3566
-
3567
- this._promises.uuid = this.getObject('system.meta.uuid').then(obj => obj?.native?.uuid);
3568
-
3569
- return this._promises.uuid;
3570
- }
3571
-
3572
- /**
3573
- * Subscribe on instance message
3574
- *
3575
- * @param targetInstance instance, like 'cameras.0'
3576
- * @param messageType message type like 'startCamera/cam3'
3577
- * @param data optional data object
3578
- * @param callback message handler
3579
- */
3580
- subscribeOnInstance(
3581
- targetInstance: string,
3582
- messageType: string,
3583
- data: any,
3584
- callback: (_data: Record<string, any>, sourceInstance: string, _messageType: string) => void,
3585
- ): Promise<{ error?: string; accepted?: boolean; heartbeat?: number }> {
3586
- if (!this.connected) {
3587
- return Promise.reject(new Error(NOT_CONNECTED));
3588
- }
3589
- return new Promise((resolve, reject) => {
3590
- this._socket.emit(
3591
- 'clientSubscribe',
3592
- targetInstance,
3593
- messageType,
3594
- data,
3595
- (err: string | null, result: { error?: string; accepted?: boolean; heartbeat?: number }) => {
3596
- if (err) {
3597
- reject(new Error(err));
3598
- } else if (result?.error) {
3599
- reject(new Error(result.error));
3600
- } else {
3601
- if (!targetInstance.startsWith('system.adapter.')) {
3602
- targetInstance = `system.adapter.${targetInstance}`;
3603
- }
3604
- // save callback
3605
- this._instanceSubscriptions[targetInstance] = this._instanceSubscriptions[targetInstance] || [];
3606
- if (
3607
- !this._instanceSubscriptions[targetInstance].find(
3608
- sub => sub.messageType === messageType && sub.callback === callback,
3609
- )
3610
- ) {
3611
- this._instanceSubscriptions[targetInstance].push({
3612
- messageType,
3613
- callback,
3614
- });
3615
- }
3616
- resolve(result);
3617
- }
3618
- },
3619
- );
3620
- });
3621
- }
3622
-
3623
- /**
3624
- * Unsubscribe from instance message
3625
- *
3626
- * @param targetInstance instance, like 'cameras.0'
3627
- * @param messageType message type like 'startCamera/cam3'
3628
- * @param callback message handler. Could be null if all callbacks for this messageType should be unsubscribed
3629
- */
3630
- unsubscribeFromInstance(
3631
- targetInstance: string,
3632
- messageType?: string,
3633
- callback?: (data: Record<string, any>, sourceInstance: string, _messageType: string) => void,
3634
- ): Promise<boolean> {
3635
- if (!targetInstance.startsWith('system.adapter.')) {
3636
- targetInstance = `system.adapter.${targetInstance}`;
3637
- }
3638
- let deleted;
3639
- const promiseResults: Promise<boolean>[] = [];
3640
- do {
3641
- deleted = false;
3642
- const index = this._instanceSubscriptions[targetInstance]?.findIndex(
3643
- sub => (!messageType || sub.messageType === messageType) && (!callback || sub.callback === callback),
3644
- );
3645
-
3646
- if (index !== undefined && index !== null && index !== -1) {
3647
- deleted = true;
3648
- // remember messageType
3649
- const _messageType = this._instanceSubscriptions[targetInstance][index].messageType;
3650
-
3651
- this._instanceSubscriptions[targetInstance].splice(index, 1);
3652
- if (!this._instanceSubscriptions[targetInstance].length) {
3653
- delete this._instanceSubscriptions[targetInstance];
3654
- }
3655
-
3656
- // try to find another subscription for this instance and messageType
3657
- const found =
3658
- this._instanceSubscriptions[targetInstance] &&
3659
- this._instanceSubscriptions[targetInstance].find(sub => sub.messageType === _messageType);
3660
-
3661
- if (!found) {
3662
- promiseResults.push(
3663
- new Promise((resolve, reject) => {
3664
- this._socket.emit(
3665
- 'clientUnsubscribe',
3666
- targetInstance,
3667
- messageType,
3668
- (err: string | null, wasSubscribed: boolean) => {
3669
- if (err) {
3670
- reject(new Error(err));
3671
- } else {
3672
- resolve(wasSubscribed);
3673
- }
3674
- },
3675
- );
3676
- }),
3677
- );
3678
- }
3679
- }
3680
- } while (deleted && (!callback || !messageType));
3681
-
3682
- if (promiseResults.length) {
3683
- return Promise.all(promiseResults).then((results: boolean[]) => results.find(result => result) || false);
3684
- }
3685
-
3686
- return Promise.resolve(false);
3687
- }
3688
-
3689
- /**
3690
- * Send log to ioBroker log
3691
- */
3692
- log(text: string, level?: 'info' | 'debug' | 'warn' | 'error' | 'silly'): void {
3693
- text && this._socket.emit('log', text, level || 'debug');
3694
- }
3695
-
3696
- /**
3697
- * Logout current user
3698
- */
3699
- logout(): Promise<void> {
3700
- if (!this.connected) {
3701
- return Promise.reject(new Error(NOT_CONNECTED));
3702
- }
3703
-
3704
- return new Promise((resolve, reject) => {
3705
- this._socket.emit('logout', (err: string | null) => (err ? reject(new Error(err)) : resolve()));
3706
- });
3707
- }
3708
-
3709
- /**
3710
- * This is a special method for vis.
3711
- * It is used to not send to server the changes about "nothing_selected" state
3712
- *
3713
- * @param id The state that has to be ignored by communication
3714
- */
3715
- setStateToIgnore(id?: string | null): void {
3716
- this.ignoreState = id || '';
3717
- }
3718
- }
3719
-
3720
- export default Connection;