diff options
-rw-r--r-- | Cargo.lock | 423 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/count.rs | 67 | ||||
-rw-r--r-- | src/main.rs | 138 |
4 files changed, 553 insertions, 76 deletions
diff --git a/Cargo.lock b/Cargo.lock index 41586eb..dc4f752 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,14 +3,256 @@ version = 4 [[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "tracing", +] + +[[package]] +name = "async-signal" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "errno" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-lite" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] name = "headlice" version = "0.1.0" dependencies = [ "pnet_datalink", "scurvy", + "smol", ] [[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] name = "ipnetwork" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -26,12 +268,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] name = "no-std-net" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" [[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] name = "pnet_base" version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -64,6 +335,21 @@ dependencies = [ ] [[package]] +name = "polling" +version = "3.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys", +] + +[[package]] name = "proc-macro2" version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -82,6 +368,19 @@ dependencies = [ ] [[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] name = "scurvy" version = "0.1.0" source = "git+https://git.dreamy.place/scurvy/#c97099648a2117d44b3bc8bef033afde66c2339a" @@ -107,6 +406,41 @@ dependencies = [ ] [[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smol" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33bd3e260892199c3ccfc487c88b2da2265080acb316cd920da72fdfd7c599f" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", +] + +[[package]] name = "syn" version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -118,6 +452,22 @@ dependencies = [ ] [[package]] +name = "tracing" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" + +[[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -144,3 +494,76 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 51b8fe6..43a9b92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] pnet_datalink = "0.35.0" scurvy = { git = "https://git.dreamy.place/scurvy/" } +smol = "2.0.2" diff --git a/src/count.rs b/src/count.rs new file mode 100644 index 0000000..c3d92bf --- /dev/null +++ b/src/count.rs @@ -0,0 +1,67 @@ +const U16_MAX: usize = u16::MAX as usize; + +pub struct Count { + tcp_tx: Box<[usize]>, + tcp_rx: Box<[usize]>, + udp_tx: Box<[usize]>, + udp_rx: Box<[usize]>, +} + +impl Count { + pub fn new() -> Self { + Self { + tcp_tx: Box::new([0; U16_MAX]), + tcp_rx: Box::new([0; U16_MAX]), + udp_tx: Box::new([0; U16_MAX]), + udp_rx: Box::new([0; U16_MAX]), + } + } + + pub fn push_tcp(&mut self, tx_flag: bool, src: u16, dst: u16, len: usize) { + // The unsafe code here is bad and not good. As far as I am aware, this + // is safe except for allowing race conditions. + if tx_flag { + let bad_mut = unsafe { &mut *(self.tcp_tx.as_ptr() as *mut [usize; U16_MAX]) }; + bad_mut[src as usize] += len; + } else { + let bad_mut = unsafe { &mut *(self.tcp_rx.as_ptr() as *mut [usize; U16_MAX]) }; + bad_mut[dst as usize] += len; + } + } + + pub fn push_udp(&mut self, tx_flag: bool, src: u16, dst: u16, len: usize) { + // The unsafe code here is bad and not good. As far as I am aware, this + // is safe except for allowing race conditions. + if tx_flag { + let bad_mut = unsafe { &mut *(self.udp_tx.as_ptr() as *mut [usize; U16_MAX]) }; + bad_mut[src as usize] += len; + } else { + let bad_mut = unsafe { &mut *(self.udp_rx.as_ptr() as *mut [usize; U16_MAX]) }; + bad_mut[dst as usize] += len; + } + } + + pub fn tcp_tx(&self, port: u16) -> usize { + self.tcp_tx[port as usize] + } + + pub fn tcp_rx(&self, port: u16) -> usize { + self.tcp_rx[port as usize] + } + + pub fn udp_tx(&self, port: u16) -> usize { + self.udp_tx[port as usize] + } + + pub fn udp_rx(&self, port: u16) -> usize { + self.udp_rx[port as usize] + } + + pub fn many_tcp_tx(&self, ports: &[u16]) -> usize { + ports.iter().fold(0, |acc, port| acc + self.tcp_tx[*port as usize]) + } + + pub fn many_tcp_rx(&self, ports: &[u16]) -> usize { + ports.iter().fold(0, |acc, port| acc + self.tcp_rx[*port as usize]) + } +} diff --git a/src/main.rs b/src/main.rs index defd70b..3b0f63c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,19 @@ -use std::{ - error::Error, - net::{Ipv4Addr, Shutdown}, - sync::mpsc::{self, Receiver, Sender, channel}, - thread::JoinHandle, - time::{Duration, Instant}, -}; +use std::{cell::UnsafeCell, error::Error, net::Ipv4Addr, rc::Rc, thread::JoinHandle}; +use count::Count; use ethertype::EtherType; use ippacket::{IpNextHeader, Ipv4Packet}; use layer3::{Tcp, Udp}; use pnet_datalink::{Channel, Config}; use scurvy::{Argument, Scurvy}; +use smol::{ + LocalExecutor, + channel::{self, Receiver, Sender}, + io::AsyncWriteExt, + net::TcpListener, +}; +mod count; mod ethertype; mod ippacket; mod layer3; @@ -41,12 +43,6 @@ fn main() -> Result<(), Box<dyn Error>> { let stat = stat_thread(); - let tx_clone = stat.tx.clone(); - std::thread::spawn(move || { - std::thread::sleep(Duration::from_secs(30)); - tx_clone.send(Meow::Show).unwrap(); - }); - loop { let pkt = channel.next()?; @@ -58,6 +54,14 @@ fn main() -> Result<(), Box<dyn Error>> { let ip = Ipv4Packet::new(eth_payload); let ip_payload = ip.get_payload(); + let ip_tx = if ip.src == ip_want { + true + } else if ip.dst == ip_want { + false + } else { + continue; + }; + // 6 byte per MAC (x2), 2 byte ethertype, 2 byte crc let total_l2_len = ip.get_packet_len() + 18; @@ -65,16 +69,8 @@ fn main() -> Result<(), Box<dyn Error>> { IpNextHeader::Tcp => { let tcp = Tcp::new(ip_payload); - let tcp_tx = if ip.src == ip_want { - true - } else if ip.dst == ip_want { - false - } else { - continue; - }; - - stat.tx.send(Meow::Tcp { - tx: tcp_tx, + stat.tx.send_blocking(Meow::Tcp { + tx: ip_tx, src: tcp.source_port(), dst: tcp.destination_port(), len: total_l2_len, @@ -83,16 +79,8 @@ fn main() -> Result<(), Box<dyn Error>> { IpNextHeader::Udp => { let udp = Udp::new(ip_payload); - let udp_tx = if ip.src == ip_want { - true - } else if ip.dst == ip_want { - false - } else { - continue; - }; - - stat.tx.send(Meow::Udp { - tx: udp_tx, + stat.tx.send_blocking(Meow::Udp { + tx: ip_tx, src: udp.source_port(), dst: udp.destination_port(), len: total_l2_len, @@ -106,6 +94,7 @@ fn main() -> Result<(), Box<dyn Error>> { } } +#[allow(dead_code)] struct StatHandle { hwnd: JoinHandle<()>, tx: Sender<Meow>, @@ -124,12 +113,10 @@ enum Meow { dst: u16, len: usize, }, - Show, - Shutdown, } fn stat_thread() -> StatHandle { - let (tx, rx) = channel(); + let (tx, rx) = channel::unbounded(); let hwnd = std::thread::spawn(|| stat(rx)); @@ -137,50 +124,49 @@ fn stat_thread() -> StatHandle { } fn stat(rx: Receiver<Meow>) { - let mut tcp_tx = vec![0; u16::MAX as usize]; - let mut tcp_rx = vec![0; u16::MAX as usize]; - - let mut last_print = Instant::now(); - loop { - if last_print.elapsed() > Duration::from_secs(10) { - let http_s = tcp_rx[80] + tcp_rx[443]; - let http_s_kb = http_s / 1000; - - let http_s_tx = tcp_tx[80] + tcp_tx[443]; - let http_s_tx_kb = http_s_tx / 1000; + let cat = Rc::new(UnsafeCell::new(Count::new())); - println!("HTTP(S) rx {}kB // tx {}kB", http_s_kb, http_s_tx_kb); + let ex = Rc::new(LocalExecutor::new()); - last_print = Instant::now(); - } - - match rx.recv() { - Err(_e) => { - eprintln!("error receiving! breaking from loop"); - break; - } - Ok(Meow::Show) => { - if last_print.elapsed() > Duration::from_secs(30) { - println!("Activated by Meow::Show"); + ex.spawn(async { + loop { + match rx.recv().await { + Err(_e) => { + eprintln!("error receiving! breaking from loop"); + break; } - } - Ok(Meow::Shutdown) => { - eprintln!("got shutdown! breaking from loop"); - break; - } - Ok(Meow::Tcp { - tx: tcp_tx_flag, - src, - dst, - len, - }) => { - if tcp_tx_flag { - tcp_tx[src as usize] += len; - } else { - tcp_rx[dst as usize] += len; + Ok(Meow::Tcp { tx, src, dst, len }) => { + unsafe { &mut *cat.get() }.push_tcp(tx, src, dst, len); + } + Ok(Meow::Udp { tx, src, dst, len }) => { + unsafe { &mut *cat.get() }.push_udp(tx, src, dst, len); } } - _ => (), } - } + }) + .detach(); + + let run_cat = Rc::clone(&cat); + let run_ex = Rc::clone(&ex); + let run = ex.run(async move { + let socket = TcpListener::bind("127.0.0.1:6666").await.unwrap(); + + loop { + let (mut stream, _caddr) = socket.accept().await.unwrap(); + let per_spawn_cat = Rc::clone(&run_cat); + + run_ex + .spawn(async move { + let cat = unsafe { &mut *per_spawn_cat.get() }; + let http_tx = cat.many_tcp_tx(&[80, 443]); + let http_rx = cat.many_tcp_rx(&[80, 443]); + + let str = format!("{http_tx}\n{http_rx}"); + stream.write_all(str.as_bytes()).await.unwrap(); + }) + .detach(); + } + }); + + smol::block_on(run); } |