def get_common_context(event: core_events.Event) -> dict: timestamp = event.get_timestamp() moment = datetime.datetime.fromtimestamp(timestamp) return { 'event': event, 'type': event.get_type(), 'timestamp': int(timestamp), 'moment': moment, 'display_moment': moment.strftime('%c'), 'public_url': settings.public_url }
async def accepts(self, event: core_events.Event, value_pair: Tuple[NullablePortValue, NullablePortValue], old_attrs: Attributes, new_attrs: Attributes, changed_attrs: Dict[str, Tuple[Attribute, Attribute]], added_attrs: Attributes, removed_attrs: Attributes) -> bool: if not self._filter_prepared: self._prepare_filter() if self._filter_event_types and event.get_type( ) not in self._filter_event_types: return False if (isinstance(event, core_events.DeviceEvent) and not await self.accepts_device(event, old_attrs, new_attrs)): return False elif (isinstance(event, core_events.PortEvent) and not await self.accepts_port(event, value_pair, old_attrs, new_attrs)): return False elif (isinstance(event, slaves_events.SlaveDeviceEvent) and not await self.accepts_slave(event, old_attrs, new_attrs)): return False return True
async def on_value_change(self, event: core_events.Event, port: core_ports.BasePort, old_value: NullablePortValue, new_value: NullablePortValue, attrs: Attributes) -> None: # When period is specified, periodic_send_values() will take care of sending values if self._period is not None: return # Look up port id -> field number mapping; if not present, values for this port are not configured for sending field_no = self._fields.get(port.get_id()) if field_no is None: return self._values_cache[field_no] = new_value # Don't send samples more often than min_period now = time.time() if now - self._last_send_time < self._min_period: return self._last_send_time = now created_at = datetime.datetime.fromtimestamp(event.get_timestamp(), tz=pytz.UTC) try: await self.send_values(self._values_cache, created_at) except Exception as e: self.error('sending values failed: %s', e, exc_info=True) self._values_cache = {}
async def handle_event(self, event: core_events.Event) -> None: if not isinstance(event, core_events.ValueChange): return # We're only interested in port value changes if not system.date.has_real_date_time(): return # Don't record history unless we've got real date/time port = event.get_port() history_interval = await port.get_history_interval() if history_interval != -1: return # Only consider ports with history interval set to special -1 (on value change) now_ms = int(time.time() * 1000) await save_sample(port, now_ms) port.set_history_last_timestamp(now_ms)
def push(self, event: core_events.Event) -> None: # Deduplicate events while True: duplicates = [e for e in self.queue if event.is_duplicate(e)] if not duplicates: break for d in duplicates: self.queue.remove(d) logger.debug('dropping duplicate event %s from %s', d, self) # Ensure max queue size while len(self.queue) >= settings.core.event_queue_size: logger.warning('%s queue full, dropping oldest event', self) self.queue.pop() self.queue.insert(0, event)
def push(self, event: core_events.Event) -> None: # Deduplicate events while True: duplicates = [e for e in self.queue if event.is_duplicate(e)] if not duplicates: break for d in duplicates: self.queue.remove(d) self.debug('dropping duplicate event %s', d) # Ensure max queue size while len(self.queue) >= settings.core.event_queue_size: # This is a debug and not a warning because we often expect event drops from queues belonging to sessions # that are no longer active and will simply no longer consume the events self.debug('queue full, dropping oldest event') self.queue.pop() self.queue.insert(0, event)
async def handle_event(self, event: core_events.Event) -> None: (value_pair, old_attrs, new_attrs, changed_attrs, added_attrs, removed_attrs) = await self._update_from_event(event) accepted = await self.accepts(event, value_pair, old_attrs, new_attrs, changed_attrs, added_attrs, removed_attrs) if not accepted: return self.debug('handling event %s', event) try: await self.on_event(event) except Exception as e: self.error('failed to handle event %s: %s', event, e, exc_info=True) try: if isinstance(event, core_events.ValueChange): old_value, new_value = value_pair await self.on_value_change(event, event.get_port(), old_value, new_value, new_attrs) elif isinstance(event, core_events.PortUpdate): await self.on_port_update(event, event.get_port(), old_attrs, new_attrs, changed_attrs, added_attrs, removed_attrs) elif isinstance(event, core_events.PortAdd): await self.on_port_add(event, event.get_port(), new_attrs) elif isinstance(event, core_events.PortRemove): await self.on_port_remove(event, event.get_port(), new_attrs) elif isinstance(event, core_events.DeviceUpdate): await self.on_device_update(event, old_attrs, new_attrs, changed_attrs, added_attrs, removed_attrs) elif isinstance(event, core_events.FullUpdate): await self.on_full_update(event) elif isinstance(event, slaves_events.SlaveDeviceUpdate): await self.on_slave_device_update(event, event.get_slave(), old_attrs, new_attrs, changed_attrs, added_attrs, removed_attrs) elif isinstance(event, slaves_events.SlaveDeviceAdd): await self.on_slave_device_add(event, event.get_slave(), new_attrs) elif isinstance(event, slaves_events.SlaveDeviceRemove): await self.on_slave_device_remove(event, event.get_slave(), new_attrs) except Exception as e: self.error('failed to handle event %s: %s', event, e, exc_info=True)
async def _update_from_event( self, event: core_events.Event ) -> Tuple[Tuple[NullablePortValue, NullablePortValue], Attributes, Attributes, Dict[str, Tuple[ Attribute, Attribute]], Attributes, Attributes]: value_pair = (None, None) old_attrs = {} new_attrs = {} changed_attrs = {} added_attrs = {} removed_attrs = {} if isinstance(event, core_events.PortEvent): port = event.get_port() old_attrs = self._port_attrs.get(port.get_id(), {}) new_attrs = await port.get_attrs() old_value = self._port_values.get(port.get_id()) new_value = port.get_last_read_value() value_pair = (old_value, new_value) if isinstance(event, (core_events.PortAdd, core_events.PortUpdate)): changed_attrs, added_attrs, removed_attrs = self._make_changed_added_removed( old_attrs, new_attrs) self._port_values[port.get_id()] = new_value self._port_attrs[port.get_id()] = new_attrs elif isinstance(event, core_events.PortRemove): self._port_values.pop(port.get_id(), None) removed_attrs = self._port_attrs.pop(port.get_id(), {}) elif isinstance(event, core_events.ValueChange): self._port_values[port.get_id()] = new_value elif isinstance(event, core_events.DeviceEvent): old_attrs = self._device_attrs new_attrs = event.get_attrs() changed_attrs, added_attrs, removed_attrs = self._make_changed_added_removed( old_attrs, new_attrs) self._device_attrs = new_attrs elif isinstance(event, slaves_events.SlaveDeviceEvent): slave = event.get_slave() slave_json = slave.to_json() # Flatten slave master properties and attributes old_attrs = self._slave_attrs.get(slave.get_name(), {}) new_attrs = dict(slave_json, **slave_json.pop('attrs')) if isinstance(event, (slaves_events.SlaveDeviceAdd, slaves_events.SlaveDeviceUpdate)): changed_attrs, added_attrs, removed_attrs = self._make_changed_added_removed( old_attrs, new_attrs) self._slave_attrs[slave.get_name()] = new_attrs elif isinstance(event, slaves_events.SlaveDeviceRemove): removed_attrs = self._slave_attrs.pop(slave.get_name(), {}) return value_pair, old_attrs, new_attrs, changed_attrs, added_attrs, removed_attrs
async def push_template_message(self, event: core_events.Event, context: dict) -> None: template = await self.render(event.get_type(), context) await self.push_message(event, **template)
def is_duplicate(self, event: core_events.Event) -> bool: return isinstance( event, self.__class__) and event.get_slave() == self.get_slave()