Cameras on devices (openpanel C1): frames in memory, a binary uplink, demand
- Volatile frames are held in memory with a byte-bounded queue instead of the /dev/shm ring scanned on every put; workers keep writing to the directory, which is trimmed on a timer. A volatile upload no longer spools to disk. ARTIFACT_VOLATILE_BYTES=0 turns the ring off. - A device sends camera frames as binary messages on its socket, held and published in one step and credited to its device node; refused frames are logged and dropped. Its snapshot carries demand and the uplink (binary, or http through the portal). - One demand registry for every socket's wanted media, the tunnel's included, plus what running flows read, mapped onto on-demand ports and published as device_demand; at most 8 media names per socket. - Per-message deflate off in serve and dev; a device may fetch the last 8 digests of a message; published dashboards cached per store revision; a revoked device socket is closed with 1008. - Media tiles want bytes only while on screen; the Devices tab previews a wired camera; the device node warns when a flow reads an on-demand port.
This commit is contained in:
@@ -35,6 +35,7 @@ from fluksio_worker.worker_main import load_function
|
||||
|
||||
from fluksio.core.config import settings
|
||||
from fluksio.flow.alerts import AlertManager
|
||||
from fluksio.flow.demand import demand
|
||||
from fluksio.flow.events import EventBus
|
||||
from fluksio.flow.executor import ExecutionService
|
||||
from fluksio.flow.messages import MessageSpec, flow_of, qualify
|
||||
@@ -853,6 +854,9 @@ class FlowController:
|
||||
)
|
||||
finally:
|
||||
self._lock.release()
|
||||
# A device created, deleted or reporting changes whose ports send on
|
||||
# demand.
|
||||
demand.refresh()
|
||||
self._publish(
|
||||
{
|
||||
"type": "pipeline_rebuilt",
|
||||
@@ -868,9 +872,13 @@ class FlowController:
|
||||
An empty dashboard name is what a device refetches its own document
|
||||
on, and what its socket rescopes on. The first build only takes note:
|
||||
a device connecting later reads the document as it is.
|
||||
|
||||
What a running flow reads may have moved with it, so demand on the
|
||||
devices' ports is worked out again too.
|
||||
"""
|
||||
if self.devices is None:
|
||||
return
|
||||
demand.refresh()
|
||||
wiring = self.devices.wiring()
|
||||
known, self._device_wiring = self._device_wiring, wiring
|
||||
if known is not None and known != wiring:
|
||||
@@ -1488,6 +1496,23 @@ class FlowController:
|
||||
def values(self, flow: str | None = None) -> dict[str, dict[str, Any]]:
|
||||
return self.pipeline.values(flow) if self.pipeline else {}
|
||||
|
||||
def consumed_messages(self) -> set[str]:
|
||||
"""The messages a node of a running flow reads.
|
||||
|
||||
What keeps a device's on-demand port sending whether or not anyone is
|
||||
watching: a node that reads a camera wants every frame. A stopped or
|
||||
batch flow reads nothing until it runs, and a device node is passive.
|
||||
"""
|
||||
pipeline = self.pipeline
|
||||
if pipeline is None:
|
||||
return set()
|
||||
idle = self.disabled | self.batch
|
||||
return {
|
||||
name
|
||||
for name, nodes in pipeline.consumes.items()
|
||||
if any(node.flow not in idle for node in nodes)
|
||||
}
|
||||
|
||||
def get_node(self, node_id: str) -> Node | None:
|
||||
entry = self.loaded.get(node_id)
|
||||
return entry.node if entry else None
|
||||
|
||||
Reference in New Issue
Block a user