lavva.exalushome
Version:
Library implementing communication and abstraction layers for ExalusHome system
773 lines • 129 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 { 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