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 let obj = h.new_object(m);
101 if let Some(proto) = h.ensure_ctor_proto(tag) {
106 h.set_proto(&obj, proto);
107 }
108 obj
109 })
110}
111
112fn get_prop(recv: &Value, key: &str) -> Option<Value> {
113 with_host(|h| match h.get(recv) {
114 Some(JsObj::Object(p)) => p.get(key).cloned(),
115 _ => None,
116 })
117}
118
119fn set_prop(recv: &Value, key: &str, val: Value) {
120 with_host(|h| {
121 if let Some(JsObj::Object(p)) = h.get_mut(recv) {
122 p.insert(key.to_string(), val);
123 }
124 });
125}
126
127fn u64_prop(recv: &Value, key: &str) -> Option<u64> {
128 get_prop(recv, key).map(|v| with_host(|h| h.to_number(&v)) as u64)
129}
130
131fn emitter_dispatch(recv: &Value, method: &str, args: &[Value]) -> Option<Result<Value, String>> {
134 super::events::METHODS
135 .contains(&method)
136 .then(|| super::events::instance_call(recv, method, args.to_vec()))
137}
138
139pub fn call(method: &str, args: &[Value]) -> Option<Result<Value, String>> {
143 match method {
144 "createServer" => Some(Ok(create_server(args.first().cloned()))),
145 "connect" | "createConnection" => Some(Ok(connect(args))),
146 "isIP" => Some(Ok(Value::Float(is_ip(&arg_string(args, 0)) as f64))),
147 "isIPv4" => Some(Ok(Value::Bool(is_ip(&arg_string(args, 0)) == 4))),
148 "isIPv6" => Some(Ok(Value::Bool(is_ip(&arg_string(args, 0)) == 6))),
149 "getDefaultAutoSelectFamily" => Some(Ok(Value::Bool(AUTO_SELECT_FAMILY.with(|c| c.get())))),
150 "setDefaultAutoSelectFamily" => {
151 let v = args
152 .first()
153 .map(|a| with_host(|h| h.truthy(a)))
154 .unwrap_or(false);
155 AUTO_SELECT_FAMILY.with(|c| c.set(v));
156 Some(Ok(Value::Undef))
157 }
158 "getDefaultAutoSelectFamilyAttemptTimeout" => {
159 Some(Ok(Value::Float(AUTO_SELECT_TIMEOUT.with(|c| c.get()))))
160 }
161 "setDefaultAutoSelectFamilyAttemptTimeout" => {
162 let v = args
163 .first()
164 .map(|a| with_host(|h| h.to_number(a)))
165 .unwrap_or(f64::NAN);
166 if v.is_finite() && v >= 1.0 {
167 AUTO_SELECT_TIMEOUT.with(|c| c.set(v));
168 }
169 Some(Ok(Value::Undef))
170 }
171 _ => None,
172 }
173}
174
175thread_local! {
176 static AUTO_SELECT_FAMILY: std::cell::Cell<bool> = const { std::cell::Cell::new(true) };
179 static AUTO_SELECT_TIMEOUT: std::cell::Cell<f64> = const { std::cell::Cell::new(250.0) };
181}
182
183fn arg_string(args: &[Value], i: usize) -> String {
185 match args.get(i) {
186 Some(v) if !matches!(v, Value::Undef) => with_host(|h| h.str_of(v)),
187 _ => String::new(),
188 }
189}
190
191fn is_ip(input: &str) -> i32 {
193 use std::net::{Ipv4Addr, Ipv6Addr};
194 if input.parse::<Ipv4Addr>().is_ok() {
195 4
196 } else if input.parse::<Ipv6Addr>().is_ok() {
197 6
198 } else {
199 0
200 }
201}
202
203pub fn constant(name: &str) -> Option<Value> {
209 match name {
210 "Server" | "Socket" | "Stream" | "SocketAddress" | "BlockList" => {
211 Some(with_host(|h| h.alloc(JsObj::Builtin(name.into()))))
212 }
213 _ => None,
214 }
215}
216
217pub fn create_server(connection_listener: Option<Value>) -> Value {
220 let mut extra = IndexMap::new();
221 if let Some(cb) = connection_listener.filter(|v| !matches!(v, Value::Undef)) {
222 extra.insert("@@connListener".into(), cb);
223 }
224 new_emitter_object("Server", extra)
225}
226
227pub fn new_socket() -> Value {
232 let sock_id = next_id();
233 let mut extra = IndexMap::new();
234 extra.insert("@@netid".into(), Value::Float(sock_id as f64));
235 extra.insert("connecting".into(), Value::Bool(false));
236 new_emitter_object("Socket", extra)
237}
238
239pub fn connect(args: &[Value]) -> Value {
243 let socket = new_socket();
244 socket_connect(&socket, args);
245 socket
246}
247
248fn parse_connect_args(args: &[Value]) -> (u16, String, Option<Value>) {
251 let mut port: u16 = 0;
252 let mut host = "localhost".to_string();
253 let mut cb: Option<Value> = None;
254 for a in args {
255 if with_host(|h| crate::host::is_callable(h, a)) {
256 cb = Some(a.clone());
257 } else if with_host(|h| h.as_str(a)).is_some() {
258 host = with_host(|h| h.str_of(a));
259 } else if matches!(a, Value::Obj(_)) {
260 if let Some(v) = get_prop(a, "port") {
261 let n = with_host(|h| h.to_number(&v));
262 if !n.is_nan() {
263 port = n as u16;
264 }
265 }
266 for key in ["host", "hostname"] {
267 if let Some(v) = get_prop(a, key).filter(|v| with_host(|h| h.as_str(v)).is_some()) {
268 host = with_host(|h| h.str_of(&v));
269 }
270 }
271 } else {
272 let n = with_host(|h| h.to_number(a));
273 if !n.is_nan() {
274 port = n as u16;
275 }
276 }
277 }
278 (port, host, cb)
279}
280
281fn socket_connect(socket: &Value, args: &[Value]) {
285 let (port, host, cb) = parse_connect_args(args);
286 if let Some(cb) = cb {
287 let _ = super::events::instance_call(
288 socket,
289 "on",
290 vec![with_host(|h| h.new_str("connect")), cb],
291 );
292 }
293 let sock_id = u64_prop(socket, "@@netid").unwrap_or_else(next_id);
294 set_prop(socket, "@@netid", Value::Float(sock_id as f64));
295 set_prop(socket, "connecting", Value::Bool(true));
296 with_host(|h| h.incr_handle());
297
298 let tx = with_host(|h| h.io_sender());
299 let socket_val = socket.clone();
300 std::thread::spawn(move || match TcpStream::connect((host.as_str(), port)) {
301 Ok(stream) => {
302 let _ = tx.send(Box::new(move || on_connect(sock_id, socket_val, stream)));
303 }
304 Err(e) => {
305 let msg = format!("connect ECONNREFUSED {host}:{port}: {e}");
306 let _ = tx.send(Box::new(move || on_connect_error(socket_val, msg)));
307 }
308 });
309}
310
311fn on_connect(sock_id: u64, socket: Value, stream: TcpStream) -> Result<(), String> {
314 let read_stream = match stream.try_clone() {
315 Ok(s) => s,
316 Err(_) => {
317 with_host(|h| h.decr_handle());
318 return Ok(());
319 }
320 };
321 let write = Arc::new(Mutex::new(stream));
322 NET.with(|s| {
323 s.borrow_mut().sockets.insert(
324 sock_id,
325 SocketRec {
326 emitter: socket.clone(),
327 write,
328 },
329 );
330 });
331 set_prop(&socket, "connecting", Value::Bool(false));
332 let tx = with_host(|h| h.io_sender());
335 std::thread::spawn(move || reader_loop(read_stream, sock_id, tx));
336 super::events::instance_call(&socket, "emit", vec![with_host(|h| h.new_str("connect"))])?;
337 Ok(())
338}
339
340fn on_connect_error(socket: Value, msg: String) -> Result<(), String> {
343 with_host(|h| h.decr_handle());
344 let _ = with_host(|h| h.io_sender()).send(Box::new(|| Ok(())));
345 let err = with_host(|h| {
346 let mut m = IndexMap::new();
347 m.insert("message".into(), h.new_str(msg.clone()));
348 m.insert("code".into(), h.new_str("ECONNREFUSED"));
349 h.new_object(m)
350 });
351 super::events::instance_call(
352 &socket,
353 "emit",
354 vec![with_host(|h| h.new_str("error")), err],
355 )?;
356 Ok(())
357}
358
359pub fn construct(name: &str, args: &[Value]) -> Option<Result<Value, String>> {
364 match name {
365 "Socket" | "Stream" => Some(Ok(new_socket())),
366 "Server" => Some(Ok(create_server(
367 args.first()
368 .cloned()
369 .filter(|v| with_host(|h| crate::host::is_callable(h, v))),
370 ))),
371 "SocketAddress" => Some(Ok(socket_address(args))),
372 "BlockList" => Some(Ok(new_block_list())),
373 _ => None,
374 }
375}
376
377fn socket_address(args: &[Value]) -> Value {
380 let opts = args.first().cloned().unwrap_or(Value::Undef);
381 let mut address = String::new();
382 let mut family = "ipv4".to_string();
383 let mut have_family = false;
384 let mut port = 0f64;
385 let mut flowlabel = 0f64;
386 if matches!(opts, Value::Obj(_)) {
387 if let Some(v) = get_prop(&opts, "address").filter(|v| with_host(|h| h.as_str(v)).is_some())
388 {
389 address = with_host(|h| h.str_of(&v));
390 }
391 if let Some(v) = get_prop(&opts, "family").filter(|v| with_host(|h| h.as_str(v)).is_some())
392 {
393 family = with_host(|h| h.str_of(&v)).to_ascii_lowercase();
394 have_family = true;
395 }
396 if let Some(v) = get_prop(&opts, "port") {
397 let n = with_host(|h| h.to_number(&v));
398 if !n.is_nan() {
399 port = n;
400 }
401 }
402 if let Some(v) = get_prop(&opts, "flowlabel") {
403 let n = with_host(|h| h.to_number(&v));
404 if !n.is_nan() {
405 flowlabel = n;
406 }
407 }
408 }
409 if !have_family {
410 family = if is_ip(&address) == 6 { "ipv6" } else { "ipv4" }.to_string();
411 }
412 if address.is_empty() {
413 address = if family == "ipv6" { "::" } else { "127.0.0.1" }.to_string();
414 }
415 with_host(|h| {
416 let mut m = IndexMap::new();
417 m.insert("@@native".into(), h.new_str("SocketAddress"));
418 m.insert("address".into(), h.new_str(address));
419 m.insert("port".into(), Value::Float(port));
420 m.insert("family".into(), h.new_str(family));
421 m.insert("flowlabel".into(), Value::Float(flowlabel));
422 h.new_object(m)
423 })
424}
425
426enum BlockRule {
431 Addr { v6: bool, val: u128 },
433 Range { v6: bool, start: u128, end: u128 },
435 Subnet {
437 v6: bool,
438 network: u128,
439 prefix: u32,
440 },
441}
442
443thread_local! {
444 static BLOCK_LISTS: std::cell::RefCell<HashMap<u64, Vec<BlockRule>>> =
445 std::cell::RefCell::new(HashMap::new());
446}
447
448fn new_block_list() -> Value {
451 let id = next_id();
452 BLOCK_LISTS.with(|b| {
453 b.borrow_mut().insert(id, Vec::new());
454 });
455 with_host(|h| {
456 let mut m = IndexMap::new();
457 m.insert("@@native".into(), h.new_str("BlockList"));
458 m.insert("@@blid".into(), Value::Float(id as f64));
459 h.new_object(m)
460 })
461}
462
463fn ip_to_u128(s: &str) -> Option<(bool, u128)> {
465 use std::net::{Ipv4Addr, Ipv6Addr};
466 if let Ok(v4) = s.parse::<Ipv4Addr>() {
467 return Some((false, u32::from(v4) as u128));
468 }
469 if let Ok(v6) = s.parse::<Ipv6Addr>() {
470 return Some((true, u128::from(v6)));
471 }
472 None
473}
474
475pub fn block_list_call(recv: &Value, method: &str, args: Vec<Value>) -> Result<Value, String> {
477 let Some(id) = u64_prop(recv, "@@blid") else {
478 return Err(crate::host::type_error("invalid BlockList"));
479 };
480 match method {
481 "addAddress" => {
482 let addr = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
483 if let Some((v6, val)) = ip_to_u128(&addr) {
484 BLOCK_LISTS.with(|b| {
485 if let Some(rules) = b.borrow_mut().get_mut(&id) {
486 rules.push(BlockRule::Addr { v6, val });
487 }
488 });
489 }
490 Ok(Value::Undef)
491 }
492 "addRange" => {
493 let start = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
494 let end = with_host(|h| h.str_of(&args.get(1).cloned().unwrap_or(Value::Undef)));
495 if let (Some((v6, s)), Some((_, e))) = (ip_to_u128(&start), ip_to_u128(&end)) {
496 BLOCK_LISTS.with(|b| {
497 if let Some(rules) = b.borrow_mut().get_mut(&id) {
498 rules.push(BlockRule::Range {
499 v6,
500 start: s.min(e),
501 end: s.max(e),
502 });
503 }
504 });
505 }
506 Ok(Value::Undef)
507 }
508 "addSubnet" => {
509 let net = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
510 let prefix =
511 with_host(|h| h.to_number(&args.get(1).cloned().unwrap_or(Value::Undef))) as u32;
512 if let Some((v6, network)) = ip_to_u128(&net) {
513 BLOCK_LISTS.with(|b| {
514 if let Some(rules) = b.borrow_mut().get_mut(&id) {
515 rules.push(BlockRule::Subnet {
516 v6,
517 network,
518 prefix,
519 });
520 }
521 });
522 }
523 Ok(Value::Undef)
524 }
525 "check" => {
526 let addr = with_host(|h| h.str_of(&args.first().cloned().unwrap_or(Value::Undef)));
527 let Some((v6, val)) = ip_to_u128(&addr) else {
528 return Ok(Value::Bool(false));
529 };
530 let blocked = BLOCK_LISTS.with(|b| {
531 b.borrow()
532 .get(&id)
533 .map(|rules| rules.iter().any(|r| rule_matches(r, v6, val)))
534 .unwrap_or(false)
535 });
536 Ok(Value::Bool(blocked))
537 }
538 _ => Err(crate::host::type_error(&format!(
539 "blocklist.{method} is not a function"
540 ))),
541 }
542}
543
544fn rule_matches(rule: &BlockRule, q_v6: bool, q_val: u128) -> bool {
546 match rule {
547 BlockRule::Addr { v6, val } => *v6 == q_v6 && *val == q_val,
548 BlockRule::Range { v6, start, end } => *v6 == q_v6 && q_val >= *start && q_val <= *end,
549 BlockRule::Subnet {
550 v6,
551 network,
552 prefix,
553 } => {
554 if *v6 != q_v6 {
555 return false;
556 }
557 let bits = if q_v6 { 128 } else { 32 };
558 let p = (*prefix).min(bits);
559 if p == 0 {
560 return true;
561 }
562 let shift = bits - p;
563 (q_val >> shift) == (*network >> shift)
564 }
565 }
566}
567
568pub fn set_conn_hook(server: &Value, hook: ConnHook) {
573 set_prop(server, "@@httpMode", Value::Bool(true));
575 PENDING_HOOKS.with(|p| p.borrow_mut().push((server.clone(), hook)));
576}
577
578thread_local! {
579 static PENDING_HOOKS: std::cell::RefCell<Vec<(Value, ConnHook)>> =
581 const { std::cell::RefCell::new(Vec::new()) };
582}
583
584fn take_pending_hook(server: &Value) -> Option<ConnHook> {
585 PENDING_HOOKS.with(|p| {
586 let mut p = p.borrow_mut();
587 p.iter()
588 .position(|(s, _)| s == server)
589 .map(|pos| p.remove(pos).1)
590 })
591}
592
593pub fn instance_call(
596 tag: &str,
597 recv: &Value,
598 method: &str,
599 args: Vec<Value>,
600) -> Result<Value, String> {
601 match tag {
602 "Server" => server_call(recv, method, args),
603 "Socket" => socket_call(recv, method, args),
604 "BlockList" => block_list_call(recv, method, args),
605 _ => Err(crate::host::type_error(&format!(
606 "{method} is not a function"
607 ))),
608 }
609}
610
611fn server_call(recv: &Value, method: &str, args: Vec<Value>) -> Result<Value, String> {
612 if let Some(r) = emitter_dispatch(recv, method, &args) {
613 return r;
614 }
615 match method {
616 "listen" => server_listen(recv, &args),
617 "close" => server_close(recv, &args),
618 "address" => Ok(get_prop(recv, "@@address").unwrap_or(Value::Undef)),
619 _ => Err(crate::host::type_error(&format!(
620 "server.{method} is not a function"
621 ))),
622 }
623}
624
625fn server_listen(recv: &Value, args: &[Value]) -> Result<Value, String> {
629 let port = with_host(|h| args.first().map(|v| h.to_number(v)).unwrap_or(0.0)) as u16;
631 let mut host = "0.0.0.0".to_string();
632 let mut cb: Option<Value> = None;
633 for a in &args[1.min(args.len())..] {
634 if with_host(|h| h.as_str(a)).is_some() {
635 host = with_host(|h| h.str_of(a));
636 } else if with_host(|h| crate::host::is_callable(h, a)) {
637 cb = Some(a.clone());
638 }
639 }
640
641 let listener = TcpListener::bind((host.as_str(), port))
642 .map_err(|e| format!("Error: listen EADDRINUSE: {e}"))?;
643 let local = listener.local_addr().ok();
644
645 let id = next_id();
647 set_prop(recv, "@@netid", Value::Float(id as f64));
648 if let Some(addr) = local {
649 let mut a = IndexMap::new();
650 a.insert("port".into(), Value::Float(addr.port() as f64));
651 a.insert(
652 "address".into(),
653 with_host(|h| h.new_str(addr.ip().to_string())),
654 );
655 a.insert(
656 "family".into(),
657 with_host(|h| h.new_str(if addr.is_ipv6() { "IPv6" } else { "IPv4" })),
658 );
659 let addr_obj = with_host(|h| h.new_object(a));
660 set_prop(recv, "@@address", addr_obj);
661 }
662 let conn_hook = take_pending_hook(recv);
663 let stop = Arc::new(AtomicBool::new(false));
664 NET.with(|s| {
665 s.borrow_mut().servers.insert(
666 id,
667 ServerRec {
668 emitter: recv.clone(),
669 stop: stop.clone(),
670 conn_hook,
671 },
672 );
673 });
674 with_host(|h| h.incr_handle());
675
676 let tx = with_host(|h| h.io_sender());
678 listener.set_nonblocking(true).ok();
679 std::thread::spawn(move || loop {
680 if stop.load(Ordering::Acquire) {
681 break;
682 }
683 match listener.accept() {
684 Ok((stream, _addr)) => {
685 let tx2 = tx.clone();
686 let _ = tx.send(Box::new(move || on_connection(id, stream, tx2)));
687 }
688 Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
689 std::thread::sleep(std::time::Duration::from_millis(5));
690 }
691 Err(_) => break,
692 }
693 });
694
695 let server = recv.clone();
697 let _ = with_host(|h| h.io_sender()).send(Box::new(move || {
698 super::events::instance_call(&server, "emit", vec![with_host(|h| h.new_str("listening"))])?;
699 if let Some(cb) = cb {
700 invoke(&cb, Vec::new(), None)?;
701 }
702 Ok(())
703 }));
704 Ok(recv.clone())
705}
706
707fn server_close(recv: &Value, args: &[Value]) -> Result<Value, String> {
709 if let Some(id) = u64_prop(recv, "@@netid") {
710 let rec = NET.with(|s| s.borrow_mut().servers.remove(&id));
711 if let Some(rec) = rec {
712 rec.stop.store(true, Ordering::Release);
713 with_host(|h| h.decr_handle());
714 let _ = with_host(|h| h.io_sender()).send(Box::new(|| Ok(())));
716 }
717 }
718 if let Some(cb) = args
720 .first()
721 .filter(|v| with_host(|h| crate::host::is_callable(h, v)))
722 {
723 invoke(cb, Vec::new(), None)?;
724 }
725 super::events::instance_call(recv, "emit", vec![with_host(|h| h.new_str("close"))])?;
726 Ok(recv.clone())
727}
728
729fn socket_call(recv: &Value, method: &str, args: Vec<Value>) -> Result<Value, String> {
730 if let Some(r) = emitter_dispatch(recv, method, &args) {
731 return r;
732 }
733 match method {
734 "write" => {
735 if let Some(id) = u64_prop(recv, "@@netid") {
736 socket_write_id(id, &value_bytes(args.first()));
737 }
738 Ok(Value::Bool(true))
739 }
740 "end" => {
741 if let Some(id) = u64_prop(recv, "@@netid") {
742 if let Some(chunk) = args.first().filter(|v| !matches!(v, Value::Undef)) {
743 socket_write_id(id, &value_bytes(Some(chunk)));
744 }
745 socket_shutdown(id);
746 }
747 Ok(recv.clone())
748 }
749 "destroy" => {
750 if let Some(id) = u64_prop(recv, "@@netid") {
751 socket_shutdown(id);
752 }
753 Ok(recv.clone())
754 }
755 "connect" => {
756 socket_connect(recv, &args);
757 Ok(recv.clone())
758 }
759 "address" => Ok(get_prop(recv, "@@address").unwrap_or(Value::Undef)),
760 "setEncoding" | "setTimeout" | "setNoDelay" | "setKeepAlive" | "ref" | "unref"
761 | "pause" | "resume" => {
762 Ok(recv.clone())
764 }
765 _ => Err(crate::host::type_error(&format!(
766 "socket.{method} is not a function"
767 ))),
768 }
769}
770
771fn value_bytes(v: Option<&Value>) -> Vec<u8> {
773 let Some(v) = v else { return Vec::new() };
774 let is_buffer =
776 with_host(|h| matches!(h.get(v), Some(JsObj::Object(p)) if p.contains_key("@@bytes")));
777 if is_buffer {
778 return with_host(|h| match h.get(v) {
779 Some(JsObj::Object(p)) => match p.get("@@bytes").and_then(|b| h.get(b)) {
780 Some(JsObj::Array(items)) => items.iter().map(|x| h.to_number(x) as u8).collect(),
781 _ => Vec::new(),
782 },
783 _ => Vec::new(),
784 });
785 }
786 with_host(|h| h.str_of(v)).into_bytes()
787}
788
789fn on_connection(
795 server_id: u64,
796 stream: TcpStream,
797 tx: std::sync::mpsc::Sender<crate::host::IoTask>,
798) -> Result<(), String> {
799 let server = NET.with(|s| {
801 s.borrow()
802 .servers
803 .get(&server_id)
804 .map(|r| r.emitter.clone())
805 });
806 let Some(server) = server else { return Ok(()) };
807
808 let _ = stream.set_nonblocking(false);
816
817 let read_stream = match stream.try_clone() {
819 Ok(s) => s,
820 Err(_) => return Ok(()),
821 };
822 let write = Arc::new(Mutex::new(stream));
823
824 let sock_id = next_id();
825 let mut extra = IndexMap::new();
826 extra.insert("@@netid".into(), Value::Float(sock_id as f64));
827 let socket = new_emitter_object("Socket", extra);
828 NET.with(|s| {
829 s.borrow_mut().sockets.insert(
830 sock_id,
831 SocketRec {
832 emitter: socket.clone(),
833 write,
834 },
835 );
836 });
837 with_host(|h| h.incr_handle());
838
839 std::thread::spawn(move || reader_loop(read_stream, sock_id, tx));
841
842 super::events::instance_call(
848 &server,
849 "emit",
850 vec![with_host(|h| h.new_str("connection")), socket.clone()],
851 )?;
852 let hook = NET.with(|s| {
853 s.borrow()
854 .servers
855 .get(&server_id)
856 .and_then(|r| r.conn_hook.clone())
857 });
858 if let Some(hook) = hook {
859 hook(&server, &socket)?;
860 } else if let Some(cb) = get_prop(&server, "@@connListener") {
861 invoke(&cb, vec![socket.clone()], None)?;
862 }
863 Ok(())
864}
865
866fn reader_loop(
868 mut stream: TcpStream,
869 sock_id: u64,
870 tx: std::sync::mpsc::Sender<crate::host::IoTask>,
871) {
872 let mut buf = [0u8; 8192];
873 loop {
874 match stream.read(&mut buf) {
875 Ok(0) => {
876 let _ = tx.send(Box::new(move || on_socket_end(sock_id)));
877 break;
878 }
879 Ok(n) => {
880 let bytes = buf[..n].to_vec();
881 let _ = tx.send(Box::new(move || on_socket_data(sock_id, bytes)));
882 }
883 Err(ref e)
890 if e.kind() == std::io::ErrorKind::WouldBlock
891 || e.kind() == std::io::ErrorKind::Interrupted =>
892 {
893 std::thread::sleep(std::time::Duration::from_millis(5));
894 }
895 Err(_) => {
896 let _ = tx.send(Box::new(move || on_socket_close(sock_id)));
897 break;
898 }
899 }
900 }
901}
902
903fn on_socket_data(sock_id: u64, bytes: Vec<u8>) -> Result<(), String> {
904 let socket = NET.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.emitter.clone()));
905 let Some(socket) = socket else { return Ok(()) };
906 super::http::feed(sock_id, &socket, &bytes)?;
908 let chunk = super::buffer::from_bytes(&bytes);
910 super::events::instance_call(
911 &socket,
912 "emit",
913 vec![with_host(|h| h.new_str("data")), chunk],
914 )?;
915 Ok(())
916}
917
918fn on_socket_end(sock_id: u64) -> Result<(), String> {
919 let socket = NET.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.emitter.clone()));
920 if let Some(socket) = socket {
921 super::events::instance_call(&socket, "emit", vec![with_host(|h| h.new_str("end"))])?;
922 }
923 on_socket_close(sock_id)
924}
925
926fn on_socket_close(sock_id: u64) -> Result<(), String> {
927 let rec = NET.with(|s| s.borrow_mut().sockets.remove(&sock_id));
928 super::http::drop_conn(sock_id);
929 if let Some(rec) = rec {
930 super::events::instance_call(
931 &rec.emitter,
932 "emit",
933 vec![with_host(|h| h.new_str("close"))],
934 )?;
935 with_host(|h| h.decr_handle());
936 let _ = with_host(|h| h.io_sender()).send(Box::new(|| Ok(())));
938 }
939 Ok(())
940}
941
942pub fn socket_write_id(sock_id: u64, data: &[u8]) {
946 let write = NET.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.write.clone()));
947 if let Some(write) = write {
948 if let Ok(mut stream) = write.lock() {
949 let _ = stream.write_all(data);
950 let _ = stream.flush();
951 }
952 }
953}
954
955fn socket_shutdown(sock_id: u64) {
957 let write = NET.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.write.clone()));
958 if let Some(write) = write {
959 if let Ok(stream) = write.lock() {
960 let _ = stream.shutdown(std::net::Shutdown::Write);
961 }
962 }
963}