+(: crawl (-> Void))
+(define (crawl)
+ (let* ([peers-sort
+ (λ (peers) (sort peers (match-lambda**
+ [((Peer n1 _ _) (Peer n2 _ _))
+ (string<? (if n1 n1 "")
+ (if n2 n2 ""))])))]
+ [peers-all-file
+ (build-path tt-home-dir "peers-all")]
+ [peers-mentioned-file
+ (build-path tt-home-dir "peers-mentioned")]
+ [peers-parsed-file
+ (build-path tt-home-dir "peers-parsed")]
+ [peers-mentioned-curr
+ (mentioned-peers-in-cache)]
+ [peers-mentioned-prev
+ (file->peers peers-mentioned-file)]
+ [peers-mentioned
+ (peers-sort (uniq (append peers-mentioned-prev
+ peers-mentioned-curr)))]
+ [peers-all-prev
+ (file->peers peers-all-file)]
+ [peers-all
+ (list->set (append peers-mentioned
+ peers-all-prev))]
+ [peers-discovered
+ (set-subtract peers-all (list->set peers-all-prev))]
+ [peers-all
+ (peers-sort (set->list peers-all))]
+ [peers-parsed
+ (filter
+ (λ (p) (< 0 (length (peer->msgs p))))
+ peers-all)])
+ ; TODO Deeper de-duping
+ (log-info "Known peers mentioned: ~a" (length peers-mentioned))
+ (log-info "Known peers parsed ~a" (length peers-parsed))
+ (log-info "Known peers total: ~a" (length peers-all))
+ (log-info "Discovered ~a new peers:~n~a"
+ (set-count peers-discovered)
+ (pretty-format (map
+ (λ (p) (cons (Peer-nick p)
+ (url->string (Peer-uri p))))
+ (set->list peers-discovered))))
+ (peers->file peers-mentioned
+ peers-mentioned-file)
+ (peers->file peers-parsed
+ peers-parsed-file)
+ (peers->file peers-all
+ peers-all-file)))
+
+(: read (-> (Listof String) Number Number Timeline-Order Out-Format Void))
+(define (read file-paths ts-min ts-max order out-format)
+ (let* ([peers
+ (paths->peers file-paths)]
+ [msgs
+ (timeline-sort (peers->timeline peers) order)]
+ [include?
+ (λ (m)
+ (and (or (not ts-min) (>= (Msg-ts-epoch m) ts-min))
+ (or (not ts-max) (<= (Msg-ts-epoch m) ts-max))))])
+ (timeline-print out-format (filter include? msgs))))
+
+(: upload (-> Void))
+(define (upload)
+ ; FIXME Should not exit from here, but only after cleanup/logger-stoppage.
+ (if (system (path->string (build-path tt-home-dir "hooks" "upload")))
+ (exit 0)
+ (exit 1)))
+
+(: download (-> (Listof String) Positive-Integer Positive-Float Void))
+(define (download file-paths num-workers timeout)
+ (let ([peers (paths->peers file-paths)])
+ (define-values (_res _cpu real-ms _gc)
+ (time-apply timeline-download (list num-workers timeout peers)))
+ (log-info "Downloaded timelines from ~a peers in ~a seconds."
+ (length peers)
+ (/ real-ms 1000.0))))
+
+(: dispatch (-> String Void))
+(define (dispatch command)
+ (match command
+ [(or "d" "download")
+ ; Initially, 15 was fastest out of the tried: 1, 5, 10, 20. Then I
+ ; started noticing significant slowdowns. Reducing to 5 seems to help.
+ (let ([num-workers 5]
+ [timeout 10.0])
+ (command-line
+ #:program "tt download"
+ #:once-each
+ [("-j" "--jobs")
+ njobs "Number of concurrent jobs."
+ (set! num-workers (string->number njobs))]
+ [("-t" "--timeout")
+ seconds "Timeout seconds per request."
+ (set! timeout (string->number seconds))]
+ #:args file-paths
+ (download file-paths num-workers timeout)))]
+ [(or "u" "upload")
+ (command-line
+ #:program "tt upload" #:args () (upload))]
+ [(or "r" "read")
+ (let ([out-format 'multi-line]
+ [order 'old->new]
+ [ts-min #f]
+ [ts-max #f])
+ (command-line
+ #:program "tt read"
+ #:once-each
+ [("-r" "--rev")
+ "Reverse displayed timeline order."
+ (set! order 'new->old)]
+ [("-m" "--min")
+ m "Earliest time to display (ignore anything before it)."
+ (set! ts-min (rfc3339->epoch m))]
+ [("-x" "--max")
+ x "Latest time to display (ignore anything after it)."
+ (set! ts-max (rfc3339->epoch x))]
+ #:once-any
+ [("-s" "--short")
+ "Short output format"
+ (set! out-format 'single-line)]
+ [("-l" "--long")
+ "Long output format"
+ (set! out-format 'multi-line)]
+ #:args file-paths
+ (read file-paths ts-min ts-max order out-format)))]
+ [(or "c" "crawl")
+ (command-line
+ #:program "tt crawl" #:args () (crawl))]
+ [command
+ (eprintf "Error: invalid command: ~v\n" command)
+ (eprintf "Please use the \"--help\" option to see a list of available commands.\n")
+ (exit 1)]))
+