#lang racket
(require "errors.ss")
(require racket/tcp)
(require racket/serialize)
(require net/url)
(require rnrs/bytevectors-6)
(require rnrs/io/ports-6)
(define (from-host-port host port)
(cons 'tcp (hash
'host host
'port port)))
(define (from-uri s)
(let* ((uri (string->url s))
(scheme (url-scheme uri))
(host (url-host uri))
(port (url-port uri)))
(cond
((equal? scheme "bert")
(from-host-port host port))
(else
(error "from-uri" "URI schemes other than 'bert' not implemented.")))))
(define (sendt-tcp transport berp-header bert-request)
(let ((host (hash-ref (cdr transport) 'host))
(port (hash-ref (cdr transport) 'port)))
(with-handlers ([exn:fail:network? (lambda(_)
(connection-error host port))])
(let-values (((in-port out-port) (tcp-connect host port)))
(put-bytevector out-port berp-header) (put-bytevector out-port bert-request) (flush-output-port out-port)
(cons (car transport) (hash 'host host
'port port
'in-port in-port
'out-port out-port))))))
(define (recvt-tcp transport)
(let* ((read-n (lambda (n)
(get-bytevector-n
(hash-ref (cdr transport) 'in-port) n)))
(len-raw (read-n 4))
(bert-response-len (bytevector-u32-ref len-raw 0 (endianness big)))
(bert-response (read-n bert-response-len)))
(close-output-port (hash-ref (cdr transport) 'out-port))
bert-response))
(define (sendt transport bert-request)
(let* ((berp-header (make-bytevector 4))
(bert-req-len (bytevector-length bert-request)))
(bytevector-u32-set! berp-header 0 bert-req-len (endianness big))
(cond
((equal? (car transport) 'tcp)
(sendt-tcp transport berp-header bert-request))
(else (error "sendt" "Other transports not implemented.")))))
(define (recvt transport)
(cond
((equal? (car transport) 'tcp)
(recvt-tcp transport))
(else (error "recvt" "Other transports not implemented."))))
(provide from-uri sendt recvt)