how to create a pipes producer from websockets?

Hello All, I am trying to use both the websockets library and the pipes library. They seem like a natural fit. However, I wanted to use the websockets library to build a pipes 'Producer' and that does not seem possible without some heavy lifting. The websockets library does not give me a connection I can read from and write to. Instead, I need to supply an IO action (called a clientApp). And execute it using something like: --runClient :: String -- ^ Host -- -> Int -- ^ Port -- -> String -- ^ Path -- -> ClientApp a -- ^ Client application -- type ClientApp a = Connection -> IO a -- -> IO a main :: IO () main = withSocketsDo $ runClient "echo.websocket.org" 80 "/" app The problem happens when you couple this restriction with the requirement that ClientApps have type 'Connection -> IO a'. Pipes producers are Monad transformer stacks. For example, I would like to build something like: messageProducer :: Producer' WebsocketMessage IO () But this does not run in the IO monad and at the same time I cannot get a 'Connection' object unless I use runClient. So, it seems I have a catch22 situation. Or have I overlooked something? I'd rather not have to do "un-lifting" on the monad transformer stack. Has anyone done this before? Any suggestions on how to go about it? Thanks, Dimitri

The yesod-websockets library has a conduit api on top of websockets which I use, so I have conduits processing messages. Conduit and pipes work similarly, so I suspect the technique from yesod-websockets will work fine for pipes, just look at the yesod-websockets source code: https://hackage.haskell.org/package/yesod-websockets-0.2.3/docs/Yesod-WebSoc... On Wed, Oct 21, 2015 at 6:42 PM, Dimitri DeFigueiredo < defigueiredo@ucdavis.edu> wrote:
Hello All,
I am trying to use both the websockets library and the pipes library. They seem like a natural fit. However, I wanted to use the websockets library to build a pipes 'Producer' and that does not seem possible without some heavy lifting.
The websockets library does not give me a connection I can read from and write to. Instead, I need to supply an IO action (called a clientApp). And execute it using something like:
--runClient :: String -- ^ Host -- -> Int -- ^ Port -- -> String -- ^ Path -- -> ClientApp a -- ^ Client application -- type ClientApp a = Connection -> IO a -- -> IO a
main :: IO () main = withSocketsDo $ runClient "echo.websocket.org" 80 "/" app
The problem happens when you couple this restriction with the requirement that ClientApps have type 'Connection -> IO a'. Pipes producers are Monad transformer stacks. For example, I would like to build something like: messageProducer :: Producer' WebsocketMessage IO ()
But this does not run in the IO monad and at the same time I cannot get a 'Connection' object unless I use runClient.
So, it seems I have a catch22 situation. Or have I overlooked something? I'd rather not have to do "un-lifting" on the monad transformer stack.
Has anyone done this before? Any suggestions on how to go about it?
Thanks,
Dimitri
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

One option is to use pipes-concurrency http://hackage.haskell.org/package/pipes-concurrency. Create http://hackage.haskell.org/package/pipes-concurrency-2.0.3/docs/Pipes-Concur... a mailbox, and pass to *runClient *a callback that reads from the Connection and writes to the mailbox http://hackage.haskell.org/package/pipes-concurrency-2.0.3/docs/Pipes-Concur... . Build http://hackage.haskell.org/package/pipes-concurrency-2.0.3/docs/Pipes-Concur...a *Producer *from the other end of the mailbox and consume it in another thread. Coordinate the threads with something like concurrently http://hackage.haskell.org/package/async-2.0.2/docs/Control-Concurrent-Async... from the async package. On Thursday, October 22, 2015 at 1:42:37 AM UTC+2, Dimitri DeFigueiredo wrote:
Hello All,
I am trying to use both the websockets library and the pipes library. They seem like a natural fit. However, I wanted to use the websockets library to build a pipes 'Producer' and that does not seem possible without some heavy lifting.
The websockets library does not give me a connection I can read from and write to. Instead, I need to supply an IO action (called a clientApp). And execute it using something like:
--runClient :: String -- ^ Host -- -> Int -- ^ Port -- -> String -- ^ Path -- -> ClientApp a -- ^ Client application -- type ClientApp a = Connection -> IO a -- -> IO a
main :: IO () main = withSocketsDo $ runClient "echo.websocket.org" 80 "/" app
The problem happens when you couple this restriction with the requirement that ClientApps have type 'Connection -> IO a'. Pipes producers are Monad transformer stacks. For example, I would like to build something like: messageProducer :: Producer' WebsocketMessage IO ()
But this does not run in the IO monad and at the same time I cannot get a 'Connection' object unless I use runClient.
So, it seems I have a catch22 situation. Or have I overlooked something? I'd rather not have to do "un-lifting" on the monad transformer stack.
Has anyone done this before? Any suggestions on how to go about it?
Thanks,
Dimitri
participants (3)
-
Daniel Díaz
-
Dimitri DeFigueiredo
-
John Lenz