0 | ||| Convert callback code into continuation monads
 1 | module Stellar.HTTP.Async
 2 |
 3 | import TyTTP.HTTP
 4 | import TyTTP.Adapter.Node.HTTP
 5 |
 6 | import Node.HTTP
 7 |
 8 | import Control.Monad.Continuation
 9 |
10 | import Data.IORef
11 |
12 | ||| A JSPublisher is a callback running in IO and producing javascript errors
13 | public export
14 | JSPublisher : Type -> Type
15 | JSPublisher = Publisher IO Error
16 |
17 | ||| JSCont is the continuation monad running in IO
18 | public export
19 | JSCont : Type -> Type
20 | JSCont = ContT () IO
21 |
22 | ||| Convert a publisher callback into a continuation
23 | export
24 | toCont : Applicative m =>
25 |          (handleErrors : e -> m ()) ->
26 |          Publisher m e a -> ContT () m a
27 | toCont err (MkPublisher sub) = MkContT $ \cb =>
28 |     sub $ MkSubscriber { onNext = cb
29 |                        , onSucceded = pure
30 |                        , onFailed = err
31 |                        }
32 |
33 | ||| convert a JSPublisher into a continuation in IO and print the errors into stdout
34 | jsToCont : JSPublisher a -> JSCont a
35 | jsToCont = toCont (\err => putStrLn err.message)
36 |
37 | ||| Convert a RawHttpRequest into a callback that returns the whole request, not just the body
38 | export
39 | asyncifyRequest : RawHttpRequest -> JSPublisher (HttpRequest String (List (String, String)) Buffer)
40 | asyncifyRequest
41 |   (MkRequest method url version headers (MkPublisher body))
42 |   = MkPublisher $ \sub => do
43 |     buffers : IORef (List Buffer) <- newIORef []
44 |     body (MkSubscriber
45 |        { onNext = \bodyValue => do
46 |            modifyIORef buffers (bodyValue ::)
47 |        , onSucceded = \_ => do
48 |            Just b <- concatBuffers !(readIORef buffers)
49 |              | Nothing => putStrLn "failed to collect buffers"
50 |            let req = MkRequest method url version headers b
51 |            sub.onNext req
52 |            sub.onSucceded ()
53 |        , onFailed = \e
54 |            => putStrLn "something went wrong"
55 |            >> sub.onFailed e
56 |        })
57 |
58 | ||| Convert a RawHttpRequest into a continuation with the entire request accessible directly
59 | export
60 | asyncify : RawHttpRequest -> JSCont (HttpRequest String (List (String, String)) Buffer)
61 | asyncify = jsToCont . asyncifyRequest
62 |