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