Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait for WebRTC component to avoid loading race condition #296

Merged
merged 1 commit into from
Jan 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 40 additions & 20 deletions src/components/live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
import { EmblaOptionsType, EmblaPluginType } from 'embla-carousel';
import { HomeAssistant } from 'custom-card-helpers';
import { Ref, createRef, ref } from 'lit/directives/ref.js';
import { Task } from '@lit-labs/task';
import { customElement, property, state } from 'lit/decorators.js';
import { until } from 'lit/directives/until.js';

Expand Down Expand Up @@ -681,6 +682,9 @@ export class FrigateCardLiveWebRTC extends LitElement {

protected hass?: HomeAssistant & ExtendedHomeAssistant;

// A task to await the load of the WebRTC component.
protected _webrtcTask = new Task(this, this._getWebRTCElement, () => [1]);

/**
* Play the video.
*/
Expand Down Expand Up @@ -709,14 +713,22 @@ export class FrigateCardLiveWebRTC extends LitElement {
return this.renderRoot?.querySelector('#video') as HTMLVideoElement | null;
}

protected async _getWebRTCElement(): Promise<CustomElementConstructor | undefined> {
await customElements.whenDefined('webrtc-camera');
return customElements.get('webrtc-camera');
}

/**
* Create the WebRTC element. May throw.
*/
protected _createWebRTC(): HTMLElement | undefined {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const webrtcElement = customElements.get('webrtc-camera') as any;
if (webrtcElement) {
const webrtc = new webrtcElement();
const webrtcElement = this._webrtcTask.value;
if (webrtcElement && this.hass) {
const webrtc = new webrtcElement() as HTMLElement & {
hass: HomeAssistant;
setConfig: (config: Record<string, unknown>) => void;
};
const config = { ...this.webRTCConfig };

// If the live WebRTC configuration does not specify a URL/entity to use,
Expand All @@ -731,31 +743,39 @@ export class FrigateCardLiveWebRTC extends LitElement {
webrtc.setConfig(config);
webrtc.hass = this.hass;
return webrtc;
} else {
throw new FrigateCardError(localize('error.webrtc_missing'));
}
return undefined;
}

/**
* Master render method.
* @returns A rendered template.
*/
protected render(): TemplateResult | void {
if (!this.hass) {
return;
}
let webrtcElement: HTMLElement | undefined;
try {
webrtcElement = this._createWebRTC();
} catch (e) {
return dispatchErrorMessageEvent(
this,
e instanceof FrigateCardError
? (e as FrigateCardError).message
: localize('error.webrtc_reported_error') + ': ' + (e as Error).message,
);
}
return html`${webrtcElement}`;
const render = (): TemplateResult | void => {
let webrtcElement: HTMLElement | undefined;
try {
webrtcElement = this._createWebRTC();
} catch (e) {
return dispatchErrorMessageEvent(
this,
e instanceof FrigateCardError
? (e as FrigateCardError).message
: localize('error.webrtc_reported_error') + ': ' + (e as Error).message,
);
}
return html`${webrtcElement}`;
};

// Use a task to allow us to asynchronously wait for the WebRTC card to
// load, but yet still have the card load be followed by the updated()
// lifecycle callback (unlike just using `until`).
return html`${this._webrtcTask.render({
initial: () => renderProgressIndicator(localize('error.webrtc_waiting')),
pending: () => renderProgressIndicator(localize('error.webrtc_waiting')),
error: (e: unknown) => dispatchErrorMessageEvent(this, (e as Error).message),
complete: () => render(),
})}`;
}

/**
Expand Down
21 changes: 14 additions & 7 deletions src/components/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ export class FrigateCardMessage extends LitElement {
<span>
<ha-icon icon="${icon}"> </ha-icon>
</span>
<span>
${this.message ? html`${this.message}` : ''}
</span>
<span> ${this.message ? html`${this.message}` : ''} </span>
</div>`;
}

Expand All @@ -50,9 +48,15 @@ export class FrigateCardErrorMessage extends LitElement {

@customElement('frigate-card-progress-indicator')
export class FrigateCardProgressIndicator extends LitElement {
@property({ attribute: false })
protected message = '';

protected render(): TemplateResult {
return html` <div class="message">
<ha-circular-progress active="true" size="large"> </ha-circular-progress>
return html` <div class="message vertical">
<span>
<ha-circular-progress active="true" size="large"> </ha-circular-progress>
</span>
${this.message ? html`<span>${this.message}</span>` : html``}
</div>`;
}

Expand All @@ -75,6 +79,9 @@ export function renderMessage(message: Message): TemplateResult {
return html``;
}

export function renderProgressIndicator(): TemplateResult {
return html` <frigate-card-progress-indicator> </frigate-card-progress-indicator> `;
export function renderProgressIndicator(message?: string): TemplateResult {
return html`
<frigate-card-progress-indicator .message=${message || ''}>
</frigate-card-progress-indicator>
`;
}
2 changes: 1 addition & 1 deletion src/localize/languages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@
"invalid_configuration": "Invalid configuration",
"invalid_configuration_no_hint": "No location hint available (bad or missing type?)",
"upgrade_available": "An automated card configuration upgrade is available, please visit the visual card editor",
"webrtc_missing": "WebRTC component not found",
"webrtc_reported_error": "WebRTC component reported an error",
"webrtc_waiting": "Waiting for WebRTC Card to load ...",
"no_cameras": "No valid cameras found, you must configure at least one camera entry",
"no_camera_id": "Could not determine camera id for the following camera, may need to set 'id' parameter manually",
"duplicate_camera_id": "Duplicate Frigate camera id for the following camera, use the 'id' parameter to uniquely identify cameras",
Expand Down
6 changes: 5 additions & 1 deletion src/scss/message.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@
padding: 10%;
}

.vertical {
flex-direction: column;
}

.message a {
color: var(--primary-text-color, white);
}

span {
padding: 10px;
word-break: break-word;
}
}