lavva.exalushome
Version:
Library implementing communication and abstraction layers for ExalusHome system
450 lines • 21.1 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Event } from "../../Event";
import { ControllerConfigurationErrorCode } from "./IControllerConfigurationService";
import { TypedEvent } from '../../TypedEvent';
import { Api } from "../../Api";
import { ExalusConnectionService } from '../ExalusConnectionService';
import { SessionService } from '../Session/SessionService';
import { DataFrame, Method, Status } from '../../DataFrame';
import { LocalStorageService } from "../LocalStorageService";
import { WebApiCacheService } from "../WebApi/WebApiCacheService";
import { Task } from '../../Helpers';
import { ControllerExtensionsService } from './ControllerExtensionsService';
import { AccessLevel } from "../Users/IUser";
import { ResponseResult } from "../FieldChangeResult";
import { DependencyContainer } from "../../DependencyContainer";
export class ControllerConfigurationService {
GetServiceName() {
return ControllerConfigurationService.ServiceName;
}
constructor() {
this._connection = null;
this._session = null;
this._localStorage = null;
this._onEnteredConfigurationEvent = new Event();
this._onExitedConfigurationEvent = new Event();
this._onConfigurationTimeCheckedEvent = new TypedEvent();
this._configurationTime = new Date();
this._appEnteredConfigurationMode = false;
this._didConfigurationChange = false;
this._synchronizationTaskCompletionSource = new Promise((resolve) => {
Api.Get(SessionService.ServiceName).OnUserLoggedInEvent().Subscribe((user) => __awaiter(this, void 0, void 0, function* () {
if (ControllerConfigurationService.ConfigurationTimeRetrieved !== null)
this._didConfigurationChange = yield this.CheckIfConfigurationTimeHasChangedAsync(ControllerConfigurationService.ConfigurationTimeRetrieved);
else
this._didConfigurationChange = yield this.CheckIfConfigurationHasChangedAsync();
if (this._didConfigurationChange)
Api.Get(WebApiCacheService.ServiceName).ClearCache();
resolve();
}));
});
this._connection = Api.Get(ExalusConnectionService.ServiceName);
this._session = Api.Get(SessionService.ServiceName);
this._localStorage = Api.Get(LocalStorageService.ServiceName);
let removeSubCallback = this._connection.SubscribeTo("/info/configuration/mode/entry", (frame) => {
Api.Get(WebApiCacheService.ServiceName).ClearCache();
if (!this._appEnteredConfigurationMode)
this._onEnteredConfigurationEvent.Invoke();
});
let removeSubCallback2 = this._connection.SubscribeTo("/info/configuration/mode/exit", (frame) => {
Api.Get(WebApiCacheService.ServiceName).ClearCache();
if (!this._appEnteredConfigurationMode)
this._onExitedConfigurationEvent.Invoke();
});
}
ImportControllerConfigurationAsync(file) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c;
let conf = yield file.text();
let chunks = this.SplitStringBySize(conf);
let req = new ImportControllerConfigurationRequest("");
req.Status = Status.MultiDataResponseStart;
let result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(req, 6000, false));
if (result === undefined || (result === null || result === void 0 ? void 0 : result.Status) != Status.OK)
return Status.Error;
for (const chunk of chunks) {
let req = new ImportControllerConfigurationRequest(chunk);
req.Status = Status.MultiDataResponse;
let result = yield ((_b = this._connection) === null || _b === void 0 ? void 0 : _b.SendAndWaitForResponseAsync(req, 6000, false));
if (result === undefined || (result === null || result === void 0 ? void 0 : result.Status) != Status.OK)
return Status.Error;
}
req.Status = Status.MultiDataResponseStop;
let result2 = yield ((_c = this._connection) === null || _c === void 0 ? void 0 : _c.SendAndWaitForResponseAsync(req, 120000, false));
if (result2 === undefined || (result2 === null || result2 === void 0 ? void 0 : result2.Status) != Status.OK)
return Status.Error;
return Status.OK;
});
}
SplitStringBySize(input, maxSizeInBytes = 100000) {
// Calculate the approximate maximum number of characters
const maxChars = Math.floor(maxSizeInBytes / 2);
const result = [];
let startIndex = 0;
while (startIndex < input.length) {
// Get the chunk of the string
let chunk = input.slice(startIndex, startIndex + maxChars);
// Check the actual byte size of the chunk and adjust if necessary
while (new Blob([chunk]).size > maxSizeInBytes) {
// Reduce the size of the chunk until it fits within the byte limit
chunk = chunk.slice(0, -1);
}
// Add the chunk to the result array
result.push(chunk);
// Move to the next chunk
startIndex += chunk.length;
}
return result;
}
GetControllerSystemTimeAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
var result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new GetControllerTimeRequest(), 8000, false));
if (result == null || result.Status == null)
return Status.Error;
if (result.Status != Status.OK)
return result.Status;
if (result.Data == null)
return Status.ResourceIsNotAvailable;
return new Date(result.Data);
}
catch (error) {
(_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Error(ControllerConfigurationService.ServiceName, `Cannot get current controller time! ${error}`);
return Status.FatalError;
}
});
}
SetControllerSystemTimeAsync(date) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
var result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new SetControllerTimeRequest(date.toISOString()), 8000, false));
if (result == null || result.Status == null)
return Status.Error;
return result.Status;
}
catch (error) {
(_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Error(ControllerConfigurationService.ServiceName, `Cannot set current controller time! ${error}`);
return Status.FatalError;
}
});
}
StartNtpTimeSynchronizationAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
var result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new SetNtpControllerTimeRequest(), 8000, false));
if (result == null || result.Status == null)
return Status.Error;
return result.Status;
}
catch (error) {
(_b = DependencyContainer.Log) === null || _b === void 0 ? void 0 : _b.Error(ControllerConfigurationService.ServiceName, `Cannot set current controller time! ${error}`);
return Status.FatalError;
}
});
}
FactoryResetAsync(func) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
Api.Get(WebApiCacheService.ServiceName).ClearCache();
var result = (_b = (yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new DoFactoryResetRequest(), 2000, false)))) === null || _b === void 0 ? void 0 : _b.Status;
if (result == Status.OK) {
let Seconds = 300; //in seconds
let currentProgress = 0;
let progressPerStep = 100 / Seconds;
let id = setInterval(() => {
currentProgress += progressPerStep;
func(parseFloat(currentProgress.toPrecision(1)));
}, 1000);
yield Task.Delay(Seconds * 1000);
Api.Get(WebApiCacheService.ServiceName).ClearCache();
clearInterval(id);
return Status.OK;
}
else
return result;
}
catch (e) {
return Status.FatalError;
}
});
}
RollbackLastUpdateAsync(func) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
Api.Get(WebApiCacheService.ServiceName).ClearCache();
var result = (_b = (yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new RestorePreviousVersionRequest(), 2000, false)))) === null || _b === void 0 ? void 0 : _b.Status;
if (result == Status.OK) {
let Seconds = 420; //in seconds
let currentProgress = 0;
let progressPerStep = 100 / Seconds;
let id = setInterval(() => {
currentProgress += progressPerStep;
func(parseFloat(currentProgress.toPrecision(1)));
}, 1000);
yield Task.Delay(Seconds * 1000);
Api.Get(WebApiCacheService.ServiceName).ClearCache();
clearInterval(id);
return Status.OK;
}
else
return result;
}
catch (e) {
return Status.FatalError;
}
});
}
RestartControllerAsync(func) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b;
try {
Api.Get(WebApiCacheService.ServiceName).ClearCache();
var result = (_b = (yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new RestartControllerRequest(), 2000, false)))) === null || _b === void 0 ? void 0 : _b.Status;
if (result == Status.OK) {
let Seconds = 240; //in seconds
let currentProgress = 0;
let progressPerStep = 100 / Seconds;
let id = setInterval(() => {
currentProgress += progressPerStep;
func(parseFloat(currentProgress.toPrecision(1)));
}, 1000);
yield Task.Delay(Seconds * 1000);
Api.Get(WebApiCacheService.ServiceName).ClearCache();
clearInterval(id);
return Status.OK;
}
else
return result;
}
catch (e) {
return Status.FatalError;
}
});
}
DidCofigurationChangeAsync() {
return __awaiter(this, void 0, void 0, function* () {
let result = yield this._synchronizationTaskCompletionSource;
return Promise.resolve(this._didConfigurationChange);
});
}
GetLastKnownConfigurationChangeTime() {
var _a;
const result = (_a = this._localStorage) === null || _a === void 0 ? void 0 : _a.Read(this.GetServiceName(), "last_configuration_time");
if (result != null)
return new Date(result);
else
return new Date();
}
SaveLastConfigurationChangeTime(time) {
var _a;
(_a = this._localStorage) === null || _a === void 0 ? void 0 : _a.Save(this.GetServiceName(), "last_configuration_time", time.toString());
}
EnterConfigurationModeAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
this._appEnteredConfigurationMode = true;
Api.Get(WebApiCacheService.ServiceName).ClearCache();
yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new EntryConfigurationModeRequest(), 20000, false));
});
}
ExitConfigurationModeAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
this._appEnteredConfigurationMode = true;
Api.Get(WebApiCacheService.ServiceName).ClearCache();
yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new ExitConfigurationModeRequest(), 20000, false));
Api.Get(WebApiCacheService.ServiceName).ClearCache();
this._appEnteredConfigurationMode = false;
});
}
OnEnteredConfigurationEvent() {
return this._onEnteredConfigurationEvent;
}
OnExitedConfigurationEvent() {
return this._onExitedConfigurationEvent;
}
OnConfigurationTimeCheckedEvent() {
return this._onConfigurationTimeCheckedEvent;
}
GetLastConfigurationChangeTimeAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
const result = yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndWaitForResponseAsync(new LastChangeTimeRequest(), 20000, false));
if (result == null || (result === null || result === void 0 ? void 0 : result.Status) != Status.OK)
throw new Error("Failed to get last configuration change time");
this._configurationTime = new Date(result.Data);
return this._configurationTime;
});
}
CheckIfConfigurationHasChangedAsync() {
return __awaiter(this, void 0, void 0, function* () {
const result = yield this.GetLastConfigurationChangeTimeAsync();
if (this.GetLastKnownConfigurationChangeTime().toString() != result.toString()) {
this.SaveLastConfigurationChangeTime(result);
this._onConfigurationTimeCheckedEvent.Invoke(result);
Api.Get(WebApiCacheService.ServiceName).ClearCache();
return true;
}
else
return false;
});
}
CheckIfConfigurationTimeHasChangedAsync(currentConfigurationTime) {
return __awaiter(this, void 0, void 0, function* () {
if (this.GetLastKnownConfigurationChangeTime().toString() != currentConfigurationTime.toString()) {
this.SaveLastConfigurationChangeTime(currentConfigurationTime);
this._onConfigurationTimeCheckedEvent.Invoke(currentConfigurationTime);
Api.Get(WebApiCacheService.ServiceName).ClearCache();
return true;
}
else
return false;
});
}
CanExportOrImportControllerConfigurationAsync() {
return __awaiter(this, void 0, void 0, function* () {
try {
let ext = yield Api.Get(ControllerExtensionsService.ServiceName).GetExtensionsInfoAsync();
let user = Api.Get(SessionService.ServiceName).User;
if (user == null || user.AccessLevel == null)
return false;
return user.AccessLevel >= AccessLevel.Admin && ext.any(e => e.ExtensionGuid == "f4f0f066-7c43-46c6-a0bd-aedf93903dc0");
}
catch (e) {
return false;
}
});
}
ExportControllerConfigurationAsync() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
let data = [];
let err = null;
yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndHandleResponseAsync(new ExportControllerConfigurationRequest(), 30000, (result) => {
switch (result.Status) {
case Status.MultiDataResponseStart:
break;
case Status.MultiDataResponse:
if (result.Data != null && result.Data !== undefined)
data.push(result.Data);
break;
case Status.MultiDataResponseStop:
break;
case Status.Error:
case Status.FatalError:
err = new ResponseResult(ControllerConfigurationErrorCode.CannotExportConfiguration, "Cannot export configuration! Controller returned error!");
}
}, true));
let prettyPrint = JSON.stringify(JSON.parse(data.join('')), null, 2);
console.log(prettyPrint);
if (err != null)
return err;
return Api.ExportStringAsFileToDownload(this.GetCurrentTimestampedFilename(), prettyPrint);
});
}
GetCurrentTimestampedFilename() {
var _a, _b;
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
const day = now.getDate().toString().padStart(2, '0');
const month = (now.getMonth() + 1).toString().padStart(2, '0'); // Month is zero-based
const year = now.getFullYear().toString();
return `${(_b = (_a = this._connection) === null || _a === void 0 ? void 0 : _a.GetAuthorizationInfo()) === null || _b === void 0 ? void 0 : _b.SerialNumber}_${hours}-${minutes}-${day}-${month}-${year}-config.cexp`;
}
}
ControllerConfigurationService.ServiceName = "ControllerConfigurationService";
ControllerConfigurationService.ConfigurationTimeRetrieved = null;
class ImportControllerConfigurationRequest extends DataFrame {
constructor(data) {
super();
this.Resource = "/configuration/backup/import";
this.Method = Method.Put;
this.Data = data;
}
}
class ExportControllerConfigurationRequest extends DataFrame {
constructor() {
super();
this.Resource = "/configuration/backup/export";
this.Method = Method.Get;
}
}
class RestartControllerRequest extends DataFrame {
constructor() {
super();
this.Resource = "/controller/restart";
this.Method = Method.Post;
}
}
class DoFactoryResetRequest extends DataFrame {
constructor() {
super();
this.Resource = "/controller/factory_reset";
this.Method = Method.Post;
}
}
class RestorePreviousVersionRequest extends DataFrame {
constructor() {
super();
this.Resource = "/controller/backups/restore/previous";
this.Method = Method.Post;
}
}
class EntryConfigurationModeRequest extends DataFrame {
constructor() {
super();
this.Resource = "/system/configuration/mode/entry";
this.Method = Method.Put;
}
}
class ExitConfigurationModeRequest extends DataFrame {
constructor() {
super();
this.Resource = "/system/configuration/mode/exit";
this.Method = Method.Put;
}
}
class LastChangeTimeRequest extends DataFrame {
constructor() {
super();
this.Resource = "/system/configuration/change/time";
this.Method = Method.Get;
}
}
class GetControllerTimeRequest extends DataFrame {
constructor() {
super();
this.Resource = "/system/time";
this.Method = Method.Get;
}
}
class SetControllerTimeRequest extends DataFrame {
constructor(date) {
super();
this.Resource = "/system/time";
this.Method = Method.Put;
this.Data = date;
}
}
class SetNtpControllerTimeRequest extends DataFrame {
constructor() {
super();
this.Resource = "/system/time/ntp/update";
this.Method = Method.Put;
}
}
//# sourceMappingURL=ControllerConfigurationService.js.map