module XMPPMonad ( XMPP , runXMPP , addPlugin , StanzaPredicate , initConfig , getConnection , liftIO , ThreadId , kickOff , Plugin(..) ) where import TCPConnection import XMLParse import Control.Monad.State import Control.Concurrent import Data.Reactive data Config = Config { conn :: TCPConnection , threads :: [(ThreadId, String)] , ev :: Event XMLElem } type XMPP = StateT Config IO type StanzaPredicate = XMLElem -> Bool data Plugin = Plugin StanzaPredicate String (XMLElem -> XMPP ()) runXMPP = runStateT getConnection :: XMPP TCPConnection getConnection = get >>= (return . conn) -- Spawn a plugin in another thread. Returns its tid. Also record its tid and description in a bookkeeping list -- The plugin is installed permanently. We need another function addOneshot. addPlugin :: Plugin -> XMPP ThreadId addPlugin (Plugin pred name thread) = do Config c th event <- get let act msg = evalStateT (thread' msg) $ Config c [] event thread' msg = when (pred msg) $ thread msg tid <- liftIO $ subscribe event act let th' = (tid, name) : th put $ Config c th' event return tid initConfig :: TCPConnection -> IO (Sink XMLElem, Config) initConfig c = do (event, sink) <- mkEvent return $ (sink, Config c [] event) kickOff :: Sink XMLElem -> XMPP () kickOff sink = do Config c _ _ <- get liftIO $ forever $ -- read the network inputs as a list getStanzas c >>= -- send them to the sink, which will trigger events mapM_ sink