1use crate::host::{invoke, with_host, JsObj};
15use fusevm::Value;
16use indexmap::IndexMap;
17use std::collections::HashMap;
18use std::io::{Read, Write};
19use std::net::{TcpListener, TcpStream};
20use std::sync::atomic::{AtomicBool, Ordering};
21use std::sync::{Arc, Mutex};
22
23pub const MODULE_METHODS: &[&str] = &[
25 "createServer",
26 "connect",
27 "createConnection",
28 "isIP",
29 "isIPv4",
30 "isIPv6",
31 "getDefaultAutoSelectFamily",
32 "setDefaultAutoSelectFamily",
33 "getDefaultAutoSelectFamilyAttemptTimeout",
34 "setDefaultAutoSelectFamilyAttemptTimeout",
35];
36
37pub const BLOCKLIST_METHODS: &[&str] = &["addAddress", "addRange", "addSubnet", "check"];
40
41type ConnHook = std::rc::Rc<dyn Fn(&Value, &Value) -> Result<(), String>>;
45
46struct ServerRec {
48 emitter: Value,
50 stop: Arc<AtomicBool>,
52 conn_hook: Option<ConnHook>,
54}
55
56struct SocketRec {
58 emitter: Value,
60 write: Arc<Mutex<TcpStream>>,
63}
64
65#[derive(Default)]
66struct NetState {
67 next_id: u64,
68 servers: HashMap<u64, ServerRec>,
69 sockets: HashMap<u64, SocketRec>,
70}
71
72thread_local! {
73 static NET: std::cell::RefCell<NetState> = std::cell::RefCell::new(NetState::default());
74}
75
76fn next_id() -> u64 {
77 NET.with(|s| {
78 let mut s = s.borrow_mut();
79 s.next_id += 1;
80 s.next_id
81 })
82}
83
84pub fn new_emitter_object(tag: &str, mut extra: IndexMap<String, Value>) -> Value {
90 with_host(|h| {
91 let on = h.new_object(IndexMap::new());
92 let once = h.new_object(IndexMap::new());
93 let mut m = IndexMap::new();
94 m.insert("@@native".into(), h.new_str(tag));
95 m.insert("@@on".into(), on);
96 m.insert("@@once".into(), once);
97 for (k, v) in extra.drain(..) {
98 m.insert(k, v);
99 }
100 h.new_object(m)
101 })
102}
103
104fn get_prop(recv: &Value, key: &str) -> Option<Value> {
105 with_host(|h| match h.get(recv) {
106 Some(JsObj::Object(p)) => p.get(key).cloned(),
107 _ => None,
108 })
109}
110
111fn set_prop(recv: &Value, key: &str, val: Value) {
112 with_host(|h| {
113 if let Some(JsObj::Object(p)) = h.get_mut(recv) {
114 p.insert(key.to_string(), val);
115 }
116 });
117}
118
119fn u64_prop(recv: &Value, key: &str) -> Option<u64> {
120 get_prop(recv, key).map(|v| with_host(|h| h.to_number(&v)) as u64)
121}
122
123fn emitter_dispatch(recv: &Value, method: &str, args: &[Value]) -> Option<Result<Value, String>> {
126 match method {
127 "on"
128 | "addListener"
129 | "prependListener"
130 | "once"
131 | "prependOnceListener"
132 | "emit"
133 | "removeListener"
134 | "off"
135 | "removeAllListeners"
136 | "listenerCount"
137 | "eventNames" => Some(super::events::instance_call(recv, method, args.to_vec())),
138 _ => None,
139 }
140}
141
142pub fn call(method: &str, args: &[Value]) -> Option<Result<Value, String>> {
146 match method {
147 "createServer" => Some(Ok(create_server(args.first().cloned()))),
148 "connect" | "createConnection" => Some(Ok(connect(args))),
149 "isIP" => Some(Ok(Value::Float(is_ip(&arg_string(args, 0)) as f64))),
150 "isIPv4" => Some(Ok(Value::Bool(is_ip(&arg_string(args, 0)) == 4))),
151 "isIPv6" => Some(Ok(Value::Bool(is_ip(&arg_string(args, 0)) == 6))),
152 "getDefaultAutoSelectFamily" => Some(Ok(Value::Bool(AUTO_SELECT_FAMILY.with(|c| c.get())))),
153 "setDefaultAutoSelectFamily" => {
154 let v = args
155 .first()
156 .map(|a| with_host(|h| h.truthy(a)))
157 .unwrap_or(false);
158 AUTO_SELECT_FAMILY.with(|c| c.set(v));
159 Some(Ok(Value::Undef))
160 }
161 "getDefaultAutoSelectFamilyAttemptTimeout" => {
162 Some(Ok(Value::Float(AUTO_SELECT_TIMEOUT.with(|c| c.get()))))
163 }
164 "setDefaultAutoSelectFamilyAttemptTimeout" => {
165 let v = args
166 .first()
167 .map(|a| with_host(|h| h.to_number(a)))
168 .unwrap_or(f64::NAN);
169 if v.is_finite() && v >= 1.0 {
170 AUTO_SELECT_TIMEOUT.with(|c| c.set(v));
171 }
172 Some(Ok(Value::Undef))
173 }
174 _ => None,
175 }
176}
177
178thread_local! {
179 static AUTO_SELECT_FAMILY: std::cell::Cell<bool> = const { std::cell::Cell::new(true) };
182 static AUTO_SELECT_TIMEOUT: std::cell::Cell<f64> = const { std::cell::Cell::new(250.0) };
184}
185
186fn arg_string(args: &[Value], i: usize) -> String {
188 match args.get(i) {
189 Some(v) if !matches!(v, Value::Undef) => with_host(|h| h.str_of(v)),
190 _ => String::new(),
191 }
192}
193
194fn is_ip(input: &str) -> i32 {
196 use std::net::{Ipv4Addr, Ipv6Addr};
197 if input.parse::<Ipv4Addr>().is_ok() {
198 4
199 } else if input.parse::<Ipv6Addr>().is_ok() {
200 6
201 } else {
202 0
203 }
204}
205
206pub fn constant(name: &str) -> Option<Value> {
212 match name {
213 "Server" | "Socket" | "Stream" | "SocketAddress" | "BlockList" => {
214 Some(with_host(|h| h.alloc(JsObj::Builtin(name.into()))))
215 }
216 _ => None,
217 }
218}
219
220pub fn create_server(connection_listener: Option<Value>) -> Value {
223 let mut extra = IndexMap::new();
224 if let Some(cb) = connection_listener.filter(|v| !matches!(v, Value::Undef)) {
225 extra.insert("@@connListener".into(), cb);
226 }
227 new_emitter_object("Server", extra)
228}
229
230pub fn new_socket() -> Value {
235 let sock_id = next_id();
236 let mut extra = IndexMap::new();
237 extra.insert("@@netid".into(), Value::Float(sock_id as f64));
238 extra.insert("connecting".into(), Value::Bool(false));
239 new_emitter_object("Socket", extra)
240}
241
242pub fn connect(args: &[Value]) -> Value {
246 let socket = new_socket();
247 socket_connect(&socket, args);
248 socket
249}
250
251fn parse_connect_args(args: &[Value]) -> (u16, String, Option<Value>) {
254 let mut port: u16 = 0;
255 let mut host = "localhost".to_string();
256 let mut cb: Option<Value> = None;
257 for a in args {
258 if with_host(|h| crate::host::is_callable(h, a)) {
259 cb = Some(a.clone());
260 } else if with_host(|h| h.as_str(a)).is_some() {
261 host = with_host(|h| h.str_of(a));
262 } else if matches!(a, Value::Obj(_)) {
263 if let Some(v) = get_prop(a, "port") {
264 let n = with_host(|h| h.to_number(&v));
265 if !n.is_nan() {
266 port = n as u16;
267 }
268 }
269 for key in ["host", "hostname"] {
270 if let Some(v) = get_prop(a, key).filter(|v| with_host(|h| h.as_str(v)).is_some()) {
271 host = with_host(|h| h.str_of(&v));
272 }
273 }
274 } else {
275 let n = with_host(|h| h.to_number(a));
276 if !n.is_nan() {
277 port = n as u16;
278 }
279 }
280 }
281 (port, host, cb)
282}
283
284fn socket_connect(socket: &Value, args: &[Value]) {
288 let (port, host, cb) = parse_connect_args(args);
289 if let Some(cb) = cb {
290 let _ = super::events::instance_call(
291 socket,
292 "on",
293 vec![with_host(|h| h.new_str("connect")), cb],
294 );
295 }
296 let sock_id = u64_prop(socket, "@@netid").unwrap_or_else(next_id);
297 set_prop(socket, "@@netid", Value::Float(sock_id as f64));
298 set_prop(socket, "connecting", Value::Bool(true));
299 with_host(|h| h.incr_handle());
300
301 let tx = with_host(|h| h.io_sender());
302 let socket_val = socket.clone();
303 std::thread::spawn(move || match TcpStream::connect((host.as_str(), port)) {
304 Ok(stream) => {
305 let _ = tx.send(Box::new(move || on_connect(sock_id, socket_val, stream)));
306 }
307 Err(e) => {
308 let msg = format!("connect ECONNREFUSED {host}:{port}: {e}");
309 let _ = tx.send(Box::new(move || on_connect_error(socket_val, msg)));
310 }
311 });
312}
313
314fn on_connect(sock_id: u64, socket: Value, stream: TcpStream) -> Result<(), String> {
317 let read_stream = match stream.try_clone() {
318 Ok(s) => s,
319 Err(_) => {
320 with_host(|h| h.decr_handle());
321 return Ok(());
322 }
323 };
324 let write = Arc::new(Mutex::new(stream));
325 NET.with(|s| {
326 s.borrow_mut().sockets.insert(
327 sock_id,
328 SocketRec {
329 emitter: socket.clone(),
330 write,
331 },
332 );
333 });
334 set_prop(&socket, "connecting", Value::Bool(false));
335 let tx = with_host(|h| h.io_sender());
338 std::thread::spawn(move || reader_loop(read_stream, sock_id, tx));
339 super::events::instance_call(&socket, "emit", vec![with_host(|h| h.new_str("connect"))])?;
340 Ok(())
341}
342
343fn on_connect_error(socket: Value, msg: String) -> Result<(), String> {
346 with_host(|h| h.decr_handle());
347 let _ = with_host(|h| h.io_sender()).send(Box::new(|| Ok(())));
348 let err = with_host(|h| {
349 let mut m = IndexMap::new();
350 m.insert("message".into(), h.new_str(msg.clone()));
351 m.insert("code".into(), h.new_str("ECONNREFUSED"));
352 h.new_object(m)
353 });
354 super::events::instance_call(
355 &socket,
356 "emit",
357 vec![with_host(|h| h.new_str("error")), err],
358 )?;
359 Ok(())
360}
361
362pub fn construct(name: &str, args: &[Value]) -> Option<Result<Value, String>> {
367 match name {
368 "Socket" | "Stream" => Some(Ok(new_socket())),
369 "Server" => Some(Ok(create_server(
370 args.first()
371 .cloned()
372 .filter(|v| with_host(|h| crate::host::is_callable(h, v))),
373 ))),
374 "SocketAddress" => Some(Ok(socket_address(args))),
375 "BlockList" => Some(Ok(new_block_list())),
376 _ => None,
377 }
378}
379
380fn socket_address(args: &[Value]) -> Value {
383 let opts = args.first().cloned().unwrap_or(Value::Undef);
384 let mut address = String::new();
385 let mut family = "ipv4".to_string();
386 let mut have_family = false;
387 let mut port = 0f64;
388 let mut flowlabel = 0f64;
389 if matches!(opts, Value::Obj(_)) {
390 if let Some(v) = get_prop(&opts, "address").filter(|v| with_host(|h| h.as_str(v)).is_some())
391 {
392 address = with_host(|h| h.str_of(&v));
393 }
394 if let Some(v) = get_prop(&opts, "family").filter(|v| with_host(|h| h.as_str(v)).is_some())
395 {
396 family = with_host(|h| h.str_of(&v)).to_ascii_lowercase();
397 have_family = true;
398 }
399 if let Some(v) = get_prop(&opts, "port") {
400 let n = with_host(|h| h.to_number(&v));
401 if !n.is_nan() {
402 port = n;
403 }
404 }
405 if let Some(v) = get_prop(&opts, "flowlabel") {
406 let n = with_host(|h| h.to_number(&v));
407 if !n.is_nan() {
408 flowlabel = n;
409 }
410 }
411 }
412 if !have_family {
413 family = if is_ip(&address) == 6 { "ipv6" } else { "ipv4" }.to_string();
414 }
415 if address.is_empty() {
416 address = if family == "ipv6" { "::" } else { "127.0.0.1" }.to_string();
417 }
418 with_host(|h| {
419 let mut m = IndexMap::new();
420 m.insert("@@native".into(), h.new_str("SocketAddress"));
421 m.insert("address".into(), h.new_str(address));
422 m.insert("port".into(), Value::Float(port));
423 m.insert("family".into(), h.new_str(family));
424 m.insert("flowlabel".into(), Value::Float(flowlabel));
425 h.new_object(m)
426 })
427}
428
429enum BlockRule {
434 Addr { v6: bool, val: u128 },
436 Range { v6: bool, start: u128, end: u128 },
438 Subnet {
440 v6: bool,
441 network: u128,
442 prefix: u32,
443 },
444}
445
446thread_local! {
447 static BLOCK_LISTS: std::cell::RefCell<HashMap<u64, Vec<BlockRule>>> =
448 std::cell::RefCell::new(HashMap::new());
449}
450
451fn new_block_list() -> Value {
454 let id = next_id();
455 BLOCK_LISTS.with(|b| {
456 b.borrow_mut().insert(id, Vec::new());
457 });
458 with_host(|h| {
459 let mut m = IndexMap::new();
460 m.insert("@@native".into(), h.new_str("BlockList"));
461 m.insert("@@blid".into(), Value::Float(id as f64));
462 h.new_object(m)
463 })
464}
465
466fn ip_to_u128(s: &str) -> Option<(bool, u128)> {
468 use std::net::{Ipv4Addr, Ipv6Addr};
469 if let Ok(v4) = s.parse::<Ipv4Addr>() {
470 return Some((false, u32::from(v4) as u128));
471 }
472 if let Ok(v6) = s.parse::<Ipv6Addr>() {
473 return Some((true, u128::from(v6)));
474 }
475 None
476}
477
478pub fn block_list_call(recv: &Value, method: &str, args: Vec<Value>) -> Result<Value, String> {
480 let Some(id) = u64_prop(recv, "@@blid") else {
481 return Err(crate::host::type_error("invalid BlockList"));
482 };
483 match method {
484 "addAddress" => {
485 let addr = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
486 if let Some((v6, val)) = ip_to_u128(&addr) {
487 BLOCK_LISTS.with(|b| {
488 if let Some(rules) = b.borrow_mut().get_mut(&id) {
489 rules.push(BlockRule::Addr { v6, val });
490 }
491 });
492 }
493 Ok(Value::Undef)
494 }
495 "addRange" => {
496 let start = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
497 let end = with_host(|h| h.str_of(&args.get(1).cloned().unwrap_or(Value::Undef)));
498 if let (Some((v6, s)), Some((_, e))) = (ip_to_u128(&start), ip_to_u128(&end)) {
499 BLOCK_LISTS.with(|b| {
500 if let Some(rules) = b.borrow_mut().get_mut(&id) {
501 rules.push(BlockRule::Range {
502 v6,
503 start: s.min(e),
504 end: s.max(e),
505 });
506 }
507 });
508 }
509 Ok(Value::Undef)
510 }
511 "addSubnet" => {
512 let net = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
513 let prefix =
514 with_host(|h| h.to_number(&args.get(1).cloned().unwrap_or(Value::Undef))) as u32;
515 if let Some((v6, network)) = ip_to_u128(&net) {
516 BLOCK_LISTS.with(|b| {
517 if let Some(rules) = b.borrow_mut().get_mut(&id) {
518 rules.push(BlockRule::Subnet {
519 v6,
520 network,
521 prefix,
522 });
523 }
524 });
525 }
526 Ok(Value::Undef)
527 }
528 "check" => {
529 let addr = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
530 let Some((v6, val)) = ip_to_u128(&addr) else {
531 return Ok(Value::Bool(false));
532 };
533 let blocked = BLOCK_LISTS.with(|b| {
534 b.borrow()
535 .get(&id)
536 .map(|rules| rules.iter().any(|r| rule_matches(r, v6, val)))
537 .unwrap_or(false)
538 });
539 Ok(Value::Bool(blocked))
540 }
541 _ => Err(crate::host::type_error(&format!(
542 "blocklist.{method} is not a function"
543 ))),
544 }
545}
546
547fn rule_matches(rule: &BlockRule, q_v6: bool, q_val: u128) -> bool {
549 match rule {
550 BlockRule::Addr { v6, val } => *v6 == q_v6 && *val == q_val,
551 BlockRule::Range { v6, start, end } => *v6 == q_v6 && q_val >= *start && q_val <= *end,
552 BlockRule::Subnet {
553 v6,
554 network,
555 prefix,
556 } => {
557 if *v6 != q_v6 {
558 return false;
559 }
560 let bits = if q_v6 { 128 } else { 32 };
561 let p = (*prefix).min(bits);
562 if p == 0 {
563 return true;
564 }
565 let shift = bits - p;
566 (q_val >> shift) == (*network >> shift)
567 }
568 }
569}
570
571pub fn set_conn_hook(server: &Value, hook: ConnHook) {
576 set_prop(server, "@@httpMode", Value::Bool(true));
578 PENDING_HOOKS.with(|p| p.borrow_mut().push((server.clone(), hook)));
579}
580
581thread_local! {
582 static PENDING_HOOKS: std::cell::RefCell<Vec<(Value, ConnHook)>> =
584 const { std::cell::RefCell::new(Vec::new()) };
585}
586
587fn take_pending_hook(server: &Value) -> Option<ConnHook> {
588 PENDING_HOOKS.with(|p| {
589 let mut p = p.borrow_mut();
590 p.iter()
591 .position(|(s, _)| s == server)
592 .map(|pos| p.remove(pos).1)
593 })
594}
595
596pub fn instance_call(
599 tag: &str,
600 recv: &Value,
601 method: &str,
602 args: Vec<Value>,
603) -> Result<Value, String> {
604 match tag {
605 "Server" => server_call(recv, method, args),
606 "Socket" => socket_call(recv, method, args),
607 "BlockList" => block_list_call(recv, method, args),
608 _ => Err(crate::host::type_error(&format!(
609 "{method} is not a function"
610 ))),
611 }
612}
613
614fn server_call(recv: &Value, method: &str, args: Vec<Value>) -> Result<Value, String> {
615 if let Some(r) = emitter_dispatch(recv, method, &args) {
616 return r;
617 }
618 match method {
619 "listen" => server_listen(recv, &args),
620 "close" => server_close(recv, &args),
621 "address" => Ok(get_prop(recv, "@@address").unwrap_or(Value::Undef)),
622 _ => Err(crate::host::type_error(&format!(
623 "server.{method} is not a function"
624 ))),
625 }
626}
627
628fn server_listen(recv: &Value, args: &[Value]) -> Result<Value, String> {
632 let port = with_host(|h| args.first().map(|v| h.to_number(v)).unwrap_or(0.0)) as u16;
634 let mut host = "0.0.0.0".to_string();
635 let mut cb: Option<Value> = None;
636 for a in &args[1.min(args.len())..] {
637 if with_host(|h| h.as_str(a)).is_some() {
638 host = with_host(|h| h.str_of(a));
639 } else if with_host(|h| crate::host::is_callable(h, a)) {
640 cb = Some(a.clone());
641 }
642 }
643
644 let listener = TcpListener::bind((host.as_str(), port))
645 .map_err(|e| format!("Error: listen EADDRINUSE: {e}"))?;
646 let local = listener.local_addr().ok();
647
648 let id = next_id();
650 set_prop(recv, "@@netid", Value::Float(id as f64));
651 if let Some(addr) = local {
652 let mut a = IndexMap::new();
653 a.insert("port".into(), Value::Float(addr.port() as f64));
654 a.insert(
655 "address".into(),
656 with_host(|h| h.new_str(addr.ip().to_string())),
657 );
658 a.insert(
659 "family".into(),
660 with_host(|h| h.new_str(if addr.is_ipv6() { "IPv6" } else { "IPv4" })),
661 );
662 let addr_obj = with_host(|h| h.new_object(a));
663 set_prop(recv, "@@address", addr_obj);
664 }
665 let conn_hook = take_pending_hook(recv);
666 let stop = Arc::new(AtomicBool::new(false));
667 NET.with(|s| {
668 s.borrow_mut().servers.insert(
669 id,
670 ServerRec {
671 emitter: recv.clone(),
672 stop: stop.clone(),
673 conn_hook,
674 },
675 );
676 });
677 with_host(|h| h.incr_handle());
678
679 let tx = with_host(|h| h.io_sender());
681 listener.set_nonblocking(true).ok();
682 std::thread::spawn(move || loop {
683 if stop.load(Ordering::Acquire) {
684 break;
685 }
686 match listener.accept() {
687 Ok((stream, _addr)) => {
688 let tx2 = tx.clone();
689 let _ = tx.send(Box::new(move || on_connection(id, stream, tx2)));
690 }
691 Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
692 std::thread::sleep(std::time::Duration::from_millis(5));
693 }
694 Err(_) => break,
695 }
696 });
697
698 let server = recv.clone();
700 let _ = with_host(|h| h.io_sender()).send(Box::new(move || {
701 super::events::instance_call(&server, "emit", vec![with_host(|h| h.new_str("listening"))])?;
702 if let Some(cb) = cb {
703 invoke(&cb, Vec::new(), None)?;
704 }
705 Ok(())
706 }));
707 Ok(recv.clone())
708}
709
710fn server_close(recv: &Value, args: &[Value]) -> Result<Value, String> {
712 if let Some(id) = u64_prop(recv, "@@netid") {
713 let rec = NET.with(|s| s.borrow_mut().servers.remove(&id));
714 if let Some(rec) = rec {
715 rec.stop.store(true, Ordering::Release);
716 with_host(|h| h.decr_handle());
717 let _ = with_host(|h| h.io_sender()).send(Box::new(|| Ok(())));
719 }
720 }
721 if let Some(cb) = args
723 .first()
724 .filter(|v| with_host(|h| crate::host::is_callable(h, v)))
725 {
726 invoke(cb, Vec::new(), None)?;
727 }
728 super::events::instance_call(recv, "emit", vec![with_host(|h| h.new_str("close"))])?;
729 Ok(recv.clone())
730}
731
732fn socket_call(recv: &Value, method: &str, args: Vec<Value>) -> Result<Value, String> {
733 if let Some(r) = emitter_dispatch(recv, method, &args) {
734 return r;
735 }
736 match method {
737 "write" => {
738 if let Some(id) = u64_prop(recv, "@@netid") {
739 socket_write_id(id, &value_bytes(args.first()));
740 }
741 Ok(Value::Bool(true))
742 }
743 "end" => {
744 if let Some(id) = u64_prop(recv, "@@netid") {
745 if let Some(chunk) = args.first().filter(|v| !matches!(v, Value::Undef)) {
746 socket_write_id(id, &value_bytes(Some(chunk)));
747 }
748 socket_shutdown(id);
749 }
750 Ok(recv.clone())
751 }
752 "destroy" => {
753 if let Some(id) = u64_prop(recv, "@@netid") {
754 socket_shutdown(id);
755 }
756 Ok(recv.clone())
757 }
758 "connect" => {
759 socket_connect(recv, &args);
760 Ok(recv.clone())
761 }
762 "address" => Ok(get_prop(recv, "@@address").unwrap_or(Value::Undef)),
763 "setEncoding" | "setTimeout" | "setNoDelay" | "setKeepAlive" | "ref" | "unref"
764 | "pause" | "resume" => {
765 Ok(recv.clone())
767 }
768 _ => Err(crate::host::type_error(&format!(
769 "socket.{method} is not a function"
770 ))),
771 }
772}
773
774fn value_bytes(v: Option<&Value>) -> Vec<u8> {
776 let Some(v) = v else { return Vec::new() };
777 let is_buffer =
779 with_host(|h| matches!(h.get(v), Some(JsObj::Object(p)) if p.contains_key("@@bytes")));
780 if is_buffer {
781 return with_host(|h| match h.get(v) {
782 Some(JsObj::Object(p)) => match p.get("@@bytes").and_then(|b| h.get(b)) {
783 Some(JsObj::Array(items)) => items.iter().map(|x| h.to_number(x) as u8).collect(),
784 _ => Vec::new(),
785 },
786 _ => Vec::new(),
787 });
788 }
789 with_host(|h| h.str_of(v)).into_bytes()
790}
791
792fn on_connection(
798 server_id: u64,
799 stream: TcpStream,
800 tx: std::sync::mpsc::Sender<crate::host::IoTask>,
801) -> Result<(), String> {
802 let server = NET.with(|s| {
804 s.borrow()
805 .servers
806 .get(&server_id)
807 .map(|r| r.emitter.clone())
808 });
809 let Some(server) = server else { return Ok(()) };
810
811 let read_stream = match stream.try_clone() {
813 Ok(s) => s,
814 Err(_) => return Ok(()),
815 };
816 let write = Arc::new(Mutex::new(stream));
817
818 let sock_id = next_id();
819 let mut extra = IndexMap::new();
820 extra.insert("@@netid".into(), Value::Float(sock_id as f64));
821 let socket = new_emitter_object("Socket", extra);
822 NET.with(|s| {
823 s.borrow_mut().sockets.insert(
824 sock_id,
825 SocketRec {
826 emitter: socket.clone(),
827 write,
828 },
829 );
830 });
831 with_host(|h| h.incr_handle());
832
833 std::thread::spawn(move || reader_loop(read_stream, sock_id, tx));
835
836 super::events::instance_call(&server, "emit", vec![with_host(|_h| socket.clone())])?;
838 let hook = NET.with(|s| {
839 s.borrow()
840 .servers
841 .get(&server_id)
842 .and_then(|r| r.conn_hook.clone())
843 });
844 if let Some(hook) = hook {
845 hook(&server, &socket)?;
846 } else if let Some(cb) = get_prop(&server, "@@connListener") {
847 invoke(&cb, vec![socket.clone()], None)?;
848 }
849 Ok(())
850}
851
852fn reader_loop(
854 mut stream: TcpStream,
855 sock_id: u64,
856 tx: std::sync::mpsc::Sender<crate::host::IoTask>,
857) {
858 let mut buf = [0u8; 8192];
859 loop {
860 match stream.read(&mut buf) {
861 Ok(0) => {
862 let _ = tx.send(Box::new(move || on_socket_end(sock_id)));
863 break;
864 }
865 Ok(n) => {
866 let bytes = buf[..n].to_vec();
867 let _ = tx.send(Box::new(move || on_socket_data(sock_id, bytes)));
868 }
869 Err(_) => {
870 let _ = tx.send(Box::new(move || on_socket_close(sock_id)));
871 break;
872 }
873 }
874 }
875}
876
877fn on_socket_data(sock_id: u64, bytes: Vec<u8>) -> Result<(), String> {
878 let socket = NET.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.emitter.clone()));
879 let Some(socket) = socket else { return Ok(()) };
880 super::http::feed(sock_id, &socket, &bytes)?;
882 let chunk = super::buffer::from_bytes(&bytes);
884 super::events::instance_call(
885 &socket,
886 "emit",
887 vec![with_host(|h| h.new_str("data")), chunk],
888 )?;
889 Ok(())
890}
891
892fn on_socket_end(sock_id: u64) -> Result<(), String> {
893 let socket = NET.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.emitter.clone()));
894 if let Some(socket) = socket {
895 super::events::instance_call(&socket, "emit", vec![with_host(|h| h.new_str("end"))])?;
896 }
897 on_socket_close(sock_id)
898}
899
900fn on_socket_close(sock_id: u64) -> Result<(), String> {
901 let rec = NET.with(|s| s.borrow_mut().sockets.remove(&sock_id));
902 super::http::drop_conn(sock_id);
903 if let Some(rec) = rec {
904 super::events::instance_call(
905 &rec.emitter,
906 "emit",
907 vec![with_host(|h| h.new_str("close"))],
908 )?;
909 with_host(|h| h.decr_handle());
910 let _ = with_host(|h| h.io_sender()).send(Box::new(|| Ok(())));
912 }
913 Ok(())
914}
915
916pub fn socket_write_id(sock_id: u64, data: &[u8]) {
920 let write = NET.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.write.clone()));
921 if let Some(write) = write {
922 if let Ok(mut stream) = write.lock() {
923 let _ = stream.write_all(data);
924 let _ = stream.flush();
925 }
926 }
927}
928
929fn socket_shutdown(sock_id: u64) {
931 let write = NET.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.write.clone()));
932 if let Some(write) = write {
933 if let Ok(stream) = write.lock() {
934 let _ = stream.shutdown(std::net::Shutdown::Write);
935 }
936 }
937}