8 changed files with 166 additions and 226 deletions
@ -1,188 +0,0 @@ |
|||||||
{-# LANGUAGE DeriveDataTypeable, NoMonomorphismRestriction #-} |
|
||||||
|
|
||||||
module Data.Conduit.Hexpat where |
|
||||||
|
|
||||||
import Control.Applicative((<$>)) |
|
||||||
import Control.Exception |
|
||||||
import Control.Monad |
|
||||||
import Control.Monad.IO.Class |
|
||||||
import Control.Monad.Trans.Class |
|
||||||
|
|
||||||
import qualified Data.ByteString as BS |
|
||||||
import Data.Conduit as C |
|
||||||
import Data.Conduit.List as CL |
|
||||||
import Data.Maybe |
|
||||||
import Data.Typeable |
|
||||||
|
|
||||||
import Text.XML.Expat.Internal.IO hiding (parse) |
|
||||||
import Text.XML.Expat.SAX |
|
||||||
import Text.XML.Expat.Tree |
|
||||||
|
|
||||||
import Foreign.Ptr |
|
||||||
|
|
||||||
import Data.IORef |
|
||||||
-- adapted from parseG |
|
||||||
|
|
||||||
-- | Parse a generalized list of ByteStrings containing XML to SAX events. |
|
||||||
-- In the event of an error, FailDocument is the last element of the output list. |
|
||||||
-- parseG :: forall tag text l . (GenericXMLString tag, GenericXMLString text, List l) => |
|
||||||
-- ParseOptions tag text -- ^ Parse options |
|
||||||
-- -> l ByteString -- ^ Input text (a lazy ByteString) |
|
||||||
-- -> l (SAXEvent tag text) |
|
||||||
-- parseG opts inputBlocks = runParser inputBlocks parser queueRef cacheRef |
|
||||||
-- where |
|
||||||
|
|
||||||
data HexpatParser tag text a = HexpatParser |
|
||||||
{ hParser :: Parser |
|
||||||
, hQueueRef :: IORef [SAXEvent tag text] |
|
||||||
} |
|
||||||
|
|
||||||
createParser |
|
||||||
:: (GenericXMLString tag, GenericXMLString text) => |
|
||||||
ParseOptions tag text -> IO (HexpatParser tag text a) |
|
||||||
createParser opts = do |
|
||||||
let enc = overrideEncoding opts |
|
||||||
let mEntityDecoder = entityDecoder opts |
|
||||||
|
|
||||||
parser <- newParser enc |
|
||||||
queueRef <- newIORef [] |
|
||||||
|
|
||||||
case mEntityDecoder of |
|
||||||
Just deco -> setEntityDecoder parser deco $ \_ txt -> do |
|
||||||
modifyIORef queueRef (CharacterData txt:) |
|
||||||
Nothing -> return () |
|
||||||
|
|
||||||
setXMLDeclarationHandler parser $ \_ cVer cEnc cSd -> do |
|
||||||
ver <- textFromCString cVer |
|
||||||
mEnc <- if cEnc == nullPtr |
|
||||||
then return Nothing |
|
||||||
else Just <$> textFromCString cEnc |
|
||||||
let sd = if cSd < 0 |
|
||||||
then Nothing |
|
||||||
else Just $ if cSd /= 0 then True else False |
|
||||||
modifyIORef queueRef (XMLDeclaration ver mEnc sd:) |
|
||||||
return True |
|
||||||
|
|
||||||
setStartElementHandler parser $ \_ cName cAttrs -> do |
|
||||||
name <- textFromCString cName |
|
||||||
attrs <- forM cAttrs $ \(cAttrName,cAttrValue) -> do |
|
||||||
attrName <- textFromCString cAttrName |
|
||||||
attrValue <- textFromCString cAttrValue |
|
||||||
return (attrName, attrValue) |
|
||||||
modifyIORef queueRef (StartElement name attrs:) |
|
||||||
return True |
|
||||||
|
|
||||||
setEndElementHandler parser $ \_ cName -> do |
|
||||||
name <- textFromCString cName |
|
||||||
modifyIORef queueRef (EndElement name:) |
|
||||||
return True |
|
||||||
|
|
||||||
setCharacterDataHandler parser $ \_ cText -> do |
|
||||||
txt <- gxFromCStringLen cText |
|
||||||
modifyIORef queueRef (CharacterData txt:) |
|
||||||
return True |
|
||||||
|
|
||||||
setStartCDataHandler parser $ \_ -> do |
|
||||||
modifyIORef queueRef (StartCData :) |
|
||||||
return True |
|
||||||
|
|
||||||
setEndCDataHandler parser $ \_ -> do |
|
||||||
modifyIORef queueRef (EndCData :) |
|
||||||
return True |
|
||||||
|
|
||||||
setProcessingInstructionHandler parser $ \_ cTarget cText -> do |
|
||||||
target <- textFromCString cTarget |
|
||||||
txt <- textFromCString cText |
|
||||||
modifyIORef queueRef (ProcessingInstruction target txt :) |
|
||||||
return True |
|
||||||
|
|
||||||
setCommentHandler parser $ \_ cText -> do |
|
||||||
txt <- textFromCString cText |
|
||||||
modifyIORef queueRef (Comment txt :) |
|
||||||
return True |
|
||||||
|
|
||||||
return (HexpatParser parser queueRef) |
|
||||||
|
|
||||||
data HexpatParseException = HexpatParseExceptio String deriving (Typeable, Show) |
|
||||||
instance Exception HexpatParseException |
|
||||||
|
|
||||||
parseBS |
|
||||||
:: (GenericXMLString text, GenericXMLString tag) => |
|
||||||
ParseOptions tag text |
|
||||||
-> Conduit BS.ByteString IO (SAXEvent tag text) |
|
||||||
parseBS opts = conduitIO |
|
||||||
(createParser opts) |
|
||||||
(\_ -> return ()) |
|
||||||
(\(HexpatParser parser queueRef) input -> do |
|
||||||
error <- withParser parser $ \pp -> parseChunk pp input False |
|
||||||
case error of |
|
||||||
Nothing -> return () |
|
||||||
Just (XMLParseError err _) -> |
|
||||||
resourceThrow $ HexpatParseExceptio err |
|
||||||
queue <- readIORef queueRef |
|
||||||
writeIORef queueRef [] |
|
||||||
return . IOProducing $ reverse queue |
|
||||||
) |
|
||||||
(\(HexpatParser parser queueRef) -> do |
|
||||||
error <- withParser parser $ \pp -> parseChunk pp BS.empty True |
|
||||||
case error of |
|
||||||
Nothing -> return () |
|
||||||
Just (XMLParseError err _) -> |
|
||||||
resourceThrow $ HexpatParseExceptio err |
|
||||||
queue <- readIORef queueRef |
|
||||||
writeIORef queueRef [] |
|
||||||
return $ reverse queue |
|
||||||
) |
|
||||||
|
|
||||||
whileJust :: Monad m => m (Maybe a) -> m [a] |
|
||||||
whileJust f = do |
|
||||||
f' <- f |
|
||||||
case f' of |
|
||||||
Just x -> liftM (x :) $ whileJust f |
|
||||||
Nothing -> return [] |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
data StreamUnfinishedException = StreamUnfinishedException deriving (Typeable, Show) |
|
||||||
instance Exception StreamUnfinishedException |
|
||||||
|
|
||||||
|
|
||||||
elementFromEvents |
|
||||||
:: (Eq tag, Show tag, MonadIO m, Resource m) => |
|
||||||
Sink (SAXEvent tag text) m (NodeG [] tag text) |
|
||||||
elementFromEvents = do |
|
||||||
Just (StartElement name attrs) <- CL.head |
|
||||||
children <- liftM catMaybes . whileJust $ do |
|
||||||
next' <- CL.peek |
|
||||||
next <- case next' of |
|
||||||
Nothing -> liftIO . throwIO $ StreamUnfinishedException |
|
||||||
Just n -> return n |
|
||||||
case next of |
|
||||||
StartElement _ _ -> Just . Just <$> elementFromEvents |
|
||||||
EndElement n -> if n == name then CL.drop 1 >> return Nothing |
|
||||||
else error $ "closing wrong element: " |
|
||||||
++ show n ++ " instead of " ++ show name |
|
||||||
CharacterData txt -> CL.drop 1 >> (return . Just . Just $ Text txt) |
|
||||||
_ -> return $ Just Nothing |
|
||||||
return $ Element name attrs children |
|
||||||
|
|
||||||
openElementFromEvents |
|
||||||
:: Resource m => Sink (SAXEvent tag text) m (NodeG [] tag text) |
|
||||||
openElementFromEvents = do |
|
||||||
throwOutJunk |
|
||||||
Just (StartElement name attrs) <- CL.head |
|
||||||
return $ Element name attrs [] |
|
||||||
|
|
||||||
throwOutJunk :: Resource m => Sink (SAXEvent t t1) m () |
|
||||||
throwOutJunk = do |
|
||||||
next <- peek |
|
||||||
case next of |
|
||||||
Nothing -> return () |
|
||||||
Just (StartElement _ _) -> return () |
|
||||||
_ -> CL.drop 1 >> throwOutJunk |
|
||||||
|
|
||||||
saxToElements |
|
||||||
:: (Eq tag, Show tag, MonadIO m, Resource m) => |
|
||||||
Conduit (SAXEvent tag text) m (Node tag text) |
|
||||||
saxToElements = C.sequence $ throwOutJunk >> elementFromEvents |
|
||||||
|
|
||||||
@ -0,0 +1,78 @@ |
|||||||
|
{-# LANGUAGE PackageImports, OverloadedStrings #-} |
||||||
|
module Main where |
||||||
|
|
||||||
|
import Data.Text as T |
||||||
|
|
||||||
|
import Network.XMPP |
||||||
|
import Network.XMPP.Concurrent |
||||||
|
import Network.XMPP.Types |
||||||
|
import Network |
||||||
|
import GHC.IO.Handle |
||||||
|
import Control.Concurrent |
||||||
|
import Control.Concurrent.STM |
||||||
|
import Control.Monad |
||||||
|
import Control.Monad.Trans.State |
||||||
|
import Control.Monad.IO.Class |
||||||
|
|
||||||
|
philonous :: JID |
||||||
|
philonous = read "uart14@species64739.dyndns.org" |
||||||
|
|
||||||
|
attXmpp :: STM a -> XMPPThread a |
||||||
|
attXmpp = liftIO . atomically |
||||||
|
|
||||||
|
autoAccept :: XMPPThread () |
||||||
|
autoAccept = forever $ do |
||||||
|
st <- pullPresence |
||||||
|
case st of |
||||||
|
Presence from _ id (Just Subscribe) _ _ _ _ -> |
||||||
|
sendS . SPresence $ |
||||||
|
Presence Nothing from id (Just Subscribed) Nothing Nothing Nothing [] |
||||||
|
_ -> return () |
||||||
|
|
||||||
|
mirror :: XMPPThread () |
||||||
|
mirror = forever $ do |
||||||
|
st <- pullMessage |
||||||
|
case st of |
||||||
|
Message (Just from) _ id tp subject (Just bd) thr _ -> |
||||||
|
sendS . SMessage $ |
||||||
|
Message Nothing from id tp subject |
||||||
|
(Just $ "you wrote: " `T.append` bd) thr [] |
||||||
|
_ -> return () |
||||||
|
|
||||||
|
-- killer = forever $ do |
||||||
|
-- st <- readChanS |
||||||
|
-- case st of |
||||||
|
-- Message _ _ id tp subject "kill" thr _ -> |
||||||
|
-- killConnection >> return () |
||||||
|
-- _ -> return () |
||||||
|
|
||||||
|
main :: IO () |
||||||
|
main = do |
||||||
|
putStrLn "hello world" |
||||||
|
wait <- newEmptyMVar |
||||||
|
connectXMPP "localhost" "species64739.dyndns.org" "bot" (Just "botsi") "pwd" |
||||||
|
$ do |
||||||
|
liftIO $ putStrLn "----------------------------" |
||||||
|
-- sendS . SPresence $ |
||||||
|
-- Presence Nothing Nothing Nothing Nothing (Just Available) Nothing Nothing [] |
||||||
|
withNewThread autoAccept |
||||||
|
withNewThread mirror |
||||||
|
-- withNewThread killer |
||||||
|
sendS . SPresence $ Presence Nothing Nothing Nothing Nothing |
||||||
|
(Just Available) Nothing Nothing [] |
||||||
|
liftIO $ putStrLn "----------------------------" |
||||||
|
|
||||||
|
sendS . SMessage $ Message Nothing philonous Nothing Nothing Nothing |
||||||
|
(Just "bla") Nothing [] |
||||||
|
forever $ pullMessage >>= liftIO . print |
||||||
|
-- withNewThread . void $ (liftIO $ threadDelay 15000000) >> killConnection |
||||||
|
|
||||||
|
-- forever $ do |
||||||
|
-- next <- nextM |
||||||
|
-- outStanza $ Message Nothing philonous "" Chat "" "pong!" "" [] |
||||||
|
-- liftIO $ print next |
||||||
|
liftIO $ putMVar wait () |
||||||
|
return () |
||||||
|
takeMVar wait |
||||||
|
return () |
||||||
|
|
||||||
Loading…
Reference in new issue