From 09e7600d8639b81600f3917d7678ebd93779a936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Thu, 18 Feb 2021 18:18:05 +0100 Subject: [PATCH] Use websockets (#8403) Co-authored-by: Bram Kragten --- cast/src/launcher/layout/hc-cast.ts | 2 +- hassio/src/addon-store/hassio-addon-store.ts | 77 ++++----- .../src/addon-view/hassio-addon-dashboard.ts | 16 +- .../src/addon-view/info/hassio-addon-info.ts | 105 ++++++++++-- hassio/src/dashboard/hassio-update.ts | 7 + hassio/src/hassio-main.ts | 11 +- hassio/src/hassio-router.ts | 3 +- hassio/src/supervisor-base-element.ts | 90 +++++++++- hassio/src/system/hassio-core-info.ts | 2 + hassio/src/system/hassio-host-info.ts | 17 +- hassio/src/system/hassio-supervisor-info.ts | 5 +- src/common/config/version.ts | 10 +- src/data/hassio/addon.ts | 156 ++++++++++++++++-- src/data/hassio/common.ts | 9 + src/data/hassio/docker.ts | 32 +++- src/data/hassio/hardware.ts | 25 ++- src/data/hassio/host.ts | 70 +++++++- src/data/hassio/ingress.ts | 45 +++-- src/data/hassio/network.ts | 35 +++- src/data/hassio/resolution.ts | 13 +- src/data/hassio/snapshot.ts | 52 +++++- src/data/hassio/supervisor.ts | 76 ++++++++- src/data/supervisor/core.ts | 11 ++ src/data/supervisor/supervisor.ts | 116 +++++++++++++ test-mocha/hassio/create_session.spec.ts | 25 ++- 25 files changed, 868 insertions(+), 142 deletions(-) diff --git a/cast/src/launcher/layout/hc-cast.ts b/cast/src/launcher/layout/hc-cast.ts index 1a00cd62dd..7bcbe70d59 100644 --- a/cast/src/launcher/layout/hc-cast.ts +++ b/cast/src/launcher/layout/hc-cast.ts @@ -48,7 +48,7 @@ class HcCast extends LitElement { protected render(): TemplateResult { if (this.lovelaceConfig === undefined) { - return html` > `; + return html``; } const error = diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts index 2e21b19f84..6add263da7 100644 --- a/hassio/src/addon-store/hassio-addon-store.ts +++ b/hassio/src/addon-store/hassio-addon-store.ts @@ -11,19 +11,18 @@ import { PropertyValues, } from "lit-element"; import { html, TemplateResult } from "lit-html"; +import memoizeOne from "memoize-one"; import { atLeastVersion } from "../../../src/common/config/version"; import { fireEvent } from "../../../src/common/dom/fire_event"; import "../../../src/common/search/search-input"; import "../../../src/components/ha-button-menu"; import "../../../src/components/ha-svg-icon"; import { - fetchHassioAddonsInfo, HassioAddonInfo, HassioAddonRepository, reloadHassioAddons, } from "../../../src/data/hassio/addon"; -import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import { fetchHassioSupervisorInfo } from "../../../src/data/hassio/supervisor"; +import { Supervisor } from "../../../src/data/supervisor/supervisor"; import "../../../src/layouts/hass-loading-screen"; import "../../../src/layouts/hass-tabs-subpage"; import { HomeAssistant, Route } from "../../../src/types"; @@ -51,46 +50,27 @@ const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => { class HassioAddonStore extends LitElement { @property({ attribute: false }) public hass!: HomeAssistant; + @property({ attribute: false }) public supervisor!: Supervisor; + @property({ type: Boolean }) public narrow!: boolean; @property({ attribute: false }) public route!: Route; - @property({ attribute: false }) private _addons?: HassioAddonInfo[]; - - @property({ attribute: false }) private _repos?: HassioAddonRepository[]; - @internalProperty() private _filter?: string; public async refreshData() { - this._repos = undefined; - this._addons = undefined; - this._filter = undefined; await reloadHassioAddons(this.hass); await this._loadData(); } protected render(): TemplateResult { - const repos: TemplateResult[] = []; + let repos: TemplateResult[] = []; - if (this._repos) { - for (const repo of this._repos) { - const addons = this._addons!.filter( - (addon) => addon.repository === repo.slug - ); - - if (addons.length === 0) { - continue; - } - - repos.push(html` - - `); - } + if (this.supervisor.addon.repositories) { + repos = this.addonRepositories( + this.supervisor.addon.repositories, + this.supervisor.addon.addons + ); } return html` @@ -159,6 +139,27 @@ class HassioAddonStore extends LitElement { this._loadData(); } + private addonRepositories = memoizeOne( + (repositories: HassioAddonRepository[], addons: HassioAddonInfo[]) => { + return repositories.sort(sortRepos).map((repo) => { + const filteredAddons = addons.filter( + (addon) => addon.repository === repo.slug + ); + + return filteredAddons.length !== 0 + ? html` + + ` + : html``; + }); + } + ); + private _handleAction(ev: CustomEvent) { switch (ev.detail.index) { case 0: @@ -181,7 +182,7 @@ class HassioAddonStore extends LitElement { private async _manageRepositories() { showRepositoriesDialog(this, { - repos: this._repos!, + repos: this.supervisor.addon.repositories, loadData: () => this._loadData(), }); } @@ -191,18 +192,8 @@ class HassioAddonStore extends LitElement { } private async _loadData() { - try { - const [addonsInfo, supervisor] = await Promise.all([ - fetchHassioAddonsInfo(this.hass), - fetchHassioSupervisorInfo(this.hass), - ]); - fireEvent(this, "supervisor-update", { supervisor }); - this._repos = addonsInfo.repositories; - this._repos.sort(sortRepos); - this._addons = addonsInfo.addons; - } catch (err) { - alert(extractApiErrorMessage(err)); - } + fireEvent(this, "supervisor-store-refresh", { store: "addon" }); + fireEvent(this, "supervisor-store-refresh", { store: "supervisor" }); } private async _filterChanged(e) { diff --git a/hassio/src/addon-view/hassio-addon-dashboard.ts b/hassio/src/addon-view/hassio-addon-dashboard.ts index add2c91e49..4c01e88c87 100644 --- a/hassio/src/addon-view/hassio-addon-dashboard.ts +++ b/hassio/src/addon-view/hassio-addon-dashboard.ts @@ -24,9 +24,7 @@ import { HassioAddonDetails, } from "../../../src/data/hassio/addon"; import { extractApiErrorMessage } from "../../../src/data/hassio/common"; -import { fetchHassioSupervisorInfo } from "../../../src/data/hassio/supervisor"; import { Supervisor } from "../../../src/data/supervisor/supervisor"; -import { showAlertDialog } from "../../../src/dialogs/generic/show-dialog-box"; import "../../../src/layouts/hass-error-screen"; import "../../../src/layouts/hass-loading-screen"; import "../../../src/layouts/hass-tabs-subpage"; @@ -192,7 +190,7 @@ class HassioAddonDashboard extends LitElement { const path: string = pathSplit[pathSplit.length - 1]; if (["uninstall", "install", "update", "start", "stop"].includes(path)) { - await this._updateSupervisor(); + fireEvent(this, "supervisor-store-refresh", { store: "supervisor" }); } if (path === "uninstall") { @@ -221,18 +219,6 @@ class HassioAddonDashboard extends LitElement { this.addon = undefined; } } - - private async _updateSupervisor(): Promise { - try { - const supervisor = await fetchHassioSupervisorInfo(this.hass); - fireEvent(this, "supervisor-update", { supervisor }); - } catch (err) { - showAlertDialog(this, { - title: "Failed to fetch supervisor information", - text: extractApiErrorMessage(err), - }); - } - } } declare global { diff --git a/hassio/src/addon-view/info/hassio-addon-info.ts b/hassio/src/addon-view/info/hassio-addon-info.ts index 5c43d2a1db..dfb1386662 100644 --- a/hassio/src/addon-view/info/hassio-addon-info.ts +++ b/hassio/src/addon-view/info/hassio-addon-info.ts @@ -43,10 +43,13 @@ import { HassioAddonSetOptionParams, HassioAddonSetSecurityParams, installHassioAddon, + restartHassioAddon, setHassioAddonOption, setHassioAddonSecurity, startHassioAddon, + stopHassioAddon, uninstallHassioAddon, + updateHassioAddon, validateHassioAddonOption, } from "../../../../src/data/hassio/addon"; import { @@ -196,13 +199,9 @@ class HassioAddonInfo extends LitElement { : ""}
- + Update - + ${this.addon.changelog ? html` @@ -579,20 +578,18 @@ class HassioAddonInfo extends LitElement { ${this.addon.version ? this._computeIsRunning ? html` - Stop - - + Restart - + ` : html` @@ -883,6 +880,82 @@ class HassioAddonInfo extends LitElement { button.progress = false; } + private async _stopClicked(ev: CustomEvent): Promise { + const button = ev.currentTarget as any; + button.progress = true; + + try { + await stopHassioAddon(this.hass, this.addon.slug); + const eventdata = { + success: true, + response: undefined, + path: "stop", + }; + fireEvent(this, "hass-api-called", eventdata); + } catch (err) { + showAlertDialog(this, { + title: "Failed to stop addon", + text: extractApiErrorMessage(err), + }); + } + button.progress = false; + } + + private async _restartClicked(ev: CustomEvent): Promise { + const button = ev.currentTarget as any; + button.progress = true; + + try { + await restartHassioAddon(this.hass, this.addon.slug); + const eventdata = { + success: true, + response: undefined, + path: "stop", + }; + fireEvent(this, "hass-api-called", eventdata); + } catch (err) { + showAlertDialog(this, { + title: "Failed to restart addon", + text: extractApiErrorMessage(err), + }); + } + button.progress = false; + } + + private async _updateClicked(ev: CustomEvent): Promise { + const button = ev.currentTarget as any; + button.progress = true; + + const confirmed = await showConfirmationDialog(this, { + title: this.addon.name, + text: "Are you sure you want to update this add-on?", + confirmText: "update add-on", + dismissText: "no", + }); + + if (!confirmed) { + button.progress = false; + return; + } + + this._error = undefined; + try { + await updateHassioAddon(this.hass, this.addon.slug); + const eventdata = { + success: true, + response: undefined, + path: "update", + }; + fireEvent(this, "hass-api-called", eventdata); + } catch (err) { + showAlertDialog(this, { + title: "Failed to update addon", + text: extractApiErrorMessage(err), + }); + } + button.progress = false; + } + private async _startClicked(ev: CustomEvent): Promise { const button = ev.currentTarget as any; button.progress = true; @@ -891,10 +964,10 @@ class HassioAddonInfo extends LitElement { this.hass, this.addon.slug ); - if (!validate.data.valid) { + if (!validate.valid) { await showConfirmationDialog(this, { title: "Failed to start addon - configuration validation failed!", - text: validate.data.message.split(" Got ")[0], + text: validate.message.split(" Got ")[0], confirm: () => this._openConfiguration(), confirmText: "Go to configuration", dismissText: "Cancel", diff --git a/hassio/src/dashboard/hassio-update.ts b/hassio/src/dashboard/hassio-update.ts index b2c8bb8bd9..488e541f2f 100644 --- a/hassio/src/dashboard/hassio-update.ts +++ b/hassio/src/dashboard/hassio-update.ts @@ -10,6 +10,7 @@ import { TemplateResult, } from "lit-element"; import memoizeOne from "memoize-one"; +import { fireEvent } from "../../../src/common/dom/fire_event"; import "../../../src/components/buttons/ha-progress-button"; import "../../../src/components/ha-card"; import "../../../src/components/ha-svg-icon"; @@ -64,6 +65,7 @@ export class HassioUpdate extends LitElement {
${this._renderUpdateCard( "Home Assistant Core", + "core", this.supervisor.core, "hassio/homeassistant/update", `https://${ @@ -72,6 +74,7 @@ export class HassioUpdate extends LitElement { )} ${this._renderUpdateCard( "Supervisor", + "supervisor", this.supervisor.supervisor, "hassio/supervisor/update", `https://github.com//home-assistant/hassio/releases/tag/${this.supervisor.supervisor.version_latest}` @@ -79,6 +82,7 @@ export class HassioUpdate extends LitElement { ${this.supervisor.host.features.includes("hassos") ? this._renderUpdateCard( "Operating System", + "os", this.supervisor.os, "hassio/os/update", `https://github.com//home-assistant/hassos/releases/tag/${this.supervisor.os.version_latest}` @@ -91,6 +95,7 @@ export class HassioUpdate extends LitElement { private _renderUpdateCard( name: string, + key: string, object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo, apiPath: string, releaseNotesUrl: string @@ -116,6 +121,7 @@ export class HassioUpdate extends LitElement { @@ -142,6 +148,7 @@ export class HassioUpdate extends LitElement { } try { await this.hass.callApi>("POST", item.apiPath); + fireEvent(this, "supervisor-store-refresh", { store: item.key }); } catch (err) { // Only show an error if the status code was not expected (user behind proxy) // or no status at all(connection terminated) diff --git a/hassio/src/hassio-main.ts b/hassio/src/hassio-main.ts index 81d736e881..31de2006d7 100644 --- a/hassio/src/hassio-main.ts +++ b/hassio/src/hassio-main.ts @@ -3,7 +3,9 @@ import { atLeastVersion } from "../../src/common/config/version"; import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element"; import { fireEvent } from "../../src/common/dom/fire_event"; import { HassioPanelInfo } from "../../src/data/hassio/supervisor"; +import { supervisorStore } from "../../src/data/supervisor/supervisor"; import { makeDialogManager } from "../../src/dialogs/make-dialog-manager"; +import "../../src/layouts/hass-loading-screen"; import { HomeAssistant, Route } from "../../src/types"; import "./hassio-router"; import { SupervisorBaseElement } from "./supervisor-base-element"; @@ -71,8 +73,15 @@ export class HassioMain extends SupervisorBaseElement { protected render() { if (!this.supervisor || !this.hass) { - return html``; + return html``; } + + if ( + Object.keys(supervisorStore).some((store) => !this.supervisor![store]) + ) { + return html``; + } + return html` ; + "supervisor-store-refresh": { store: SupervisorObject }; } } @@ -25,6 +41,20 @@ export class SupervisorBaseElement extends urlSyncMixin( ) { @property({ attribute: false }) public supervisor?: Supervisor; + @internalProperty() private _unsubs: Record = {}; + + @internalProperty() private _collections: Record< + string, + Collection + > = {}; + + public disconnectedCallback() { + super.disconnectedCallback(); + Object.keys(this._unsubs).forEach((unsub) => { + this._unsubs[unsub](); + }); + } + protected _updateSupervisor(obj: Partial): void { this.supervisor = { ...this.supervisor!, ...obj }; } @@ -32,13 +62,59 @@ export class SupervisorBaseElement extends urlSyncMixin( protected firstUpdated(changedProps: PropertyValues): void { super.firstUpdated(changedProps); this._initSupervisor(); - this.addEventListener("supervisor-update", (ev) => - this._updateSupervisor(ev.detail) + } + + private async _handleSupervisorStoreRefreshEvent(ev) { + const store = ev.detail.store; + if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) { + this._collections[store].refresh(); + return; + } + + const response = await this.hass.callApi>( + "GET", + `hassio${supervisorStore[store]}` ); + this._updateSupervisor({ [store]: response.data }); } private async _initSupervisor(): Promise { + this.addEventListener( + "supervisor-store-refresh", + this._handleSupervisorStoreRefreshEvent + ); + + if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) { + Object.keys(supervisorStore).forEach((store) => { + this._unsubs[store] = subscribeSupervisorEvents( + this.hass, + (data) => this._updateSupervisor({ [store]: data }), + store, + supervisorStore[store] + ); + if (this._collections[store]) { + this._collections[store].refresh(); + } else { + this._collections[store] = getSupervisorEventCollection( + this.hass.connection, + store, + supervisorStore[store] + ); + } + }); + + if (this.supervisor === undefined) { + Object.keys(this._collections).forEach((collection) => + this._updateSupervisor({ + [collection]: this._collections[collection].state, + }) + ); + } + return; + } + const [ + addon, supervisor, host, core, @@ -47,6 +123,7 @@ export class SupervisorBaseElement extends urlSyncMixin( network, resolution, ] = await Promise.all([ + fetchHassioAddonsInfo(this.hass), fetchHassioSupervisorInfo(this.hass), fetchHassioHostInfo(this.hass), fetchHassioHomeAssistantInfo(this.hass), @@ -57,6 +134,7 @@ export class SupervisorBaseElement extends urlSyncMixin( ]); this.supervisor = { + addon, supervisor, host, core, @@ -65,5 +143,9 @@ export class SupervisorBaseElement extends urlSyncMixin( network, resolution, }; + + this.addEventListener("supervisor-update", (ev) => + this._updateSupervisor(ev.detail) + ); } } diff --git a/hassio/src/system/hassio-core-info.ts b/hassio/src/system/hassio-core-info.ts index 96c3aad65f..985a242773 100644 --- a/hassio/src/system/hassio-core-info.ts +++ b/hassio/src/system/hassio-core-info.ts @@ -10,6 +10,7 @@ import { property, TemplateResult, } from "lit-element"; +import { fireEvent } from "../../../src/common/dom/fire_event"; import "../../../src/components/buttons/ha-progress-button"; import "../../../src/components/ha-button-menu"; import "../../../src/components/ha-card"; @@ -166,6 +167,7 @@ class HassioCoreInfo extends LitElement { try { await updateCore(this.hass); + fireEvent(this, "supervisor-store-refresh", { store: "core" }); } catch (err) { showAlertDialog(this, { title: "Failed to update Home Assistant Core", diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts index b4fd17f9b2..69245d8663 100644 --- a/hassio/src/system/hassio-host-info.ts +++ b/hassio/src/system/hassio-host-info.ts @@ -13,6 +13,7 @@ import { TemplateResult, } from "lit-element"; import memoizeOne from "memoize-one"; +import { atLeastVersion } from "../../../src/common/config/version"; import { fireEvent } from "../../../src/common/dom/fire_event"; import "../../../src/components/buttons/ha-progress-button"; import "../../../src/components/ha-button-menu"; @@ -26,7 +27,6 @@ import { fetchHassioHardwareInfo } from "../../../src/data/hassio/hardware"; import { changeHostOptions, configSyncOS, - fetchHassioHostInfo, rebootHost, shutdownHost, updateOS, @@ -340,6 +340,7 @@ class HassioHostInfo extends LitElement { try { await updateOS(this.hass); + fireEvent(this, "supervisor-store-refresh", { store: "os" }); } catch (err) { showAlertDialog(this, { title: "Failed to update", @@ -368,8 +369,7 @@ class HassioHostInfo extends LitElement { if (hostname && hostname !== curHostname) { try { await changeHostOptions(this.hass, { hostname }); - const host = await fetchHassioHostInfo(this.hass); - fireEvent(this, "supervisor-update", { host }); + fireEvent(this, "supervisor-store-refresh", { store: "host" }); } catch (err) { showAlertDialog(this, { title: "Setting hostname failed", @@ -382,8 +382,7 @@ class HassioHostInfo extends LitElement { private async _importFromUSB(): Promise { try { await configSyncOS(this.hass); - const host = await fetchHassioHostInfo(this.hass); - fireEvent(this, "supervisor-update", { host }); + fireEvent(this, "supervisor-store-refresh", { store: "host" }); } catch (err) { showAlertDialog(this, { title: "Failed to import from USB", @@ -393,8 +392,12 @@ class HassioHostInfo extends LitElement { } private async _loadData(): Promise { - const network = await fetchNetworkInfo(this.hass); - fireEvent(this, "supervisor-update", { network }); + if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) { + fireEvent(this, "supervisor-store-refresh", { store: "network" }); + } else { + const network = await fetchNetworkInfo(this.hass); + fireEvent(this, "supervisor-update", { network }); + } } static get styles(): CSSResult[] { diff --git a/hassio/src/system/hassio-supervisor-info.ts b/hassio/src/system/hassio-supervisor-info.ts index b29252d2ad..ebc96ab32a 100644 --- a/hassio/src/system/hassio-supervisor-info.ts +++ b/hassio/src/system/hassio-supervisor-info.ts @@ -19,7 +19,6 @@ import { HassioStats, } from "../../../src/data/hassio/common"; import { - fetchHassioSupervisorInfo, reloadSupervisor, restartSupervisor, setSupervisorOption, @@ -318,8 +317,7 @@ class HassioSupervisorInfo extends LitElement { private async _reloadSupervisor(): Promise { await reloadSupervisor(this.hass); - const supervisor = await fetchHassioSupervisorInfo(this.hass); - fireEvent(this, "supervisor-update", { supervisor }); + fireEvent(this, "supervisor-store-refresh", { store: "supervisor" }); } private async _supervisorRestart(ev: CustomEvent): Promise { @@ -368,6 +366,7 @@ class HassioSupervisorInfo extends LitElement { try { await updateSupervisor(this.hass); + fireEvent(this, "supervisor-store-refresh", { store: "supervisor" }); } catch (err) { showAlertDialog(this, { title: "Failed to update the supervisor", diff --git a/src/common/config/version.ts b/src/common/config/version.ts index cc6ccf7f7f..affdf9d94d 100644 --- a/src/common/config/version.ts +++ b/src/common/config/version.ts @@ -1,11 +1,15 @@ export const atLeastVersion = ( version: string, major: number, - minor: number + minor: number, + patch?: number ): boolean => { - const [haMajor, haMinor] = version.split(".", 2); + const [haMajor, haMinor, haPatch] = version.split(".", 3); return ( Number(haMajor) > major || - (Number(haMajor) === major && Number(haMinor) >= minor) + (Number(haMajor) === major && Number(haMinor) >= minor) || + (patch !== undefined && + Number(haMajor) === major && Number(haMinor) === minor && + Number(haPatch) >= patch) ); }; diff --git a/src/data/hassio/addon.ts b/src/data/hassio/addon.ts index 0429734bbd..b17f327097 100644 --- a/src/data/hassio/addon.ts +++ b/src/data/hassio/addon.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HaFormSchema } from "../../components/ha-form/ha-form"; import { HomeAssistant } from "../../types"; import { SupervisorArch } from "../supervisor/supervisor"; @@ -102,10 +103,28 @@ export interface HassioAddonSetOptionParams { } export const reloadHassioAddons = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/addons/reload", + method: "post", + }); + return; + } await hass.callApi>("POST", `hassio/addons/reload`); }; -export const fetchHassioAddonsInfo = async (hass: HomeAssistant) => { +export const fetchHassioAddonsInfo = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/addons", + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>("GET", `hassio/addons`) ); @@ -114,7 +133,15 @@ export const fetchHassioAddonsInfo = async (hass: HomeAssistant) => { export const fetchHassioAddonInfo = async ( hass: HomeAssistant, slug: string -) => { +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/info`, + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -149,6 +176,16 @@ export const setHassioAddonOption = async ( slug: string, data: HassioAddonSetOptionParams ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/options`, + method: "post", + data, + }); + return; + } + await hass.callApi>( "POST", `hassio/addons/${slug}/options`, @@ -159,21 +196,64 @@ export const setHassioAddonOption = async ( export const validateHassioAddonOption = async ( hass: HomeAssistant, slug: string -) => { - return await hass.callApi< - HassioResponse<{ message: string; valid: boolean }> - >("POST", `hassio/addons/${slug}/options/validate`); +): Promise<{ message: string; valid: boolean }> => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/options/validate`, + method: "post", + }); + } + + return ( + await hass.callApi>( + "POST", + `hassio/addons/${slug}/options/validate` + ) + ).data; }; export const startHassioAddon = async (hass: HomeAssistant, slug: string) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/start`, + method: "post", + timeout: null, + }); + } + return hass.callApi("POST", `hassio/addons/${slug}/start`); }; +export const stopHassioAddon = async (hass: HomeAssistant, slug: string) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/stop`, + method: "post", + timeout: null, + }); + } + + return hass.callApi("POST", `hassio/addons/${slug}/stop`); +}; + export const setHassioAddonSecurity = async ( hass: HomeAssistant, slug: string, data: HassioAddonSetSecurityParams ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/security`, + method: "post", + data, + }); + return; + } + await hass.callApi>( "POST", `hassio/addons/${slug}/security`, @@ -181,15 +261,61 @@ export const setHassioAddonSecurity = async ( ); }; -export const installHassioAddon = async (hass: HomeAssistant, slug: string) => { - return hass.callApi>( +export const installHassioAddon = async ( + hass: HomeAssistant, + slug: string +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/install`, + method: "post", + timeout: null, + }); + return; + } + + await hass.callApi>( "POST", `hassio/addons/${slug}/install` ); }; -export const restartHassioAddon = async (hass: HomeAssistant, slug: string) => { - return hass.callApi>( +export const updateHassioAddon = async ( + hass: HomeAssistant, + slug: string +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/update`, + method: "post", + timeout: null, + }); + return; + } + + await hass.callApi>( + "POST", + `hassio/addons/${slug}/update` + ); +}; + +export const restartHassioAddon = async ( + hass: HomeAssistant, + slug: string +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/restart`, + method: "post", + timeout: null, + }); + return; + } + + await hass.callApi>( "POST", `hassio/addons/${slug}/restart` ); @@ -199,6 +325,16 @@ export const uninstallHassioAddon = async ( hass: HomeAssistant, slug: string ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/addons/${slug}/uninstall`, + method: "post", + timeout: null, + }); + return; + } + await hass.callApi>( "POST", `hassio/addons/${slug}/uninstall` diff --git a/src/data/hassio/common.ts b/src/data/hassio/common.ts index 57a0afa59a..de6a28c68b 100644 --- a/src/data/hassio/common.ts +++ b/src/data/hassio/common.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; export interface HassioResponse { @@ -33,6 +34,14 @@ export const fetchHassioStats = async ( hass: HomeAssistant, container: string ): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/${container}/stats`, + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", diff --git a/src/data/hassio/docker.ts b/src/data/hassio/docker.ts index 4bc9a194c5..c8884336e0 100644 --- a/src/data/hassio/docker.ts +++ b/src/data/hassio/docker.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { hassioApiResultExtractor, HassioResponse } from "./common"; @@ -5,7 +6,17 @@ interface HassioDockerRegistries { [key: string]: { username: string; password?: string }; } -export const fetchHassioDockerRegistries = async (hass: HomeAssistant) => { +export const fetchHassioDockerRegistries = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/docker/registries`, + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -18,6 +29,16 @@ export const addHassioDockerRegistry = async ( hass: HomeAssistant, data: HassioDockerRegistries ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/docker/registries`, + method: "post", + data, + }); + return; + } + await hass.callApi>( "POST", "hassio/docker/registries", @@ -29,6 +50,15 @@ export const removeHassioDockerRegistry = async ( hass: HomeAssistant, registry: string ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/docker/registries/${registry}`, + method: "delete", + }); + return; + } + await hass.callApi>( "DELETE", `hassio/docker/registries/${registry}` diff --git a/src/data/hassio/hardware.ts b/src/data/hassio/hardware.ts index 2df7a8bcdd..11e70e8b69 100644 --- a/src/data/hassio/hardware.ts +++ b/src/data/hassio/hardware.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { hassioApiResultExtractor, HassioResponse } from "./common"; @@ -21,7 +22,17 @@ export interface HassioHardwareInfo { audio: Record; } -export const fetchHassioHardwareAudio = async (hass: HomeAssistant) => { +export const fetchHassioHardwareAudio = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/hardware/audio`, + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -30,7 +41,17 @@ export const fetchHassioHardwareAudio = async (hass: HomeAssistant) => { ); }; -export const fetchHassioHardwareInfo = async (hass: HomeAssistant) => { +export const fetchHassioHardwareInfo = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/hardware/info`, + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", diff --git a/src/data/hassio/host.ts b/src/data/hassio/host.ts index 79e518b4c9..2718adbcb4 100644 --- a/src/data/hassio/host.ts +++ b/src/data/hassio/host.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { hassioApiResultExtractor, HassioResponse } from "./common"; @@ -23,7 +24,17 @@ export interface HassioHassOSInfo { version: string | null; } -export const fetchHassioHostInfo = async (hass: HomeAssistant) => { +export const fetchHassioHostInfo = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/host/info", + method: "get", + }); + } + const response = await hass.callApi>( "GET", "hassio/host/info" @@ -31,7 +42,17 @@ export const fetchHassioHostInfo = async (hass: HomeAssistant) => { return hassioApiResultExtractor(response); }; -export const fetchHassioHassOsInfo = async (hass: HomeAssistant) => { +export const fetchHassioHassOsInfo = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/os/info", + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -41,22 +62,67 @@ export const fetchHassioHassOsInfo = async (hass: HomeAssistant) => { }; export const rebootHost = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/host/reboot", + method: "post", + timeout: null, + }); + } + return hass.callApi>("POST", "hassio/host/reboot"); }; export const shutdownHost = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/host/shutdown", + method: "post", + timeout: null, + }); + } + return hass.callApi>("POST", "hassio/host/shutdown"); }; export const updateOS = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/os/update", + method: "post", + timeout: null, + }); + } + return hass.callApi>("POST", "hassio/os/update"); }; export const configSyncOS = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "os/config/sync", + method: "post", + timeout: null, + }); + } + return hass.callApi>("POST", "hassio/os/config/sync"); }; export const changeHostOptions = async (hass: HomeAssistant, options: any) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/host/options", + method: "post", + data: options, + }); + } + return hass.callApi>( "POST", "hassio/host/options", diff --git a/src/data/hassio/ingress.ts b/src/data/hassio/ingress.ts index ced84a2698..83a211fc2e 100644 --- a/src/data/hassio/ingress.ts +++ b/src/data/hassio/ingress.ts @@ -1,26 +1,49 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { HassioResponse } from "./common"; import { CreateSessionResponse } from "./supervisor"; -export const createHassioSession = async (hass: HomeAssistant) => { - const response = await hass.callApi>( - "POST", - "hassio/ingress/session" - ); - document.cookie = `ingress_session=${ - response.data.session - };path=/api/hassio_ingress/;SameSite=Strict${ +function setIngressCookie(session: string): string { + document.cookie = `ingress_session=${session};path=/api/hassio_ingress/;SameSite=Strict${ location.protocol === "https:" ? ";Secure" : "" }`; - return response.data.session; + return session; +} + +export const createHassioSession = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + const wsResponse: { session: string } = await hass.callWS({ + type: "supervisor/api", + endpoint: "/ingress/session", + method: "post", + }); + return setIngressCookie(wsResponse.session); + } + + const restResponse: { data: { session: string } } = await hass.callApi< + HassioResponse + >("POST", "hassio/ingress/session"); + return setIngressCookie(restResponse.data.session); }; export const validateHassioSession = async ( hass: HomeAssistant, session: string -) => - await hass.callApi>( +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/ingress/validate_session", + method: "post", + data: session, + }); + } + + await hass.callApi>( "POST", "hassio/ingress/validate_session", { session } ); +}; diff --git a/src/data/hassio/network.ts b/src/data/hassio/network.ts index 542ee25d95..5aef6cc336 100644 --- a/src/data/hassio/network.ts +++ b/src/data/hassio/network.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { hassioApiResultExtractor, HassioResponse } from "./common"; @@ -51,7 +52,17 @@ export interface NetworkInfo { docker: DockerNetwork; } -export const fetchNetworkInfo = async (hass: HomeAssistant) => { +export const fetchNetworkInfo = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/network/info", + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -65,6 +76,17 @@ export const updateNetworkInterface = async ( network_interface: string, options: Partial ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: `/network/interface/${network_interface}/update`, + method: "post", + data: options, + timeout: null, + }); + return; + } + await hass.callApi>( "POST", `hassio/network/interface/${network_interface}/update`, @@ -75,7 +97,16 @@ export const updateNetworkInterface = async ( export const accesspointScan = async ( hass: HomeAssistant, network_interface: string -) => { +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/network/interface/${network_interface}/accesspoints`, + method: "get", + timeout: null, + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", diff --git a/src/data/hassio/resolution.ts b/src/data/hassio/resolution.ts index 677404f551..f108083cc5 100644 --- a/src/data/hassio/resolution.ts +++ b/src/data/hassio/resolution.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { hassioApiResultExtractor, HassioResponse } from "./common"; @@ -8,7 +9,17 @@ export interface HassioResolution { suggestions: string[]; } -export const fetchHassioResolution = async (hass: HomeAssistant) => { +export const fetchHassioResolution = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/resolution/info", + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", diff --git a/src/data/hassio/snapshot.ts b/src/data/hassio/snapshot.ts index 18157d1255..ecd82ded1c 100644 --- a/src/data/hassio/snapshot.ts +++ b/src/data/hassio/snapshot.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { hassioApiResultExtractor, HassioResponse } from "./common"; @@ -33,7 +34,18 @@ export interface HassioPartialSnapshotCreateParams { password?: string; } -export const fetchHassioSnapshots = async (hass: HomeAssistant) => { +export const fetchHassioSnapshots = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + const data: { snapshots: HassioSnapshot[] } = await hass.callWS({ + type: "supervisor/api", + endpoint: `/snapshots`, + method: "get", + }); + return data.snapshots; + } + return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -45,8 +57,15 @@ export const fetchHassioSnapshots = async (hass: HomeAssistant) => { export const fetchHassioSnapshotInfo = async ( hass: HomeAssistant, snapshot: string -) => { +): Promise => { if (hass) { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: `/snapshots/${snapshot}/info`, + method: "get", + }); + } return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -63,6 +82,15 @@ export const fetchHassioSnapshotInfo = async ( }; export const reloadHassioSnapshots = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/snapshots/reload", + method: "post", + }); + return; + } + await hass.callApi>("POST", `hassio/snapshots/reload`); }; @@ -70,6 +98,15 @@ export const createHassioFullSnapshot = async ( hass: HomeAssistant, data: HassioFullSnapshotCreateParams ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/snapshots/new/full", + method: "post", + timeout: null, + }); + return; + } await hass.callApi>( "POST", `hassio/snapshots/new/full`, @@ -81,6 +118,17 @@ export const createHassioPartialSnapshot = async ( hass: HomeAssistant, data: HassioFullSnapshotCreateParams ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/snapshots/new/partial", + method: "post", + timeout: null, + data, + }); + return; + } + await hass.callApi>( "POST", `hassio/snapshots/new/partial`, diff --git a/src/data/hassio/supervisor.ts b/src/data/hassio/supervisor.ts index a21cfd1915..f7ce56a64e 100644 --- a/src/data/hassio/supervisor.ts +++ b/src/data/hassio/supervisor.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant, PanelInfo } from "../../types"; import { SupervisorArch } from "../supervisor/supervisor"; import { HassioAddonInfo, HassioAddonRepository } from "./addon"; @@ -83,18 +84,57 @@ export interface SupervisorOptions { } export const reloadSupervisor = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/supervisor/reload", + method: "post", + }); + return; + } + await hass.callApi>("POST", `hassio/supervisor/reload`); }; export const restartSupervisor = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/supervisor/restart", + method: "post", + timeout: null, + }); + return; + } + await hass.callApi>("POST", `hassio/supervisor/restart`); }; export const updateSupervisor = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/supervisor/update", + method: "post", + timeout: null, + }); + return; + } + await hass.callApi>("POST", `hassio/supervisor/update`); }; -export const fetchHassioHomeAssistantInfo = async (hass: HomeAssistant) => { +export const fetchHassioHomeAssistantInfo = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/core/info", + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -103,7 +143,17 @@ export const fetchHassioHomeAssistantInfo = async (hass: HomeAssistant) => { ); }; -export const fetchHassioSupervisorInfo = async (hass: HomeAssistant) => { +export const fetchHassioSupervisorInfo = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/supervisor/info", + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>( "GET", @@ -112,7 +162,17 @@ export const fetchHassioSupervisorInfo = async (hass: HomeAssistant) => { ); }; -export const fetchHassioInfo = async (hass: HomeAssistant) => { +export const fetchHassioInfo = async ( + hass: HomeAssistant +): Promise => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + return await hass.callWS({ + type: "supervisor/api", + endpoint: "/info", + method: "get", + }); + } + return hassioApiResultExtractor( await hass.callApi>("GET", "hassio/info") ); @@ -129,6 +189,16 @@ export const setSupervisorOption = async ( hass: HomeAssistant, data: SupervisorOptions ) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/supervisor/options", + method: "post", + data, + }); + return; + } + await hass.callApi>( "POST", "hassio/supervisor/options", diff --git a/src/data/supervisor/core.ts b/src/data/supervisor/core.ts index 611fbabd36..0191dbe278 100644 --- a/src/data/supervisor/core.ts +++ b/src/data/supervisor/core.ts @@ -1,3 +1,4 @@ +import { atLeastVersion } from "../../common/config/version"; import { HomeAssistant } from "../../types"; import { HassioResponse } from "../hassio/common"; @@ -6,5 +7,15 @@ export const restartCore = async (hass: HomeAssistant) => { }; export const updateCore = async (hass: HomeAssistant) => { + if (atLeastVersion(hass.config.version, 2021, 2, 4)) { + await hass.callWS({ + type: "supervisor/api", + endpoint: "/core/update", + method: "post", + timeout: null, + }); + return; + } + await hass.callApi>("POST", `hassio/core/update`); }; diff --git a/src/data/supervisor/supervisor.ts b/src/data/supervisor/supervisor.ts index bc0161becf..1dbaecef2c 100644 --- a/src/data/supervisor/supervisor.ts +++ b/src/data/supervisor/supervisor.ts @@ -1,3 +1,7 @@ +import { Connection, getCollection } from "home-assistant-js-websocket"; +import { Store } from "home-assistant-js-websocket/dist/store"; +import { HomeAssistant } from "../../types"; +import { HassioAddonsInfo } from "../hassio/addon"; import { HassioHassOSInfo, HassioHostInfo } from "../hassio/host"; import { NetworkInfo } from "../hassio/network"; import { HassioResolution } from "../hassio/resolution"; @@ -7,7 +11,46 @@ import { HassioSupervisorInfo, } from "../hassio/supervisor"; +export const supervisorWSbaseCommand = { + type: "supervisor/api", + method: "GET", +}; + +export const supervisorStore = { + host: "/host/info", + supervisor: "/supervisor/info", + info: "/info", + core: "/core/info", + network: "/network/info", + resolution: "/resolution/info", + os: "/os/info", + addon: "/addons", +}; + export type SupervisorArch = "armhf" | "armv7" | "aarch64" | "i386" | "amd64"; +export type SupervisorObject = + | "host" + | "supervisor" + | "info" + | "core" + | "network" + | "resolution" + | "os" + | "addon"; + +interface supervisorApiRequest { + endpoint: string; + method?: "get" | "post" | "delete" | "put"; + force_rest?: boolean; + data?: any; +} + +export interface SupervisorEvent { + event: string; + update_key?: SupervisorObject; + data?: any; + [key: string]: any; +} export interface Supervisor { host: HassioHostInfo; @@ -17,4 +60,77 @@ export interface Supervisor { network: NetworkInfo; resolution: HassioResolution; os: HassioHassOSInfo; + addon: HassioAddonsInfo; } + +export const supervisorApiWsRequest = ( + conn: Connection, + request: supervisorApiRequest +): Promise => + conn.sendMessagePromise({ ...supervisorWSbaseCommand, ...request }); + +async function processEvent( + conn: Connection, + store: Store, + event: SupervisorEvent, + key: string +) { + if ( + !event.data || + event.data.event !== "supervisor-update" || + event.data.update_key !== key + ) { + return; + } + + if (Object.keys(event.data.data).length === 0) { + const data = await supervisorApiWsRequest(conn, { + endpoint: supervisorStore[key], + }); + store.setState(data); + return; + } + + const state = store.state; + if (state === undefined) { + return; + } + + store.setState({ + ...state, + ...event.data.data, + }); +} + +const subscribeSupervisorEventUpdates = ( + conn: Connection, + store: Store, + key: string +) => + conn.subscribeEvents( + (event) => processEvent(conn, store, event as SupervisorEvent, key), + "supervisor_event" + ); + +export const getSupervisorEventCollection = ( + conn: Connection, + key: string, + endpoint: string +) => + getCollection( + conn, + `_supervisor${key}Event`, + () => supervisorApiWsRequest(conn, { endpoint }), + (connection, store) => + subscribeSupervisorEventUpdates(connection, store, key) + ); + +export const subscribeSupervisorEvents = ( + hass: HomeAssistant, + onChange: (event) => void, + key: string, + endpoint: string +) => + getSupervisorEventCollection(hass.connection, key, endpoint).subscribe( + onChange + ); diff --git a/test-mocha/hassio/create_session.spec.ts b/test-mocha/hassio/create_session.spec.ts index 5fb5e7f59d..e308036eef 100644 --- a/test-mocha/hassio/create_session.spec.ts +++ b/test-mocha/hassio/create_session.spec.ts @@ -1,20 +1,21 @@ import * as assert from "assert"; import { createHassioSession } from "../../src/data/hassio/ingress"; -const sessionID = "fhdsu73rh3io4h8f3irhjel8ousafehf8f3yh"; - describe("Create hassio session", function () { + const hass = { + config: { version: "1.0.0" }, + callApi: async function () { + return { data: { session: "fhdsu73rh3io4h8f3irhjel8ousafehf8f3yh" } }; + }, + }; + it("Test create session without HTTPS", async function () { // @ts-ignore global.document = {}; // @ts-ignore global.location = {}; - await createHassioSession({ - // @ts-ignore - callApi: async function () { - return { data: { session: sessionID } }; - }, - }); + // @ts-ignore + await createHassioSession(hass); assert.strictEqual( // @ts-ignore global.document.cookie, @@ -26,12 +27,8 @@ describe("Create hassio session", function () { global.document = {}; // @ts-ignore global.location = { protocol: "https:" }; - await createHassioSession({ - // @ts-ignore - callApi: async function () { - return { data: { session: sessionID } }; - }, - }); + // @ts-ignore + await createHassioSession(hass); assert.strictEqual( // @ts-ignore global.document.cookie,