hoffmation-base 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +27 -0
- package/.prettierrc.js +9 -0
- package/LICENSE +21 -0
- package/README.md +1 -0
- package/index.js +1 -0
- package/models/connectionCallbacks.ts +13 -0
- package/models/daytime.ts +3 -0
- package/models/deviceConfig.ts +8 -0
- package/models/dimmerSettings.ts +5 -0
- package/models/lampSettings.ts +5 -0
- package/models/ledSettings.ts +19 -0
- package/models/logLevel.ts +9 -0
- package/models/persistence/BasicRoomInfo.ts +3 -0
- package/models/persistence/DailyMovementCount.ts +3 -0
- package/models/persistence/RoomDetailInfo.ts +4 -0
- package/models/persistence/temperaturDataPoint.ts +12 -0
- package/models/persistence/todaysCount.ts +3 -0
- package/models/rooms/RoomBase.ts +357 -0
- package/models/rooms/RoomSettings/RoomSettings.ts +159 -0
- package/models/rooms/RoomSettings/hmIPRoomSettings.ts +53 -0
- package/models/rooms/RoomSettings/iRoomDefaultSettings.ts +17 -0
- package/models/rooms/RoomSettings/readme.md +18 -0
- package/models/rooms/RoomSettings/zigbeeRoomSettings.ts +51 -0
- package/models/rooms/iRoomImportEnforcer.ts +3 -0
- package/models/rooms/readme.md +11 -0
- package/models/temperaturSettings.ts +22 -0
- package/models/timeCallback.ts +90 -0
- package/package.json +57 -0
- package/server/config/config-readme.md +19 -0
- package/server/config/iConfig.ts +53 -0
- package/server/devices/DeviceInfo.ts +66 -0
- package/server/devices/Griffe.ts +31 -0
- package/server/devices/Heizgruppen.ts +91 -0
- package/server/devices/Rollos.ts +48 -0
- package/server/devices/deviceUpdater.ts +72 -0
- package/server/devices/devices.ts +189 -0
- package/server/devices/groups/fensterGroup.ts +175 -0
- package/server/devices/groups/heatGroup.ts +32 -0
- package/server/devices/groups/lampenGroup.ts +88 -0
- package/server/devices/groups/praesenzGroup.ts +182 -0
- package/server/devices/groups/smokeGroup.ts +16 -0
- package/server/devices/groups/sonosGroup.ts +33 -0
- package/server/devices/groups/tasterGroup.ts +48 -0
- package/server/devices/groups/waterGroup.ts +16 -0
- package/server/devices/hmIPDevices/Fenster.ts +114 -0
- package/server/devices/hmIPDevices/FensterPosition.ts +5 -0
- package/server/devices/hmIPDevices/TuerPosition.ts +4 -0
- package/server/devices/hmIPDevices/hmIpBewegung.ts +126 -0
- package/server/devices/hmIPDevices/hmIpDevice.ts +90 -0
- package/server/devices/hmIPDevices/hmIpDeviceType.ts +14 -0
- package/server/devices/hmIPDevices/hmIpGriff.ts +143 -0
- package/server/devices/hmIPDevices/hmIpHeizgruppe.ts +172 -0
- package/server/devices/hmIPDevices/hmIpHeizung.ts +69 -0
- package/server/devices/hmIPDevices/hmIpLampe.ts +119 -0
- package/server/devices/hmIPDevices/hmIpPraezenz.ts +99 -0
- package/server/devices/hmIPDevices/hmIpRoll.ts +133 -0
- package/server/devices/hmIPDevices/hmIpTaste.ts +72 -0
- package/server/devices/hmIPDevices/hmIpTaster.ts +73 -0
- package/server/devices/hmIPDevices/hmIpTherm.ts +19 -0
- package/server/devices/hmIPDevices/hmIpTuer.ts +115 -0
- package/server/devices/hmIPDevices/hmIpWippe.ts +55 -0
- package/server/devices/iDeviceUpdater.ts +4 -0
- package/server/devices/iIoBrokerDevice.ts +44 -0
- package/server/devices/wledDevice.ts +124 -0
- package/server/devices/zigbee/ZigbeeActuator.ts +113 -0
- package/server/devices/zigbee/zigbeeAquaraVibra.ts +171 -0
- package/server/devices/zigbee/zigbeeAquaraWater.ts +94 -0
- package/server/devices/zigbee/zigbeeBlitzShp.ts +77 -0
- package/server/devices/zigbee/zigbeeDevice.ts +115 -0
- package/server/devices/zigbee/zigbeeDeviceType.ts +13 -0
- package/server/devices/zigbee/zigbeeHeimanSmoke.ts +99 -0
- package/server/devices/zigbee/zigbeeIkeaSteckdose.ts +31 -0
- package/server/devices/zigbee/zigbeeIlluActuator.ts +37 -0
- package/server/devices/zigbee/zigbeeIlluDimmer.ts +165 -0
- package/server/devices/zigbee/zigbeeIlluLampe.ts +33 -0
- package/server/devices/zigbee/zigbeeIlluLedRGBCCT.ts +137 -0
- package/server/ioBroker/connection.ts +1655 -0
- package/server/ioBroker/ioBroker.main.ts +99 -0
- package/server/ioBroker/socketIOAuthInfo.ts +5 -0
- package/server/ioBroker/socketIOConnectOptions.ts +6 -0
- package/server/ioBroker/socketIOLogging.ts +29 -0
- package/server/ioBroker/socketIOVisCommand.ts +11 -0
- package/server/services/HTTPSOptions.ts +14 -0
- package/server/services/Sonos/mp3-server.ts +75 -0
- package/server/services/Sonos/polly-service.ts +100 -0
- package/server/services/Sonos/sonos-service.ts +199 -0
- package/server/services/Telegram/telegram-Commands.ts +215 -0
- package/server/services/Telegram/telegram-service.ts +171 -0
- package/server/services/Telegram/telegramMessageCalback.ts +11 -0
- package/server/services/calendar/m/303/274ll-service.ts +224 -0
- package/server/services/dbo/persist.ts +125 -0
- package/server/services/https-service.ts +71 -0
- package/server/services/log-service.ts +69 -0
- package/server/services/news-service.ts +81 -0
- package/server/services/settings-service.ts +23 -0
- package/server/services/time-callback-service.ts +223 -0
- package/server/services/utils/ringstorage.ts +24 -0
- package/server/services/utils/utils.ts +52 -0
- package/server/services/weather/weather-alert.ts +7 -0
- package/server/services/weather/weather-current.ts +26 -0
- package/server/services/weather/weather-daily.ts +22 -0
- package/server/services/weather/weather-feelsLike.ts +6 -0
- package/server/services/weather/weather-hourly.ts +17 -0
- package/server/services/weather/weather-item.ts +6 -0
- package/server/services/weather/weather-minutes.ts +4 -0
- package/server/services/weather/weather-service.ts +277 -0
- package/server/services/weather/weather-temp.ts +8 -0
- package/tsconfig.json +59 -0
|
@@ -0,0 +1,1655 @@
|
|
|
1
|
+
/* eslint-disable prefer-rest-params */
|
|
2
|
+
import { IncomingMessage } from 'http';
|
|
3
|
+
import { SocketIOAuthInfo } from './socketIOAuthInfo';
|
|
4
|
+
import { SocketIOConnectOpts } from './socketIOConnectOptions';
|
|
5
|
+
import { SocketIoLogging, SocketIoLogLevel } from './socketIOLogging';
|
|
6
|
+
import { SocketIOVisCommand } from './socketIOVisCommand';
|
|
7
|
+
import { ConnectionCallbacks } from '../../models/connectionCallbacks';
|
|
8
|
+
import io from 'socket.io-client';
|
|
9
|
+
import { Utils } from '../services/utils/utils';
|
|
10
|
+
|
|
11
|
+
let session: unknown;
|
|
12
|
+
let app: unknown;
|
|
13
|
+
let socketSession: unknown;
|
|
14
|
+
let storage: unknown;
|
|
15
|
+
const socketNamespace: string = '';
|
|
16
|
+
const socketUrl: string = '';
|
|
17
|
+
const socketForceWebSockets: boolean = true;
|
|
18
|
+
|
|
19
|
+
export class IOBrokerConnection {
|
|
20
|
+
private _isExecutedInBrowser: boolean = false;
|
|
21
|
+
private _authInfo: SocketIOAuthInfo = new SocketIOAuthInfo();
|
|
22
|
+
private _authRunning: boolean = false;
|
|
23
|
+
private _cmdData: unknown;
|
|
24
|
+
private _cmdQueue?: Array<{ func: string; args: IArguments }> = new Array<{ func: string; args: IArguments }>();
|
|
25
|
+
private _connCallbacks: ConnectionCallbacks = new ConnectionCallbacks();
|
|
26
|
+
private _cmdInstance: string = '';
|
|
27
|
+
private _countDown: number = 0;
|
|
28
|
+
private _defaultMode: number = 0x644;
|
|
29
|
+
private _disconnectedSince?: Date;
|
|
30
|
+
private _enums?: {
|
|
31
|
+
[groupName: string]: Record<string, ioBroker.Enum>;
|
|
32
|
+
}; // used if _useStorage === true
|
|
33
|
+
private _isAuthDone: boolean = false;
|
|
34
|
+
private _isAuthRequired: boolean = false;
|
|
35
|
+
private _isConnected: boolean = false;
|
|
36
|
+
private _isSecure: boolean = false;
|
|
37
|
+
private _lastTimer?: Date;
|
|
38
|
+
private _namespace: string = 'vis.0';
|
|
39
|
+
private _objects?: Record<string, ioBroker.Object>; // used if _useStorage === true
|
|
40
|
+
private _onConnChange: unknown;
|
|
41
|
+
private _onUpdate: unknown;
|
|
42
|
+
private _reconnectInterval: number = 10000; // reconnect interval
|
|
43
|
+
private _reloadInterval: number = 30; // if connection was absent longer than 30 seconds
|
|
44
|
+
private _socket: SocketIOClient.Socket;
|
|
45
|
+
private _type: string = 'socket.io'; // [SignalR | socket.io | local]
|
|
46
|
+
private _timer?: NodeJS.Timeout;
|
|
47
|
+
private _timeout: number = 0; // 0 - use transport default timeout to detect disconnect
|
|
48
|
+
private _user: string = '';
|
|
49
|
+
private _useStorage: boolean = false;
|
|
50
|
+
private _connectInterval?: NodeJS.Timeout;
|
|
51
|
+
private _countInterval?: NodeJS.Timeout;
|
|
52
|
+
private _gettingStates?: number;
|
|
53
|
+
|
|
54
|
+
//#region GetterSetter
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Getter isExecutedInBrowser
|
|
58
|
+
* @return {boolean }
|
|
59
|
+
*/
|
|
60
|
+
public get isExecutedInBrowser(): boolean {
|
|
61
|
+
return this._isExecutedInBrowser;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Getter enums
|
|
66
|
+
* @return {unknown}
|
|
67
|
+
*/
|
|
68
|
+
public get enums():
|
|
69
|
+
| {
|
|
70
|
+
[groupName: string]: Record<string, ioBroker.Enum>;
|
|
71
|
+
}
|
|
72
|
+
| undefined {
|
|
73
|
+
return this._enums;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Getter isAuthDone
|
|
78
|
+
* @return {boolean }
|
|
79
|
+
*/
|
|
80
|
+
public get isAuthDone(): boolean {
|
|
81
|
+
return this._isAuthDone;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Getter namespace
|
|
86
|
+
* @return {string }
|
|
87
|
+
*/
|
|
88
|
+
public get namespace(): string {
|
|
89
|
+
return this._namespace;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Getter objects
|
|
94
|
+
* @return {unknown}
|
|
95
|
+
*/
|
|
96
|
+
public get objects(): Record<string, ioBroker.Object> | undefined {
|
|
97
|
+
return this._objects;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Getter type
|
|
102
|
+
* @return {string }
|
|
103
|
+
*/
|
|
104
|
+
public get type(): string {
|
|
105
|
+
return this._type;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Getter timeout
|
|
110
|
+
* @return {number }
|
|
111
|
+
*/
|
|
112
|
+
public get timeout(): number {
|
|
113
|
+
return this._timeout;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Getter user
|
|
118
|
+
* @return {unknown}
|
|
119
|
+
*/
|
|
120
|
+
public get user(): string {
|
|
121
|
+
return this._user;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Setter enums
|
|
126
|
+
* @param {unknown} value
|
|
127
|
+
*/
|
|
128
|
+
public set enums(
|
|
129
|
+
value:
|
|
130
|
+
| {
|
|
131
|
+
[groupName: string]: Record<string, ioBroker.Enum>;
|
|
132
|
+
}
|
|
133
|
+
| undefined,
|
|
134
|
+
) {
|
|
135
|
+
this._enums = value;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Setter namespace
|
|
140
|
+
* @param {string } value
|
|
141
|
+
*/
|
|
142
|
+
public set namespace(value: string) {
|
|
143
|
+
this._namespace = value;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Setter objects
|
|
148
|
+
* @param {unknown} value
|
|
149
|
+
*/
|
|
150
|
+
public set objects(value: Record<string, ioBroker.Object> | undefined) {
|
|
151
|
+
this._objects = value;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Setter type
|
|
156
|
+
* @param {string } value
|
|
157
|
+
*/
|
|
158
|
+
public set type(value: string) {
|
|
159
|
+
this._type = value;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Setter timeout
|
|
164
|
+
* @param {number } value
|
|
165
|
+
*/
|
|
166
|
+
public set timeout(value: number) {
|
|
167
|
+
this._timeout = value;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Setter user
|
|
172
|
+
* @param {unknown} value
|
|
173
|
+
*/
|
|
174
|
+
public set user(value: string) {
|
|
175
|
+
this._user = value;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
//#endregion
|
|
179
|
+
|
|
180
|
+
public constructor(
|
|
181
|
+
connOptions: SocketIOConnectOpts = {},
|
|
182
|
+
connCallbacks: ConnectionCallbacks = new ConnectionCallbacks(),
|
|
183
|
+
objectsRequired: boolean = false,
|
|
184
|
+
) {
|
|
185
|
+
// init namespace
|
|
186
|
+
if (typeof socketNamespace !== 'undefined') this.namespace = socketNamespace;
|
|
187
|
+
|
|
188
|
+
if (!connOptions.name) connOptions.name = this.namespace;
|
|
189
|
+
|
|
190
|
+
// To start vis as local use one of:
|
|
191
|
+
// - start vis from directory with name local, e.g. c:/blbla/local/ioBroker.vis/www/index.html
|
|
192
|
+
// - do not create "_socket/info.js" file in "www" directory
|
|
193
|
+
// - create "_socket/info.js" file with
|
|
194
|
+
// var socketUrl = "local"; var socketSession = ""; sysLang="en";
|
|
195
|
+
// in this case you can overwrite browser language settings
|
|
196
|
+
if (
|
|
197
|
+
this._isExecutedInBrowser &&
|
|
198
|
+
(document.URL.split('/local/')[1] ||
|
|
199
|
+
(typeof socketUrl === 'undefined' && !connOptions.connLink) ||
|
|
200
|
+
(typeof socketUrl !== 'undefined' && socketUrl === 'local'))
|
|
201
|
+
) {
|
|
202
|
+
this._type = 'local';
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (typeof session !== 'undefined') {
|
|
206
|
+
const user = session.get('user');
|
|
207
|
+
if (user) {
|
|
208
|
+
this._authInfo.user = user;
|
|
209
|
+
this._authInfo.hash = session.get('hash');
|
|
210
|
+
this._authInfo.salt = session.get('salt');
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this._connCallbacks = connCallbacks;
|
|
215
|
+
|
|
216
|
+
let connLink = connOptions.connLink;
|
|
217
|
+
if (!connOptions.connLink && this._isExecutedInBrowser) {
|
|
218
|
+
connLink = window.localStorage.getItem('connLink');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Connection data from "/_socket/info.js"
|
|
222
|
+
if (!connLink && typeof socketUrl !== 'undefined') connLink = socketUrl;
|
|
223
|
+
if (!connOptions.socketSession && typeof socketSession !== 'undefined') connOptions.socketSession = socketSession;
|
|
224
|
+
if (connOptions.socketForceWebSockets === undefined && typeof socketForceWebSockets !== 'undefined') {
|
|
225
|
+
connOptions.socketForceWebSockets = socketForceWebSockets;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
connOptions.socketSession = connOptions.socketSession || 'nokey';
|
|
229
|
+
|
|
230
|
+
let url;
|
|
231
|
+
if (connLink) {
|
|
232
|
+
url = connLink;
|
|
233
|
+
if (typeof connLink !== 'undefined') {
|
|
234
|
+
if (connLink[0] === ':') connLink = location.protocol + '://' + location.hostname + connLink;
|
|
235
|
+
}
|
|
236
|
+
} else {
|
|
237
|
+
url = location.protocol + '//' + location.host;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const opts: SocketIOClient.ConnectOpts = {
|
|
241
|
+
query: 'key=' + connOptions.socketSession,
|
|
242
|
+
reconnectionDelayMax: 10000,
|
|
243
|
+
reconnectionAttempts: Infinity,
|
|
244
|
+
reconnection: false,
|
|
245
|
+
upgrade: !connOptions.socketForceWebSockets,
|
|
246
|
+
rememberUpgrade: connOptions.socketForceWebSockets,
|
|
247
|
+
transports: connOptions.socketForceWebSockets ? ['websocket'] : undefined,
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Trace, `Going to create socket for url ${url}`);
|
|
251
|
+
console.log(opts);
|
|
252
|
+
this._socket = io(url, opts);
|
|
253
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Trace, 'Created socket');
|
|
254
|
+
|
|
255
|
+
this._socket.on('connect', () => {
|
|
256
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Trace, 'In Connect callback');
|
|
257
|
+
if (this._disconnectedSince) {
|
|
258
|
+
const offlineTime = new Date().getTime() - this._disconnectedSince.getTime();
|
|
259
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'was offline for ' + offlineTime / 1000 + 's');
|
|
260
|
+
|
|
261
|
+
// reload whole page if no connection longer than some period
|
|
262
|
+
if (this._isExecutedInBrowser && this._reloadInterval && offlineTime > this._reloadInterval * 1000) {
|
|
263
|
+
window.location.reload();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
this._disconnectedSince = undefined;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (this._connectInterval) {
|
|
270
|
+
clearInterval(this._connectInterval);
|
|
271
|
+
this._connectInterval = undefined;
|
|
272
|
+
}
|
|
273
|
+
if (this._countInterval) {
|
|
274
|
+
clearInterval(this._countInterval);
|
|
275
|
+
this._countInterval = undefined;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (this.isExecutedInBrowser) {
|
|
279
|
+
const elem = document.getElementById('server-disconnect');
|
|
280
|
+
if (elem) elem.style.display = 'none';
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
this._socket.emit('name', connOptions.name);
|
|
284
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, new Date().toISOString() + ' Connected => authenticate');
|
|
285
|
+
Utils.guardedTimeout(
|
|
286
|
+
() => {
|
|
287
|
+
const wait = Utils.guardedTimeout(
|
|
288
|
+
() => {
|
|
289
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Error, 'No answer from server');
|
|
290
|
+
if (this._isExecutedInBrowser) window.location.reload();
|
|
291
|
+
},
|
|
292
|
+
3000,
|
|
293
|
+
this,
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
this._socket.emit('authenticate', (isOk: boolean, isSecure: boolean) => {
|
|
297
|
+
clearTimeout(wait);
|
|
298
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, new Date().toISOString() + ' Authenticated: ' + isOk);
|
|
299
|
+
if (isOk) {
|
|
300
|
+
this._onAuth(objectsRequired, isSecure);
|
|
301
|
+
} else {
|
|
302
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'permissionError');
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
},
|
|
306
|
+
50,
|
|
307
|
+
this,
|
|
308
|
+
);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
this._socket.on('reauthenticate', () => {
|
|
312
|
+
if (this._connCallbacks.onConnChange) {
|
|
313
|
+
this._connCallbacks.onConnChange(false);
|
|
314
|
+
if (typeof app !== 'undefined') app.onConnChange(false);
|
|
315
|
+
}
|
|
316
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Warn, 'reauthenticate');
|
|
317
|
+
if (this._isExecutedInBrowser) window.location.reload();
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
this._socket.on('connect_error', (err: unknown) => {
|
|
321
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Error, `Couldn't Connect --> Reconecting (Error: ${err})`);
|
|
322
|
+
|
|
323
|
+
this.reconnect(connOptions);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
this._socket.on('disconnect', () => {
|
|
327
|
+
this._disconnectedSince = new Date();
|
|
328
|
+
|
|
329
|
+
// called only once when connection lost (and it was here before)
|
|
330
|
+
this._isConnected = false;
|
|
331
|
+
if (this._connCallbacks.onConnChange !== undefined) {
|
|
332
|
+
Utils.guardedTimeout(
|
|
333
|
+
() => {
|
|
334
|
+
if (typeof this._connCallbacks.onConnChange !== 'undefined') {
|
|
335
|
+
this._connCallbacks.onConnChange(this._isConnected);
|
|
336
|
+
}
|
|
337
|
+
if (typeof app !== 'undefined') app.onConnChange(this._isConnected);
|
|
338
|
+
},
|
|
339
|
+
5000,
|
|
340
|
+
this,
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// reconnect
|
|
345
|
+
this.reconnect(connOptions);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
// after reconnect the "connect" event will be called
|
|
349
|
+
this._socket.on('reconnect', () => {
|
|
350
|
+
const discoSinceTime: number = this._disconnectedSince === undefined ? 0 : this._disconnectedSince?.getTime();
|
|
351
|
+
const offlineTime = new Date().getTime() - discoSinceTime;
|
|
352
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Info, `was offline for ${offlineTime / 1000}s`);
|
|
353
|
+
|
|
354
|
+
// reload whole page if no connection longer than one minute
|
|
355
|
+
if (this._reloadInterval && offlineTime > this._reloadInterval * 1000) {
|
|
356
|
+
window.location.reload();
|
|
357
|
+
}
|
|
358
|
+
// anyway "on connect" is called
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
this._socket.on('objectChange', (id: string, obj: ioBroker.Object) => {
|
|
362
|
+
// If cache used
|
|
363
|
+
if (this._useStorage && typeof storage !== 'undefined') {
|
|
364
|
+
const objects = this._objects || storage.get('objects');
|
|
365
|
+
if (objects) {
|
|
366
|
+
if (obj) {
|
|
367
|
+
objects[id] = obj;
|
|
368
|
+
} else {
|
|
369
|
+
if (objects[id]) delete objects[id];
|
|
370
|
+
}
|
|
371
|
+
storage.set('objects', objects);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
if (this._connCallbacks.onObjectChange) {
|
|
376
|
+
this._connCallbacks.onObjectChange(id, obj);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
this._socket.on('stateChange', (id: string, state: ioBroker.State) => {
|
|
381
|
+
if (!id || state === null || typeof state !== 'object') return;
|
|
382
|
+
|
|
383
|
+
if (this._connCallbacks.onCommand && id === this.namespace + '.control.command') {
|
|
384
|
+
if (state.ack) return;
|
|
385
|
+
|
|
386
|
+
if (
|
|
387
|
+
state.val &&
|
|
388
|
+
typeof state.val === 'string' &&
|
|
389
|
+
state.val[0] === '{' &&
|
|
390
|
+
state.val[state.val.length - 1] === '}'
|
|
391
|
+
) {
|
|
392
|
+
try {
|
|
393
|
+
state.val = JSON.parse(state.val);
|
|
394
|
+
} catch (e) {
|
|
395
|
+
SocketIoLogging.writeLog(
|
|
396
|
+
SocketIoLogLevel.Debug,
|
|
397
|
+
'Command seems to be an object, but cannot parse it: ' + state.val,
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
// if command is an object {instance: 'iii', command: 'cmd', data: 'ddd'}
|
|
402
|
+
if (state.val && typeof state.val === 'object' && (state.val as unknown).instance) {
|
|
403
|
+
// vis only:
|
|
404
|
+
const visCommand: SocketIOVisCommand = new SocketIOVisCommand(state.val as unknown);
|
|
405
|
+
if (this._connCallbacks.onCommand(visCommand.instance, visCommand.command, visCommand.data)) {
|
|
406
|
+
// clear state
|
|
407
|
+
this.setState(id, { val: '', ack: true });
|
|
408
|
+
}
|
|
409
|
+
} else {
|
|
410
|
+
if (this._connCallbacks.onCommand(this._cmdInstance, state.val, this._cmdData)) {
|
|
411
|
+
// clear state
|
|
412
|
+
this.setState(id, { val: '', ack: true });
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
} else if (id === this.namespace + '.control.data') {
|
|
416
|
+
this._cmdData = state.val;
|
|
417
|
+
} else if (id === this.namespace + '.control.instance') {
|
|
418
|
+
this._cmdInstance = state.val as string;
|
|
419
|
+
} else if (this._connCallbacks.onUpdate) {
|
|
420
|
+
this._connCallbacks.onUpdate(id, state);
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
this._socket.on('permissionError', (err: Error) => {
|
|
425
|
+
if (this._connCallbacks.onError) {
|
|
426
|
+
/* {
|
|
427
|
+
command:
|
|
428
|
+
type:
|
|
429
|
+
operation:
|
|
430
|
+
arg:
|
|
431
|
+
}*/
|
|
432
|
+
this._connCallbacks.onError(err);
|
|
433
|
+
} else {
|
|
434
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'permissionError');
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private _checkConnection(pFunc: unknown, pArguments: IArguments): boolean {
|
|
440
|
+
if (!this._isConnected) {
|
|
441
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Warn, 'No connection!');
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (this._queueCmdIfRequired(pFunc, pArguments)) {
|
|
446
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Warn, 'Command queued');
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
//socket.io
|
|
451
|
+
if (this._socket === null) {
|
|
452
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Warn, 'socket.io not initialized');
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
private _monitor(): void {
|
|
459
|
+
if (this._timer !== undefined) return;
|
|
460
|
+
const ts: number = new Date().getTime();
|
|
461
|
+
const lastTimerTime: number = this._lastTimer === undefined ? 0 : this._lastTimer.getTime();
|
|
462
|
+
if (this._reloadInterval && ts - lastTimerTime > this._reloadInterval * 1000) {
|
|
463
|
+
// It seems, that PC was in a sleep => Reload page to request authentication anew
|
|
464
|
+
if (this._isExecutedInBrowser) window.location.reload();
|
|
465
|
+
} else {
|
|
466
|
+
this._lastTimer = new Date(ts);
|
|
467
|
+
}
|
|
468
|
+
this._timer = Utils.guardedTimeout(
|
|
469
|
+
() => {
|
|
470
|
+
this._timer = undefined;
|
|
471
|
+
this._monitor();
|
|
472
|
+
},
|
|
473
|
+
10000,
|
|
474
|
+
this,
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
private _onAuth(pObjectsRequired: boolean, pIsSecure: boolean): void {
|
|
479
|
+
this._isSecure = pIsSecure;
|
|
480
|
+
|
|
481
|
+
if (this._isSecure) {
|
|
482
|
+
this._lastTimer = new Date();
|
|
483
|
+
this._monitor();
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
this._socket.emit('subscribe', '*');
|
|
487
|
+
if (pObjectsRequired) this._socket.emit('subscribeObjects', '*');
|
|
488
|
+
|
|
489
|
+
if (this._isConnected === true) {
|
|
490
|
+
// This seems to be a reconnect because we're already connected!
|
|
491
|
+
// -> prevent firing onConnChange twice
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
this._isConnected = true;
|
|
496
|
+
if (this._connCallbacks.onConnChange) {
|
|
497
|
+
Utils.guardedNewThread(() => {
|
|
498
|
+
this._socket.emit('authEnabled', (auth: unknown, user: string) => {
|
|
499
|
+
this._user = user;
|
|
500
|
+
if (typeof this._connCallbacks.onConnChange !== 'undefined') {
|
|
501
|
+
this._connCallbacks.onConnChange(this._isConnected);
|
|
502
|
+
}
|
|
503
|
+
if (typeof app !== 'undefined') app.onConnChange(this._isConnected);
|
|
504
|
+
});
|
|
505
|
+
}, this);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
public reconnect(pConnOptions: unknown): void {
|
|
510
|
+
// reconnect
|
|
511
|
+
if (this._connectInterval !== undefined || (pConnOptions.mayReconnect && !pConnOptions.mayReconnect())) {
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
this._connectInterval = Utils.guardedInterval(
|
|
516
|
+
() => {
|
|
517
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'Trying connect...');
|
|
518
|
+
this._socket.connect();
|
|
519
|
+
this._countDown = Math.floor(this._reconnectInterval / 1000);
|
|
520
|
+
SocketIoLogging.writeLog(
|
|
521
|
+
SocketIoLogLevel.Trace,
|
|
522
|
+
`Connection.ts: Connection Retry Countdown ${this._countDown}`,
|
|
523
|
+
);
|
|
524
|
+
},
|
|
525
|
+
this._reconnectInterval,
|
|
526
|
+
this,
|
|
527
|
+
);
|
|
528
|
+
|
|
529
|
+
this._countDown = Math.floor(this._reconnectInterval / 1000);
|
|
530
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Trace, `Connection.ts: Connection Retry Countdown ${this._countDown}`);
|
|
531
|
+
|
|
532
|
+
this._countInterval = Utils.guardedInterval(
|
|
533
|
+
() => {
|
|
534
|
+
this._countDown--;
|
|
535
|
+
SocketIoLogging.writeLog(
|
|
536
|
+
SocketIoLogLevel.Trace,
|
|
537
|
+
`Connection.ts: Connection Retry Countdown ${this._countDown}`,
|
|
538
|
+
);
|
|
539
|
+
},
|
|
540
|
+
1000,
|
|
541
|
+
this,
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// FIXME: CallBack Type
|
|
546
|
+
public logout(callback: unknown): void {
|
|
547
|
+
if (!this._isConnected) {
|
|
548
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'No connection!');
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
this._socket.emit('logout', callback);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// FIXME: CallBack Type
|
|
556
|
+
public getVersion(callback: unknown): void {
|
|
557
|
+
if (!this._checkConnection('getVersion', arguments)) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
this._socket.emit(
|
|
562
|
+
'getVersion',
|
|
563
|
+
// FIXME: version Type
|
|
564
|
+
(error: unknown, version: string) => {
|
|
565
|
+
if (callback) {
|
|
566
|
+
callback(error, version);
|
|
567
|
+
}
|
|
568
|
+
},
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// FIXME: CallBack Type
|
|
573
|
+
private _checkAuth(callback: unknown) {
|
|
574
|
+
if (!this._isConnected) {
|
|
575
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, '_checkAuth: No connection!');
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
//socket.io
|
|
579
|
+
if (this._socket === null) {
|
|
580
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.DeepTrace, '_checkAuth: socket.io not initialized');
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
this._socket.emit(
|
|
584
|
+
'getVersion',
|
|
585
|
+
// FIXME: CallBack Type
|
|
586
|
+
(error: unknown, version: unknown) => {
|
|
587
|
+
if (callback) {
|
|
588
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.DeepTrace, '_checkAuth: socket.io getVersion Callback');
|
|
589
|
+
callback(error, version);
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
public readFile(filename: string, callback: ioBroker.ReadFileCallback, isRemote: boolean): void {
|
|
596
|
+
if (!callback) throw 'No callback set';
|
|
597
|
+
|
|
598
|
+
if (this._type === 'local') {
|
|
599
|
+
try {
|
|
600
|
+
const data = storage.get(filename);
|
|
601
|
+
callback(null, data ? JSON.parse(storage.get(filename)) : null);
|
|
602
|
+
} catch (err) {
|
|
603
|
+
callback(err, undefined);
|
|
604
|
+
}
|
|
605
|
+
} else {
|
|
606
|
+
if (!this._checkConnection('readFile', arguments)) return;
|
|
607
|
+
|
|
608
|
+
if (!isRemote && typeof app !== 'undefined') {
|
|
609
|
+
app.readLocalFile(filename.replace(/^\/vis\.0\//, ''), callback);
|
|
610
|
+
} else {
|
|
611
|
+
let adapter = this.namespace;
|
|
612
|
+
if (filename[0] === '/') {
|
|
613
|
+
const p = filename.split('/');
|
|
614
|
+
adapter = p[1];
|
|
615
|
+
p.splice(0, 2);
|
|
616
|
+
filename = p.join('/');
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
this._socket.emit(
|
|
620
|
+
'readFile',
|
|
621
|
+
adapter,
|
|
622
|
+
filename,
|
|
623
|
+
(err: Error, data: string | Buffer | undefined, mimeType: string) => {
|
|
624
|
+
Utils.guardedNewThread(() => {
|
|
625
|
+
callback(err, data, mimeType);
|
|
626
|
+
}, this);
|
|
627
|
+
},
|
|
628
|
+
);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
public getMimeType(ext: string): string {
|
|
634
|
+
if (ext.indexOf('.') !== -1) {
|
|
635
|
+
const regMatch = ext.toLowerCase().match(/\.[^.]+$/);
|
|
636
|
+
ext = regMatch !== null && regMatch.length > 0 ? regMatch[0] : '';
|
|
637
|
+
}
|
|
638
|
+
let _mimeType = '';
|
|
639
|
+
if (ext === '.css') {
|
|
640
|
+
_mimeType = 'text/css';
|
|
641
|
+
} else if (ext === '.bmp') {
|
|
642
|
+
_mimeType = 'image/bmp';
|
|
643
|
+
} else if (ext === '.png') {
|
|
644
|
+
_mimeType = 'image/png';
|
|
645
|
+
} else if (ext === '.jpg') {
|
|
646
|
+
_mimeType = 'image/jpeg';
|
|
647
|
+
} else if (ext === '.jpeg') {
|
|
648
|
+
_mimeType = 'image/jpeg';
|
|
649
|
+
} else if (ext === '.gif') {
|
|
650
|
+
_mimeType = 'image/gif';
|
|
651
|
+
} else if (ext === '.tif') {
|
|
652
|
+
_mimeType = 'image/tiff';
|
|
653
|
+
} else if (ext === '.js') {
|
|
654
|
+
_mimeType = 'application/javascript';
|
|
655
|
+
} else if (ext === '.html') {
|
|
656
|
+
_mimeType = 'text/html';
|
|
657
|
+
} else if (ext === '.htm') {
|
|
658
|
+
_mimeType = 'text/html';
|
|
659
|
+
} else if (ext === '.json') {
|
|
660
|
+
_mimeType = 'application/json';
|
|
661
|
+
} else if (ext === '.xml') {
|
|
662
|
+
_mimeType = 'text/xml';
|
|
663
|
+
} else if (ext === '.svg') {
|
|
664
|
+
_mimeType = 'image/svg+xml';
|
|
665
|
+
} else if (ext === '.eot') {
|
|
666
|
+
_mimeType = 'application/vnd.ms-fontobject';
|
|
667
|
+
} else if (ext === '.ttf') {
|
|
668
|
+
_mimeType = 'application/font-sfnt';
|
|
669
|
+
} else if (ext === '.woff') {
|
|
670
|
+
_mimeType = 'application/font-woff';
|
|
671
|
+
} else if (ext === '.wav') {
|
|
672
|
+
_mimeType = 'audio/wav';
|
|
673
|
+
} else if (ext === '.mp3') {
|
|
674
|
+
_mimeType = 'audio/mpeg3';
|
|
675
|
+
} else {
|
|
676
|
+
_mimeType = 'text/javascript';
|
|
677
|
+
}
|
|
678
|
+
return _mimeType;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// FIXME: Callback Type
|
|
682
|
+
public readFile64(filename: string, callback: unknown, isRemote: boolean): void {
|
|
683
|
+
if (!callback) {
|
|
684
|
+
throw 'No callback set';
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (!this._checkConnection('readFile', arguments)) return;
|
|
688
|
+
|
|
689
|
+
if (!isRemote && typeof app !== 'undefined') {
|
|
690
|
+
// FIXME: data Type
|
|
691
|
+
app.readLocalFile(filename.replace(/^\/vis\.0\//, ''), (err: Error, data: string, mimeType: string) => {
|
|
692
|
+
Utils.guardedNewThread(() => {
|
|
693
|
+
if (data) {
|
|
694
|
+
callback(err, { mime: mimeType || this.getMimeType(filename), data: btoa(data) }, filename);
|
|
695
|
+
} else {
|
|
696
|
+
callback(err, filename);
|
|
697
|
+
}
|
|
698
|
+
}, this);
|
|
699
|
+
});
|
|
700
|
+
} else {
|
|
701
|
+
let adapter = this.namespace;
|
|
702
|
+
if (filename[0] === '/') {
|
|
703
|
+
const p = filename.split('/');
|
|
704
|
+
adapter = p[1];
|
|
705
|
+
p.splice(0, 2);
|
|
706
|
+
filename = p.join('/');
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
this._socket.emit(
|
|
710
|
+
'readFile64',
|
|
711
|
+
adapter,
|
|
712
|
+
filename,
|
|
713
|
+
// FIXME: data Type
|
|
714
|
+
(err: Error, data: unknown, mimeType: string) => {
|
|
715
|
+
Utils.guardedNewThread(() => {
|
|
716
|
+
if (data) {
|
|
717
|
+
callback(err, { mime: mimeType || this.getMimeType(filename), data: data }, filename);
|
|
718
|
+
} else {
|
|
719
|
+
callback(err, { mime: mimeType || this.getMimeType(filename) }, filename);
|
|
720
|
+
}
|
|
721
|
+
}, this);
|
|
722
|
+
},
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
public writeFile(
|
|
728
|
+
filename: string,
|
|
729
|
+
data: unknown | string,
|
|
730
|
+
mode: number,
|
|
731
|
+
callback: ioBroker.ErrnoCallback,
|
|
732
|
+
...args: unknown[]
|
|
733
|
+
): void {
|
|
734
|
+
if (this._type === 'local') {
|
|
735
|
+
storage.set(filename, JSON.stringify(data));
|
|
736
|
+
if (callback) {
|
|
737
|
+
callback();
|
|
738
|
+
}
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if (!this._checkConnection('writeFile', arguments)) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
const sData: string = typeof data === 'object' ? JSON.stringify(data, null, 2) : data;
|
|
746
|
+
|
|
747
|
+
const parts = filename.split('/');
|
|
748
|
+
const adapter = parts[1];
|
|
749
|
+
parts.splice(0, 2);
|
|
750
|
+
if (adapter === 'vis') {
|
|
751
|
+
this._socket.emit(
|
|
752
|
+
'writeFile',
|
|
753
|
+
adapter,
|
|
754
|
+
parts.join('/'),
|
|
755
|
+
sData,
|
|
756
|
+
mode ? { mode: this._defaultMode } : {},
|
|
757
|
+
callback,
|
|
758
|
+
);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
this._socket.emit('writeFile', this.namespace, filename, sData, mode ? { mode: this._defaultMode } : {}, callback);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Write file base 64
|
|
766
|
+
public writeFile64(filename: string, data: string, callback: ioBroker.ErrnoCallback): void {
|
|
767
|
+
if (!this._checkConnection('writeFile', arguments)) return;
|
|
768
|
+
|
|
769
|
+
const parts = filename.split('/');
|
|
770
|
+
const adapter = parts[1];
|
|
771
|
+
parts.splice(0, 2);
|
|
772
|
+
|
|
773
|
+
this._socket.emit('writeFile', adapter, parts.join('/'), atob(data), { mode: this._defaultMode }, callback);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
public readDir(dirname: string, callback: ioBroker.ReadDirCallback): void {
|
|
777
|
+
//socket.io
|
|
778
|
+
if (this._socket === null) {
|
|
779
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'socket.io not initialized');
|
|
780
|
+
return;
|
|
781
|
+
}
|
|
782
|
+
if (!dirname) dirname = '/';
|
|
783
|
+
const parts = dirname.split('/');
|
|
784
|
+
const adapter = parts[1];
|
|
785
|
+
parts.splice(0, 2);
|
|
786
|
+
|
|
787
|
+
this._socket.emit(
|
|
788
|
+
'readDir',
|
|
789
|
+
adapter,
|
|
790
|
+
parts.join('/'),
|
|
791
|
+
{ filter: true },
|
|
792
|
+
(err: Error, data: ioBroker.ReadDirResult[]) => {
|
|
793
|
+
if (callback) callback(err, data);
|
|
794
|
+
},
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
public mkdir(dirname: string, callback: ioBroker.ErrnoCallback): void {
|
|
799
|
+
const parts = dirname.split('/');
|
|
800
|
+
const adapter = parts[1];
|
|
801
|
+
parts.splice(0, 2);
|
|
802
|
+
|
|
803
|
+
this._socket.emit('mkdir', adapter, parts.join('/'), (err: Error) => {
|
|
804
|
+
callback && callback(err);
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
public unlink(name: string, callback: ioBroker.ErrorCallback): void {
|
|
809
|
+
const parts = name.split('/');
|
|
810
|
+
const adapter = parts[1];
|
|
811
|
+
parts.splice(0, 2);
|
|
812
|
+
|
|
813
|
+
this._socket.emit('unlink', adapter, parts.join('/'), (err: Error) => {
|
|
814
|
+
callback && callback(err);
|
|
815
|
+
});
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
public renameFile(oldname: string, newname: string, callback: ioBroker.ErrnoCallback): void {
|
|
819
|
+
const parts1 = oldname.split('/');
|
|
820
|
+
const adapter = parts1[1];
|
|
821
|
+
parts1.splice(0, 2);
|
|
822
|
+
const parts2 = newname.split('/');
|
|
823
|
+
parts2.splice(0, 2);
|
|
824
|
+
this._socket.emit('rename', adapter, parts1.join('/'), parts2.join('/'), (err: Error) => {
|
|
825
|
+
callback && callback(err);
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
public setState(
|
|
830
|
+
pointId: string,
|
|
831
|
+
state: string | number | boolean | ioBroker.State | ioBroker.SettableState | null,
|
|
832
|
+
callback?: ioBroker.SetStateCallback,
|
|
833
|
+
): void {
|
|
834
|
+
//socket.io
|
|
835
|
+
if (this._socket === null) {
|
|
836
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'socket.io not initialized');
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
if (!callback) {
|
|
840
|
+
callback = (err?, id?) => {
|
|
841
|
+
if (err) {
|
|
842
|
+
SocketIoLogging.writeLog(
|
|
843
|
+
SocketIoLogLevel.Error,
|
|
844
|
+
`socket.io setState Error: ${err}\nwith updating ${pointId} to value ${state}\nid:${id}`,
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
}
|
|
849
|
+
this._socket.emit('setState', pointId, state, callback);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
public sendTo(
|
|
853
|
+
instance: string,
|
|
854
|
+
command: string,
|
|
855
|
+
payload: ioBroker.MessagePayload,
|
|
856
|
+
callback: ioBroker.MessageCallback | ioBroker.MessageCallbackInfo,
|
|
857
|
+
): void {
|
|
858
|
+
//socket.io
|
|
859
|
+
if (this._socket === null) {
|
|
860
|
+
//SocketIoLogging.writeLog(SocketIoLogLevel.Debug,'socket.io not initialized');
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
this._socket.emit('sendTo', instance, command, payload, callback);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// callback(err: Error, data)
|
|
867
|
+
public getStates(IDs: string[] | null, callback: ioBroker.GetStatesCallback): void {
|
|
868
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.DeepTrace, 'getStates');
|
|
869
|
+
if (this._type === 'local') {
|
|
870
|
+
return callback(null, {});
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
if (!this._checkConnection('getStates', arguments)) {
|
|
874
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'getStates: No Connection');
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
this._gettingStates = this._gettingStates || 0;
|
|
878
|
+
this._gettingStates++;
|
|
879
|
+
if (this._gettingStates > 1) {
|
|
880
|
+
// fix for slow devices
|
|
881
|
+
SocketIoLogging.writeLog(
|
|
882
|
+
SocketIoLogLevel.Trace,
|
|
883
|
+
'Trying to get empty list, because the whole list could not be loaded',
|
|
884
|
+
);
|
|
885
|
+
// FIXME: Check if this is correct to get all
|
|
886
|
+
IDs = null;
|
|
887
|
+
}
|
|
888
|
+
this._socket.emit('getStates', IDs, (err: Error, data: Record<string, ioBroker.State>) => {
|
|
889
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Trace, `getStates Callback; Error: "${err}"`);
|
|
890
|
+
this._gettingStates !== undefined && this._gettingStates--;
|
|
891
|
+
if (err || !data) {
|
|
892
|
+
if (callback) {
|
|
893
|
+
callback(err || new Error('Authentication required'));
|
|
894
|
+
}
|
|
895
|
+
} else if (callback) {
|
|
896
|
+
callback(null, data);
|
|
897
|
+
}
|
|
898
|
+
});
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// TODO: check if ioBroker.Object is correct
|
|
902
|
+
private _fillChildren(objects: { [id: string]: ioBroker.Object & { children?: string[] } }): void {
|
|
903
|
+
const items: Array<string> = [];
|
|
904
|
+
|
|
905
|
+
for (const id in objects) {
|
|
906
|
+
items.push(id);
|
|
907
|
+
}
|
|
908
|
+
items.sort();
|
|
909
|
+
|
|
910
|
+
for (let i = 0; i < items.length; i++) {
|
|
911
|
+
if (objects[items[i]].common) {
|
|
912
|
+
let j = i + 1;
|
|
913
|
+
const children = [];
|
|
914
|
+
const len = items[i].length + 1;
|
|
915
|
+
const name = items[i] + '.';
|
|
916
|
+
while (j < items.length && items[j].substring(0, len) === name) {
|
|
917
|
+
children.push(items[j++]);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
objects[items[i]].children = children;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// callback(err: Error, data)
|
|
926
|
+
public getObjects(useCache: boolean, callback: ioBroker.GetObjectsCallback): void {
|
|
927
|
+
if (typeof useCache === 'function') {
|
|
928
|
+
callback = useCache;
|
|
929
|
+
useCache = false;
|
|
930
|
+
}
|
|
931
|
+
// If cache used
|
|
932
|
+
if (this._useStorage && useCache) {
|
|
933
|
+
if (typeof storage !== 'undefined') {
|
|
934
|
+
const objects = this._objects || storage.get('objects');
|
|
935
|
+
if (objects) return callback(null, objects);
|
|
936
|
+
} else if (this._objects) {
|
|
937
|
+
return callback(null, this._objects);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
if (!this._checkConnection('getObjects', arguments)) return;
|
|
942
|
+
this._socket.emit('getObjects', (err: Error, data: Record<string, ioBroker.Object>) => {
|
|
943
|
+
if (err) {
|
|
944
|
+
callback(err);
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Read all enums
|
|
949
|
+
this._socket.emit(
|
|
950
|
+
'getObjectView',
|
|
951
|
+
'system',
|
|
952
|
+
'enum',
|
|
953
|
+
{ startkey: 'enum.', endkey: 'enum.\u9999' },
|
|
954
|
+
(err: Error, res: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
955
|
+
if (err) {
|
|
956
|
+
callback(err);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
const enums: Record<string, ioBroker.Object> = {};
|
|
960
|
+
for (const row of res.rows) {
|
|
961
|
+
const currentId = row.id;
|
|
962
|
+
if (row.value !== null) {
|
|
963
|
+
data[currentId] = row.value;
|
|
964
|
+
enums[currentId] = row.value;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
// Read all adapters for images
|
|
969
|
+
this._socket.emit(
|
|
970
|
+
'getObjectView',
|
|
971
|
+
'system',
|
|
972
|
+
'instance',
|
|
973
|
+
{ startkey: 'system.adapter.', endkey: 'system.adapter.\u9999' },
|
|
974
|
+
(err: Error, res: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
975
|
+
if (err) {
|
|
976
|
+
callback(err);
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
for (const row of res.rows) {
|
|
980
|
+
if (row.value !== null) {
|
|
981
|
+
data[row.id] = row.value;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
// find out default file mode
|
|
985
|
+
if (
|
|
986
|
+
data['system.adapter.' + this.namespace] &&
|
|
987
|
+
data['system.adapter.' + this.namespace].native &&
|
|
988
|
+
data['system.adapter.' + this.namespace].native.defaultFileMode
|
|
989
|
+
) {
|
|
990
|
+
this._defaultMode = data['system.adapter.' + this.namespace].native.defaultFileMode;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
// Read all channels for images
|
|
994
|
+
this._socket.emit(
|
|
995
|
+
'getObjectView',
|
|
996
|
+
'system',
|
|
997
|
+
'channel',
|
|
998
|
+
{ startkey: '', endkey: '\u9999' },
|
|
999
|
+
(err: Error, res: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
1000
|
+
if (err) {
|
|
1001
|
+
callback(err);
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
for (const row of res.rows) {
|
|
1006
|
+
if (row.value !== null) {
|
|
1007
|
+
data[row.id] = row.value;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Read all devices for images
|
|
1012
|
+
this._socket.emit(
|
|
1013
|
+
'getObjectView',
|
|
1014
|
+
'system',
|
|
1015
|
+
'device',
|
|
1016
|
+
{ startkey: '', endkey: '\u9999' },
|
|
1017
|
+
(err: Error, res: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
1018
|
+
if (err) {
|
|
1019
|
+
callback(err);
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
for (const row of res.rows) {
|
|
1024
|
+
if (row.value !== null) {
|
|
1025
|
+
data[row.id] = row.value;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
if (this._useStorage) {
|
|
1030
|
+
this._fillChildren(data);
|
|
1031
|
+
this._objects = data;
|
|
1032
|
+
this._enums = enums;
|
|
1033
|
+
|
|
1034
|
+
if (typeof storage !== 'undefined') {
|
|
1035
|
+
storage.set('objects', data);
|
|
1036
|
+
storage.set('enums', enums);
|
|
1037
|
+
storage.set('timeSync', new Date().getTime());
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
if (callback) callback(err, data);
|
|
1042
|
+
},
|
|
1043
|
+
);
|
|
1044
|
+
},
|
|
1045
|
+
);
|
|
1046
|
+
},
|
|
1047
|
+
);
|
|
1048
|
+
},
|
|
1049
|
+
);
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
public getChildren(
|
|
1054
|
+
id: string,
|
|
1055
|
+
useCache: boolean,
|
|
1056
|
+
callback: (err?: Error | null, children?: string[]) => void,
|
|
1057
|
+
...args: unknown[]
|
|
1058
|
+
): void {
|
|
1059
|
+
if (!this._checkConnection('getChildren', arguments)) return;
|
|
1060
|
+
|
|
1061
|
+
if (!id) return callback(new Error('getChildren: no id given'));
|
|
1062
|
+
|
|
1063
|
+
const data: Record<string, ioBroker.Object> = {};
|
|
1064
|
+
|
|
1065
|
+
if (this._useStorage && useCache) {
|
|
1066
|
+
if (typeof storage !== 'undefined') {
|
|
1067
|
+
const objects = storage.get('objects');
|
|
1068
|
+
if (objects && objects[id] && objects[id].children) {
|
|
1069
|
+
return callback(null, objects[id].children);
|
|
1070
|
+
}
|
|
1071
|
+
} else if (this._objects && this._objects[id] && this._objects[id].children) {
|
|
1072
|
+
return callback(null, this._objects[id].children);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// Read all devices
|
|
1077
|
+
this._socket.emit(
|
|
1078
|
+
'getObjectView',
|
|
1079
|
+
'system',
|
|
1080
|
+
'device',
|
|
1081
|
+
{ startkey: id + '.', endkey: id + '.\u9999' },
|
|
1082
|
+
(err: Error, res: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
1083
|
+
if (err) {
|
|
1084
|
+
callback(err);
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
for (const row of res.rows) {
|
|
1089
|
+
if (row.value !== null) {
|
|
1090
|
+
data[row.id] = row.value;
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
this._socket.emit(
|
|
1095
|
+
'getObjectView',
|
|
1096
|
+
'system',
|
|
1097
|
+
'channel',
|
|
1098
|
+
{ startkey: id + '.', endkey: id + '.\u9999' },
|
|
1099
|
+
(err: Error, res: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
1100
|
+
if (err) {
|
|
1101
|
+
callback(err);
|
|
1102
|
+
return;
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
for (const row of res.rows) {
|
|
1106
|
+
if (row.value !== null) {
|
|
1107
|
+
data[row.id] = row.value;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// Read all adapters for images
|
|
1112
|
+
this._socket.emit(
|
|
1113
|
+
'getObjectView',
|
|
1114
|
+
'system',
|
|
1115
|
+
'state',
|
|
1116
|
+
{ startkey: id + '.', endkey: id + '.\u9999' },
|
|
1117
|
+
(err: Error, res: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
1118
|
+
if (err) {
|
|
1119
|
+
callback(err);
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
for (const row of res.rows) {
|
|
1124
|
+
if (row.value !== null) {
|
|
1125
|
+
data[row.id] = row.value;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
const list = [];
|
|
1130
|
+
|
|
1131
|
+
const count = id.split('.').length;
|
|
1132
|
+
|
|
1133
|
+
// find direct children
|
|
1134
|
+
for (const _id in data) {
|
|
1135
|
+
const parts = _id.split('.');
|
|
1136
|
+
if (count + 1 === parts.length) {
|
|
1137
|
+
list.push(_id);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
list.sort();
|
|
1141
|
+
|
|
1142
|
+
if (this._useStorage && typeof storage !== 'undefined') {
|
|
1143
|
+
const objects = storage.get('objects') || {};
|
|
1144
|
+
|
|
1145
|
+
for (const id_ in data) {
|
|
1146
|
+
objects[id_] = data[id_];
|
|
1147
|
+
}
|
|
1148
|
+
if (objects[id] && objects[id].common) {
|
|
1149
|
+
objects[id].children = list;
|
|
1150
|
+
}
|
|
1151
|
+
// Store for every element theirs children
|
|
1152
|
+
const items = [];
|
|
1153
|
+
for (const __id in data) {
|
|
1154
|
+
items.push(__id);
|
|
1155
|
+
}
|
|
1156
|
+
items.sort();
|
|
1157
|
+
|
|
1158
|
+
for (let k = 0; k < items.length; k++) {
|
|
1159
|
+
if (objects[items[k]].common) {
|
|
1160
|
+
let j = k + 1;
|
|
1161
|
+
const children = [];
|
|
1162
|
+
const len = items[k].length + 1;
|
|
1163
|
+
const name = items[k] + '.';
|
|
1164
|
+
while (j < items.length && items[j].substring(0, len) === name) {
|
|
1165
|
+
children.push(items[j++]);
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
objects[items[k]].children = children;
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
storage.set('objects', objects);
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
if (callback) callback(err, list);
|
|
1176
|
+
},
|
|
1177
|
+
);
|
|
1178
|
+
},
|
|
1179
|
+
);
|
|
1180
|
+
},
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
public getObject(id: string, useCache: boolean, callback: ioBroker.GetObjectCallback): void {
|
|
1185
|
+
if (!id) return callback(new Error('no id given'));
|
|
1186
|
+
|
|
1187
|
+
// If cache used
|
|
1188
|
+
if (this._useStorage && useCache && typeof storage !== 'undefined') {
|
|
1189
|
+
if (typeof storage !== 'undefined') {
|
|
1190
|
+
const objects = this._objects || storage.get('objects');
|
|
1191
|
+
if (objects && objects[id]) return callback(null, objects[id]);
|
|
1192
|
+
} else if (this._enums) {
|
|
1193
|
+
return callback(null, this._enums as unknown as ioBroker.OtherObject);
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
this._socket.emit('getObject', id, (err: Error, obj: ioBroker.Object) => {
|
|
1198
|
+
if (err) {
|
|
1199
|
+
callback(err);
|
|
1200
|
+
return;
|
|
1201
|
+
}
|
|
1202
|
+
if (this._useStorage && typeof storage !== 'undefined') {
|
|
1203
|
+
const objects = storage.get('objects') || {};
|
|
1204
|
+
objects[id] = obj;
|
|
1205
|
+
storage.set('objects', objects);
|
|
1206
|
+
}
|
|
1207
|
+
return callback(null, obj);
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
public getEnums(enumName: string, useCache: boolean, callback: ioBroker.GetEnumsCallback): void {
|
|
1212
|
+
// If cache used
|
|
1213
|
+
if (this._useStorage && useCache) {
|
|
1214
|
+
if (typeof storage !== 'undefined') {
|
|
1215
|
+
const enums: { [id: string]: ioBroker.Enum } = this._enums || storage.get('enums');
|
|
1216
|
+
if (enums) return callback(null, enums);
|
|
1217
|
+
} else if (this._enums) {
|
|
1218
|
+
return callback(null, this._enums);
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
if (this._type === 'local') {
|
|
1223
|
+
return callback(null, {});
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
enumName = enumName ? enumName + '.' : '';
|
|
1227
|
+
|
|
1228
|
+
// Read all enums
|
|
1229
|
+
this._socket.emit(
|
|
1230
|
+
'getObjectView',
|
|
1231
|
+
'system',
|
|
1232
|
+
'enum',
|
|
1233
|
+
{ startkey: 'enum.' + enumName, endkey: 'enum.' + enumName + '\u9999' },
|
|
1234
|
+
(err: Error, res: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
1235
|
+
if (err) {
|
|
1236
|
+
callback(err);
|
|
1237
|
+
return;
|
|
1238
|
+
}
|
|
1239
|
+
const enums: Record<string, ioBroker.Object> = {};
|
|
1240
|
+
for (const row of res.rows) {
|
|
1241
|
+
if (row.value !== null) {
|
|
1242
|
+
enums[row.id] = row.value;
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
if (this._useStorage && typeof storage !== 'undefined') {
|
|
1247
|
+
storage.set('enums', enums);
|
|
1248
|
+
}
|
|
1249
|
+
callback(null, enums);
|
|
1250
|
+
},
|
|
1251
|
+
);
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
// return time when the objects were synchronized
|
|
1255
|
+
public getSyncTime(): Date {
|
|
1256
|
+
if (this._useStorage && typeof storage !== 'undefined') {
|
|
1257
|
+
const timeSync = storage.get('timeSync');
|
|
1258
|
+
if (timeSync) return new Date(timeSync);
|
|
1259
|
+
}
|
|
1260
|
+
return new Date(0);
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// FIXME finish implementation of this file
|
|
1264
|
+
public addObject(objId: unknown, obj: unknown, callback: unknown): void {
|
|
1265
|
+
if (!this._isConnected) {
|
|
1266
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'No connection!');
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1269
|
+
//socket.io
|
|
1270
|
+
if (this._socket === null) {
|
|
1271
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'socket.io not initialized');
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
|
|
1276
|
+
public delObject(objId: string): void {
|
|
1277
|
+
if (!this._checkConnection('delObject', arguments)) return;
|
|
1278
|
+
|
|
1279
|
+
this._socket.emit('delObject', objId);
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
public httpGet(url: string, callback: (res: IncomingMessage | Error) => void): void {
|
|
1283
|
+
if (!this._isConnected) {
|
|
1284
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'No connection!');
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
//socket.io
|
|
1288
|
+
if (this._socket === null) {
|
|
1289
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'socket.io not initialized');
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
this._socket.emit('httpGet', url, (data: IncomingMessage | Error) => {
|
|
1293
|
+
if (callback) callback(data);
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
public logError(errorText: string): void {
|
|
1298
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'Error: ' + errorText);
|
|
1299
|
+
if (!this._isConnected) {
|
|
1300
|
+
//SocketIoLogging.writeLog(SocketIoLogLevel.Debug,'No connection!');
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
//socket.io
|
|
1304
|
+
if (this._socket === null) {
|
|
1305
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'socket.io not initialized');
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
this._socket.emit('log', 'error', 'Addon DashUI ' + errorText);
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
private _queueCmdIfRequired(func: string, args: IArguments) {
|
|
1312
|
+
if (this.isAuthDone) {
|
|
1313
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.DeepTrace, `_queueCmdIfRequired: Auth is already done`);
|
|
1314
|
+
return false;
|
|
1315
|
+
}
|
|
1316
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.DeepTrace, `_queueCmdIfRequired: Auth is not yet done`);
|
|
1317
|
+
// Queue command
|
|
1318
|
+
this._cmdQueue.push({ func: func, args: args });
|
|
1319
|
+
if (this._authRunning) {
|
|
1320
|
+
SocketIoLogging.writeLog(
|
|
1321
|
+
SocketIoLogLevel.DeepTrace,
|
|
1322
|
+
`_queueCmdIfRequired: Authentication Process is already Running`,
|
|
1323
|
+
);
|
|
1324
|
+
return true;
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.DeepTrace, `_queueCmdIfRequired: Starting Authentication Process`);
|
|
1328
|
+
this._authRunning = true;
|
|
1329
|
+
// Try to read version
|
|
1330
|
+
this._checkAuth((error: unknown, version: string) => {
|
|
1331
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.DeepTrace, `_queueCmdIfRequired: _checkAuth CB data: "${version}"`);
|
|
1332
|
+
// If we have got version string, so there is no authentication, or we are authenticated
|
|
1333
|
+
this._authRunning = false;
|
|
1334
|
+
if (!version) {
|
|
1335
|
+
// Auth required
|
|
1336
|
+
this._isAuthRequired = true;
|
|
1337
|
+
// What for AuthRequest from server
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
this._isAuthDone = true;
|
|
1341
|
+
// Repeat all stored requests
|
|
1342
|
+
const __cmdQueue = this._cmdQueue;
|
|
1343
|
+
// Trigger GC
|
|
1344
|
+
this._cmdQueue = undefined;
|
|
1345
|
+
this._cmdQueue = [];
|
|
1346
|
+
for (let t = 0, len = __cmdQueue.length; t < len; t++) {
|
|
1347
|
+
(this as unknown)[__cmdQueue[t].func].apply(this, __cmdQueue[t].args);
|
|
1348
|
+
}
|
|
1349
|
+
});
|
|
1350
|
+
|
|
1351
|
+
return true;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
public authenticate(user: string, password: string, salt: string): void {
|
|
1355
|
+
this._authRunning = true;
|
|
1356
|
+
|
|
1357
|
+
if (user !== undefined) {
|
|
1358
|
+
this._authInfo = {
|
|
1359
|
+
user: user,
|
|
1360
|
+
hash: password + salt,
|
|
1361
|
+
salt: salt,
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
if (!this._isConnected) {
|
|
1366
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'No connection!');
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
if (!this._authInfo) {
|
|
1371
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'No credentials!');
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
public getConfig(
|
|
1376
|
+
useCache: boolean,
|
|
1377
|
+
callback: (error: Error | null, conf?: Record<string, any>) => void,
|
|
1378
|
+
...args: unknown[]
|
|
1379
|
+
): void {
|
|
1380
|
+
if (!this._checkConnection('getConfig', arguments)) return;
|
|
1381
|
+
|
|
1382
|
+
if (typeof useCache === 'function') {
|
|
1383
|
+
callback = useCache;
|
|
1384
|
+
useCache = false;
|
|
1385
|
+
}
|
|
1386
|
+
if (this._useStorage && useCache) {
|
|
1387
|
+
if (typeof storage !== 'undefined') {
|
|
1388
|
+
const objects = storage.get('objects');
|
|
1389
|
+
if (objects && objects['system.config']) {
|
|
1390
|
+
return callback(null, objects['system.config'].common);
|
|
1391
|
+
}
|
|
1392
|
+
} else if (this._objects && this._objects['system.config']) {
|
|
1393
|
+
return callback(null, this._objects['system.config'].common);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
this._socket.emit('getObject', 'system.config', (err: Error, obj: ioBroker.Object) => {
|
|
1397
|
+
if (err || !obj || !obj.common) {
|
|
1398
|
+
callback(new Error('Cannot read language'));
|
|
1399
|
+
return;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
if (this._useStorage && typeof storage !== 'undefined') {
|
|
1403
|
+
const objects = storage.get('objects') || {};
|
|
1404
|
+
objects['system.config'] = obj;
|
|
1405
|
+
storage.set('objects', objects);
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
callback(null, obj.common);
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
public sendCommand(
|
|
1413
|
+
instance: string,
|
|
1414
|
+
command: string,
|
|
1415
|
+
data: string | number | boolean | unknown[] | Record<string, any> | null,
|
|
1416
|
+
ack: boolean = true,
|
|
1417
|
+
): void {
|
|
1418
|
+
this.setState(this.namespace + '.control.instance', { val: instance || 'notdefined', ack: true });
|
|
1419
|
+
this.setState(this.namespace + '.control.data', { val: data, ack: true });
|
|
1420
|
+
this.setState(this.namespace + '.control.command', { val: command, ack: ack });
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
private _detectViews(
|
|
1424
|
+
projectDir: string,
|
|
1425
|
+
callback: (
|
|
1426
|
+
err?: NodeJS.ErrnoException | null,
|
|
1427
|
+
obj?: { name: string; readOnly: undefined | boolean; mode: number },
|
|
1428
|
+
) => void,
|
|
1429
|
+
) {
|
|
1430
|
+
this.readDir(
|
|
1431
|
+
'/' + this.namespace + '/' + projectDir,
|
|
1432
|
+
(err?: NodeJS.ErrnoException | null, dirs?: ioBroker.ReadDirResult[]) => {
|
|
1433
|
+
if (err) {
|
|
1434
|
+
callback(err);
|
|
1435
|
+
return;
|
|
1436
|
+
}
|
|
1437
|
+
|
|
1438
|
+
// find vis-views.json
|
|
1439
|
+
if (dirs === undefined) {
|
|
1440
|
+
callback(new Error('No directories found'));
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
for (const dir of dirs) {
|
|
1445
|
+
if (dir.file === 'vis-views.json' && (!dir.acl || dir.acl.read)) {
|
|
1446
|
+
return callback(err, {
|
|
1447
|
+
name: projectDir,
|
|
1448
|
+
readOnly: dir.acl && !dir.acl.write,
|
|
1449
|
+
mode: dir.acl ? dir.acl.permissions : 0,
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
callback(err);
|
|
1454
|
+
},
|
|
1455
|
+
);
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
public readProjects(
|
|
1459
|
+
callback: (
|
|
1460
|
+
err?: NodeJS.ErrnoException | null,
|
|
1461
|
+
objects?: Array<{ name: string; readOnly: undefined | boolean; mode: number }>,
|
|
1462
|
+
) => void,
|
|
1463
|
+
): void {
|
|
1464
|
+
this.readDir('/' + this.namespace, (err?: NodeJS.ErrnoException | null, dirs?: ioBroker.ReadDirResult[]) => {
|
|
1465
|
+
const result: Array<{ name: string; readOnly: undefined | boolean; mode: number }> = [];
|
|
1466
|
+
let count = 0;
|
|
1467
|
+
if (err) {
|
|
1468
|
+
callback(err);
|
|
1469
|
+
return;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
if (dirs === undefined) {
|
|
1473
|
+
callback(new Error('No Dirs Found'));
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
for (const dir of dirs) {
|
|
1478
|
+
if (!dir.isDir) {
|
|
1479
|
+
continue;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
count++;
|
|
1483
|
+
this._detectViews(dir.file, (subErr, project) => {
|
|
1484
|
+
if (project) result.push(project);
|
|
1485
|
+
|
|
1486
|
+
err = err || subErr;
|
|
1487
|
+
if (!--count) callback(err, result);
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
public chmodProject(projectDir: string, mode: number | string, callback: ioBroker.ChownFileCallback): void {
|
|
1494
|
+
//socket.io
|
|
1495
|
+
if (this._socket === null) {
|
|
1496
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'socket.io not initialized');
|
|
1497
|
+
return;
|
|
1498
|
+
}
|
|
1499
|
+
this._socket.emit(
|
|
1500
|
+
'chmodFile',
|
|
1501
|
+
this.namespace,
|
|
1502
|
+
projectDir + '*',
|
|
1503
|
+
{ mode: mode },
|
|
1504
|
+
(err: Error, data?: ioBroker.ChownFileResult[], id?: string) => {
|
|
1505
|
+
if (callback) callback(err, data, id);
|
|
1506
|
+
},
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
public clearCache(): void {
|
|
1511
|
+
if (typeof storage !== 'undefined') {
|
|
1512
|
+
storage.empty();
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
public getHistory(
|
|
1517
|
+
id: string,
|
|
1518
|
+
options: ioBroker.GetHistoryOptions & { timeout?: number },
|
|
1519
|
+
callback: ioBroker.GetHistoryCallback,
|
|
1520
|
+
...args: unknown[]
|
|
1521
|
+
): void {
|
|
1522
|
+
if (!this._checkConnection('getHistory', arguments)) return;
|
|
1523
|
+
|
|
1524
|
+
if (!options) options = {};
|
|
1525
|
+
|
|
1526
|
+
if (!options.timeout) {
|
|
1527
|
+
options.timeout = 2000;
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
let timeout: NodeJS.Timeout | undefined = Utils.guardedTimeout(
|
|
1531
|
+
() => {
|
|
1532
|
+
timeout = undefined;
|
|
1533
|
+
callback(new Error('timeout'));
|
|
1534
|
+
},
|
|
1535
|
+
(options as any).timeout,
|
|
1536
|
+
this,
|
|
1537
|
+
);
|
|
1538
|
+
this._socket.emit('getHistory', id, options, (err: Error, result: ioBroker.GetHistoryResult) => {
|
|
1539
|
+
if (timeout) {
|
|
1540
|
+
clearTimeout(timeout);
|
|
1541
|
+
timeout = undefined;
|
|
1542
|
+
}
|
|
1543
|
+
callback(err, result);
|
|
1544
|
+
});
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
private getLiveHost(callback: (host: string) => void) {
|
|
1548
|
+
this._socket.emit(
|
|
1549
|
+
'getObjectView',
|
|
1550
|
+
'system',
|
|
1551
|
+
'host',
|
|
1552
|
+
{ startkey: 'system.host.', endkey: 'system.host.\u9999' },
|
|
1553
|
+
(err?: Error, res?: { rows: ioBroker.GetObjectViewItem[] }) => {
|
|
1554
|
+
if (err || res === undefined || res.rows.length === 0) {
|
|
1555
|
+
callback('');
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
const _hosts = [];
|
|
1560
|
+
|
|
1561
|
+
for (const row of res.rows) {
|
|
1562
|
+
_hosts.push(row.id + '.alive');
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
this.getStates(_hosts, (err, states) => {
|
|
1566
|
+
if (err) {
|
|
1567
|
+
callback('');
|
|
1568
|
+
}
|
|
1569
|
+
for (const h in states) {
|
|
1570
|
+
if (states[h].val) {
|
|
1571
|
+
callback(h.substring(0, h.length - '.alive'.length));
|
|
1572
|
+
return;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
callback('');
|
|
1576
|
+
});
|
|
1577
|
+
},
|
|
1578
|
+
);
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
private readDirAsZip(project: string, useConvert: boolean = false, callback: ioBroker.ReadDirCallback) {
|
|
1582
|
+
if (!this._isConnected) {
|
|
1583
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'No connection!');
|
|
1584
|
+
return;
|
|
1585
|
+
}
|
|
1586
|
+
//socket.io
|
|
1587
|
+
if (this._socket === null) {
|
|
1588
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'socket.io not initialized');
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
if (project.match(/\/$/)) project = project.substring(0, project.length - 1);
|
|
1592
|
+
|
|
1593
|
+
this.getLiveHost((host) => {
|
|
1594
|
+
if (!host) {
|
|
1595
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Error, 'No active host found');
|
|
1596
|
+
return;
|
|
1597
|
+
}
|
|
1598
|
+
// to do find active host
|
|
1599
|
+
this._socket.emit(
|
|
1600
|
+
'sendToHost',
|
|
1601
|
+
host,
|
|
1602
|
+
'readDirAsZip',
|
|
1603
|
+
{
|
|
1604
|
+
id: this.namespace,
|
|
1605
|
+
name: project || 'main',
|
|
1606
|
+
options: {
|
|
1607
|
+
settings: useConvert,
|
|
1608
|
+
},
|
|
1609
|
+
},
|
|
1610
|
+
// (data: ioBroker.Message) => {
|
|
1611
|
+
// FIXME: ioBroker.Message has no attribute error
|
|
1612
|
+
(data: unknown) => {
|
|
1613
|
+
if (data.error) SocketIoLogging.writeLog(SocketIoLogLevel.Error, data.error);
|
|
1614
|
+
if (callback) callback(data.error, data.data);
|
|
1615
|
+
},
|
|
1616
|
+
);
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
private writeDirAsZip(project: string, base64: string, callback: ioBroker.ReadDirCallback): void {
|
|
1621
|
+
if (!this._isConnected) {
|
|
1622
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'No connection!');
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
//socket.io
|
|
1626
|
+
if (this._socket === null) {
|
|
1627
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Debug, 'socket.io not initialized');
|
|
1628
|
+
return;
|
|
1629
|
+
}
|
|
1630
|
+
if (project.match(/\/$/)) project = project.substring(0, project.length - 1);
|
|
1631
|
+
|
|
1632
|
+
this.getLiveHost((host) => {
|
|
1633
|
+
if (!host) {
|
|
1634
|
+
SocketIoLogging.writeLog(SocketIoLogLevel.Error, 'No active host found');
|
|
1635
|
+
return;
|
|
1636
|
+
}
|
|
1637
|
+
this._socket.emit(
|
|
1638
|
+
'sendToHost',
|
|
1639
|
+
host,
|
|
1640
|
+
'writeDirAsZip',
|
|
1641
|
+
{
|
|
1642
|
+
id: this.namespace,
|
|
1643
|
+
name: project || 'main',
|
|
1644
|
+
data: base64,
|
|
1645
|
+
},
|
|
1646
|
+
// (data: ioBroker.Message) => {
|
|
1647
|
+
// FIXME: ioBroker.Message has no attribute error
|
|
1648
|
+
(data: unknown) => {
|
|
1649
|
+
if (data.error) SocketIoLogging.writeLog(SocketIoLogLevel.Error, data.error);
|
|
1650
|
+
if (callback) callback(data.error, data.message);
|
|
1651
|
+
},
|
|
1652
|
+
);
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
}
|