From e6bfa1c50f751696f217d1f8be5716cffd7089ec Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Wed, 13 Apr 2022 11:25:14 +0200 Subject: [PATCH] Better dynamic entities discovery --- .../src/components/panels/Entities/Index.vue | 55 +++++++------------ platypush/entities/_engine.py | 19 +++++++ platypush/entities/devices.py | 2 +- platypush/entities/lights.py | 2 +- platypush/entities/switches.py | 2 +- 5 files changed, 43 insertions(+), 37 deletions(-) diff --git a/platypush/backend/http/webapp/src/components/panels/Entities/Index.vue b/platypush/backend/http/webapp/src/components/panels/Entities/Index.vue index 4b82501ae5..e72ea268b3 100644 --- a/platypush/backend/http/webapp/src/components/panels/Entities/Index.vue +++ b/platypush/backend/http/webapp/src/components/panels/Entities/Index.vue @@ -143,44 +143,30 @@ export default { }, async refresh() { - const actions = Object.keys( - Object.values(this.selector.selectedEntities).reduce((obj, entity) => { - if (entity.plugin) - obj[entity.plugin] = true - return obj - }, {}) - ).map((plugin) => `${plugin}.status`) + this.loadingEntities = Object.entries(this.entities).reduce((obj, [id, entity]) => { + const self = this + if (this.entityTimeouts[id]) + clearTimeout(this.entityTimeouts[id]) - this.loadingEntities = { - ...this.loadingEntities, - ...Object.keys(this.selector.selectedEntities).reduce((obj, id) => { - const self = this - const entity = this.entities[id] + this.entityTimeouts[id] = setTimeout(() => { + if (self.loadingEntities[id]) + delete self.loadingEntities[id] + if (self.entityTimeouts[id]) + delete self.entityTimeouts[id] - if (this.entityTimeouts[id]) - clearTimeout(this.entityTimeouts[id]) + self.errorEntities[id] = entity + self.notify({ + error: true, + title: entity.plugin, + text: `Scan timeout for ${entity.name}`, + }) + }, this.entityScanTimeout * 1000) - this.entityTimeouts[id] = setTimeout(() => { - if (self.loadingEntities[id]) - delete self.loadingEntities[id] - if (self.entityTimeouts[id]) - delete self.entityTimeouts[id] + obj[id] = true + return obj + }, {}) - self.errorEntities[id] = entity - self.notify({ - error: true, - title: entity.plugin, - text: `Scan timeout for ${entity.name}`, - }) - }, this.entityScanTimeout * 1000) - - obj[id] = true - return obj - }, {}), - } - - // Force refresh by calling `.status` on all the selected plugins - await Promise.all(actions.map((act) => this.request(act))) + await this.request('entities.scan') }, async sync() { @@ -231,6 +217,7 @@ export default { ...event.entity, meta: { ...(this.entities[entityId]?.meta || {}), + ...(meta[event.entity.type] || {}), ...(event.entity?.meta || {}), }, } diff --git a/platypush/entities/_engine.py b/platypush/entities/_engine.py index e7a72726f8..5330e68209 100644 --- a/platypush/entities/_engine.py +++ b/platypush/entities/_engine.py @@ -1,3 +1,4 @@ +import json from logging import getLogger from queue import Queue, Empty from threading import Thread, Event, RLock @@ -23,6 +24,7 @@ class EntitiesEngine(Thread): self.logger = getLogger(name=obj_name) self._queue = Queue() self._should_stop = Event() + self._entities_awaiting_flush = set() self._entities_cache_lock = RLock() self._entities_cache = { 'by_id': {}, @@ -110,6 +112,16 @@ class EntitiesEngine(Thread): self._populate_entity_id_from_cache(entity) if entity.id: get_bus().post(EntityUpdateEvent(entity=entity)) + else: + self._entities_awaiting_flush.add(self._to_entity_awaiting_flush(entity)) + + @staticmethod + def _to_entity_awaiting_flush(entity: Entity): + e = entity.to_json() + return json.dumps( + {k: v for k, v in e.items() if k in {'external_id', 'name', 'plugin'}}, + sort_keys=True, + ) def post(self, *entities: Entity): for entity in entities: @@ -226,3 +238,10 @@ class EntitiesEngine(Thread): with self._entities_cache_lock: for entity in entities: self._cache_entities(entity, overwrite_cache=True) + + entities_awaiting_flush = {*self._entities_awaiting_flush} + for entity in entities: + e = self._to_entity_awaiting_flush(entity) + if e in entities_awaiting_flush: + self._process_event(entity) + self._entities_awaiting_flush.remove(e) diff --git a/platypush/entities/devices.py b/platypush/entities/devices.py index 24820eef98..619a225293 100644 --- a/platypush/entities/devices.py +++ b/platypush/entities/devices.py @@ -6,7 +6,7 @@ from ._base import Entity class Device(Entity): __tablename__ = 'device' - id = Column(Integer, ForeignKey(Entity.id), primary_key=True) + id = Column(Integer, ForeignKey(Entity.id, ondelete='CASCADE'), primary_key=True) __mapper_args__ = { 'polymorphic_identity': __tablename__, diff --git a/platypush/entities/lights.py b/platypush/entities/lights.py index 44392aecba..b8fa26f3ac 100644 --- a/platypush/entities/lights.py +++ b/platypush/entities/lights.py @@ -6,7 +6,7 @@ from .devices import Device class Light(Device): __tablename__ = 'light' - id = Column(Integer, ForeignKey(Device.id), primary_key=True) + id = Column(Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True) __mapper_args__ = { 'polymorphic_identity': __tablename__, diff --git a/platypush/entities/switches.py b/platypush/entities/switches.py index e7dcfbde4d..3c7d6d1001 100644 --- a/platypush/entities/switches.py +++ b/platypush/entities/switches.py @@ -6,7 +6,7 @@ from .devices import Device class Switch(Device): __tablename__ = 'switch' - id = Column(Integer, ForeignKey(Device.id), primary_key=True) + id = Column(Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True) state = Column(Boolean) __mapper_args__ = {