fix: Fix initialization race condition that occurs in certain circumstances (#1545)
* fix: Fix initialization race condition in certain circumstances * Minor improvements and camera iris logo
This commit is contained in:
+12
-7
@@ -11,6 +11,7 @@ import {
|
||||
CardHelpers,
|
||||
ExtendedHomeAssistant,
|
||||
FrigateCardError,
|
||||
LovelaceCardWithEditor,
|
||||
SignedPath,
|
||||
signedPathSchema,
|
||||
StateParameters,
|
||||
@@ -316,17 +317,21 @@ export const sideLoadHomeAssistantElements = async (): Promise<boolean> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const helpers: CardHelpers = await (window as any).loadCardHelpers();
|
||||
|
||||
// The picture-glance editor loads everything this card needs.
|
||||
const pictureGlance = await helpers.createCardElement({
|
||||
// This bizarre combination of hacks creates a dummy picture glance card, then
|
||||
// waits for it to be fully loaded/upgraded as a custom element, so it will
|
||||
// have the getConfigElement() method which is necessary to load all the
|
||||
// elements this card requires.
|
||||
await helpers.createCardElement({
|
||||
type: 'picture-glance',
|
||||
entities: [],
|
||||
camera_image: 'dummy-to-load-editor-components',
|
||||
});
|
||||
if (pictureGlance.constructor.getConfigElement) {
|
||||
await pictureGlance.constructor.getConfigElement();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
const pgcConstructor = await customElements.whenDefined('hui-picture-glance-card');
|
||||
const pgc = new pgcConstructor() as LovelaceCardWithEditor;
|
||||
|
||||
await pgc.constructor.getConfigElement();
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,21 +1,14 @@
|
||||
import { allPromises } from '../basic';
|
||||
|
||||
enum InitializationState {
|
||||
INITIALIZING = 'initializing',
|
||||
INITIALIZED = 'initialized',
|
||||
}
|
||||
|
||||
type InitializationCallback = () => Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Manages initialization state & calling initializers.
|
||||
* Manages initialization state & calling initializers. There is no guarantee
|
||||
* something will not be initialized twice unless there are concurrency controls
|
||||
* applied to the usage of this class.
|
||||
*/
|
||||
export class Initializer {
|
||||
protected _state: Map<string, InitializationState>;
|
||||
|
||||
constructor() {
|
||||
this._state = new Map();
|
||||
}
|
||||
protected _initialized: Set<string> = new Set();
|
||||
|
||||
public async initializeMultipleIfNecessary(
|
||||
aspects: Record<string, InitializationCallback>,
|
||||
@@ -27,43 +20,30 @@ export class Initializer {
|
||||
return results.every(Boolean);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param aspect The aspect to initialize.
|
||||
* @param initializer The initializer to call.
|
||||
* @returns `true` if the state is confirmed as initialized, `false`
|
||||
* otherwise (i.e. initializing).
|
||||
*/
|
||||
public async initializeIfNecessary(
|
||||
aspect: string,
|
||||
initializer?: InitializationCallback,
|
||||
): Promise<boolean> {
|
||||
const state = this._state.get(aspect);
|
||||
if (state !== InitializationState.INITIALIZED) {
|
||||
if (state !== InitializationState.INITIALIZING) {
|
||||
if (initializer) {
|
||||
this._state.set(aspect, InitializationState.INITIALIZING);
|
||||
if (await initializer()) {
|
||||
this._state.set(aspect, InitializationState.INITIALIZED);
|
||||
} else {
|
||||
this.uninitialize(aspect);
|
||||
}
|
||||
} else {
|
||||
this._state.set(aspect, InitializationState.INITIALIZED);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
if (this._initialized.has(aspect)) {
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
if (!initializer) {
|
||||
this._initialized.add(aspect);
|
||||
return true;
|
||||
}
|
||||
if (await initializer()) {
|
||||
this._initialized.add(aspect);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public uninitialize(aspect: string) {
|
||||
return this._state.delete(aspect);
|
||||
public uninitialize(aspect: string): void {
|
||||
this._initialized.delete(aspect);
|
||||
}
|
||||
|
||||
public isInitialized(aspect: string): boolean {
|
||||
return this._state.get(aspect) == InitializationState.INITIALIZED;
|
||||
return this._initialized.has(aspect);
|
||||
}
|
||||
|
||||
public isInitializedMultiple(aspects: string[]): boolean {
|
||||
|
||||
Reference in New Issue
Block a user