0 | module TyTTP.Adapter.Node.HTTP
2 | import public Data.Buffer
3 | import Data.Buffer.Ext
4 | import public Node.Error
5 | import public Node.HTTP
7 | import public TyTTP.Adapter.Node.Error
10 | %hide Node.Net.Server.Server
13 | RawHttpRequest : Type
14 | RawHttpRequest = HttpRequest String StringHeaders $
Publisher IO Error Buffer
17 | RawHttpResponse : Type
18 | RawHttpResponse = Response Status StringHeaders $
Publisher IO Error Buffer
20 | toNodeResponse : RawHttpResponse -> ServerResponse -> IO ()
21 | toNodeResponse res nodeRes = do
22 | let status = res.status.code
23 | headers <- mapHeaders res.headers
25 | nodeRes.writeHead status headers
26 | res.body.subscribe $
MkSubscriber
27 | { onNext = \a => nodeRes.write a Nothing }
28 | { onFailed = \e => pure () }
29 | { onSucceded = \_ => nodeRes.end Nothing { d = Buffer } }
31 | mapHeaders : StringHeaders -> IO Headers
34 | foldlM (\hs, (k,v) => hs.setHeader k v) newHeaders h
36 | fromPromiseToNodeResponse : Error e
37 | => (e -> RawHttpResponse)
38 | -> Promise e IO (Context Method String Version StringHeaders Status StringHeaders b $
Publisher IO Error Buffer)
41 | fromPromiseToNodeResponse errorHandler (MkPromise cont) nodeRes =
42 | let callbacks = MkCallbacks
43 | { onSucceded = \a => toNodeResponse a.response nodeRes }
44 | { onFailed = \e => toNodeResponse (errorHandler e) nodeRes }
48 | fromNodeRequest : IncomingMessage -> RawHttpRequest
49 | fromNodeRequest nodeReq =
50 | let method = parseMethod nodeReq.method
52 | headers = nodeReq.headers.asList
53 | version = parseVersion nodeReq.httpVersion
54 | in mkRequest method path version headers $
MkPublisher $
\s => do
55 | nodeReq.onData s.onNext
56 | nodeReq.onError s.onFailed
57 | nodeReq.onEnd $
s.onSucceded ()
60 | record Options e where
61 | constructor MkOptions
62 | listenOptions : Listen.Options
63 | serverOptions : HTTP.CreateServer.Options
64 | errorHandler : (e -> RawHttpResponse)
67 | defaultOptions : Error e => Adapter.Node.HTTP.Options e
68 | defaultOptions = MkOptions
71 | , host := Just "localhost"
72 | } Listen.defaultOptions
73 | , serverOptions = HTTP.CreateServer.defaultOptions
74 | , errorHandler = \e => MkResponse
75 | { status = INTERNAL_SERVER_ERROR
77 | [ ("Content-Type", "text/plain")
78 | , ("Content-Length", show $
length $
TyTTP.Core.Error.message e)
80 | , body = singleton $
fromString $
TyTTP.Core.Error.message e
88 | -> Adapter.Node.HTTP.Options e
90 | Context Method String Version StringHeaders Status StringHeaders (Publisher IO Error Buffer) ()
91 | -> Promise e IO $
Context Method String Version StringHeaders Status StringHeaders b (Publisher IO Error Buffer)
94 | listen http options handler = do
95 | server <- http.createServer options.serverOptions
97 | server.onRequest $
\req => \res => do
98 | let handlerReq = fromNodeRequest req
99 | initialRes = MkResponse OK [] () {h = StringHeaders}
100 | result = handler $
MkContext handlerReq initialRes
102 | fromPromiseToNodeResponse options.errorHandler result res
104 | server.listen options.listenOptions
110 | => { auto http : HTTPModule }
112 | Context Method String Version StringHeaders Status StringHeaders (Publisher IO Error Buffer) ()
113 | -> Promise e IO $
Context Method String Version StringHeaders Status StringHeaders b (Publisher IO Error Buffer)
116 | listen' {http} handler = listen http defaultOptions handler