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].