swactor/crates/datastream/src/publisher_actor.rs
Zachery Aaron Shores-Chmielewski ce57012e11 feat: rework datastream into catalog events, add gguf metadata
- Rework the datastream endpoint into a catalog/event model (DatastreamEvent,
  SubscriptionRequest, channel/stream descriptors, DatastreamPublisherActor) across
  endpoint/frame/mux/wire/views.
- Add gguf_metadata planning reader, a dashboard hardware view, and iroh-driver
  datastream transport.
- Grow mvp-system orchestrator/worker_node bins and staging/provisioning; rename
  mvp_one_node_chat->mvp_chat; extend tinygrad worker.


Signed-off-by: Zachery Aaron Shores-Chmielewski <zacheryasc@gmail.com>
2026-07-12 10:14:34 +04:00

101 lines
3.3 KiB
Rust

//! Actor wrapper that exposes a local [`DatastreamEndpoint`] to remote
//! collectors.
//!
//! The actor owns the process-local subscription step. Transport-specific code is
//! injected by the runtime crate so the datastream core does not depend on the
//! concrete QUIC writer implementation.
use std::marker::PhantomData;
use std::sync::Arc;
use iroh::EndpointAddr;
use serde::Serialize;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize as DeriveSerialize};
use swactor::Error;
use swactor::actor::ActorInterface;
use swactor::runtime::Ctx;
use swactor_transport::{Codec, CodecRegistry, NetworkMessage};
use crate::{DatastreamEndpoint, DatastreamSubscription, SubscriptionRequest};
/// Well-known actor registry name for node-side datastream subscription requests.
pub const DATASTREAM_PUBLISHER_NAME: &str = "datastream-publisher";
/// Request sent from a collector/orchestrator to a node-local datastream publisher.
#[derive(Clone, Debug, DeriveSerialize, Deserialize)]
pub struct DatastreamSubscribe {
pub collector: EndpointAddr,
pub request: SubscriptionRequest,
pub flow_id: [u8; 16],
pub token: Vec<u8>,
}
/// Messages accepted by [`DatastreamPublisherActor`].
#[derive(Clone, Debug, DeriveSerialize, Deserialize)]
pub enum DatastreamPublisherMsg {
Subscribe(DatastreamSubscribe),
}
impl NetworkMessage for DatastreamPublisherMsg {
fn type_tag() -> &'static str {
"swactor::DatastreamPublisherMsg"
}
}
/// Node-side actor that turns remote subscribe messages into local endpoint
/// subscriptions, then hands the subscription to the caller's transport writer.
pub struct DatastreamPublisherActor {
endpoint: Arc<DatastreamEndpoint>,
on_subscribe: Box<dyn FnMut(DatastreamSubscribe, DatastreamSubscription) + Send>,
}
impl DatastreamPublisherActor {
pub fn new(
endpoint: Arc<DatastreamEndpoint>,
on_subscribe: impl FnMut(DatastreamSubscribe, DatastreamSubscription) + Send + 'static,
) -> Self {
Self {
endpoint,
on_subscribe: Box::new(on_subscribe),
}
}
}
impl ActorInterface for DatastreamPublisherActor {
type Incoming = DatastreamPublisherMsg;
type Response = ();
fn handle(&mut self, _ctx: &Ctx, msg: Self::Incoming) {
match msg {
DatastreamPublisherMsg::Subscribe(subscribe) => {
let subscription = self
.endpoint
.subscribe("remote-collector", subscribe.request.clone());
(self.on_subscribe)(subscribe, subscription);
}
}
}
}
/// Register JSON encoding for remote datastream publisher messages.
pub fn register_datastream_publisher_codec(registry: &mut CodecRegistry) {
registry.register::<DatastreamPublisherMsg, JsonCodec<DatastreamPublisherMsg>>(JsonCodec(
PhantomData,
));
}
struct JsonCodec<M>(PhantomData<M>);
impl<M> Codec<M> for JsonCodec<M>
where
M: Serialize + DeserializeOwned + Clone + Send + Sync + 'static,
{
fn encode(&self, msg: &M) -> Result<Vec<u8>, Error> {
serde_json::to_vec(msg).map_err(|e| Error::from(format!("encode: {e}")))
}
fn decode(&self, bytes: &[u8]) -> Result<M, Error> {
serde_json::from_slice(bytes).map_err(|e| Error::from(format!("decode: {e}")))
}
}