The way you will want to do this is to use `pipes-attoparsec`. All you need to do is define an `attoparsec` parser for a single IRC message:

     decodeIRC :: Attoparsec.Parser Message

Once you have that, you can feed it to the `parsed` function from `pipes-attoparsec` to get:

    parsed decodeIRC
:: Monad m
=> Producer ByteString m r -> Producer Message m (Either (ParsingError, Producer ByteString m r) r)

You can then apply that function directly to your socket stream:

    parsed decodeIRC (fromConnect 4096 s p)
:: MonadSafe m => Producer Message m (Either (ParsingError, Producer ByteString m r) r)

That's it! Now you have a `Producer` that emits message. If there is a decoding error of any sort that `Producer` will return a `Left` that has the specific parse error and the undecoded remainder of the stream.

On 2/27/2014 10:02 AM, Karl-Oskar Rikås wrote:
Okey, I tried pipes back 3.0 but did not understand much and moved on. Now I got (a bit) more experience and thought I could try this out again. I'm writing a IRC bot. So, I got some question regarding this; I have a Producer that yields ByteString for each line my bot receives to a Pipe which yields Message which is the internal format I deal with IRC messages. I've got a bit confused about how to do this though, and it feels like there's a more streaming way of doing this. So here's my code so far:

import Pipes
import Pipes.Network.TCP.Safe
import Data.Monoid ((<>))
import qualified Data.ByteString.Char8 as B
import Control.Monad (forever)

import Tob.IRC.Types (Message(..))
import Tob.IRC.Decode (decodeIrc)

server :: (MonadSafe m, Base m ~ IO) => HostName -> ServiceName -> Producer' ByteString m ()
server s p = fromConnect 4096 s p >~ go
    go chunk = do
      let (line, rest) = B.breakSubstring "\r\n" chunk
        notDone = do
          more <- await
          if B.null more
             then error "received null"
             else parser $ chunk <> more
      bs <- await
      if B.null rest
        then notDone
        else yield $ line <> take 2 rest
      getDone = do
        more <- await
        if B.null more
          then return ()
          else go $ chunk

parser :: Pipe ByteString Message IO r
parser = forever $ do
  bs <- await
  case decodeIrc bs of
    Just m -> yield m
    _ -> putStrLn $ "failed to parse: " ++ show bs

(wrote on my phone, so haven't tried if it compiles but it will get an general idea of how my design is intended)

So I basically wait till I got a full bytestring till I yield it to next pipe, then I parse using my parser that rely on the attoparsec parser that is wrapped in maybeResult.

So what I wonder:

* Is this really a streaming way of doing it?
* Is there perhaps a way to use the attoparsec parser as a Pipe in a better fashion? (what happens when something Fail or Partial results?)

Thanks, Karl-Oskar "klrr" Rikås
--
You received this message because you are subscribed to the Google Groups "Haskell Pipes" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].

--
You received this message because you are subscribed to the Google Groups "Haskell 
Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].

Reply via email to