UNPKG

lavva.exalushome

Version:

Library implementing communication and abstraction layers for ExalusHome system

759 lines (758 loc) 99 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 { AppStateService } from "../AppStateService"; import { LoggerService } from "../Logging/LoggerService"; import { ExalusConnectionService } from "../ExalusConnectionService"; import { Helpers, ParseObjToMap } from "../../Helpers"; import { SessionService } from "../Session/SessionService"; export class UpdatesService { constructor() { this._controllerUpdates = []; this._updateRequestTimeout = 120000; this._oldUpdateVersion = 5; this._oldUpdateBuild = 56; this._updateOfflineStageTime = 11; 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); } 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; updateInfo.map((d) => __awaiter(this, void 0, void 0, function* () { 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; }); } 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; 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.UpdateIdentifier = result.Data.Guid; update.NewResourceVersion = `${result.Data.Version.BaseRuntime}.${result.Data.Version.ContainerSoftwareVersion}`; update.UpdateIsDownloading = false; update.DownloadProgress = 0; update.UpdateCreationTime = result.Data.Creationtime; updates.UpdatesAvailable.push(update); this._controllerUpdates.push(Object.assign(Object.assign({}, updateInfo), { UpdateIdentifier: update.UpdateIdentifier, ProviderName: UpdatesService.ServiceName, UpdateType: ControllerUpdateType.SoftwareUpdate })); break; default: throw new Error(`Cannot check updates! Response status is not OK. Status: ${result.Status}`); } } } //Software updates (old way) else { const url = `https://exalus-updates.tr7.pl/software/${runtimeInfo.UpdateChannel}/${runtimeInfo.RuntimeVersion}/${runtimeInfo.SoftwareVersion}/update.json`; try { const response = yield fetch(url); let updateData; let updateInfo = new UpdateInfo(); const error = new ControllerUpdateNotAvailableInfo(); error.UpdateType = ControllerUpdateType.SoftwareUpdate; error.UpdatedResourceName = new Map([["pl-PL", "Oprogramowanie kontrolera"], ["en-US", "Controller software"]]); switch (response.status) { case 200: if (response.body != null) updateData = (yield response.json()); break; case 404: error.ResponseResult = new ResponseResult(UpdateErrorCode.DeviceIsUpToDate, `Updates not found, controller is already up-to-date.`); updates.UpdatesNotAvailable.push(error); break; default: error.ResponseResult = new ResponseResult(UpdateErrorCode.CannotGetUpdates, `Response status code does not indicate success. Status: ${response.status}`); updates.UpdatesNotAvailable.push(error); break; } if (updateData != null) { updateInfo.CurrentResourceVersion = `${runtimeInfo.RuntimeVersion}.${runtimeInfo.SoftwareVersion}`; updateInfo.Update = updateData; const update = new ControllerUpdate(); update.UpdatedResourceName = new Map([["pl-PL", "Oprogramowanie kontrolera"], ["en-US", "Controller software"]]); update.CurrentResourceVersion = updateInfo.CurrentResourceVersion; update.NewResourceVersion = updateInfo.Update.Version; update.UpdateDescription = new Map([["pl-PL", updateInfo.Update.Description]]); update.UpdateType = ControllerUpdateType.SoftwareUpdate; update.UpdateIdentifier = Helpers.GenerateUUID(); update.DownloadProgress = 100; update.UpdateIsDownloading = false; update.UpdateCreationTime = null; updates.UpdatesAvailable.push(update); this._controllerUpdates.push(Object.assign(Object.assign({}, updateInfo), { UpdateIdentifier: update.UpdateIdentifier, ProviderName: UpdatesService.ServiceName, UpdateType: ControllerUpdateType.SoftwareUpdate })); } else if (response.status == 200) throw (new Error(`Cannot get Update Data from response. Status: ${response.status}`)); } catch (err) { const runtimeInfo = (yield this.getRuntimeInfoAsync()); if (runtimeInfo instanceof ResponseResult) { const error = new ControllerUpdateNotAvailableInfo(); error.UpdateType = ControllerUpdateType.SoftwareUpdate; error.UpdatedResourceName = new Map([["pl-PL", "Oprogramowanie kontrolera"], ["en-US", "Controller software"]]); error.ResponseResult = runtimeInfo; updates.UpdatesNotAvailable.push(error); } else { 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.CannotGetUpdates, `Cannot get available updates! ${err}`); error.CurrentResourceVersion = `${runtimeInfo.RuntimeVersion}.${runtimeInfo.SoftwareVersion}`; updates.UpdatesNotAvailable.push(error); } } } return updates; }); } CheckControllerVersionAsync() { return __awaiter(this, void 0, void 0, function* () { const updateProviderServices = yield this._updateProviders.GetUpdatesProvidersAsync(ProviderType.Controller); const runtimeInfo = (yield this.getRuntimeInfoAsync()); if (runtimeInfo instanceof ResponseResult) { return runtimeInfo; } const result = []; let version; //Software updates version = new ControllerVersion(); version.Resource = "Controller software"; version.Type = ControllerUpdateType.SoftwareUpdate; version.Version = `${runtimeInfo.RuntimeVersion}.${runtimeInfo.SoftwareVersion}`; result.push(version); //Radio updates for (let i = 0; i < updateProviderServices.length; i++) { version = new ControllerVersion(); version.Version = yield updateProviderServices[i].GetCurrentRadioVersionAsync(); version.Type = 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}`); } version.Resource = protocol; result.push(version); } return result; }); } GetControllerUpdateBranchAsync() { 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}`); const result = yield this._connection.SendAndWaitForResponseAsync(new GetUpdateBranchRequest(), 10000, false); if (result == null || (result === null || result === void 0 ? void 0 : result.Status) != Status.OK) return new ResponseResult(UpdateErrorCode.CannotGetUpdatesBranch, `Cannot get update branch, response is empty or status is not OK. Status: ${result === null || result === void 0 ? void 0 : result.Status}`); switch (result.Data) { case 0: return UpdateBranch.Public; case 1: return UpdateBranch.Beta; case 2: return UpdateBranch.Development; default: return new ResponseResult(UpdateErrorCode.CannotGetUpdatesBranch, `Cannot get update branch, unknown branch number. Branch number: ${result.Data}`); } }); } SetControllerUpdateBranchAsync(updateBranch) { 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 set update branch, feature unsupported in current version. Current version: ${ver}`); const result = yield this._connection.SendAndWaitForResponseAsync(new SetUpdateBranchRequest(updateBranch), 10000, false); if (result == null || (result === null || result === void 0 ? void 0 : result.Status) != Status.OK) return new ResponseResult(UpdateErrorCode.CannotSetUpdatesBranch, `Cannot set update branch, response is empty or status is not OK. Status: ${result === null || result === void 0 ? void 0 : result.Status}`); return Status.OK; }); } EnableAutomaticControllerUpdateDonwloadAsync() { 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 enable automatic updates download, feature unsupported in current version. Current version: ${ver}`); const result = yield this._connection.SendAndWaitForResponseAsync(new EnableAutomaticUpdatesRequest(), 10000, false); if (result == null || (result === null || result === void 0 ? void 0 : result.Status) != Status.OK) return new ResponseResult(UpdateErrorCode.CannotSetUpdatesBranch, `Cannot enable automatic updates download, response is empty or status is not OK. Status: ${result === null || result === void 0 ? void 0 : result.Status}`); return Status.OK; }); } DisableAutomaticControllerUpdateDonwloadAsync() { 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 disable automatic update download, feature unsupported in current version. Current version: ${ver}`); const result = yield this._connection.SendAndWaitForResponseAsync(new DisableAutomaticUpdatesRequest(), 10000, false); if (result == null || (result === null || result === void 0 ? void 0 : result.Status) != Status.OK) return new ResponseResult(UpdateErrorCode.CannotSetUpdatesBranch, `Cannot disable automatic update download, response is empty or status is not OK. Status: ${result === null || result === void 0 ? void 0 : result.Status}`); return Status.OK; }); } GetControllerUpdatesHistoryAsync() { 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 disable automatic update download, feature unsupported in current version. Current version: ${ver}`); const result = yield this._connection.SendAndWaitForResponseAsync(new GetUpdatesHistoryRequest(), 10000, false); if (result == null) return new ResponseResult(UpdateErrorCode.CannotGetUpdates, `Cannot get updates history, response is empty.`); switch (result.Status) { case Status.OK: if (result.Data != null) return result.Data.map(d => { const update = new UpdateHistory(); update.UpdatedResourceName = ParseObjToMap(d.UpdateName); update.UpdateDescription = ParseObjToMap(d.UpdateDescription); update.UpdateCreationTime = d.Creationtime; update.UpdateChannel = d.UpdateChannel; update.Version = `${d.Version.BaseRuntime}.${d.Version.ContainerSoftwareVersion}`; return update; }); else return new ResponseResult(UpdateErrorCode.CannotGetUpdates, `Cannot get updates history, response data is empty.`); case Status.NoData: return []; default: return new ResponseResult(UpdateErrorCode.CannotGetUpdates, `Cannot get updates history, response status is not OK. Status: ${result.Status}`); } }); } InstallControllerUpdateAsync(updateProgress, downloadProgress, guidOrAction, downloadOnlyOrAction, updateAction) { 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 ((typeof guidOrAction === 'string') && regGuid.test(guidOrAction)) { let updateResult; const updateToInstall = this._controllerUpdates.find(update => update.UpdateIdentifier == guidOrAction); if (updateToInstall == null) return new ResponseResult(UpdateErrorCode.CannotGetUpdates, `Update with requested guid (${guidOrAction}) 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: if (downloadOnlyOrAction) return new ResponseResult(UpdateErrorCode.UpdateAlreadyDownloaded, `Update already downloaded set flag downloadOnly to false to install it.`); updateResult = yield (yield this._updateProviders.GetUpdatesProviderAsync(updateToInstall.ProviderName)).InstallRadioUpdateAsync(updateToInstall, updateProgress, updateAction); this._appStateService.AllowHibernation(); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != guidOrAction); return updateResult; case ControllerUpdateType.SoftwareUpdate: //Old way if (swVerInt < this._oldUpdateVersion || (swVerInt === this._oldUpdateVersion && buildVerInt <= this._oldUpdateBuild)) { if (downloadOnlyOrAction) return new ResponseResult(UpdateErrorCode.UpdateAlreadyDownloaded, `Update already downloaded set flag downloadOnly to false to install it.`); updateResult = yield this.UpdateControllerUsingScriptAsync(updateToInstall.Update, updateProgress); this._appStateService.AllowHibernation(); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != guidOrAction); } //New way else { updateResult = yield this.UpdateControllerUsingApiAsync(updateProgress, downloadProgress, downloadOnlyOrAction); this._appStateService.AllowHibernation(); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != guidOrAction); } 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, guidOrAction); //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, downloadOnlyOrAction); this._appStateService.AllowHibernation(); if (updateResult == Status.OK) this._controllerUpdates = this._controllerUpdates.filter(update => update.UpdateIdentifier != guidOrAction); 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(); return new ResponseResult(UpdateErrorCode.UpdatesPartiallyInstalled, `Update installation finished - not all updates were successfully installed. Installation error codes: ${errors}`); } this._appStateService.AllowHibernation(); return Status.OK; } }); } UpdateControllerUsingScriptAsync(update, updateProgress) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f; switch (update.UpdateType) { case UpdateTypes.Container: case UpdateTypes.ContainerSoftware: try { yield ((_a = this._connection) === null || _a === void 0 ? void 0 : _a.SendAndHandleResponseAsync(new ScriptControllerUpdateRequest(update.DownloadUri), this._updateRequestTimeout, (resp) => { const progressInfo = new UpdateProgressInfo(); progressInfo.UpdatedResourceName = new Map([["pl-PL", "Oprogramowanie kontrolera"], ["en-US", "Controller software"]]); switch (resp.Status) { case Status.MultiDataResponseStart: progressInfo.Status = UpdateStatus.PreparingForUpgrade; break; case Status.MultiDataResponse: if (resp.Data == null) { this._logger.Warning(UpdatesService.ServiceName, `Recived update response without data! URI: ${update.DownloadUri}`); return; } progressInfo.Percentage = Math.round(resp.Data.Progress); switch (resp.Data.State) { case UpdateState.CheckingApplicability: case UpdateState.CheckingIntegrity: case UpdateState.CheckingPackageIntegrity: progressInfo.Status = UpdateStatus.CheckingPackage; break; case UpdateState.CreatingBackup: case UpdateState.MigratingData: case UpdateState.Removing: progressInfo.Status = UpdateStatus.MovingData; break; case UpdateState.Deploying: case UpdateState.Installing: progressInfo.Status = UpdateStatus.Upgrading; break; case UpdateState.Downloading: progressInfo.Status = UpdateStatus.DownloadingPackage; break; case UpdateState.Error: progressInfo.Status = UpdateStatus.Error; break; case UpdateState.Installed: progressInfo.Status = UpdateStatus.Upgraded; break; case UpdateState.PreparingSystem: