1- use base64 :: { decode_config , encode_config } ;
2- use clipboard_win :: { get_clipboard_string , set_clipboard_string } ;
1+ mod protocol ;
2+ use protocol :: { Packet , PacketData , PacketStart , Protocol } ;
33use std:: {
44 env:: Args ,
55 fs:: File ,
@@ -53,16 +53,16 @@ fn parse_args(a: Args) -> Result<AppSetting, String> {
5353
5454 for x in a {
5555 match x. as_str ( ) {
56- "--size" => {
56+ "--size" | "-s" => {
5757 state = ArgState :: Size ;
5858 }
59- "--skip" => {
59+ "--skip" | "-S" => {
6060 state = ArgState :: Skip ;
6161 }
62- "--send-timeout" => {
62+ "--send-timeout" | "-st" => {
6363 state = ArgState :: SendTimeout ;
6464 }
65- "--recv-timeout" => {
65+ "--recv-timeout" | "-rt" => {
6666 state = ArgState :: RecvTimeout ;
6767 }
6868 "--dry-run" => {
@@ -148,103 +148,91 @@ fn main() -> Result<(), String> {
148148 }
149149 } )
150150}
151- enum RecvState {
152- Wait ,
153- Start ,
154- End ,
155- }
151+
156152fn sleep_ms ( ms : u64 ) {
157153 std:: thread:: sleep ( std:: time:: Duration :: from_millis ( ms) )
158154}
159155fn recv_file ( s : & AppRecvSetting ) -> Result < ( ) , io:: Error > {
160- let _ = set_clipboard_string ( "---" ) ?;
161156 let mut writer: Option < BufWriter < File > > = None ;
162- let mut state = RecvState :: Wait ;
163157 let mut last_index = 0 ;
164158 let mut has_started = false ;
165159 let mut time_wait_ms = 0 ;
160+ let mut timeout_ms = s. timeout ;
166161 let mut total_len = 0u64 ;
167162 let mut recved_len = 0u64 ;
163+ let protocol = Protocol :: new ( ) ;
168164 println ! ( "waiting for file" ) ;
169165 loop {
170- match state {
171- RecvState :: Wait => {
172- if let Ok ( x) = get_clipboard_string ( ) {
173- if x. starts_with ( "ftoc-start" ) {
174- if has_started {
175- continue ;
166+ if let Ok ( x) = protocol. recv_decoded ( ) {
167+ match x {
168+ Packet :: Noop => {
169+ sleep_ms ( 1000 ) ;
170+ }
171+ Packet :: Start ( x) => {
172+ if has_started {
173+ continue ;
174+ }
175+ has_started = true ;
176+
177+ match File :: create ( Path :: new ( & x. name ) ) {
178+ Ok ( f) => {
179+ println ! ( "start recv file: {}" , x. name) ;
180+ writer = Some ( BufWriter :: new ( f) ) ;
181+ total_len = x. length ;
182+ timeout_ms = ( x. timeout - 150 ) as u64 ;
183+ println ! ( "reset timeout from sender side to {} ms" , timeout_ms) ;
176184 }
177- has_started = true ;
178- let x: Vec < & str > = x. split ( ":" ) . collect ( ) ;
179- match File :: create ( Path :: new ( x[ 1 ] ) ) {
180- Ok ( f) => {
181- println ! ( "start recv file: {}" , x[ 1 ] ) ;
182- writer = Some ( BufWriter :: new ( f) ) ;
183- state = RecvState :: Start ;
184- total_len = x[ 2 ] . parse ( ) . expect ( "can't read total length of file" ) ;
185- }
186- Err ( e) => {
187- dbg ! ( e) ;
188- break ;
189- }
185+ Err ( e) => {
186+ dbg ! ( e) ;
187+ break ;
190188 }
191- } else {
192- sleep_ms ( 1000 ) ;
193189 }
194- } else {
195- sleep_ms ( 100 ) ;
196- continue ;
197190 }
198- }
199- RecvState :: Start => {
200- if let Ok ( x) = get_clipboard_string ( ) {
201- if x. starts_with ( "ftoc-end" ) {
202- state = RecvState :: End ;
203- } else if x. starts_with ( "ftoc-start" ) {
204- sleep_ms ( 100 ) ;
191+ Packet :: Data ( x) => {
192+ if !has_started {
205193 continue ;
206- } else if x. starts_with ( "ftoc" ) {
207- let x: Vec < & str > = x. split ( ":" ) . collect ( ) ;
208- let idx: i32 = x[ 1 ] . parse ( ) . expect ( "invalid index" ) ;
194+ }
195+ let idx = x. index ;
209196
210- if last_index == idx - 1 {
211- if let Ok ( v) = decode_config ( x[ 2 ] , base64:: URL_SAFE_NO_PAD ) {
212- if let Some ( x) = & mut writer {
213- time_wait_ms = 0 ;
214- last_index = idx;
215- recved_len += v. len ( ) as u64 ;
197+ if last_index == idx - 1 {
198+ if let Some ( w) = & mut writer {
199+ time_wait_ms = 0 ;
200+ last_index = idx;
201+ recved_len += x. data . len ( ) as u64 ;
216202
217- let percentage: f32 = ( recved_len as f32 ) / ( total_len as f32 ) ;
218- println ! ( "recv block {} ({:.2}%)" , idx, percentage * 100f32 ) ;
219- let _ = x. write ( v. as_ref ( ) ) ;
220- } else {
221- println ! ( "warn: block {} write failed" , idx)
222- }
223- } else {
224- println ! ( "warn: block {} decode failed" , idx)
203+ let percentage: f32 = ( recved_len as f32 ) / ( total_len as f32 ) ;
204+ println ! ( "recv block {} ({:.2}%)" , idx, percentage * 100f32 ) ;
205+ if let Err ( _) = w. write ( x. data . as_ref ( ) ) {
206+ println ! ( "warning: can't write to destination file" ) ;
225207 }
226208 } else {
227- // wait for missed block or retransmission
228- time_wait_ms += s. timeout ;
229- if time_wait_ms > 10000 {
230- println ! ( "warning: recv staled, last_index={}" , last_index) ;
231- time_wait_ms = 0 ;
232- }
209+ println ! ( "warning: block {} write failed" , idx)
210+ }
211+ } else {
212+ // wait for missed block or retransmission
213+ time_wait_ms += s. timeout ;
214+ if time_wait_ms > 10000 {
215+ println ! ( "warning: recv staled, last_index={}" , last_index) ;
216+ time_wait_ms = 0 ;
233217 }
234218 }
235- sleep_ms ( s. timeout ) ;
236- } else {
237- sleep_ms ( 100 ) ;
238- continue ;
219+ sleep_ms ( timeout_ms) ;
239220 }
240- }
241- RecvState :: End => {
242- if let Some ( x) = & mut writer {
243- let _ = x. flush ( ) ;
244- println ! ( "file saved" )
221+ Packet :: End => {
222+ if recved_len != total_len {
223+ println ! ( "[warn] recved end but data is incomplete" ) ;
224+ continue ;
225+ }
226+ if let Some ( x) = & mut writer {
227+ let _ = x. flush ( ) ;
228+ println ! ( "file saved" ) ;
229+ break ;
230+ }
245231 }
246- break ;
247232 }
233+ } else {
234+ sleep_ms ( 100 ) ;
235+ continue ;
248236 }
249237 }
250238 Ok ( ( ) )
@@ -253,6 +241,7 @@ fn send_file(s: &AppSendSetting) -> Result<(), io::Error> {
253241 let p = Path :: new ( & s. file_path ) ;
254242 let file = File :: open ( p) ?;
255243 let mut reader = BufReader :: new ( file) ;
244+ let protocol = Protocol :: new ( ) ;
256245
257246 let mut eof = false ;
258247
@@ -268,10 +257,12 @@ fn send_file(s: &AppSendSetting) -> Result<(), io::Error> {
268257 reader. seek ( io:: SeekFrom :: End ( 0 ) ) ?;
269258 let len = reader. stream_position ( ) ?;
270259 reader. seek ( io:: SeekFrom :: Start ( 0 ) ) ?;
271- let x = format ! ( "ftoc-start:{}:{}" , filename, len) ;
272260 println ! ( "sending file : {} with {} bytes long" , filename, len) ;
273-
274- let _ = set_clipboard_string ( x. as_str ( ) ) ;
261+ let _ = protocol. send_encoded ( Packet :: Start ( PacketStart {
262+ timeout : s. timeout as u32 ,
263+ name : filename. to_owned ( ) ,
264+ length : len,
265+ } ) ) ;
275266
276267 sleep_ms ( 2000 ) ;
277268
@@ -288,14 +279,16 @@ fn send_file(s: &AppSendSetting) -> Result<(), io::Error> {
288279 eof = true ;
289280 } else {
290281 index += 1 ;
291- let s = encode_config ( & v[ 0 ..s] , base64:: URL_SAFE_NO_PAD ) ;
292- let text = format ! ( "ftoc:{}:{}" , index, s) ;
293- let _ = set_clipboard_string ( text. as_str ( ) ) ;
282+ let packet = Packet :: Data ( PacketData {
283+ index : index,
284+ data : v[ 0 ..s] . to_vec ( ) ,
285+ } ) ;
286+ let _ = protocol. send_encoded ( packet) ;
294287 println ! ( "sending block {}" , index) ;
295288 }
296289 } ) ;
297290 if eof {
298- let _ = set_clipboard_string ( "ftoc-end" ) ? ;
291+ let _ = protocol . send_encoded ( Packet :: End ) ;
299292 println ! ( "file sent" ) ;
300293 break ;
301294 }
0 commit comments