@iobroker/adapter-react
Version:
React classes to develop admin interfaces for ioBroker with react.
1,694 lines (1,424 loc) • 99.1 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = exports.PROGRESS = exports.ERRORS = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _propTypes = _interopRequireDefault(require("prop-types"));
/**
* Copyright 2020-2022, bluefox <dogafox@gmail.com>
*
* MIT License
*
**/
/** Possible progress states. */
var PROGRESS = {
/** The socket is connecting. */
CONNECTING: 0,
/** The socket is successfully connected. */
CONNECTED: 1,
/** All objects are loaded. */
OBJECTS_LOADED: 2,
/** The socket is ready for use. */
READY: 3
};
exports.PROGRESS = PROGRESS;
var PERMISSION_ERROR = 'permissionError';
var NOT_CONNECTED = 'notConnectedError';
var TIMEOUT_FOR_ADMIN4 = 1300;
var ERRORS = {
PERMISSION_ERROR: PERMISSION_ERROR,
NOT_CONNECTED: NOT_CONNECTED
};
exports.ERRORS = ERRORS;
function fixAdminUI(obj) {
if (obj && obj.common && !obj.common.adminUI) {
if (obj.common.noConfig) {
obj.common.adminUI = obj.common.adminUI || {};
obj.common.adminUI.config = 'none';
} else if (obj.common.jsonConfig) {
obj.common.adminUI = obj.common.adminUI || {};
obj.common.adminUI.config = 'json';
} else if (obj.common.materialize) {
obj.common.adminUI = obj.common.adminUI || {};
obj.common.adminUI.config = 'materialize';
} else {
obj.common.adminUI = obj.common.adminUI || {};
obj.common.adminUI.config = 'html';
}
if (obj.common.jsonCustom) {
obj.common.adminUI = obj.common.adminUI || {};
obj.common.adminUI.custom = 'json';
} else if (obj.common.supportCustoms) {
obj.common.adminUI = obj.common.adminUI || {};
obj.common.adminUI.custom = 'json';
}
if (obj.common.materializeTab && obj.common.adminTab) {
obj.common.adminUI = obj.common.adminUI || {};
obj.common.adminUI.tab = 'materialize';
} else if (obj.common.adminTab) {
obj.common.adminUI = obj.common.adminUI || {};
obj.common.adminUI.tab = 'html';
}
obj.common.adminUI && console.debug("Please add to \"".concat(obj._id.replace(/\.\d+$/, ''), "\" common.adminUI=").concat(JSON.stringify(obj.common.adminUI)));
}
return obj;
}
var Connection = /*#__PURE__*/function () {
/**
* @param {import('./types').ConnectionProps} props
*/
function Connection(props) {
var _this = this;
(0, _classCallCheck2["default"])(this, Connection);
props = props || {
protocol: window.location.protocol,
host: window.location.hostname
};
this.props = props;
this.autoSubscribes = this.props.autoSubscribes || [];
this.autoSubscribeLog = this.props.autoSubscribeLog;
this.props.protocol = this.props.protocol || window.location.protocol;
this.props.host = this.props.host || window.location.hostname;
this.props.port = this.props.port || (window.location.port === '3000' ? Connection.isWeb() ? 8082 : 8081 : window.location.port);
this.props.ioTimeout = Math.max(this.props.ioTimeout || 20000, 20000);
this.props.cmdTimeout = Math.max(this.props.cmdTimeout || 5000, 5000); // breaking change. Do not load all objects by default is true
this.doNotLoadAllObjects = this.props.doNotLoadAllObjects === undefined ? true : this.props.doNotLoadAllObjects;
this.doNotLoadACL = this.props.doNotLoadACL === undefined ? true : this.props.doNotLoadACL;
/** @type {Record<string, ioBroker.State>} */
this.states = {};
this.objects = null;
this.acl = null;
this.firstConnect = true;
this.waitForRestart = false;
/** @type {ioBroker.Languages} */
this.systemLang = 'en';
this.connected = false;
this._waitForFirstConnection = new Promise(function (resolve) {
_this._waitForFirstConnectionResolve = resolve;
});
/** @type {Record<string, { reg: RegExp; cbs: ioBroker.StateChangeHandler[]}>} */
this.statesSubscribes = {}; // subscribe for states
/** @type {Record<string, { reg: RegExp; cbs: import('./types').ObjectChangeHandler[]}>} */
this.objectsSubscribes = {}; // subscribe for objects
this.onProgress = this.props.onProgress || function () {};
this.onError = this.props.onError || function (err) {
console.error(err);
};
this.loaded = false;
this.loadTimer = null;
this.loadCounter = 0;
this.admin5only = this.props.admin5only || false;
/** @type {((connected: boolean) => void)[]} */
this.onConnectionHandlers = [];
/** @type {((message: string) => void)[]} */
this.onLogHandlers = [];
/** @type {Record<string, Promise<any>>} */
this._promises = {};
this.log.error = function (text) {
return _this.log(text, 'error');
};
this.log.warn = function (text) {
return _this.log(text, 'warn');
};
this.log.info = function (text) {
return _this.log(text, 'info');
};
this.log.debug = function (text) {
return _this.log(text, 'debug');
};
this.log.silly = function (text) {
return _this.log(text, 'silly');
};
this.startSocket();
}
/**
* Checks if this connection is running in a web adapter and not in an admin.
* @returns {boolean} True if running in a web adapter or in a socketio adapter.
*/
(0, _createClass2["default"])(Connection, [{
key: "startSocket",
value:
/**
* Starts the socket.io connection.
* @returns {void}
*/
function startSocket() {
var _this2 = this;
// if socket io is not yet loaded
if (typeof window.io === 'undefined') {
// if in index.html the onLoad function not defined
if (typeof window.registerSocketOnLoad !== 'function') {
// poll if loaded
this.scriptLoadCounter = this.scriptLoadCounter || 0;
this.scriptLoadCounter++;
if (this.scriptLoadCounter < 30) {
// wait till the script loaded
setTimeout(function () {
return _this2.startSocket();
}, 100);
return;
} else {
window.alert('Cannot load socket.io.js!');
}
} else {
// register on load
window.registerSocketOnLoad(function () {
return _this2.startSocket();
});
}
return;
} else {
// socket was initialized, do not repeat
if (this._socket) {
return;
}
}
var host = this.props.host;
var port = this.props.port;
var protocol = this.props.protocol.replace(':', '');
var path = window.location.pathname;
if (window.location.hostname === 'iobroker.net' || window.location.hostname === 'iobroker.pro') {
path = '';
} else {
// if web adapter, socket io could be on other port or even host
if (window.socketUrl) {
var parts = window.socketUrl.split(':');
host = parts[0] || host;
port = parts[1] || port;
if (host.includes('://')) {
parts = host.split('://');
protocol = parts[0];
host = parts[1];
}
} // get current path
var pos = path.lastIndexOf('/');
if (pos !== -1) {
path = path.substring(0, pos + 1);
}
if (Connection.isWeb()) {
// remove one level, like echarts, vis, .... We have here: '/echarts/'
var _parts = path.split('/');
if (_parts.length > 2) {
_parts.pop();
_parts.pop();
path = _parts.join('/');
if (!path.endsWith('/')) {
path += '/';
}
}
}
}
var url = port ? "".concat(protocol, "://").concat(host, ":").concat(port).concat(path) : "".concat(protocol, "://").concat(host).concat(path);
this._socket = window.io.connect(url, {
path: path.endsWith('/') ? path + 'socket.io' : path + '/socket.io',
query: 'ws=true',
name: this.props.name,
timeout: this.props.ioTimeout
});
this._socket.on('connect', function (noTimeout) {
// If the user is not admin it takes some time to install the handlers, because all rights must be checked
if (noTimeout !== true) {
setTimeout(function () {
return _this2.getVersion().then(function (info) {
var _info$version$split = info.version.split('.'),
_info$version$split2 = (0, _slicedToArray2["default"])(_info$version$split, 3),
major = _info$version$split2[0],
minor = _info$version$split2[1],
patch = _info$version$split2[2];
var v = parseInt(major, 10) * 10000 + parseInt(minor, 10) * 100 + parseInt(patch, 10);
if (v < 40102) {
_this2._authTimer = null; // possible this is old version of admin
_this2.onPreConnect(false, false);
} else {
_this2._socket.emit('authenticate', function (isOk, isSecure) {
return _this2.onPreConnect(isOk, isSecure);
});
}
});
}, 500);
} else {
// iobroker websocket waits, till all handlers are installed
_this2._socket.emit('authenticate', function (isOk, isSecure) {
return _this2.onPreConnect(isOk, isSecure);
});
}
});
this._socket.on('reconnect', function () {
_this2.onProgress(PROGRESS.READY);
_this2.connected = true;
if (_this2.waitForRestart) {
window.location.reload(false);
} else {
_this2._subscribe(true);
_this2.onConnectionHandlers.forEach(function (cb) {
return cb(true);
});
}
});
this._socket.on('disconnect', function () {
_this2.connected = false;
_this2.subscribed = false;
_this2.onProgress(PROGRESS.CONNECTING);
_this2.onConnectionHandlers.forEach(function (cb) {
return cb(false);
});
});
this._socket.on('reauthenticate', function () {
return _this2.authenticate();
});
this._socket.on('log', function (message) {
_this2.props.onLog && _this2.props.onLog(message);
_this2.onLogHandlers.forEach(function (cb) {
return cb(message);
});
});
this._socket.on('error', function (err) {
var _err = err || '';
if (typeof _err.toString !== 'function') {
_err = JSON.stringify(_err);
console.error("Received strange error: ".concat(_err));
}
_err = _err.toString();
if (_err.includes('User not authorized')) {
_this2.authenticate();
} else {
window.alert("Socket Error: ".concat(err));
}
});
this._socket.on('connect_error', function (err) {
return console.error("Connect error: ".concat(err));
});
this._socket.on('permissionError', function (err) {
return _this2.onError({
message: 'no permission',
operation: err.operation,
type: err.type,
id: err.id || ''
});
});
this._socket.on('objectChange', function (id, obj) {
return setTimeout(function () {
return _this2.objectChange(id, obj);
}, 0);
});
this._socket.on('stateChange', function (id, state) {
return setTimeout(function () {
return _this2.stateChange(id, state);
}, 0);
});
this._socket.on('cmdStdout', function (id, text) {
return _this2.onCmdStdoutHandler && _this2.onCmdStdoutHandler(id, text);
});
this._socket.on('cmdStderr', function (id, text) {
return _this2.onCmdStderrHandler && _this2.onCmdStderrHandler(id, text);
});
this._socket.on('cmdExit', function (id, exitCode) {
return _this2.onCmdExitHandler && _this2.onCmdExitHandler(id, exitCode);
});
}
/**
* Called internally.
* @private
* @param {boolean} isOk
* @param {boolean} isSecure
*/
}, {
key: "onPreConnect",
value: function onPreConnect(isOk, isSecure) {
var _this3 = this;
if (this._authTimer) {
clearTimeout(this._authTimer);
this._authTimer = null;
}
this.connected = true;
this.isSecure = isSecure;
if (this.waitForRestart) {
window.location.reload(false);
} else {
if (this.firstConnect) {
// retry strategy
this.loadTimer = setTimeout(function () {
_this3.loadTimer = null;
_this3.loadCounter++;
if (_this3.loadCounter < 10) {
_this3.onConnect();
}
}, 1000);
if (!this.loaded) {
this.onConnect();
}
} else {
this.onProgress(PROGRESS.READY);
}
this._subscribe(true);
this.onConnectionHandlers.forEach(function (cb) {
return cb(true);
});
}
if (this._waitForFirstConnectionResolve) {
this._waitForFirstConnectionResolve();
this._waitForFirstConnectionResolve = null;
}
}
/**
* Checks if the socket is connected.
* @returns {boolean} true if connected.
*/
}, {
key: "isConnected",
value: function isConnected() {
return this.connected;
}
/**
* Checks if the socket is connected.
* @returns {Promise<void>} Promise resolves if once connected.
*/
}, {
key: "waitForFirstConnection",
value: function waitForFirstConnection() {
return this._waitForFirstConnection;
}
/**
* Called internally.
* @private
*/
}, {
key: "_getUserPermissions",
value: function _getUserPermissions(cb) {
if (this.doNotLoadACL) {
return cb && cb();
} else {
this._socket.emit('getUserPermissions', cb);
}
}
/**
* Called internally.
* @private
*/
}, {
key: "onConnect",
value: function onConnect() {
var _this4 = this;
this._getUserPermissions(function (err, acl) {
if (err) {
return _this4.onError('Cannot read user permissions: ' + err);
} else if (!_this4.doNotLoadACL) {
if (_this4.loaded) {
return;
}
_this4.loaded = true;
clearTimeout(_this4.loadTimer);
_this4.loadTimer = null;
_this4.onProgress(PROGRESS.CONNECTED);
_this4.firstConnect = false;
_this4.acl = acl;
} // Read system configuration
return (_this4.admin5only && !window.vendorPrefix ? _this4.getCompactSystemConfig() : _this4.getSystemConfig()).then(function (data) {
if (_this4.doNotLoadACL) {
if (_this4.loaded) {
return undefined;
}
_this4.loaded = true;
clearTimeout(_this4.loadTimer);
_this4.loadTimer = null;
_this4.onProgress(PROGRESS.CONNECTED);
_this4.firstConnect = false;
}
_this4.systemConfig = data;
if (_this4.systemConfig && _this4.systemConfig.common) {
_this4.systemLang = _this4.systemConfig.common.language;
} else {
_this4.systemLang = window.navigator.userLanguage || window.navigator.language;
if (_this4.systemLang !== 'en' && _this4.systemLang !== 'de' && _this4.systemLang !== 'ru') {
_this4.systemConfig.common.language = 'en';
_this4.systemLang = 'en';
}
}
_this4.props.onLanguage && _this4.props.onLanguage(_this4.systemLang);
if (!_this4.doNotLoadAllObjects) {
return _this4.getObjects().then(function () {
_this4.onProgress(PROGRESS.READY);
_this4.props.onReady && _this4.props.onReady(_this4.objects);
});
} else {
_this4.objects = _this4.admin5only ? {} : {
'system.config': data
};
_this4.onProgress(PROGRESS.READY);
_this4.props.onReady && _this4.props.onReady(_this4.objects);
}
return undefined;
})["catch"](function (e) {
return _this4.onError('Cannot read system config: ' + e);
});
});
}
/**
* Called internally.
* @private
*/
}, {
key: "authenticate",
value: function authenticate() {
if (window.location.search.includes('&href=')) {
window.location = "".concat(window.location.protocol, "//").concat(window.location.host).concat(window.location.pathname).concat(window.location.search).concat(window.location.hash);
} else {
window.location = "".concat(window.location.protocol, "//").concat(window.location.host).concat(window.location.pathname, "?login&href=").concat(window.location.search).concat(window.location.hash);
}
}
/**
* Subscribe to changes of the given state.
* @param {string} id The ioBroker state ID.
* @param {ioBroker.StateChangeHandler} cb The callback.
*/
/**
* Subscribe to changes of the given state.
* @param {string} id The ioBroker state ID.
* @param {boolean} binary Set to true if the given state is binary and requires Base64 decoding.
* @param {ioBroker.StateChangeHandler} cb The callback.
*/
}, {
key: "subscribeState",
value: function subscribeState(id, binary, cb) {
if (typeof binary === 'function') {
cb = binary;
binary = false;
}
if (!this.statesSubscribes[id]) {
var reg = id.replace(/\./g, '\\.').replace(/\*/g, '.*').replace(/\(/g, '\\(').replace(/\)/g, '\\)').replace(/\+/g, '\\+').replace(/\[/g, '\\[');
if (reg.indexOf('*') === -1) {
reg += '$';
}
this.statesSubscribes[id] = {
reg: new RegExp(reg),
cbs: []
};
this.statesSubscribes[id].cbs.push(cb);
if (this.connected) {
this._socket.emit('subscribe', id);
}
} else {
!this.statesSubscribes[id].cbs.includes(cb) && this.statesSubscribes[id].cbs.push(cb);
}
if (typeof cb === 'function' && this.connected) {
if (binary) {
this.getBinaryState(id).then(function (base64) {
return cb(id, base64);
})["catch"](function (e) {
return console.error("Cannot getForeignStates \"".concat(id, "\": ").concat(JSON.stringify(e)));
});
} else {
if (Connection.isWeb()) {
this._socket.emit('getStates', id, function (err, states) {
err && console.error("Cannot getForeignStates \"".concat(id, "\": ").concat(JSON.stringify(err)));
states && Object.keys(states).forEach(function (id) {
return cb(id, states[id]);
});
});
} else {
this._socket.emit('getForeignStates', id, function (err, states) {
err && console.error("Cannot getForeignStates \"".concat(id, "\": ").concat(JSON.stringify(err)));
states && Object.keys(states).forEach(function (id) {
return cb(id, states[id]);
});
});
}
}
}
}
/**
* Unsubscribes all callbacks from changes of the given state.
* @param {string} id The ioBroker state ID.
*/
/**
* Unsubscribes the given callback from changes of the given state.
* @param {string} id The ioBroker state ID.
* @param {ioBroker.StateChangeHandler} cb The callback.
*/
}, {
key: "unsubscribeState",
value: function unsubscribeState(id, cb) {
if (this.statesSubscribes[id]) {
if (cb) {
var pos = this.statesSubscribes[id].cbs.indexOf(cb);
pos !== -1 && this.statesSubscribes[id].cbs.splice(pos, 1);
} else {
this.statesSubscribes[id].cbs = [];
}
if (!this.statesSubscribes[id].cbs || !this.statesSubscribes[id].cbs.length) {
delete this.statesSubscribes[id];
this.connected && this._socket.emit('unsubscribe', id);
}
}
}
/**
* Subscribe to changes of the given object.
* @param {string} id The ioBroker object ID.
* @param {import('./types').ObjectChangeHandler} cb The callback.
* @returns {Promise<void>}
*/
}, {
key: "subscribeObject",
value: function subscribeObject(id, cb) {
if (!this.objectsSubscribes[id]) {
var reg = id.replace(/\./g, '\\.').replace(/\*/g, '.*');
if (!reg.includes('*')) {
reg += '$';
}
this.objectsSubscribes[id] = {
reg: new RegExp(reg),
cbs: []
};
this.objectsSubscribes[id].cbs.push(cb);
this.connected && this._socket.emit('subscribeObjects', id);
} else {
!this.objectsSubscribes[id].cbs.includes(cb) && this.objectsSubscribes[id].cbs.push(cb);
}
return Promise.resolve();
}
/**
* Unsubscribes all callbacks from changes of the given object.
* @param {string} id The ioBroker object ID.
* @returns {Promise<void>}
*/
/**
* Unsubscribes the given callback from changes of the given object.
* @param {string} id The ioBroker object ID.
* @param {import('./types').ObjectChangeHandler} cb The callback.
* @returns {Promise<void>}
*/
}, {
key: "unsubscribeObject",
value: function unsubscribeObject(id, cb) {
if (this.objectsSubscribes[id]) {
if (cb) {
var pos = this.objectsSubscribes[id].cbs.indexOf(cb);
pos !== -1 && this.objectsSubscribes[id].cbs.splice(pos, 1);
} else {
this.objectsSubscribes[id].cbs = [];
}
if (this.connected && (!this.objectsSubscribes[id].cbs || !this.objectsSubscribes[id].cbs.length)) {
delete this.objectsSubscribes[id];
this.connected && this._socket.emit('unsubscribeObjects', id);
}
}
return Promise.resolve();
}
/**
* Called internally.
* @private
* @param {string} id
* @param {ioBroker.Object | null | undefined} obj
*/
}, {
key: "objectChange",
value: function objectChange(id, obj) {
var _this5 = this;
// update main.objects cache
if (!this.objects) {
return;
}
/** @type {import("./types").OldObject} */
var oldObj;
var changed = false;
if (obj) {
if (obj._rev && this.objects[id]) {
this.objects[id]._rev = obj._rev;
}
if (this.objects[id]) {
oldObj = {
_id: id,
type: this.objects[id].type
};
}
if (!this.objects[id] || JSON.stringify(this.objects[id]) !== JSON.stringify(obj)) {
this.objects[id] = obj;
changed = true;
}
} else if (this.objects[id]) {
oldObj = {
_id: id,
type: this.objects[id].type
};
delete this.objects[id];
changed = true;
}
Object.keys(this.objectsSubscribes).forEach(function (_id) {
if (_id === id || _this5.objectsSubscribes[_id].reg.test(id)) {
//@ts-ignore
_this5.objectsSubscribes[_id].cbs.forEach(function (cb) {
return cb(id, obj, oldObj);
});
}
});
if (changed && this.props.onObjectChange) {
this.props.onObjectChange(id, obj);
}
}
/**
* Called internally.
* @private
* @param {string} id
* @param {ioBroker.State | null | undefined} state
*/
}, {
key: "stateChange",
value: function stateChange(id, state) {
for (var task in this.statesSubscribes) {
if (this.statesSubscribes.hasOwnProperty(task) && this.statesSubscribes[task].reg.test(id)) {
this.statesSubscribes[task].cbs.forEach(function (cb) {
return cb(id, state);
});
}
}
}
/**
* Gets all states.
* @param {boolean} disableProgressUpdate don't call onProgress() when done
* @returns {Promise<Record<string, ioBroker.State>>}
*/
}, {
key: "getStates",
value: function getStates(disableProgressUpdate) {
var _this6 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve, reject) {
return _this6._socket.emit('getStates', function (err, res) {
_this6.states = res; //@ts-ignore
!disableProgressUpdate && _this6.onProgress(PROGRESS.STATES_LOADED);
return err ? reject(err) : resolve(_this6.states);
});
});
}
/**
* Gets the given state.
* @param {string} id The state ID.
* @returns {Promise<ioBroker.State | null | undefined>}
*/
}, {
key: "getState",
value: function getState(id) {
var _this7 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve, reject) {
return _this7._socket.emit('getState', id, function (err, state) {
return err ? reject(err) : resolve(state);
});
});
}
/**
* Gets the given binary state.
* @param {string} id The state ID.
* @returns {Promise<Buffer | undefined>}
*/
}, {
key: "getBinaryState",
value: function getBinaryState(id) {
var _this8 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
} // the data will come in base64
return new Promise(function (resolve, reject) {
return _this8._socket.emit('getBinaryState', id, function (err, state) {
return err ? reject(err) : resolve(state);
});
});
}
/**
* Sets the given binary state.
* @param {string} id The state ID.
* @param {string} base64 The Base64 encoded binary data.
* @returns {Promise<void>}
*/
}, {
key: "setBinaryState",
value: function setBinaryState(id, base64) {
var _this9 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
} // the data will come in base64
return new Promise(function (resolve, reject) {
return _this9._socket.emit('setBinaryState', id, base64, function (err) {
return err ? reject(err) : resolve();
});
});
}
/**
* Sets the given state value.
* @param {string} id The state ID.
* @param {string | number | boolean | ioBroker.State | ioBroker.SettableState | null} val The state value.
* @returns {Promise<void>}
*/
}, {
key: "setState",
value: function setState(id, val) {
var _this10 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve, reject) {
return _this10._socket.emit('setState', id, val, function (err) {
return err ? reject(err) : resolve();
});
});
}
/**
* Gets all objects.
* @param {(objects?: Record<string, ioBroker.Object>) => void} update Callback that is executed when all objects are retrieved.
* @returns {void}
*/
/**
* Gets all objects.
* @param {boolean} update Set to true to retrieve all objects from the server (instead of using the local cache).
* @param {boolean} disableProgressUpdate don't call onProgress() when done
* @returns {Promise<Record<string, ioBroker.Object>> | undefined}
*/
}, {
key: "getObjects",
value: function getObjects(update, disableProgressUpdate) {
var _this11 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
} else {
return new Promise(function (resolve, reject) {
if (!update && _this11.objects) {
return resolve(_this11.objects);
}
_this11._socket.emit(Connection.isWeb() ? 'getObjects' : 'getAllObjects', function (err, res) {
_this11.objects = res;
disableProgressUpdate && _this11.onProgress(PROGRESS.OBJECTS_LOADED);
err ? reject(err) : resolve(_this11.objects);
});
});
}
}
/**
* Called internally.
* @private
* @param {boolean} isEnable
*/
}, {
key: "_subscribe",
value: function _subscribe(isEnable) {
var _this12 = this;
if (isEnable && !this.subscribed) {
this.subscribed = true;
this.autoSubscribes.forEach(function (id) {
return _this12._socket.emit('subscribeObjects', id);
}); // re subscribe objects
Object.keys(this.objectsSubscribes).forEach(function (id) {
return _this12._socket.emit('subscribeObjects', id);
}); // re-subscribe logs
this.autoSubscribeLog && this._socket.emit('requireLog', true); // re subscribe states
Object.keys(this.statesSubscribes).forEach(function (id) {
return _this12._socket.emit('subscribe', id);
});
} else if (!isEnable && this.subscribed) {
this.subscribed = false; // un-subscribe objects
this.autoSubscribes.forEach(function (id) {
return _this12._socket.emit('unsubscribeObjects', id);
});
Object.keys(this.objectsSubscribes).forEach(function (id) {
return _this12._socket.emit('unsubscribeObjects', id);
}); // un-subscribe logs
this.autoSubscribeLog && this._socket.emit('requireLog', false); // un-subscribe states
Object.keys(this.statesSubscribes).forEach(function (id) {
return _this12._socket.emit('unsubscribe', id);
});
}
}
/**
* Requests log updates.
* @param {boolean} isEnabled Set to true to get logs.
* @returns {Promise<void>}
*/
}, {
key: "requireLog",
value: function requireLog(isEnabled) {
var _this13 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve, reject) {
return _this13._socket.emit('requireLog', isEnabled, function (err) {
return err ? reject(err) : resolve();
});
});
}
/**
* Deletes the given object.
* @param {string} id The object ID.
* @param {boolean} maintenance Force deletion of non conform IDs.
* @returns {Promise<void>}
*/
}, {
key: "delObject",
value: function delObject(id, maintenance) {
var _this14 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve, reject) {
return _this14._socket.emit('delObject', id, {
maintenance: !!maintenance
}, function (err) {
return err ? reject(err) : resolve();
});
});
}
/**
* Deletes the given object and all its children.
* @param {string} id The object ID.
* @param {boolean} maintenance Force deletion of non conform IDs.
* @returns {Promise<void>}
*/
}, {
key: "delObjects",
value: function delObjects(id, maintenance) {
var _this15 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve, reject) {
return _this15._socket.emit('delObjects', id, {
maintenance: !!maintenance
}, function (err) {
return err ? reject(err) : resolve();
});
});
}
/**
* Sets the object.
* @param {string} id The object ID.
* @param {ioBroker.SettableObject} obj The object.
* @returns {Promise<void>}
*/
}, {
key: "setObject",
value: function setObject(id, obj) {
var _this16 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
if (!obj) {
return Promise.reject('Null object is not allowed');
}
obj = JSON.parse(JSON.stringify(obj));
if (obj.hasOwnProperty('from')) {
delete obj.from;
}
if (obj.hasOwnProperty('user')) {
delete obj.user;
}
if (obj.hasOwnProperty('ts')) {
delete obj.ts;
}
return new Promise(function (resolve, reject) {
return _this16._socket.emit('setObject', id, obj, function (err) {
return err ? reject(err) : resolve();
});
});
}
/**
* Gets the object with the given id from the server.
* @param {string} id The object ID.
* @returns {ioBroker.GetObjectPromise} The object.
*/
}, {
key: "getObject",
value: function getObject(id) {
var _this17 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve, reject) {
return _this17._socket.emit('getObject', id, function (err, obj) {
return err ? reject(err) : resolve(obj);
});
});
}
/**
* Get all adapter instances.
* @param {boolean} [update] Force update.
* @returns {Promise<ioBroker.Object[]>}
*/
/**
* Get all instances of the given adapter.
* @param {string} adapter The name of the adapter.
* @param {boolean} [update] Force update.
* @returns {Promise<ioBroker.Object[]>}
*/
}, {
key: "getAdapterInstances",
value: function getAdapterInstances(adapter, update) {
var _this18 = this;
if (typeof adapter === 'boolean') {
update = adapter;
adapter = '';
}
adapter = adapter || '';
if (!update && this._promises['instances_' + adapter]) {
return this._promises['instances_' + adapter];
}
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
this._promises['instances_' + adapter] = new Promise(function (resolve, reject) {
var timeout = setTimeout(function () {
timeout = null;
_this18.getObjectView("system.adapter.".concat(adapter ? adapter + '.' : ''), "system.adapter.".concat(adapter ? adapter + '.' : '', "\u9999"), 'instance').then(function (items) {
return resolve(Object.keys(items).map(function (id) {
return fixAdminUI(items[id]);
}));
})["catch"](function (e) {
return reject(e);
});
}, TIMEOUT_FOR_ADMIN4);
_this18._socket.emit('getAdapterInstances', adapter, function (err, instances) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
return err ? reject(err) : resolve(instances);
}
});
});
return this._promises['instances_' + adapter];
}
/**
* Get all adapters.
* @param {boolean} [update] Force update.
* @returns {Promise<ioBroker.Object[]>}
*/
/**
* Get adapters with the given name.
* @param {string} adapter The name of the adapter.
* @param {boolean} [update] Force update.
* @returns {Promise<ioBroker.Object[]>}
*/
}, {
key: "getAdapters",
value: function getAdapters(adapter, update) {
var _this19 = this;
if (Connection.isWeb()) {
return Promise.reject('Allowed only in admin');
}
if (typeof adapter === 'boolean') {
update = adapter;
adapter = '';
}
adapter = adapter || '';
if (!update && this._promises['adapter_' + adapter]) {
return this._promises['adapter_' + adapter];
}
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
this._promises['adapter_' + adapter] = new Promise(function (resolve, reject) {
var timeout = setTimeout(function () {
timeout = null;
_this19.getObjectView("system.adapter.".concat(adapter, "."), "system.adapter.".concat(adapter, ".\u9999"), 'adapter').then(function (items) {
return resolve(Object.keys(items).map(function (id) {
return fixAdminUI(items[id]);
}));
})["catch"](function (e) {
return reject(e);
});
}, TIMEOUT_FOR_ADMIN4);
_this19._socket.emit('getAdapters', adapter, function (err, adapters) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
return err ? reject(err) : resolve(adapters);
}
});
});
return this._promises['adapter_' + adapter];
}
/**
* Called internally.
* @private
* @param {any[]} objs
* @param {(err?: any) => void} cb
*/
}, {
key: "_renameGroups",
value: function _renameGroups(objs, cb) {
var _this20 = this;
if (!objs || !objs.length) {
cb && cb();
} else {
var obj = objs.pop();
var oldId = obj._id;
obj._id = obj.newId;
delete obj.newId;
this.setObject(obj._id, obj).then(function () {
return _this20.delObject(oldId);
}).then(function () {
return setTimeout(function () {
return _this20._renameGroups(objs, cb);
}, 0);
})["catch"](function (err) {
return cb && cb(err);
});
}
}
/**
* Rename a group.
* @param {string} id The id.
* @param {string} newId The new id.
* @param {string | { [lang in ioBroker.Languages]?: string; }} newName The new name.
*/
}, {
key: "renameGroup",
value: function renameGroup(id, newId, newName) {
var _this21 = this;
if (Connection.isWeb()) {
return Promise.reject('Allowed only in admin');
}
return this.getGroups(true).then(function (groups) {
if (groups.length) {
// find all elements
var groupsToRename = groups.filter(function (group) {
return group._id.startsWith(id + '.');
});
groupsToRename.forEach(function (group) {
return group.newId = newId + group._id.substring(id.length);
});
return new Promise(function (resolve, reject) {
return _this21._renameGroups(groupsToRename, function (err) {
return err ? reject(err) : resolve();
});
}).then(function () {
var obj = groups.find(function (group) {
return group._id === id;
});
if (obj) {
obj._id = newId;
if (newName !== undefined) {
obj.common = obj.common || {};
obj.common.name = newName;
}
return _this21.setObject(obj._id, obj).then(function () {
return _this21.delObject(id);
});
}
});
}
});
}
/**
* Sends a message to a specific instance or all instances of some specific adapter.
* @param {string} instance The instance to send this message to.
* @param {string} [command] Command name of the target instance.
* @param {ioBroker.MessagePayload} [data] The message data to send.
* @returns {Promise<ioBroker.Message | undefined>}
*/
}, {
key: "sendTo",
value: function sendTo(instance, command, data) {
var _this22 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve) {
return _this22._socket.emit('sendTo', instance, command, data, function (result) {
return resolve(result);
});
});
}
/**
* Extend an object and create it if it might not exist.
* @param {string} id The id.
* @param {ioBroker.PartialObject} obj The object.
*/
}, {
key: "extendObject",
value: function extendObject(id, obj) {
var _this23 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
obj = JSON.parse(JSON.stringify(obj));
if (obj.hasOwnProperty('from')) {
delete obj.from;
}
if (obj.hasOwnProperty('user')) {
delete obj.user;
}
if (obj.hasOwnProperty('ts')) {
delete obj.ts;
}
return new Promise(function (resolve, reject) {
return _this23._socket.emit('extendObject', id, obj, function (err) {
return err ? reject(err) : resolve();
});
});
}
/**
* Register a handler for log messages.
* @param {(message: string) => void} handler The handler.
*/
}, {
key: "registerLogHandler",
value: function registerLogHandler(handler) {
!this.onLogHandlers.includes(handler) && this.onLogHandlers.push(handler);
}
/**
* Unregister a handler for log messages.
* @param {(message: string) => void} handler The handler.
*/
}, {
key: "unregisterLogHandler",
value: function unregisterLogHandler(handler) {
var pos = this.onLogHandlers.indexOf(handler);
pos !== -1 && this.onLogHandlers.splice(pos, 1);
}
/**
* Register a handler for the connection state.
* @param {(connected: boolean) => void} handler The handler.
*/
}, {
key: "registerConnectionHandler",
value: function registerConnectionHandler(handler) {
!this.onConnectionHandlers.includes(handler) && this.onConnectionHandlers.push(handler);
}
/**
* Unregister a handler for the connection state.
* @param {(connected: boolean) => void} handler The handler.
*/
}, {
key: "unregisterConnectionHandler",
value: function unregisterConnectionHandler(handler) {
var pos = this.onConnectionHandlers.indexOf(handler);
pos !== -1 && this.onConnectionHandlers.splice(pos, 1);
}
/**
* Set the handler for standard output of a command.
* @param {(id: string, text: string) => void} handler The handler.
*/
}, {
key: "registerCmdStdoutHandler",
value: function registerCmdStdoutHandler(handler) {
this.onCmdStdoutHandler = handler;
}
/**
* Unset the handler for standard output of a command.
* @param {(id: string, text: string) => void} handler The handler.
*/
}, {
key: "unregisterCmdStdoutHandler",
value: function unregisterCmdStdoutHandler(handler) {
this.onCmdStdoutHandler = null;
}
/**
* Set the handler for standard error of a command.
* @param {(id: string, text: string) => void} handler The handler.
*/
}, {
key: "registerCmdStderrHandler",
value: function registerCmdStderrHandler(handler) {
this.onCmdStderrHandler = handler;
}
/**
* Unset the handler for standard error of a command.
* @param {(id: string, text: string) => void} handler The handler.
*/
}, {
key: "unregisterCmdStderrHandler",
value: function unregisterCmdStderrHandler(handler) {
this.onCmdStderrHandler = null;
}
/**
* Set the handler for exit of a command.
* @param {(id: string, exitCode: number) => void} handler The handler.
*/
}, {
key: "registerCmdExitHandler",
value: function registerCmdExitHandler(handler) {
this.onCmdExitHandler = handler;
}
/**
* Unset the handler for exit of a command.
* @param {(id: string, exitCode: number) => void} handler The handler.
*/
}, {
key: "unregisterCmdExitHandler",
value: function unregisterCmdExitHandler(handler) {
this.onCmdExitHandler = null;
}
/**
* Get all enums with the given name.
* @param {string} [_enum] The name of the enum
* @param {boolean} [update] Force update.
* @returns {Promise<Record<string, ioBroker.Object>>}
*/
}, {
key: "getEnums",
value: function getEnums(_enum, update) {
var _this24 = this;
if (!update && this._promises['enums_' + (_enum || 'all')]) {
return this._promises['enums_' + (_enum || 'all')];
}
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
this._promises['enums_' + (_enum || 'all')] = new Promise(function (resolve, reject) {
_this24._socket.emit('getObjectView', 'system', 'enum', {
startkey: 'enum.' + (_enum || ''),
endkey: 'enum.' + (_enum ? _enum + '.' : '') + "\u9999"
}, function (err, res) {
if (!err && res) {
var _res = {};
for (var i = 0; i < res.rows.length; i++) {
if (_enum && res.rows[i].id === 'enum.' + _enum) {
continue;
}
_res[res.rows[i].id] = res.rows[i].value;
}
resolve(_res);
} else {
reject(err);
}
});
});
return this._promises['enums_' + (_enum || 'all')];
}
/**
* Query a predefined object view.
* @param {string} start The start ID.
* @param {string} end The end ID.
* @param {string} type The type of object.
* @returns {Promise<Record<string, ioBroker.Object>>}
*/
}, {
key: "getObjectView",
value: function getObjectView(start, end, type) {
var _this25 = this;
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
start = start || '';
end = end || "\u9999";
return new Promise(function (resolve, reject) {
_this25._socket.emit('getObjectView', 'system', type, {
startkey: start,
endkey: end
}, function (err, res) {
if (!err) {
var _res = {};
if (res && res.rows) {
for (var i = 0; i < res.rows.length; i++) {
_res[res.rows[i].id] = res.rows[i].value;
}
}
resolve(_res);
} else {
reject(err);
}
});
});
}
/**
* Get the stored certificates.
* @param {boolean} [update] Force update.
* @returns {Promise<{name: string; type: 'public' | 'private' | 'chained'}[]>}
*/
}, {
key: "getCertificates",
value: function getCertificates(update) {
if (Connection.isWeb()) {
return Promise.reject('Allowed only in admin');
}
if (this._promises.cert && !update) {
return this._promises.cert;
}
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
this._promises.cert = this.getObject('system.certificates').then(function (res) {
var certs = [];
if (res && res["native"] && res["native"].certificates) {
Object.keys(res["native"].certificates).forEach(function (c) {
var cert = res["native"].certificates[c];
if (!cert) {
return;
}
var _cert = {
name: c,
type: ''
}; // If it is filename, it could be everything
if (cert.length < 700 && (cert.indexOf('/') !== -1 || cert.indexOf('\\') !== -1)) {
if (c.toLowerCase().includes('private')) {
_cert.type = 'private';
} else if (cert.toLowerCase().includes('private')) {
_cert.type = 'private';
} else if (c.toLowerCase().includes('public')) {
_cert.type = 'public';
} else if (cert.toLowerCase().includes('public')) {
_cert.type = 'public';
}
certs.push(_cert);
} else {
_cert.type = cert.substring(0, '-----BEGIN RSA PRIVATE KEY'.length) === '-----BEGIN RSA PRIVATE KEY' || cert.substring(0, '-----BEGIN PRIVATE KEY'.length) === '-----BEGIN PRIVATE KEY' ? 'private' : 'public';
if (_cert.type === 'public') {
var m = cert.split('-----END CERTIFICATE-----');
if (m.filter(function (t) {
return t.replace(/\r\n|\r|\n/, '').trim();
}).length > 1) {
_cert.type = 'chained';
}
}
certs.push(_cert);
}
});
}
return certs;
});
return this._promises.cert;
}
/**
* Get the logs from a host (only for admin connection).
* @param {string} host
* @param {number} [linesNumber]
* @returns {Promise<string[]>}
*/
}, {
key: "getLogs",
value: function getLogs(host, linesNumber) {
var _this26 = this;
if (Connection.isWeb()) {
return Promise.reject('Allowed only in admin');
}
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve) {
return _this26._socket.emit('sendToHost', host, 'getLogs', linesNumber || 200, function (lines) {
return resolve(lines);
});
});
}
/**
* Get the log files (only for admin connection).
* @returns {Promise<string[]>}
*/
}, {
key: "getLogsFiles",
value: function getLogsFiles(host) {
var _this27 = this;
if (Connection.isWeb()) {
return Promise.reject('Allowed only in admin');
}
if (!this.connected) {
return Promise.reject(NOT_CONNECTED);
}
return new Promise(function (resolve, reject) {
return _this27._socket.emit('readLogs', host, function (err, files) {