UNPKG

lavva.exalushome

Version:

Library implementing communication and abstraction layers for ExalusHome system

773 lines 129 kB
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 { Api } from "../../Api"; import { DataFrame, Method, Status } from "../../DataFrame"; import { ControllerExtensionsService } from "../Controller/ControllerExtensionsService"; import { DevicesService } from "../Devices/DevicesService"; import { ResponseResult } from "../FieldChangeResult"; import { CannotGetRuntimeErrorCode, CannotGetRuntimeInfo, UpdatesProvider } from "./UpdatesProvider"; import { ControllerUpdatesInfo, ControllerUpdateType, ControllerVersion, DeviceUpdateShortInfo, UpdateHistory } from "./IUpdateInfo"; import { ProviderType, UpdateInfo, UpdateTypes, UpdatesProviderNotFound } from "./IUpdatesProvider"; import { BulkUpdateResult, BulkUpdateStatus, DownloadProgressInfo, DownloadTask, UpdateBranch, UpdateErrorCode, UpdateProgressInfo, UpdateState, UpdateStatus, UserInput } from './IUpdatesService'; import { AppState } from "../IAppStateService"; import { AppStateService } from "../AppStateService"; import { LoggerService } from "../Logging/LoggerService"; import { ExalusConnectionService } from "../ExalusConnectionService"; import { Helpers, ParseObjToMap, Task } from "../../Helpers"; import { SessionService } from "../Session/SessionService"; import { ControllerConfigurationService } from "../Controller/ControllerConfigurationService"; export class UpdatesService { constructor() { this._controllerUpdates = []; this._updateRequestTimeout = 120000; this._oldUpdateVersion = 5; this._oldUpdateBuild = 56; this._updateOfflineStageTime = 15; this._updateProviders = Api.Get(UpdatesProvider.ServiceName); this._logger = Api.Get(LoggerService.ServiceName); this._connection = Api.Get(ExalusConnectionService.ServiceName); this._appStateService = Api.Get(AppStateService.ServiceName); this._extensionService = Api.Get(ControllerExtensionsService.ServiceName); } IsBranchAndAutomaticUpdatesSettingSupportedAsync() { return __awaiter(this, void 0, void 0, function* () { const ver = (yield this.getRuntimeInfoAsync()); if (ver instanceof ResponseResult) return false; const swVerInt = parseInt(ver.SoftwareVersion.toString().split('.')[0]); const buildVerInt = parseInt(ver.SoftwareVersion.toString().split('.')[1]); if (swVerInt < this._oldUpdateVersion || (swVerInt === this._oldUpdateVersion && buildVerInt <= this._oldUpdateBuild)) return false; return true; }); } DownloadControllerUpdateAsync(downloadProgress) { return __awaiter(this, void 0, void 0, function* () { // This method downloads the controller update using the new API, if available. // It does not install the update, only downloads it. try { const ver = yield this.getRuntimeInfoAsync(); if (ver instanceof ResponseResult) { return ver; } const swVerInt = parseInt(ver.SoftwareVersion.toString().split('.')[0]); const buildVerInt = parseInt(ver.SoftwareVersion.toString().split('.')[1]); // Only supported for new API (version > _oldUpdateVersion/_oldUpdateBuild) if (swVerInt < this._oldUpdateVersion || (swVerInt === this._oldUpdateVersion && buildVerInt <= this._oldUpdateBuild)) { return new ResponseResult(UpdateErrorCode.FeatureUnsupportedInCurrentVersion, `Cannot download update, feature unsupported in current version. Current version: ${ver}`); } // Use the API to download the update (downloadOnly = true) return yield this.DownloadControllerUpdateUsingApiAsync(() => { }, // No updateProgress callback needed for download-only downloadProgress, true); } catch (error) { return new ResponseResult(UpdateErrorCode.CannotProcessUpdate, `Failed to download controller update: ${error}`); } }); } InstallControllerOrRadioUpdateAsync(updateProgress, downloadProgress, updateGuid) { return __awaiter(this, void 0, void 0, function* () { const regGuid = new RegExp("^[{]?[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}[}]?$"); const numberOfUpdates = this._controllerUpdates.length; const ver = (yield this.getRuntimeInfoAsync()); if (ver instanceof ResponseResult) { return ver; } const swVerInt = parseInt(ver.SoftwareVersion.toString().split('.')[0]); const buildVerInt = parseInt(ver.SoftwareVersion.toString().split('.')[1]); //Check if any updates are avaliable if (this._controllerUpdates.length == 0) return new ResponseResult(UpdateErrorCode.CannotGetUpdates, `Cannot find any updates, make sure you check for available updates by calling CheckControllerUpdateAsync().`); //Install single update if (updateGuid !== undefined && (typeof updateGuid === 'string') && regGuid.test(updateGuid)) { let updateResult; const updateToInstall = this._controllerUpdates.find(update => update.UpdateIdentifier == updateGuid); if (updateToInstall == null) return new ResponseResult(UpdateErrorCode.CannotGetUpdates, `Update with requested guid (${updateGuid}) not found.`); this._logger.Debug(`Installing single update type: ${updateToInstall.Update.UpdateType}, resource: ${updateToInstall.UpdatedResourceName}, version: ${updateToInstall.Update.Version}`); this._appStateService.DisallowHibernation(); switch (updateToInstall.UpdateType) { case ControllerUpdateType.RadioUpdate: updateResult = yield (yield this._updateProviders.GetUpdatesProviderAsync(updateToInstall.ProviderName)).InstallRadioUpdateAsync(updateToInstall, updateProgress); this._appStateService.AllowHibernation(); this._logger.Debug(`Radio update result: ${updateResult}`); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != updateGuid); return updateResult; case ControllerUpdateType.SoftwareUpdate: //Old way if (swVerInt < this._oldUpdateVersion || (swVerInt === this._oldUpdateVersion && buildVerInt <= this._oldUpdateBuild)) { updateResult = yield this.UpdateControllerUsingScriptAsync(updateToInstall.Update, updateProgress); this._appStateService.AllowHibernation(); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != updateGuid); } //New way else { let availableUpdate = yield this.CheckControllerUpdatesAsync(); //let isDownloaded = availableUpdate.UpdatesAvailable.any(a => a.IsDownloadOnly); //if (!isDownloaded) { // await this.DownloadControllerUpdateAsync(downloadProgress); //} updateResult = yield this.UpdateControllerUsingApiAsync(updateProgress, downloadProgress, false); this._appStateService.AllowHibernation(); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != updateGuid); } return updateResult; default: return new ResponseResult(UpdateErrorCode.CannotProcessUpdate, `Update with type ${updateToInstall.UpdateType} is not supported by UpdateService.`); } } //Install all updates else { //Handle update progress with multiple updates. const updateNumberRef = [1]; const updateProgressWrapper = (progressInfo) => { progressInfo.UpdateNumber = updateNumberRef[0]; progressInfo.AvailableUpdates = numberOfUpdates; updateProgress(progressInfo); }; const timeout = (ms) => __awaiter(this, void 0, void 0, function* () { return new Promise(resolve => setTimeout(resolve, ms)); }); //First insall radio updates let updatesToInstall = this._controllerUpdates.where(update => update.UpdateType == ControllerUpdateType.RadioUpdate).toArray(); let result = []; this._appStateService.DisallowHibernation(); for (let i = 0; i < updatesToInstall.length; i++) { const updateResult = yield (yield this._updateProviders.GetUpdatesProviderAsync(updatesToInstall[i].ProviderName)).InstallRadioUpdateAsync(updatesToInstall[i], updateProgressWrapper); //Wait between updates yield timeout(5000); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != updatesToInstall[i].UpdateIdentifier); result.push(updateResult); updateNumberRef[0]++; } //Install other updates (in the future) //....// // //Install controller update const controlerUpdate = this._controllerUpdates.find(update => update.UpdateType == ControllerUpdateType.SoftwareUpdate); if (controlerUpdate != null) { //Old way if (swVerInt < this._oldUpdateVersion || (swVerInt === this._oldUpdateVersion && buildVerInt <= this._oldUpdateBuild)) { const updateResult = yield this.UpdateControllerUsingScriptAsync(controlerUpdate.Update, updateProgressWrapper); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != controlerUpdate.UpdateIdentifier); result.push(updateResult); updateNumberRef[0]++; } //New way else { const updateResult = yield this.UpdateControllerUsingApiAsync(updateProgressWrapper, downloadProgress, false); this._appStateService.AllowHibernation(); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != updateGuid); result.push(updateResult); updateNumberRef[0]++; } } const resultWithError = result.where(r => r instanceof ResponseResult).toArray(); if (resultWithError != null && resultWithError.length != 0) { let errors = ""; resultWithError.forEach(err => errors += `${err.Type}, `); this._appStateService.AllowHibernation(); if (resultWithError.any(err => err.Type == UpdateErrorCode.UpdateDownloadFailed)) return new ResponseResult(UpdateErrorCode.UpdateDownloadFailed, `Update download failed - not all updates were successfully downloaded. Installation error codes: ${errors}`); return new ResponseResult(UpdateErrorCode.UpdatesPartiallyInstalled, `Update installation finished - not all updates were successfully installed. Installation error codes: ${errors}`); } this._appStateService.AllowHibernation(); return Status.OK; } }); } GetAutomaticControllerUpdateDownloadStatusAsync() { return __awaiter(this, void 0, void 0, function* () { const ver = (yield this.getRuntimeInfoAsync()); if (ver instanceof ResponseResult) { return ver; } const swVerInt = parseInt(ver.SoftwareVersion.toString().split('.')[0]); const buildVerInt = parseInt(ver.SoftwareVersion.toString().split('.')[1]); if (swVerInt < this._oldUpdateVersion || (swVerInt === this._oldUpdateVersion && buildVerInt <= this._oldUpdateBuild)) return new ResponseResult(UpdateErrorCode.FeatureUnsupportedInCurrentVersion, `Cannot get update branch, feature unsupported in current version. Current version: ${ver}`); let result = yield this._connection.SendAndWaitForResponseAsync(new GetAutomaticUpdatesStatusRequest(), 10000, false); if (result.Status == Status.OK && result.Data) return true; else return false; }); } GetServiceName() { return UpdatesService.ServiceName; } CheckDeviceVersionAsync(dev) { return __awaiter(this, void 0, void 0, function* () { var _a; let device; if (typeof dev == 'string') { const result = yield Api.Get(DevicesService.ServiceName).GetDevice(dev); if (result != null) device = result; else return new ResponseResult(UpdateErrorCode.CannotFindDevice, `Device with specified GUID ${dev} does not exists.`); } else { device = dev; } if (device.ProtocolGuid == null) return new ResponseResult(UpdateErrorCode.UnsupportedDevice, `Device does not contains data about protocol GUID.`); const softwareInfo = yield ((_a = (yield this._updateProviders.GetUpdatesProvidersByProtocolAsync(device.ProtocolGuid, ProviderType.Device)).first()) === null || _a === void 0 ? void 0 : _a.GetSoftwareVersionAsync(device)); if (softwareInfo.Type != null) return softwareInfo; return softwareInfo; }); } CheckDeviceUpdateAsync(dev) { return __awaiter(this, void 0, void 0, function* () { var _a; let device; if (typeof dev == 'string') { const result = yield Api.Get(DevicesService.ServiceName).GetDevice(dev); if (result != null) device = result; else return new ResponseResult(UpdateErrorCode.CannotFindDevice, `Device with specified GUID ${dev} does not exists.`); } else { device = dev; } if (device.ProtocolGuid == null) return new ResponseResult(UpdateErrorCode.UnsupportedDevice, `Device does not contains data about protocol GUID.`); const updateInfo = yield ((_a = (yield this._updateProviders.GetUpdatesProvidersByProtocolAsync(device.ProtocolGuid, ProviderType.Device)).first()) === null || _a === void 0 ? void 0 : _a.GetAvailableUpdateAsync(device)); if (updateInfo.Type != null) return updateInfo; const result = new DeviceUpdate(); result.CurrentResourceVersion = updateInfo.CurrentResourceVersion; result.NewResourceVersion = updateInfo.Update.Version; result.UpdatedResourceName = updateInfo.UpdatedResourceName; result.UpdateResourceGuid = updateInfo.Update.ResourceGuid; result.UpdateDescription = new Map([["pl-PL", updateInfo.Update.Description]]); let protocol = "n/a"; try { protocol = (yield this._extensionService.GetProtocolInfoAsync(device.ProtocolGuid)).first().Name; } catch (error) { this._logger.Warning(`Cannot get protocol name! error: ${error}`); } result.Protocol = protocol; result.ProtocolGuid = device.ProtocolGuid; if ((yield Api.Get(DevicesService.ServiceName).GetDevicesAsync()).any(dev => dev.ModelGuid == "952ddc14-76c4-4f47-b0bc-5d106c1f9b02")) result.IsUpdateSafe = false; return result; }); } CheckDeviceUpdatesBulkAsync(reloadCache) { return __awaiter(this, void 0, void 0, function* () { const updateProviders = yield (yield this._updateProviders.GetUpdatesProvidersAsync(ProviderType.Device)); const result = []; for (var provider of updateProviders) { const updateInfo = yield provider.CheckUpdateBulkAsync(reloadCache); if (updateInfo instanceof ResponseResult) return updateInfo; for (const d of updateInfo) { const update = new DeviceUpdate(); update.CurrentResourceVersion = d.CurrentResourceVersion; update.NewResourceVersion = d.Update.Version; update.UpdatedResourceName = d.UpdatedResourceName; update.UpdateDescription = d.UpdateDescription; update.IsUpdateSafe = true; let protocol = "n/a"; try { protocol = (yield this._extensionService.GetProtocolInfoAsync(provider.ProtocolGuid)).first().Name; } catch (error) { this._logger.Warning(`Cannot get protocol name! error: ${error}`); } update.Protocol = protocol; update.ProtocolGuid = provider.ProtocolGuid; update.UpdateResourceGuid = d.Update.ResourceGuid; result.push(update); } } return result; }); } InstallDeviceUpdateAsync(dev_1, updateProgress_1, updateAction_1) { return __awaiter(this, arguments, void 0, function* (dev, updateProgress, updateAction, force = false) { var _a; let device; if (typeof dev == 'string') { const result = yield Api.Get(DevicesService.ServiceName).GetDevice(dev); if (result != null) device = result; else return new ResponseResult(UpdateErrorCode.CannotFindDevice, `Device with specified GUID ${dev} does not exists.`); } else { device = dev; } if (device.ProtocolGuid == null) return new ResponseResult(UpdateErrorCode.UnsupportedDevice, `Device does not contains data about protocol GUID.`); const updateInfo = yield ((_a = (yield this._updateProviders.GetUpdatesProvidersByProtocolAsync(device.ProtocolGuid, ProviderType.Device)).first()) === null || _a === void 0 ? void 0 : _a.GetAvailableUpdateAsync(device)); if (updateInfo.Type != null) return updateInfo; this._appStateService.DisallowHibernation(); const updateInstallResult = yield (yield this._updateProviders.GetUpdatesProvidersByProtocolAsync(device.ProtocolGuid, ProviderType.Device)).first().InstallUpdateAsync(updateInfo, updateProgress, updateAction, force); if (updateInstallResult.Type != null) { this._appStateService.AllowHibernation(); return updateInstallResult; } this._appStateService.AllowHibernation(); return Status.OK; }); } InstallDevicesUpdateBulkAsync(deviceGuids, updateProgress, updateAction) { return __awaiter(this, void 0, void 0, function* () { const grouppedDevs = (yield Api.Get(DevicesService.ServiceName).GetDevicesAsync()).where(d => deviceGuids.includes(d.Guid)).groupBy(d => d.ProtocolGuid); const result = []; this._appStateService.DisallowHibernation(); const grpCnt = grouppedDevs.count(); for (let i = 0; i < grpCnt; i++) { const grp = grouppedDevs.elementAt(i); const totalStartRange = i * (100 / grpCnt); const totalEndRange = (i + 1) * (100 / grpCnt); const progressFunctionWrapper = (progress) => { progress.PercentageTotal = Math.floor((progress.PercentageTotal / 100) * (totalEndRange - totalStartRange) + totalStartRange); updateProgress(progress); }; const updateProvider = yield (yield this._updateProviders.GetUpdatesProvidersByProtocolAsync(grp.key, ProviderType.Device)); const r = yield updateProvider.first().InstalUpdateBulkAsync(grp.select(d => d.Guid).toArray(), progressFunctionWrapper, updateAction); if (r instanceof ResponseResult) return r; result.push(r); } this._appStateService.AllowHibernation(); if (result.length == 1) return result[0]; else { const newBulkResult = new BulkUpdateResult(); if (result.some(r => r.DevicesUpdateResults.count() > 0) && result.any(r => r.BulkUpdateStatus != BulkUpdateStatus.Success)) { newBulkResult.BulkUpdateStatus = BulkUpdateStatus.PartialSuccess; } else if (result.any(r => r.BulkUpdateStatus != BulkUpdateStatus.Success)) { newBulkResult.BulkUpdateStatus = result.first().BulkUpdateStatus; } else { newBulkResult.BulkUpdateStatus = BulkUpdateStatus.Success; } for (const r of result) { r.DevicesUpdateResults.forEach((value, key) => { newBulkResult.DevicesUpdateResults.set(key, value); }); } return newBulkResult; } }); } CheckControllerSoftwareUpdateAvailabilityAsync() { return __awaiter(this, void 0, void 0, function* () { const user = Api.Get(SessionService.ServiceName).User; if (user == null) return false; //Very old software, does not contains information about software version (before 15.02.2024) if (user.SoftwareVersion == "" || user.SoftwareVersion == null) return true; //Old software, containse information about software version but does not supports API that gets updates in backgroud (new way) const [major, build] = user.SoftwareVersion.split('.'); if (parseFloat(major) < this._oldUpdateVersion || (parseFloat(major) == this._oldUpdateVersion && parseFloat(build) <= this._oldUpdateBuild)) return true; const result = yield this._connection.SendAndWaitForResponseAsync(new PendingUpdatesRequest(), 10000, false); if (result == null || result.Status != Status.OK || result.Data == null) return false; const [majorPening, buildPending] = result.Data.Update.Version.ContainerSoftwareVersion.toString().split('.'); if (parseInt(majorPening) > parseInt(major) || (parseInt(majorPening) == parseInt(major) && parseInt(buildPending) > parseInt(build))) return true; else return false; }); } CanCancelFailedControllerUpdateOrGetPendingUpdateProgress() { return Api.Get(ControllerConfigurationService.ServiceName).CheckIfControllerSoftwareVersionIsEnough(6, 66); } CancelFailedControllerUpdateAsync() { return __awaiter(this, void 0, void 0, function* () { const result = yield this._connection.SendAndWaitForResponseAsync(new CancelFailedUpdateRequest(), 10000, false); switch (result.Status) { case Status.OK: return Status.OK; case Status.OperationNotPermitted: return Status.OperationNotPermitted; case Status.Error: default: return Status.Error; } }); } CheckControllerPendingUpdateProgressAsync(updateProgress, downloadProgess) { return __awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { var _a; const user = Api.Get(SessionService.ServiceName).User; if (user == null) return resolve(new ResponseResult(UpdateErrorCode.UpdateActionsNotSupported, "No user data found, cannot check pending update progress.")); //Very old software, does not contains information about software version (before 15.02.2024) if (user.SoftwareVersion == "" || user.SoftwareVersion == null) return resolve(new ResponseResult(UpdateErrorCode.CannotGetCurrentControllerVersion, "No software version data found, cannot check pending update progress.")); //Old software, containse information about software version but does not supports API that gets updates in backgroud (new way) const [major, build] = user.SoftwareVersion.split('.'); if (parseFloat(major) < this._oldUpdateVersion || (parseFloat(major) == this._oldUpdateVersion && parseFloat(build) <= this._oldUpdateBuild)) return resolve(new ResponseResult(UpdateErrorCode.UnsupportedApiVersion, "Not supported API version, cannot check pending update progress.")); const pendingUpdateResult = yield this._connection.SendAndWaitForResponseAsync(new PendingUpdatesRequest(), 10000, false); let isAnyUpdatePending = pendingUpdateResult.Status == Status.OK; if (!isAnyUpdatePending) return resolve(new ResponseResult(UpdateErrorCode.CannotGetUpdates, "No pending updates found.")); let downloadOnly = (_a = pendingUpdateResult.Data) === null || _a === void 0 ? void 0 : _a.DownloadOnly; let endPercentage = 100; const totalTime = this._updateOfflineStageTime * 60 * 1000; // minutes let percentage = 0; const info = new UpdateProgressInfo(); let downloadProgressEndPercentage = 50; let dp = new DownloadProgressInfo(); let up = new UpdateProgressInfo(); let receivedFirstFrame = false; if (!downloadOnly) { dp.DownloadOnly = downloadOnly; downloadProgressEndPercentage = 100; } let downloadProgressOnePercentageMultiplier = 100 / downloadProgressEndPercentage; const handleReponse = (data) => { let tmp = data.Data; this._logger.Debug(`Update progress: ${tmp.UpdateStep}, ${tmp.StepProgressInPercentage}%, ${tmp.UpdateProgressInPercentage}% data frame status: ${data.Status}`); info.Percentage = Math.round(tmp.StepProgressInPercentage); info.PercentageTotal = Math.round(tmp.UpdateProgressInPercentage); dp.SpeedMbps = tmp.DownloadSpeedInMbs; dp.Percentage = Math.round(tmp.StepProgressInPercentage); dp.PercentageTotal = Math.round(tmp.UpdateProgressInPercentage); dp.UpdatedResourceName = new Map([["pl-PL", "Oprogramowanie kontrolera"], ["en-US", "Controller software"]]); up.AvailableUpdates = 1; up.Percentage = tmp.StepProgressInPercentage; up.PercentageTotal = tmp.UpdateProgressInPercentage; up.UpdatedResourceName = new Map([["pl-PL", "Oprogramowanie kontrolera"], ["en-US", "Controller software"]]); percentage = tmp.StepProgressInPercentage; switch (tmp.UpdateStep) { case UpdateStep.DownloadingInstaller: dp.CurrentTask = DownloadTask.DownloadingInstaller; up.Status = UpdateStatus.DownloadingPackage; downloadProgess(dp); //updateProgress(up); break; case UpdateStep.DownloadingUpdate: dp.CurrentTask = DownloadTask.DownloadingUpdate; up.Status = UpdateStatus.DownloadingPackage; downloadProgess(dp); //updateProgress(up); break; case UpdateStep.CheckingUpdate: dp.CurrentTask = DownloadTask.CheckingUpdate; up.Status = UpdateStatus.CheckingPackage; //downloadProgess(dp); updateProgress(up); break; case UpdateStep.PreparingUpdate: up.Status = UpdateStatus.PreparingForUpgrade; dp.CurrentTask = DownloadTask.CheckingUpdate; updateProgress(up); break; case UpdateStep.OfflineUpdateStep: case UpdateStep.InstallingUpdate: up.Status = UpdateStatus.Upgrading; updateProgress(up); break; case UpdateStep.InstallerFileSignCheckFailed: up.Status = UpdateStatus.InstallationError; updateProgress(up); break; case UpdateStep.UpdateFileSignCheckFailed: up.Status = UpdateStatus.InstallationError; updateProgress(up); break; case UpdateStep.UpdateDownloadFailed: up.Status = UpdateStatus.InstallationStopped; updateProgress(up); break; case UpdateStep.UpdateInstallationFailed: up.Status = UpdateStatus.InstallationError; updateProgress(up); break; case UpdateStep.UpdateFileCheckFailed: up.Status = UpdateStatus.IncompatiblePackage; updateProgress(up); break; case UpdateStep.UpdateDownloaded: dp.Percentage = 100; if (downloadOnly) dp.PercentageTotal = Math.round(tmp.UpdateProgressInPercentage * downloadProgressOnePercentageMultiplier); else dp.PercentageTotal = Math.round(tmp.UpdateProgressInPercentage); dp.SpeedMbps = 0; dp.CurrentTask = DownloadTask.CheckingUpdate; downloadProgess(dp); dp.CurrentTask = DownloadTask.UpdateDownloadedAndChecked; downloadProgess(dp); break; } }; let intervalId = null; const onReconnect = (state) => __awaiter(this, void 0, void 0, function* () { if (state == AppState.Connected) { clearInterval(intervalId); info.Status = UpdateStatus.Upgraded; info.Percentage = 100; info.PercentageTotal = 100; updateProgress(info); clearInterval(intervalId); yield Task.Delay(5000); resolve(Status.OK); Api.Get(AppStateService.ServiceName).OnAppStateChanged().Unsubscribe(onReconnect); } }); const result = yield this._connection.SendAndHandleResponseAsync(new PendingUpdateProgressRequest(), 100000, (data) => { var _a, _b, _c, _d, _e; switch (data.Status) { case Status.MultiDataResponseStart: if (!receivedFirstFrame) { if (((_a = data.Data) === null || _a === void 0 ? void 0 : _a.UpdateStep) == UpdateStep.UpdateDownloaded) endPercentage = 100; else endPercentage = 50; // 50% for download progress receivedFirstFrame = true; } handleReponse(data); break; case Status.MultiDataResponse: handleReponse(data); break; case Status.MultiDataResponseStop: switch ((_b = data.Data) === null || _b === void 0 ? void 0 : _b.UpdateStep) { case UpdateStep.UpdateInstallationFailed: up.Status = UpdateStatus.InstallationError; updateProgress(up); info.Percentage = 0; info.PercentageTotal = 0; updateProgress(info); resolve(new ResponseResult(UpdateErrorCode.CannotProcessUpdate, `Update installation failed!`)); break; case UpdateStep.InstallerFileSignCheckFailed: case UpdateStep.UpdateFileSignCheckFailed: case UpdateStep.UpdateDownloadFailed: case UpdateStep.UpdateFileCheckFailed: up.Status = UpdateStatus.DownloadingFailure; updateProgress(up); info.Percentage = 0; info.PercentageTotal = 0; updateProgress(info); resolve(new ResponseResult(UpdateErrorCode.UpdateDownloadFailed, `Update download failed!`)); break; case UpdateStep.OfflineUpdateStep: handleReponse(data); info.Percentage = Math.round(data.Data.StepProgressInPercentage); info.PercentageTotal = Math.round(data.Data.UpdateProgressInPercentage); let oneUpdateProgressPercent = (100 - info.PercentageTotal) / 100; let updateProgressPercent = info.PercentageTotal; //info.PercentageTotal = resp.Data.UpdateProgressInPercentage as Progress; // 78% const incrementTime = totalTime / (endPercentage - percentage); intervalId = setInterval(() => { percentage++; updateProgressPercent += oneUpdateProgressPercent; if (updateProgressPercent > 100) updateProgressPercent = 100; if (percentage >= endPercentage) { info.Status = UpdateStatus.Upgraded; info.Percentage = 100; info.PercentageTotal = 100; updateProgress(info); clearInterval(intervalId); resolve(Status.OK); } else { info.Status = UpdateStatus.Upgrading; info.Percentage = Math.round(percentage); info.PercentageTotal = Math.round(updateProgressPercent); updateProgress(info); } }, incrementTime); Api.Get(AppStateService.ServiceName).OnAppStateChanged().Subscribe(onReconnect); break; case UpdateStep.UpdateDownloaded: dp.Percentage = 100; if (downloadOnly) dp.PercentageTotal = Math.round(((_c = data.Data) === null || _c === void 0 ? void 0 : _c.UpdateProgressInPercentage) * downloadProgressOnePercentageMultiplier); else dp.PercentageTotal = Math.round((_d = data.Data) === null || _d === void 0 ? void 0 : _d.UpdateProgressInPercentage); dp.SpeedMbps = 0; dp.CurrentTask = DownloadTask.CheckingUpdate; downloadProgess(dp); dp.CurrentTask = DownloadTask.UpdateDownloadedAndChecked; downloadProgess(dp); if (downloadOnly) resolve(Status.OK); break; default: handleReponse(data); resolve(new ResponseResult(UpdateErrorCode.CannotProcessUpdate, `Update installation failed, received UpdateStep code: ${(_e = data.Data) === null || _e === void 0 ? void 0 : _e.UpdateStep}!`)); break; } break; default: reject(new ResponseResult(UpdateErrorCode.CannotGetUpdates, `Cannot get pending update progress, response is empty or status is not OK. Status: ${data === null || data === void 0 ? void 0 : data.Status}`)); } }, true); })); }); } CheckDevicesUpdatesAvailabilityAsync() { return __awaiter(this, void 0, void 0, function* () { const user = Api.Get(SessionService.ServiceName).User; if (user == null) return []; //Very old software, does not contains information about software version (before 15.02.2024) if (user.SoftwareVersion == "" || user.SoftwareVersion == null) return []; //Old software, containse information about software version but does not supports API that gets updates in backgroud (new way) const [major, build] = user.SoftwareVersion.split('.'); if (parseFloat(major) < 6 || (parseFloat(major) == 6 && parseFloat(build) <= 4)) return []; const result = yield this._connection.SendAndWaitForResponseAsync(new CheckDevicesUpdatesRequest(), 10000, false); const fResult = []; if (result == null || (result === null || result === void 0 ? void 0 : result.Status) != Status.OK || (result === null || result === void 0 ? void 0 : result.Data) == null) return []; result === null || result === void 0 ? void 0 : result.Data.forEach(d => { if (!d.IsAvailable) return; const info = new DeviceUpdateShortInfo(); info.DeviceGuid = d.DeviceGuid; info.CurrentVersion = d.CurrentVersion; info.NewVersion = d.NewVersion; fResult.push(info); }); return fResult; }); } CheckControllerUpdatesAsync() { return __awaiter(this, void 0, void 0, function* () { this._controllerUpdates = []; let updateProviderServices = []; const updates = new ControllerUpdatesInfo(); const runtimeInfo = yield this.getRuntimeInfoAsync(); if (runtimeInfo instanceof ResponseResult) { const error = new ControllerUpdateNotAvailableInfo(); error.UpdateType = ControllerUpdateType.SoftwareUpdate; error.ResponseResult = runtimeInfo; updates.UpdatesNotAvailable.push(error); return updates; } const swVerInt = parseInt(runtimeInfo.SoftwareVersion.toString().split('.')[0]); const buildVerInt = parseInt(runtimeInfo.SoftwareVersion.toString().split('.')[1]); try { updateProviderServices = yield this._updateProviders.GetUpdatesProvidersAsync(ProviderType.Controller); } catch (error) { if (error instanceof UpdatesProviderNotFound) { this._logger.Warning(`Cannot get update providers for controller protocols! Avaliable only controller software updates!`); } else throw error; } //Radio updates for (let i = 0; i < updateProviderServices.length; i++) { const result = yield updateProviderServices[i].GetAvailableRadioUpdateAsync(); if (result.Type != null) { const error = new ControllerUpdateNotAvailableInfo(); error.ResponseResult = result; error.UpdateType = ControllerUpdateType.RadioUpdate; let protocol = "n/a"; try { protocol = (yield this._extensionService.GetProtocolInfoAsync(updateProviderServices[i].ProtocolGuid)).first().Name; } catch (error) { this._logger.Warning(`Cannot get protocol name! error: ${error}`); } error.UpdatedResourceName = new Map([["pl-PL", protocol], ["en-US", protocol]]); error.CurrentResourceVersion = yield updateProviderServices[i].GetCurrentRadioVersionAsync(); updates.UpdatesNotAvailable.push(error); } else { const updateInfo = result; const update = new ControllerUpdate(); update.UpdatedResourceName = new Map([["pl-PL", updateInfo.UpdatedResourceName], ["en-US", updateInfo.UpdatedResourceName]]); update.CurrentResourceVersion = updateInfo.CurrentResourceVersion; update.NewResourceVersion = updateInfo.Update.Version; update.UpdateDescription = new Map([["pl-PL", updateInfo.Update.Description]]); update.UpdateType = ControllerUpdateType.RadioUpdate; update.UpdateIdentifier = Helpers.GenerateUUID(); update.UpdateIsDownloading = false; update.DownloadProgress = 100; update.UpdateCreationTime = null; updates.UpdatesAvailable.push(update); this._controllerUpdates.push(Object.assign(Object.assign({}, updateInfo), { UpdateIdentifier: update.UpdateIdentifier, ProviderName: updateProviderServices[i].GetUpdateProviderName(), UpdateType: ControllerUpdateType.RadioUpdate })); } } let isNewWayUpdate = true; if (swVerInt < this._oldUpdateVersion || (swVerInt === this._oldUpdateVersion && buildVerInt <= this._oldUpdateBuild)) isNewWayUpdate = false; //Software updates (new way) if (isNewWayUpdate) { const result = yield this._connection.SendAndWaitForResponseAsync(new PendingUpdatesRequest(), 15000, false); if (result == null || (result.Status != Status.OK && result.Status != Status.NoData)) throw (new Error(`Cannot get pending updates! Response is empty or status is not OK. Status: ${result === null || result === void 0 ? void 0 : result.Status}`)); if (result.Data != null) { const updateInfo = new UpdateInfo(); updateInfo.CurrentResourceVersion = `${runtimeInfo.RuntimeVersion}.${runtimeInfo.SoftwareVersion}`; updateInfo.UpdateDescription = ParseObjToMap(result.Data.Update.UpdateDescription); updateInfo.UpdatedResourceName = ParseObjToMap(result.Data.Update.UpdateName).get("en-US"); const update = new ControllerUpdate(); update.UpdatedResourceName = ParseObjToMap(result.Data.Update.UpdateName); update.UpdateDescription = ParseObjToMap(result.Data.Update.UpdateDescription); update.CurrentResourceVersion = `${runtimeInfo.RuntimeVersion}.${runtimeInfo.SoftwareVersion}`; update.NewResourceVersion = `${result.Data.Update.Version.BaseRuntime}.${result.Data.Update.Version.ContainerSoftwareVersion}`; update.UpdateType = ControllerUpdateType.SoftwareUpdate; update.UpdateIdentifier = result.Data.Update.Guid; update.UpdateIsDownloading = (result.Data.UpdateStep == UpdateStep.DownloadingInstaller || result.Data.UpdateStep == UpdateStep.DownloadingUpdate || result.Data.UpdateStep == UpdateStep.CheckingUpdate) ? true : false; update.DownloadProgress = result.Data.DownloadProgress; update.UpdateCreationTime = result.Data.Update.Creationtime; update.IsDownloadOnly = result.Data.DownloadOnly; updates.UpdatesAvailable.push(update); this._controllerUpdates.push(Object.assign(Object.assign({}, updateInfo), { UpdateIdentifier: update.UpdateIdentifier, ProviderName: UpdatesService.ServiceName, UpdateType: ControllerUpdateType.SoftwareUpdate })); } else { //If no updates - returns status NoData const result = yield this._connection.SendAndWaitForResponseAsync(new CheckUpdatesRequest(), 15000, false); if (result == null) throw new Error(`Cannot check updates! Response is empty.`); switch (result.Status) { case Status.NoData: const error = new ControllerUpdateNotAvailableInfo(); error.UpdateType = ControllerUpdateType.SoftwareUpdate; error.UpdatedResourceName = new Map([["pl-PL", "Oprogramowanie kontrolera"], ["en-US", "Controller software"]]); error.ResponseResult = new ResponseResult(UpdateErrorCode.DeviceIsUpToDate, `Updates not found, controller is already up-to-date.`); updates.UpdatesNotAvailable.push(error); break; case Status.OK: if (result.Data == null) throw new Error(`Cannot check updates! Response data is empty.`); const updateInfo = new UpdateInfo(); updateInfo.CurrentResourceVersion = `${runtimeInfo.RuntimeVersion}.${runtimeInfo.SoftwareVersion}`; updateInfo.UpdateDescription = ParseObjToMap(result.Data.UpdateDescription); updateInfo.UpdatedResourceName = ParseObjToMap(result.Data.UpdateName).get("en-US"); const update = new ControllerUpdate(); update.UpdatedResourceName = ParseObjToMap(result.Data.UpdateName); update.UpdateDescription = ParseObjToMap(result.Data.UpdateDescription); update.CurrentResourceVersion = `${runtimeInfo.RuntimeVersion}.${runtimeInfo.SoftwareVersion}`; update.UpdateType = ControllerUpdateType.SoftwareUpdate; update.UpdateIdentifi