makepad_studio/file_system/
file_client_desktop.rs1use {
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 {
20path: 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}