2026-07-30 08:13:24 +08:00
|
|
|
//! Resident event/effect fixture covering every current Host-driven I/O family.
|
|
|
|
|
//!
|
|
|
|
|
//! The callback echoes stream chunks and datagrams, rearms fired timers,
|
|
|
|
|
//! acknowledges messages, and reflects extension commands. It owns no socket,
|
|
|
|
|
//! timer, or subscription handles; those resources remain in the Host driver.
|
|
|
|
|
|
2026-07-30 07:40:02 +08:00
|
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
|
|
|
|
|
|
|
|
mod bindings {
|
2026-07-30 08:13:24 +08:00
|
|
|
// One generated module contains both the base service export and resident
|
|
|
|
|
// actor export because this component world composes both WIT packages.
|
2026-07-30 07:40:02 +08:00
|
|
|
wit_bindgen::generate!({
|
|
|
|
|
path: "wit",
|
|
|
|
|
world: "resident-probe-component",
|
|
|
|
|
generate_all,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
use bindings::exports::wasmeld::resident::actor::{
|
|
|
|
|
DatagramSend, Effect, Event, Guest as ResidentGuest, MessageAck, SourceCommand, StreamWrite,
|
|
|
|
|
TimerArm,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static EVENTS_HANDLED: AtomicU64 = AtomicU64::new(0);
|
|
|
|
|
|
|
|
|
|
struct ResidentProbe;
|
|
|
|
|
|
|
|
|
|
impl bindings::Guest for ResidentProbe {
|
|
|
|
|
fn init(_config: Vec<u8>) -> Result<(), bindings::ServiceError> {
|
|
|
|
|
EVENTS_HANDLED.store(0, Ordering::Relaxed);
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn invoke(_input: Vec<u8>) -> Result<Vec<u8>, bindings::ServiceError> {
|
|
|
|
|
Ok(EVENTS_HANDLED
|
|
|
|
|
.load(Ordering::Relaxed)
|
|
|
|
|
.to_le_bytes()
|
|
|
|
|
.to_vec())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ResidentGuest for ResidentProbe {
|
|
|
|
|
fn handle_event(
|
|
|
|
|
input: Event,
|
|
|
|
|
) -> Result<Vec<Effect>, bindings::exports::wasmeld::resident::actor::ResidentError> {
|
2026-07-30 08:13:24 +08:00
|
|
|
// Event callbacks are serialized with normal invocations by the same
|
|
|
|
|
// Actor mailbox, so this in-memory count is deterministic per Actor.
|
2026-07-30 07:40:02 +08:00
|
|
|
EVENTS_HANDLED.fetch_add(1, Ordering::Relaxed);
|
|
|
|
|
Ok(match input {
|
|
|
|
|
Event::StreamData(chunk) => vec![Effect::WriteStream(StreamWrite {
|
|
|
|
|
stream_id: chunk.stream_id,
|
|
|
|
|
bytes: chunk.bytes,
|
|
|
|
|
})],
|
|
|
|
|
Event::Datagram(datagram) => vec![Effect::SendDatagram(DatagramSend {
|
|
|
|
|
endpoint_id: datagram.endpoint_id,
|
|
|
|
|
peer: datagram.peer,
|
|
|
|
|
bytes: datagram.bytes,
|
|
|
|
|
})],
|
|
|
|
|
Event::Timer(timer) => vec![Effect::ArmTimer(TimerArm {
|
|
|
|
|
timer_id: timer.timer_id,
|
|
|
|
|
delay_ms: 10,
|
|
|
|
|
interval_ms: None,
|
|
|
|
|
})],
|
|
|
|
|
Event::Message(message) => vec![Effect::AcknowledgeMessage(MessageAck {
|
|
|
|
|
subscription_id: message.subscription_id,
|
|
|
|
|
message_id: message.message_id,
|
|
|
|
|
})],
|
|
|
|
|
Event::Source(source) => vec![Effect::SourceCommand(SourceCommand {
|
|
|
|
|
source_id: source.source_id,
|
|
|
|
|
command: source.kind,
|
|
|
|
|
payload: source.payload,
|
|
|
|
|
})],
|
|
|
|
|
Event::StreamOpened(_)
|
|
|
|
|
| Event::StreamWritable(_)
|
|
|
|
|
| Event::StreamHalfClosed(_)
|
|
|
|
|
| Event::StreamClosed(_)
|
|
|
|
|
| Event::Shutdown => Vec::new(),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bindings::export!(ResidentProbe with_types_in bindings);
|