agentos_v8_runtime/
stream.rs1pub fn dispatch_stream_event(scope: &mut v8::HandleScope, event_type: &str, payload: &[u8]) {
16 let context = scope.get_current_context();
18 let global = context.global(scope);
19
20 let dispatch_names: &[&str] = match event_type {
21 "child_stdout" | "child_stderr" | "child_exit" => &["_childProcessDispatch"],
22 "http_request" => &["_httpServerDispatch"],
23 "http2" => &["_http2Dispatch"],
24 "stdin" | "stdin_end" => &["_stdinDispatch"],
25 "net_socket" => &["_netSocketDispatch"],
26 "signal" => &["__secureExecWasmSignalDispatch", "_signalDispatch"],
27 "timer" => &["_timerDispatch"],
28 _ => return, };
30
31 for dispatch_name in dispatch_names {
32 let key = v8::String::new(scope, dispatch_name).unwrap();
33 let maybe_fn = global.get(scope, key.into());
34
35 if let Some(func_val) = maybe_fn {
36 if func_val.is_function() {
37 let func = v8::Local::<v8::Function>::try_from(func_val).unwrap();
38
39 let event_str = v8::String::new(scope, event_type).unwrap();
41 let payload_val = if !payload.is_empty() {
42 let maybe_v8_payload = {
43 let tc = &mut v8::TryCatch::new(scope);
44 crate::bridge::deserialize_v8_value(tc, payload).ok()
45 };
46 match maybe_v8_payload {
47 Some(v) => v,
48 None => match std::str::from_utf8(payload) {
49 Ok(text) => match v8::String::new(scope, text) {
50 Some(json_text) => v8::json::parse(scope, json_text)
51 .unwrap_or_else(|| json_text.into()),
52 None => v8::null(scope).into(),
53 },
54 Err(_) => v8::null(scope).into(),
55 },
56 }
57 } else {
58 v8::null(scope).into()
59 };
60
61 let undefined = v8::undefined(scope);
62 let args: &[v8::Local<v8::Value>] = &[event_str.into(), payload_val];
63 func.call(scope, undefined.into(), args);
64 return;
65 }
66 }
67 }
68}
69
70pub fn dispatch_signal_event(scope: &mut v8::HandleScope, signal_name: &str, signal: i32) {
71 let payload = v8::Object::new(scope);
72 let signal_key = v8::String::new(scope, "signal").expect("static V8 string");
73 let signal_value = v8::String::new(scope, signal_name).expect("signal V8 string");
74 payload.set(scope, signal_key.into(), signal_value.into());
75 let number_key = v8::String::new(scope, "number").expect("static V8 string");
76 let number_value = v8::Integer::new(scope, signal);
77 payload.set(scope, number_key.into(), number_value.into());
78 let action_key = v8::String::new(scope, "action").expect("static V8 string");
79 let action_value = v8::String::new(scope, "default").expect("static V8 string");
80 payload.set(scope, action_key.into(), action_value.into());
81 dispatch_stream_value(scope, "signal", payload.into());
82}
83
84pub fn dispatch_timer_event(scope: &mut v8::HandleScope, timer_id: u64) {
85 let timer_id = v8::Number::new(scope, timer_id as f64);
86 dispatch_stream_value(scope, "timer", timer_id.into());
87}
88
89fn dispatch_stream_value(
90 scope: &mut v8::HandleScope,
91 event_type: &str,
92 payload: v8::Local<v8::Value>,
93) {
94 let context = scope.get_current_context();
95 let global = context.global(scope);
96 let dispatch_names: &[&str] = match event_type {
97 "signal" => &["__secureExecWasmSignalDispatch", "_signalDispatch"],
98 "timer" => &["_timerDispatch"],
99 _ => return,
100 };
101 for dispatch_name in dispatch_names {
102 let Some(key) = v8::String::new(scope, dispatch_name) else {
103 continue;
104 };
105 let Some(value) = global.get(scope, key.into()) else {
106 continue;
107 };
108 let Ok(function) = v8::Local::<v8::Function>::try_from(value) else {
109 continue;
110 };
111 let Some(event) = v8::String::new(scope, event_type) else {
112 return;
113 };
114 let undefined = v8::undefined(scope);
115 function.call(scope, undefined.into(), &[event.into(), payload]);
116 return;
117 }
118}
119
120#[derive(Clone, Copy, Debug, Eq, PartialEq)]
124pub enum ReadinessDispatch {
125 Delivered,
126 TargetMissing,
127 BridgeMissing,
128}
129
130pub fn dispatch_readiness(
131 scope: &mut v8::HandleScope,
132 capability_id: u64,
133 capability_generation: u64,
134 flags: agentos_runtime::readiness::ReadyFlags,
135) -> ReadinessDispatch {
136 let context = scope.get_current_context();
137 let global = context.global(scope);
138 let Some(key) = v8::String::new(scope, "_agentOSReadyDispatch") else {
139 return ReadinessDispatch::BridgeMissing;
140 };
141 let Some(value) = global.get(scope, key.into()) else {
142 return ReadinessDispatch::BridgeMissing;
143 };
144 let Ok(function) = v8::Local::<v8::Function>::try_from(value) else {
145 return ReadinessDispatch::BridgeMissing;
146 };
147
148 let capability_id = v8::BigInt::new_from_u64(scope, capability_id);
149 let capability_generation = v8::BigInt::new_from_u64(scope, capability_generation);
150 let flags = v8::Integer::new_from_unsigned(scope, u32::from(flags.bits()));
151 let undefined = v8::undefined(scope);
152 match function.call(
153 scope,
154 undefined.into(),
155 &[
156 capability_id.into(),
157 capability_generation.into(),
158 flags.into(),
159 ],
160 ) {
161 Some(result) if result.is_true() => ReadinessDispatch::Delivered,
162 _ => ReadinessDispatch::TargetMissing,
163 }
164}