#lang racket
(require xml
net/base64
(planet gh/http/request)
(planet gh/http/head)
"exn.rkt"
"util.rkt")
(define/contract/provide (post-with-retry uri xs-post-data heads [try 1])
((string? dict? dict?)
(exact-positive-integer?)
. ->* .
xexpr?)
(define data (string->bytes/utf-8 (dict->form-urlencoded xs-post-data)))
(log-debug (tr "POST" data))
(call/output-request
"1.1" "POST" uri data #f heads
(lambda (in h)
(define e (read-entity/xexpr in h))
(match (extract-http-code h)
[200 e]
[503
(if (<= try 5)
(let ([sleep-time (sqr try)]) (log-info (format "AWS returned 503. Try ~a in ~a secs."
(add1 try) sleep-time))
(sleep sleep-time)
(post-with-retry uri xs-post-data heads (add1 try)))
(error 'post-with-retry "too many 503 retries; giving up"))]
[else
(raise (header&response->exn:fail:aws
h e (current-continuation-marks)))]))))
(define/provide (set-next-token params token)
(cons (list 'NextToken token)
(filter (lambda (x) (not (equal? (car x) 'NextToken)))
params)))
(define/provide (timestamp [seconds (current-seconds)])
(seconds->gmt-8601-string 'T/Z seconds))
(define/contract/provide (attribute-xexpr->attrib-pair x)
(xexpr? . -> . (list/c symbol? string?))
(match x
[(list 'Attribute _ name val)
(let ([name (maybe-decode name)]
[val (maybe-decode val)])
(list (if (string? name) (string->symbol name) name)
val))]))
(define/provide (maybe-decode x)
(match x
[(list (or 'Name 'Value) attrs val)
(match (assoc 'Encoding attrs)
[(list 'Encoding "base64") (base64-decode val)]
[else val])]))