ferroui_remote_protocol/
tcp_transport_base.rs1use std::io::{Read, Write};
2use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr, TcpListener, TcpStream};
3use std::sync::atomic::{AtomicBool, Ordering};
4use std::sync::Arc;
5use std::time::Duration;
6
7use crate::error::Error;
8use crate::i_message_type_resolver::IMessageTypeResolver;
9use crate::i_transport::IFerroRemoteTransportConnection;
10
11pub type DisposeCallback = Box<dyn Fn() + Send + Sync>;
13
14pub struct DisposableServer {
18 address: SocketAddr,
19 stopped: Arc<AtomicBool>,
20}
21
22impl DisposableServer {
23 pub fn local_addr(&self) -> SocketAddr {
27 self.address
28 }
29
30 pub fn dispose(&self) {
31 if self.stopped.swap(true, Ordering::SeqCst) {
32 return;
33 }
34 let mut address = self.address;
38 if address.ip().is_unspecified() {
39 let loopback = match address {
40 SocketAddr::V4(_) => IpAddr::V4(Ipv4Addr::LOCALHOST),
41 SocketAddr::V6(_) => IpAddr::V6(Ipv6Addr::LOCALHOST),
42 };
43 address.set_ip(loopback);
44 }
45 let _ = TcpStream::connect_timeout(&address, Duration::from_secs(1));
47 }
48}
49
50fn create_transport_of_stream<T: TcpTransportBase>(
53 transport: &T,
54 stream: TcpStream,
55) -> Result<Arc<dyn IFerroRemoteTransportConnection>, Error> {
56 let input = stream.try_clone()?;
57 let output = stream.try_clone()?;
58 let dispose_callback: DisposeCallback = Box::new(move || {
59 let _ = stream.shutdown(Shutdown::Both);
60 });
61 Ok(transport.create_transport(transport.resolver(), Box::new(input), Box::new(output), dispose_callback))
62}
63
64pub trait TcpTransportBase: Clone + Send + 'static {
70 fn resolver(&self) -> Arc<dyn IMessageTypeResolver>;
72
73 fn create_transport(
77 &self,
78 resolver: Arc<dyn IMessageTypeResolver>,
79 input_stream: Box<dyn Read + Send>,
80 output_stream: Box<dyn Write + Send>,
81 dispose_callback: DisposeCallback,
82 ) -> Arc<dyn IFerroRemoteTransportConnection>;
83
84 fn listen(
97 &self,
98 address: IpAddr,
99 port: u16,
100 cb: impl Fn(Arc<dyn IFerroRemoteTransportConnection>) + Send + Sync + 'static,
101 ) -> Result<DisposableServer, Error> {
102 let server = TcpListener::bind(SocketAddr::new(address, port))?;
103 let local_address = server.local_addr()?;
104 let stopped = Arc::new(AtomicBool::new(false));
105 let cb = Arc::new(cb);
106 let this = self.clone();
107 let accept_stopped = stopped.clone();
108 std::thread::Builder::new().name("remote-protocol-listener".to_string()).spawn(move || loop {
109 let cl = match server.accept() {
110 Ok((cl, _)) => cl,
111 Err(_) => break,
113 };
114 if accept_stopped.load(Ordering::SeqCst) {
115 break;
116 }
117 let this = this.clone();
118 let cb = cb.clone();
119 let _ = std::thread::Builder::new().name("remote-protocol-accept".to_string()).spawn(move || {
120 if let Ok(t) = create_transport_of_stream(&this, cl) {
122 cb(t);
123 }
124 });
125 })?;
126 Ok(DisposableServer { address: local_address, stopped })
127 }
128
129 fn connect(&self, address: IpAddr, port: u16) -> Result<Arc<dyn IFerroRemoteTransportConnection>, Error> {
134 let c = TcpStream::connect(SocketAddr::new(address, port))?;
135 create_transport_of_stream(self, c)
136 }
137}