makepad_studio/file_system/
file_client_desktop.rs

1use {
2    crate::{
3        makepad_micro_serde::*,
4        makepad_platform::*,
5        makepad_file_protocol::{FileRequest, FileClientAction},
6        makepad_file_server::{FileServerConnection, FileServer},
7    },
8    std::{
9        env,
10        io::{Read, Write},
11        net::{TcpListener, TcpStream},
12        sync::mpsc::{self, Receiver, Sender, TryRecvError},
13        thread,
14        path::PathBuf
15    },
16};
17
18#[derive(Default)]
19pub struct FileClient {
20//    bind: Option<String>,
21    path: String,
22    inner: Option<FileClientInner>
23}
24
25pub struct FileClientInner {
26    pub request_sender: Sender<FileRequest>,
27    pub action_signal: Signal,
28    pub action_receiver: Receiver<FileClientAction>,
29}
30
31impl FileClient {
32    pub fn init(&mut self, _cx:&mut Cx){
33        if self.inner.is_none() {
34            self.inner = Some(FileClientInner::new_with_local_server(&self.path))
35        }
36    }
37    
38    pub fn send_request(&mut self, request: FileRequest) {
39        self.inner.as_ref().unwrap().request_sender.send(request).unwrap();
40    }
41    
42    pub fn request_sender(&mut self) -> impl FnMut(FileRequest) + '_ {
43        let request_sender = &self.inner.as_ref().unwrap().request_sender;
44        move | request | request_sender.send(request).unwrap()
45    }
46    
47    pub fn handle_event(&mut self, cx: &mut Cx, event: &Event) -> Vec<FileClientAction> {
48        let mut a = Vec::new();
49        self.handle_event_with(cx, event, &mut | _, v | a.push(v));
50        a
51    }
52    
53    pub fn handle_event_with(&mut self, cx: &mut Cx, event: &Event, dispatch_action: &mut dyn FnMut(&mut Cx, FileClientAction)) {
54        let inner = self.inner.as_ref().unwrap();
55        match event {
56            Event::Signal=>{
57                loop {
58                    match inner.action_receiver.try_recv() {
59                        Ok(action) => dispatch_action(cx, action),
60                        Err(TryRecvError::Empty) => break,
61                        _ => panic!(),
62                    }
63                }
64            }
65            _ => {}
66        }
67    }
68    
69}
70
71impl FileClientInner {
72    pub fn new_with_local_server(subdir:&str) -> Self {
73        let (request_sender, request_receiver) = mpsc::channel();
74        let action_signal = Signal::new();
75        let (action_sender, action_receiver) = mpsc::channel();
76        
77        let base_path = env::current_dir().unwrap();
78        let final_path = base_path.join(subdir.split('/').collect::<PathBuf>());
79        let mut server = FileServer::new(final_path);
80        spawn_local_request_handler(
81            request_receiver,
82            server.connect(Box::new({
83                let action_sender = action_sender.clone();
84                let action_signal = action_signal.clone();
85                move | notification | {
86                    action_sender.send(FileClientAction::Notification(notification)).unwrap();
87                    action_signal.set();
88                }
89            })),
90            action_signal.clone(),
91            action_sender,
92        );
93        spawn_connection_listener(TcpListener::bind("127.0.0.1:0").unwrap(), server);
94        
95        Self {
96            request_sender,
97            action_signal,
98            action_receiver
99        }
100    }
101    
102    pub fn new_connect_remote(to_server: &str) -> Self {
103        let (request_sender, request_receiver) = mpsc::channel();
104        let action_signal = Signal::new();
105        let (action_sender, action_receiver) = mpsc::channel();
106        
107        let stream = TcpStream::connect(to_server).unwrap();
108        spawn_request_sender(request_receiver, stream.try_clone().unwrap());
109        spawn_response_or_notification_receiver(stream, action_signal.clone(), action_sender,);
110        
111        Self {
112            request_sender,
113            action_signal,
114            action_receiver
115        }
116    }
117    
118}
119
120fn spawn_connection_listener(listener: TcpListener, mut server: FileServer) {
121    thread::spawn(move || {
122        log!("Server listening on {}", listener.local_addr().unwrap());
123        for stream in listener.incoming() {
124            let stream = stream.unwrap();
125            log!("Incoming connection from {}", stream.peer_addr().unwrap());
126            let (action_sender, action_receiver) = mpsc::channel();
127            let connection = server.connect(Box::new({
128                let action_sender = action_sender.clone();
129                move | notification | {
130                    action_sender.send(FileClientAction::Notification(notification)).unwrap();
131                }
132            }));
133            spawn_remote_request_handler(
134                connection,
135                stream.try_clone().unwrap(),
136                action_sender,
137            );
138            spawn_response_or_notification_sender(action_receiver, stream);
139        }
140    });
141}
142
143fn spawn_remote_request_handler(
144    connection: FileServerConnection,
145    mut stream: TcpStream,
146    action_sender: Sender<FileClientAction>,
147) {
148    thread::spawn(move || loop {
149        let mut len_bytes = [0; 4];
150        stream.read_exact(&mut len_bytes).unwrap();
151        let len = u32::from_be_bytes(len_bytes);
152        let mut request_bytes = vec![0; len as usize];
153        stream.read_exact(&mut request_bytes).unwrap();
154        
155        let request = DeBin::deserialize_bin(request_bytes.as_slice()).unwrap();
156        let response = connection.handle_request(request);
157        action_sender.send(FileClientAction::Response(response)).unwrap();
158    });
159}
160
161fn spawn_response_or_notification_sender(
162    action_receiver: Receiver<FileClientAction>,
163    mut stream: TcpStream,
164) {
165    thread::spawn(move || loop {
166        let action = action_receiver.recv().unwrap();
167        let mut action_bytes = Vec::new();
168        
169        action.ser_bin(&mut action_bytes);
170        
171        let len_bytes = action_bytes.len().to_be_bytes();
172        stream.write_all(&len_bytes).unwrap();
173        stream.write_all(&action_bytes).unwrap();
174    });
175}
176
177fn spawn_request_sender(request_receiver: Receiver<FileRequest>, mut stream: TcpStream) {
178    thread::spawn(move || loop {
179        let request = request_receiver.recv().unwrap();
180        let mut request_bytes = Vec::new();
181        request.ser_bin(&mut request_bytes);
182        let len_bytes = request_bytes.len().to_be_bytes();
183        stream.write_all(&len_bytes).unwrap();
184        stream.write_all(&request_bytes).unwrap();
185    });
186}
187
188fn spawn_response_or_notification_receiver(
189    mut stream: TcpStream,
190    action_signal: Signal,
191    action_sender: Sender<FileClientAction>,
192) {
193    thread::spawn(move || loop {
194        let mut len_bytes = [0; 4];
195        stream.read_exact(&mut len_bytes).unwrap();
196        
197        let len = u32::from_be_bytes(len_bytes);
198        let mut action_bytes = vec![0; len as usize];
199        stream.read_exact(&mut action_bytes).unwrap();
200        let action = DeBin::deserialize_bin(action_bytes.as_slice()).unwrap();
201        action_sender.send(action).unwrap();
202        action_signal.set()
203    });
204}
205
206fn spawn_local_request_handler(
207    request_receiver: Receiver<FileRequest>,
208    connection: FileServerConnection,
209    action_signal: Signal,
210    action_sender: Sender<FileClientAction>,
211) {
212    thread::spawn(move || loop {
213        let request = request_receiver.recv().unwrap();
214        let response = connection.handle_request(request);
215        action_sender.send(FileClientAction::Response(response)).unwrap();
216        action_signal.set()
217    });
218}