aboutsummaryrefslogtreecommitdiff
path: root/tools/obu-ping
blob: 2897e235d5a1f7ebac3dc3cdb87916f9eecca00c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env gosh

(use rfc.json)
(use rfc.uri)
(use rfc.http)
(use srfi-19)
(use file.util)
(use util.match)
(use gauche.parseopt)
(use gauche.process)
(use text.edn)
(use scheme.mapping.hash)

(define (show-help progname)
  (display (format
"~a: tracktrain's on-board reporting thing. Excepts input to be
piped from gpsd's `gpspipe --json` onto stdin.

Arguments:
 -u --url: base url of the tracktrain server [required]
 -n: number of positions to fetch (default is to loop forever)
 -d --no-ping: just print the positions, don't send anything
 -s --statefile: state file
 -c --config: config file (default is /etc/tracktrain/obu.conf)
 -h --help: display this help
" progname))
  (exit 0))

(define (main args)
  (let-args
   (cdr args)
   ((statefile "s|state=s")
    (baseurl "u|url=s")
    (n "n=i")
    (no-ping "d|no-ping")
    (help "h|help" => (cut show-help (car args)))
    . restargs)
   (if (and (equal? baseurl #f) (equal? no-ping #f))
       (show-help (car args))
       (with-input-from-process
        '(gpspipe --json)
        (cut report-position
             (if (equal? statefile #f) "./obu-state.edn" statefile)
             baseurl
             n
             no-ping)
        :on-abnormal-exit :ignore))
   (exit 0)))


(define (try-get-current-pos)
  (define json
    (parameterize
      ; replace all json keys with symbols; everything else is confusing
      ([json-object-handler
        (cut map (lambda p `(,(string->symbol (car (car p))) . ,(cdr (car p)))) <>)])
      (parse-json)))
  (define class
    (assoc-ref json 'class))
  (match class
    ("TPV" `((lat . ,(assoc-ref json 'lat))
                      (lon . ,(assoc-ref json 'lon))
                      (time . ,(assoc-ref json 'time))))
    (_ (try-get-current-pos))))

(define json-symbol-key
  (cut map (lambda p `(,(string->symbol (car (car p))) . ,(cdr (car p)))) <>))

(define (report-position statefile url n no-ping)
  (define trip
    (if no-ping #f
    (process-output->string `(obu-guess-trip -u ,url))))
  (define token
    (if no-ping #f (get-token url trip statefile)))
  (if n
    (dotimes (i n)
      (ping-pos statefile url token))
    (while #t
      (ping-pos statefile url token))))

(define (ping-pos dir url token)
  (let ([pos (try-get-current-pos)])
    (display (format "~a\n" pos))
    (if (not (equal? token #f))
        (display (format "server: ~a\n" (ping url token pos))))))

(define (get-token url trip statefile)
  (define cached?
    (with-input-from-process `(obu-config -s ,statefile token) read))
  (if cached?
      (symbol->string cached?)
      (let* ([token (fetch-token url trip)])
        (do-process `(obu-config -s ,statefile token ,token))
        token)))

(define (fetch-token url trip)
  (define tls
    (equal? (uri-ref url 'scheme) "https"))
  (display (format "fetching new token for trip ~a…\n" trip))
  (parameterize
      ; replace all json keys with symbols; everything else is confusing
      ([json-object-handler json-symbol-key])
    (parse-json-string
     (values-ref (http-post
                  (uri-ref url 'host+port)
                  (format "/api/train/register/~a" trip)
                  (construct-json-string '((agent . "onboard-unit")))
                  :content-type "application/json"
                  :secure tls)
                 2))))

(define (ping url token pos)
  (define tls
    (equal? (uri-ref url 'scheme) "https"))
  (parameterize ([json-object-handler json-symbol-key])
    (parse-json-string
     (values-ref (http-post
                  (uri-ref url 'host+port)
                  "/api/train/ping"
                  (construct-json-string `((token . ,token)
                                           (lat . ,(assoc-ref pos 'lat))
                                           (long . ,(assoc-ref pos 'lon))
                                           (timestamp . ,(assoc-ref pos 'time))))
                  :content-type "application/json"
                  :secure tls)
                 2))))