<p style="margin:0px;font-family:Times;font-size:medium">I want to use ftp-download-file to download something, but I want to show the progress in my gui app.</p><p style="margin:0px;font-family:Times;font-size:medium">So I change net/ftp.rkt a little, let ftp-download-file can report current progress, ftp-download-file now changed to:</p>
<p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium">(define (ftp-download-file tcp-ports folder filename [hook #f])</p>
<p style="margin:0px;font-family:Times;font-size:medium"> ;; Save the file under the name tmp.file, rename it once download is</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; complete this assures we don't over write any existing file without</p>
<p style="margin:0px;font-family:Times;font-size:medium"> ;; having a good file down</p><p style="margin:0px;font-family:Times;font-size:medium"> (let* ([tmpfile (make-temporary-file</p><p style="margin:0px;font-family:Times;font-size:medium">
(string-append</p><p style="margin:0px;font-family:Times;font-size:medium"> (regexp-replace</p><p style="margin:0px;font-family:Times;font-size:medium"> #rx"~"</p>
<p style="margin:0px;font-family:Times;font-size:medium"> (path->string (build-path folder "ftptmp"))</p><p style="margin:0px;font-family:Times;font-size:medium"> "~~")</p>
<p style="margin:0px;font-family:Times;font-size:medium"> "~a"))]</p><p style="margin:0px;font-family:Times;font-size:medium"> [new-file (open-output-file tmpfile #:exists 'replace)]</p>
<p style="margin:0px;font-family:Times;font-size:medium"> [tcp-data (establish-data-connection tcp-ports)])</p><p style="margin:0px;font-family:Times;font-size:medium"> (fprintf (ftp-connection-out tcp-ports) "RETR ~a\r\n" filename)</p>
<p style="margin:0px;font-family:Times;font-size:medium"> (ftp-check-response (ftp-connection-in tcp-ports)</p><p style="margin:0px;font-family:Times;font-size:medium"> (ftp-connection-out tcp-ports)</p>
<p style="margin:0px;font-family:Times;font-size:medium"> (list #"125" #"150") print-msg (void))</p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium">
;; hook is a lambda (-> channel? channel? any?)</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; (hook receive-channel control-channel)</p><p style="margin:0px;font-family:Times;font-size:medium">
;; in this lambda, can use (channel-get rcv-ch) to get bytes has downloaded.</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; after (channel-get rcv-ch), use (channel-put ctrl-ch 0) to launch sender to get a new size info the rcv-ch channel.</p>
<p style="margin:0px;font-family:Times;font-size:medium"> ;; Two channels used here is want to control the "refresh speed". It prevent receiver get size too frequently.</p><p style="margin:0px;font-family:Times;font-size:medium">
;; It means only if hook (channel-put ctrl-ch 0), then the sender will get the downloading file size.</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; Example:</p><p style="margin:0px;font-family:Times;font-size:medium">
;; (ftp-download-file ftp-conn "." "testfile"</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; (lambda (rcv-ch ctrl-ch)</p><p style="margin:0px;font-family:Times;font-size:medium">
;; (letrec ([recur</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; (lambda ()</p><p style="margin:0px;font-family:Times;font-size:medium">
;; (let ([data (channel-get rcv-ch)])</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; (when (not (= data -1))</p><p style="margin:0px;font-family:Times;font-size:medium">
;; (channel-put ctrl-ch 0)</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; (printf "~a~%" data)</p><p style="margin:0px;font-family:Times;font-size:medium">
;; (sleep 1) //not too fast</p><p style="margin:0px;font-family:Times;font-size:medium"> ;; (recur))))])</p><p style="margin:0px;font-family:Times;font-size:medium">
;; (recur))))</p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium"> (let ([rcv-ch (make-channel)]</p><p style="margin:0px;font-family:Times;font-size:medium">
[ctrl-ch (make-channel)])</p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium"> (when (procedure? hook)</p><p style="margin:0px;font-family:Times;font-size:medium">
(thread</p><p style="margin:0px;font-family:Times;font-size:medium"> (lambda ()</p><p style="margin:0px;font-family:Times;font-size:medium"> (hook rcv-ch ctrl-ch)))</p><p style="margin:0px;font-family:Times;font-size:medium">
<br></p><p style="margin:0px;font-family:Times;font-size:medium"> (thread</p><p style="margin:0px;font-family:Times;font-size:medium"> (lambda ()</p><p style="margin:0px;font-family:Times;font-size:medium">
(letrec ([recur</p><p style="margin:0px;font-family:Times;font-size:medium"> (lambda ()</p><p style="margin:0px;font-family:Times;font-size:medium"> (channel-put rcv-ch (file-size tmpfile))</p>
<p style="margin:0px;font-family:Times;font-size:medium"> (when (= 0 (channel-get ctrl-ch))</p><p style="margin:0px;font-family:Times;font-size:medium"> (recur)))])</p><p style="margin:0px;font-family:Times;font-size:medium">
(recur)))))</p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium"> (copy-port tcp-data new-file)</p><p style="margin:0px;font-family:Times;font-size:medium">
<br></p><p style="margin:0px;font-family:Times;font-size:medium"> (when (procedure? hook)</p><p style="margin:0px;font-family:Times;font-size:medium"> ; send -1 to stop receiver thread</p><p style="margin:0px;font-family:Times;font-size:medium">
(channel-put rcv-ch (file-size tmpfile))</p><p style="margin:0px;font-family:Times;font-size:medium"> (channel-get ctrl-ch)</p><p style="margin:0px;font-family:Times;font-size:medium"> (channel-put rcv-ch -1)</p>
<p style="margin:0px;font-family:Times;font-size:medium"> </p><p style="margin:0px;font-family:Times;font-size:medium"> ; send -1 to stop sender thread</p><p style="margin:0px;font-family:Times;font-size:medium">
(channel-get rcv-ch)</p><p style="margin:0px;font-family:Times;font-size:medium"> (channel-put ctrl-ch -1)))</p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium">
<br></p><p style="margin:0px;font-family:Times;font-size:medium"> (close-output-port new-file)</p><p style="margin:0px;font-family:Times;font-size:medium"> (close-input-port tcp-data)</p><p style="margin:0px;font-family:Times;font-size:medium">
(ftp-check-response (ftp-connection-in tcp-ports)</p><p style="margin:0px;font-family:Times;font-size:medium"> (ftp-connection-out tcp-ports)</p><p style="margin:0px;font-family:Times;font-size:medium">
#"226" print-msg (void))</p><p style="margin:0px;font-family:Times;font-size:medium"> (rename-file-or-directory tmpfile (build-path folder filename) #t)))</p><p style="margin:0px;font-family:Times;font-size:medium">
<br></p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium">A little complicated? But is worked.</p><p style="margin:0px;font-family:Times;font-size:medium">
<br></p><p style="margin:0px;font-family:Times;font-size:medium">You must send control-channel 0 to let sender to refresh current tmp file size and reget file size.</p><p style="margin:0px;font-family:Times;font-size:medium">
This prevent sender refresh file size too frequently.</p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium">Below is the example:</p><p style="margin:0px;font-family:Times;font-size:medium">
<br></p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><p style="margin:0px;font-family:Times;font-size:medium"> (ftp-download-file ftp-conn "." "testfile"</p><p style="margin:0px;font-family:Times;font-size:medium">
(lambda (rcv-ch snd-ch)</p><p style="margin:0px;font-family:Times;font-size:medium"> (letrec ([recur</p><p style="margin:0px;font-family:Times;font-size:medium"> (lambda ()</p>
<p style="margin:0px;font-family:Times;font-size:medium"> (let ([data (channel-get rcv-ch)])</p><p style="margin:0px;font-family:Times;font-size:medium"> (when (not (= data -1))</p>
<p style="margin:0px;font-family:Times;font-size:medium"> (channel-put snd-ch 0)</p><p style="margin:0px;font-family:Times;font-size:medium"> (printf "~a~%" (inexact->exact (round (* 100 (/ data total-size)))))</p>
<p style="margin:0px;font-family:Times;font-size:medium"> (sleep 1)</p><p style="margin:0px;font-family:Times;font-size:medium"> (recur))))])</p>
<p style="margin:0px;font-family:Times;font-size:medium"> (recur))))</p><p style="margin:0px;font-family:Times;font-size:medium"><br></p><div style="font-family:Times;font-size:medium"></div>