In this case, you really want to use purescript-aff-coroutines . This will give you the Producer coroutine, which you can then connect to the Consumer , which inserts the messages into the driver:
module Main where import Prelude import Control.Coroutine (Producer, Consumer, consumer, runProcess, ($$)) import Control.Coroutine.Aff (produce) import Control.Monad.Aff (Aff) import Control.Monad.Aff.AVar (AVAR) import Control.Monad.Eff (Eff) import Control.Monad.Eff.Exception (EXCEPTION) import Control.Monad.Eff.Var (($=)) import Data.Array as Array import Data.Either (Either(..)) import Data.Maybe (Maybe(..)) import Halogen as H import Halogen.HTML.Indexed as HH import Halogen.Util (runHalogenAff, awaitBody) import WebSocket (WEBSOCKET, Connection(..), Message(..), URL(..), runMessageEvent, runMessage, newWebSocket) ---------------------------------------------------------------------------- -- Halogen component. This just displays a list of messages and has a query -- to accept new messages. ---------------------------------------------------------------------------- type State = { messages :: Array String } initialState :: State initialState = { messages: [] } data Query a = AddMessage String a ui :: forall g. H.Component State Query g ui = H.component { render, eval } where render :: State -> H.ComponentHTML Query render state = HH.ol_ $ map (\msg -> HH.li_ [ HH.text msg ]) state.messages eval :: Query ~> H.ComponentDSL State Query g eval (AddMessage msg next) = do H.modify \st -> { messages: st.messages `Array.snoc` msg } pure next ---------------------------------------------------------------------------- -- Websocket coroutine producer. This uses `purescript-aff-coroutines` to -- create a producer of messages from a websocket. ---------------------------------------------------------------------------- wsProducer :: forall eff. Producer String (Aff (avar :: AVAR, err :: EXCEPTION, ws :: WEBSOCKET | eff)) Unit wsProducer = produce \emit -> do Connection socket <- newWebSocket (URL "ws://echo.websocket.org") [] -- This part is probably unnecessary in the real world, but it gives us -- some messages to consume when using the echo service socket.onopen $= \event -> do socket.send (Message "hello") socket.send (Message "something") socket.send (Message "goodbye") socket.onmessage $= \event -> do emit $ Left $ runMessage (runMessageEvent event) ---------------------------------------------------------------------------- -- Coroutine consumer. This accepts a Halogen driver function and sends -- `AddMessage` queries in when the coroutine consumes an input. ---------------------------------------------------------------------------- wsConsumer :: forall eff . (Query ~> Aff (H.HalogenEffects (ws :: WEBSOCKET | eff))) -> Consumer String (Aff (H.HalogenEffects (ws :: WEBSOCKET | eff))) Unit wsConsumer driver = consumer \msg -> do driver $ H.action $ AddMessage msg pure Nothing ---------------------------------------------------------------------------- -- Normal Halogen-style `main`, the only addition is a use of `runProcess` -- to connect the producer and consumer and start sending messages to the -- Halogen component. ---------------------------------------------------------------------------- main :: forall eff. Eff (H.HalogenEffects (ws :: WEBSOCKET | eff)) Unit main = runHalogenAff do body <- awaitBody driver <- H.runUI ui initialState body runProcess (wsProducer $$ wsConsumer driver) pure unit
This will give you a page that prints almost immediately:
But he does everything you need, honest! If you use a producer with a "real" source, you will get something more that you need.
source share