diff --git a/scripts/aoc-lib.rkt b/scripts/aoc-lib.rkt new file mode 100644 index 0000000..10f4b6f --- /dev/null +++ b/scripts/aoc-lib.rkt @@ -0,0 +1,59 @@ +#lang racket + +(require net/uri-codec net/http-client) +(provide aoc-fetch-input aoc-submit-answer) + +(define *host* "adventofcode.com") + +(define/contract (puzzle-path year day endpoint) + (-> string? string? (or/c "input" "answer") path?) + (build-path "/" year "day" day endpoint)) + +(define (make-headers session) + (list (string-append "Cookie: session=" session))) + +(define (aoc-request year day endpoint session [method 'GET] [data #f]) + (define (parse-headers hlist) + (for/list ([h (in-list hlist)]) + (match h + [(pregexp #px"^([^:]+): (.*?)$" (list _ k v)) + (cons (string->symbol (string-downcase (bytes->string/utf-8 k))) + (bytes->string/utf-8 v))] + [x (cons 'unknown x)]))) + + (define (do-request path headers) + (define-values [status headers-out content] + (http-sendrecv *host* path #:ssl? #t #:headers headers)) + (define headers-out/parsed (parse-headers headers-out)) + + (match status + [(pregexp #px"^HTTP/1\\.[10] 200") content] + [(pregexp #px"^HTTP/1\\.[10] 302") + (define location (cdr (or (assoc 'location headers-out/parsed) + (error "got 302 with no location")))) + (printf "got redirect to ~a\n" location) + (close-input-port content) + (do-request location headers)] + [(pregexp #px"^HTTP/1\\.[10] 404") + (error "endpoint returned 404\n response: " (port->bytes content))] + [stat + (error "endpoint returned unexpected data\n status: " stat "\n response: " + (port->bytes content))])) + (do-request (path->string (puzzle-path year day endpoint)) (make-headers session))) + +(define/contract (aoc-fetch-input year day session) + (-> string? string? string? input-port?) + (aoc-request year day "input" session)) + +(define/contract (aoc-submit-answer year day session part answer) + (-> string? string? string? (or/c 1 2 "1" "2") string? (or/c symbol? bytes?)) + (define data `((level . ,(~a part)) + (answer . ,answer))) + (define resp + (port->bytes (aoc-request year day "answer" session 'POST (alist->form-urlencoded data)))) + + (match resp + [(pregexp #px"Both parts of this puzzle are complete") 'day-complete] + [(pregexp #px"That's the right answer") 'answer-correct] + [(pregexp #px"That's not the right answer") 'answer-incorrect] + [x x])) diff --git a/scripts/get-input b/scripts/get-input index 4ef33c2..33c4668 100755 --- a/scripts/get-input +++ b/scripts/get-input @@ -1,14 +1,10 @@ #!/usr/bin/env racket #lang racket -(require net/http-client) -(define *year* "2020") +(require "aoc-lib.rkt") (command-line #:program "get-input" #:args (day) - (define-values [status headers content] - (http-sendrecv "adventofcode.com" (format "/~a/day/~a/input" *year* day) - #:ssl? #t - #:headers (list (format "Cookie: session=~a" (getenv "AOC_SESSION"))))) - (call-with-output-file (build-path "inputs" day) (lambda (out) (copy-port content out)))) + (define in (aoc-fetch-input (getenv "AOC_YEAR") day (getenv "AOC_SESSION"))) + (call-with-output-file (build-path "inputs" day) (lambda (out) (copy-port in out)))) diff --git a/scripts/make-day b/scripts/make-day index e81d7c7..187fa40 100755 --- a/scripts/make-day +++ b/scripts/make-day @@ -19,7 +19,7 @@ (command-line - #:program "get-input" + #:program "make-day" #:args (day) (call-with-output-file (format "~a.rkt" day) diff --git a/scripts/submit-answer b/scripts/submit-answer new file mode 100755 index 0000000..611abdb --- /dev/null +++ b/scripts/submit-answer @@ -0,0 +1,10 @@ +#!/usr/bin/env racket +#lang racket + +(require "aoc-lib.rkt") + +(command-line + #:program "submit-answer" + #:args (day part answer) + (define resp (aoc-submit-answer (getenv "AOC_YEAR") day (getenv "AOC_SESSION") part answer)) + (printf "server returned: ~a\n" resp))