Question

I'm using John Millikin's enumerator package and am trying to create something roughly equivalent to Data.Enumerator.Binary.enumHandle, except it connects the socket itself, then tries to enumerate the resulting handle. The difficulty comes from the fact that the connection is unreliable, and I'd like it to reconnect and resume enumerating if something goes wrong.

I'd normally expect Enumerator to be its own meaningful Monad instance, but since it's a type alias for a function, monadic behavior on it is just a reader of its input step, which doesn't appear to be much use here. I tried to throw something together that just kept looping the Enumerator, using catchError, but it didn't do what I expected and I couldn't figure out what it was doing, so I was wondering if anyone could suggest a nice idiomatic approach to this. I'm fine with just a skeleton of a solution, since there are obviously many details that I've omitted.

Any ideas?

Was it helpful?

Solution

You probably have to write that yourself. I don't think it's predefined anywhere. However, it's not that difficult:

enumConnectAgain :: forall b m. MonadIO m => IO Handle -> Enumerator ByteString m b
enumConnectAgain open step =
    fix $ \again -> do
        mh <- liftIO (Ex.try open)
        case mh of
          Left (ex :: SomeException) -> again
          Right h                    -> loop h step

    where
    loop :: Handle -> Step ByteString m b -> Iteratee ByteString m b
    loop h step@(Continue k) = do
        mstr <- liftIO (Ex.try $ B.hGetSome h 1024)
        case mstr of
          Left (ex :: SomeException) -> enumConnectAgain open step
          Right str                  -> k (Chunks [str]) >>== loop h
    loop h step = returnI step

That should work.

OTHER TIPS

From a slightly higher view point, if you're doing stuff with sockets, especially potentially unreliable ones, I can't recommend zeromq highly enough.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top