#lang racket
(require web-server/servlet
"serialise.rkt"
"protocol.rkt"
xml
web-server/http)
(provide (all-defined-out))
(define (handler-exists? environment id)
(hash-ref environment id #f))
(define (invoke-handler environment name args)
(let* ([fun (hash-ref environment name)]
[arg-length (length args)])
(if (procedure-arity-includes? fun arg-length)
(with-handlers
([exn?
(λ (x)
(make-handler-fault
(format "Error during handler evaluation: ~a"
(exn-message x))
101))])
(let* ([result (apply fun args)]
[serialised-result (serialise result)])
(make-response serialised-result)))
(make-handler-fault
(format "You invoked '~a' with ~a parameters; '~a'"
name arg-length name)
101))))
(define (make-response serialised-result)
(let* ([response
`(methodResponse
(params
(param
,serialised-result)))]
[output (string->bytes/utf-8 (xexpr->string response))])
(make-response/full
200 #"Okay" (current-seconds)
#"text/xml" '()
(list output))))
(define (make-handler-fault string code)
(let ([errorHash (make-hash)])
(hash-set!
errorHash 'faultString string)
(hash-set!
errorHash 'faultCode code)
`(methodResponse (fault ,(serialise errorHash)))))
(define (extract-xml-rpc-bindings request)
(bytes->string/utf-8 (request-post-data/raw request)))
(define ((make-handle-xml-rpc environment) request)
(let ([call (decode-xml-rpc-call
(extract-xml-rpc-bindings request))])
(let ([name (rpc-call-name call)]
[args (rpc-call-args call)])
(if (handler-exists? environment name)
(invoke-handler environment name args)
(make-handler-fault
(format "No handler found on server for '~a'" name)
100)))))