From 90b4d249d47b461324c33b24884cede4468e9760 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 18 Feb 2023 16:58:53 -0800 Subject: [PATCH] Avoid duplicate engine creation. --- src/camera-manager/engine-factory.ts | 2 +- src/camera-manager/manager.ts | 55 +++++++++++++++++++--------- src/camera-manager/store.ts | 9 ++--- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/camera-manager/engine-factory.ts b/src/camera-manager/engine-factory.ts index 896e4251..850dddd2 100644 --- a/src/camera-manager/engine-factory.ts +++ b/src/camera-manager/engine-factory.ts @@ -22,7 +22,7 @@ export class CameraManagerEngineFactory { this._cardWideConfig = cardWideConfig; } - public async createEngine(engine: Engine): Promise { + public createEngine(engine: Engine): CameraManagerEngine | null { let cameraManagerEngine: CameraManagerEngine | null = null; switch (engine) { case Engine.Generic: diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index 9665a167..1a707984 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -30,6 +30,7 @@ import { RecordingSegmentsQueryResultsMap, ResultsMap, CameraEndpoints, + Engine, } from './types.js'; import orderBy from 'lodash-es/orderBy'; import { CameraManagerEngineFactory } from './engine-factory.js'; @@ -106,26 +107,39 @@ export class CameraManager { this._store = new CameraManagerStore(); } + protected async _getEnginesForCameras( + hass: HomeAssistant, + camerasConfig: CamerasConfig, + ): Promise> { + const output: Map = new Map(); + const engines: Map = new Map(); + + for (const cameraConfig of camerasConfig) { + const engineType = await this._engineFactory.getEngineForCamera( + hass, + cameraConfig, + ); + const engine = engineType + ? engines.get(engineType) ?? this._engineFactory.createEngine(engineType) + : null; + if (!engine || !engineType) { + throw new CameraInitializationError( + localize('error.no_camera_engine'), + cameraConfig, + ); + } + engines.set(engineType, engine); + output.set(cameraConfig, engine); + } + return output; + } + protected async _initializeCamera( hass: HomeAssistant, + engine: CameraManagerEngine, entityRegistryManager: EntityRegistryManager, inputCameraConfig: CameraConfig, ): Promise { - const engineType = await this._engineFactory.getEngineForCamera( - hass, - inputCameraConfig, - ); - const engine = engineType - ? this._store.getEngineOfType(engineType) ?? - (await this._engineFactory.createEngine(engineType)) - : null; - if (!engine) { - throw new CameraInitializationError( - localize('error.no_camera_engine'), - inputCameraConfig, - ); - } - const initializedConfig = await engine.initializeCamera( hass, entityRegistryManager, @@ -159,10 +173,15 @@ export class CameraManager { await entityRegistryManager.fetchEntityList(hass); } + // Engines are created sequentially, to avoid duplicate creation of the same + // engine. See: https://github.com/dermotduffy/frigate-hass-card/issues/941 + const engineByConfig = await this._getEnginesForCameras(hass, camerasConfig); + + // Configuration is initialized in parallel. const results = await allPromises( - camerasConfig, - async (cameraConfig) => - await this._initializeCamera(hass, entityRegistryManager, cameraConfig), + engineByConfig.entries(), + async ([cameraConfig, engine]) => + await this._initializeCamera(hass, engine, entityRegistryManager, cameraConfig), ); // Do the additions based off the result-order, to ensure the map order is diff --git a/src/camera-manager/store.ts b/src/camera-manager/store.ts index 7d13415c..c6203a20 100644 --- a/src/camera-manager/store.ts +++ b/src/camera-manager/store.ts @@ -1,4 +1,3 @@ -import uniq from 'lodash-es/uniq'; import { CameraConfig } from '../types'; import { ViewMedia } from '../view/media'; import { CameraManagerEngine } from './engine'; @@ -8,7 +7,7 @@ type CameraManagerEngineCameraIDMap = Map>; export class CameraManagerStore { protected _configs: Map = new Map(); - protected _engines: Map = new Map(); + protected _enginesByCamera: Map = new Map(); protected _enginesByType: Map = new Map(); public addCamera( @@ -17,7 +16,7 @@ export class CameraManagerStore { engine: CameraManagerEngine, ): void { this._configs.set(cameraID, cameraConfig); - this._engines.set(cameraID, engine); + this._enginesByCamera.set(cameraID, engine); this._enginesByType.set(engine.getEngineType(), engine); } @@ -54,7 +53,7 @@ export class CameraManagerStore { } public getEngineForCameraID(cameraID: string): CameraManagerEngine | null { - return this._engines.get(cameraID) ?? null; + return this._enginesByCamera.get(cameraID) ?? null; } public getEnginesForCameraIDs( @@ -84,6 +83,6 @@ export class CameraManagerStore { } public getAllEngines(): CameraManagerEngine[] { - return uniq([...this._engines.values()]); + return [...this._enginesByType.values()]; } }