|
|
|
@ -1,3 +1,4 @@ |
|
|
|
|
|
|
|
{-# LANGUAGE ScopedTypeVariables #-} |
|
|
|
{-# LANGUAGE OverloadedStrings #-} |
|
|
|
{-# LANGUAGE OverloadedStrings #-} |
|
|
|
module Network.XMPP.Concurrent.Threads where |
|
|
|
module Network.XMPP.Concurrent.Threads where |
|
|
|
|
|
|
|
|
|
|
|
@ -36,12 +37,27 @@ import qualified Text.XML.Stream.Render as XR |
|
|
|
readWorker :: TChan (Either MessageError Message) |
|
|
|
readWorker :: TChan (Either MessageError Message) |
|
|
|
-> TChan (Either PresenceError Presence) |
|
|
|
-> TChan (Either PresenceError Presence) |
|
|
|
-> TVar IQHandlers |
|
|
|
-> TVar IQHandlers |
|
|
|
-> XMPPConState |
|
|
|
-> TMVar XMPPConState |
|
|
|
-> ResourceT IO () |
|
|
|
-> IO () |
|
|
|
readWorker messageC presenceC handlers s = Ex.catch |
|
|
|
readWorker messageC presenceC handlers stateRef = |
|
|
|
(forever . flip runStateT s $ do |
|
|
|
Ex.mask_ . forever $ do |
|
|
|
sta <- pull |
|
|
|
s <- liftIO . atomically $ takeTMVar stateRef |
|
|
|
|
|
|
|
(sta', s') <- flip runStateT s $ Ex.catch ( do |
|
|
|
|
|
|
|
-- we don't know whether pull will necessarily be interruptible |
|
|
|
|
|
|
|
liftIO $ Ex.allowInterrupt |
|
|
|
|
|
|
|
Just <$> pull |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
(\(Interrupt t) -> do |
|
|
|
|
|
|
|
liftIO . atomically $ |
|
|
|
|
|
|
|
putTMVar stateRef s |
|
|
|
|
|
|
|
liftIO . atomically $ takeTMVar t |
|
|
|
|
|
|
|
return Nothing |
|
|
|
|
|
|
|
) |
|
|
|
liftIO . atomically $ do |
|
|
|
liftIO . atomically $ do |
|
|
|
|
|
|
|
case sta' of |
|
|
|
|
|
|
|
Nothing -> return () |
|
|
|
|
|
|
|
Just sta -> do |
|
|
|
|
|
|
|
putTMVar stateRef s' |
|
|
|
case sta of |
|
|
|
case sta of |
|
|
|
MessageS m -> do writeTChan messageC $ Right m |
|
|
|
MessageS m -> do writeTChan messageC $ Right m |
|
|
|
_ <- readTChan messageC -- Sic! |
|
|
|
_ <- readTChan messageC -- Sic! |
|
|
|
@ -65,11 +81,7 @@ readWorker messageC presenceC handlers s = Ex.catch |
|
|
|
IQRequestS i -> handleIQRequest handlers i |
|
|
|
IQRequestS i -> handleIQRequest handlers i |
|
|
|
IQResultS i -> handleIQResponse handlers (Right i) |
|
|
|
IQResultS i -> handleIQResponse handlers (Right i) |
|
|
|
IQErrorS i -> handleIQResponse handlers (Left i) |
|
|
|
IQErrorS i -> handleIQResponse handlers (Left i) |
|
|
|
) |
|
|
|
|
|
|
|
( \(ReaderSignal a) -> do |
|
|
|
|
|
|
|
((),s') <- runStateT a s |
|
|
|
|
|
|
|
readWorker messageC presenceC handlers s' |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
handleIQRequest handlers iq = do |
|
|
|
handleIQRequest handlers iq = do |
|
|
|
(byNS, _) <- readTVar handlers |
|
|
|
(byNS, _) <- readTVar handlers |
|
|
|
@ -110,8 +122,10 @@ startThreads |
|
|
|
:: XMPPConMonad ( TChan (Either MessageError Message) |
|
|
|
:: XMPPConMonad ( TChan (Either MessageError Message) |
|
|
|
, TChan (Either PresenceError Presence) |
|
|
|
, TChan (Either PresenceError Presence) |
|
|
|
, TVar IQHandlers |
|
|
|
, TVar IQHandlers |
|
|
|
, TChan Stanza, IO () |
|
|
|
, TChan Stanza |
|
|
|
|
|
|
|
, IO () |
|
|
|
, TMVar (BS.ByteString -> IO ()) |
|
|
|
, TMVar (BS.ByteString -> IO ()) |
|
|
|
|
|
|
|
, TMVar XMPPConState |
|
|
|
, ThreadId |
|
|
|
, ThreadId |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
@ -122,24 +136,28 @@ startThreads = do |
|
|
|
iqC <- liftIO newTChanIO |
|
|
|
iqC <- liftIO newTChanIO |
|
|
|
outC <- liftIO newTChanIO |
|
|
|
outC <- liftIO newTChanIO |
|
|
|
handlers <- liftIO $ newTVarIO ( Map.empty, Map.empty) |
|
|
|
handlers <- liftIO $ newTVarIO ( Map.empty, Map.empty) |
|
|
|
|
|
|
|
conS <- liftIO . newTMVarIO =<< get |
|
|
|
lw <- liftIO . forkIO $ writeWorker outC writeLock |
|
|
|
lw <- liftIO . forkIO $ writeWorker outC writeLock |
|
|
|
cp <- liftIO . forkIO $ connPersist writeLock |
|
|
|
cp <- liftIO . forkIO $ connPersist writeLock |
|
|
|
s <- get |
|
|
|
s <- get |
|
|
|
rd <- lift . resourceForkIO $ readWorker messageC presenceC handlers s |
|
|
|
rd <- liftIO . forkIO $ readWorker messageC presenceC handlers conS |
|
|
|
return (messageC, presenceC, handlers, outC, killConnection writeLock [lw, rd, cp], writeLock, rd) |
|
|
|
return (messageC, presenceC, handlers, outC |
|
|
|
|
|
|
|
, killConnection writeLock [lw, rd, cp] |
|
|
|
|
|
|
|
, writeLock, conS ,rd) |
|
|
|
where |
|
|
|
where |
|
|
|
killConnection writeLock threads = liftIO $ do |
|
|
|
killConnection writeLock threads = liftIO $ do |
|
|
|
_ <- atomically $ takeTMVar writeLock -- Should we put it back? |
|
|
|
_ <- atomically $ takeTMVar writeLock -- Should we put it back? |
|
|
|
_ <- forM threads killThread |
|
|
|
_ <- forM threads killThread |
|
|
|
return() |
|
|
|
return() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- | Start worker threads and run action. The supplied action will run |
|
|
|
-- | Start worker threads and run action. The supplied action will run |
|
|
|
-- in the calling thread. use 'forkXMPP' to start another thread. |
|
|
|
-- in the calling thread. use 'forkXMPP' to start another thread. |
|
|
|
runThreaded :: XMPPThread a |
|
|
|
runThreaded :: XMPPThread a |
|
|
|
-> XMPPConMonad a |
|
|
|
-> XMPPConMonad a |
|
|
|
runThreaded a = do |
|
|
|
runThreaded a = do |
|
|
|
(mC, pC, hand, outC, _stopThreads, writeR, rdr ) <- startThreads |
|
|
|
liftIO . putStrLn $ "starting threads" |
|
|
|
|
|
|
|
(mC, pC, hand, outC, _stopThreads, writeR, conS, rdr ) <- startThreads |
|
|
|
|
|
|
|
liftIO . putStrLn $ "threads running" |
|
|
|
workermCh <- liftIO . newIORef $ Nothing |
|
|
|
workermCh <- liftIO . newIORef $ Nothing |
|
|
|
workerpCh <- liftIO . newIORef $ Nothing |
|
|
|
workerpCh <- liftIO . newIORef $ Nothing |
|
|
|
idRef <- liftIO $ newTVarIO 1 |
|
|
|
idRef <- liftIO $ newTVarIO 1 |
|
|
|
@ -147,7 +165,10 @@ runThreaded a = do |
|
|
|
curId <- readTVar idRef |
|
|
|
curId <- readTVar idRef |
|
|
|
writeTVar idRef (curId + 1 :: Integer) |
|
|
|
writeTVar idRef (curId + 1 :: Integer) |
|
|
|
return . read. show $ curId |
|
|
|
return . read. show $ curId |
|
|
|
liftIO $ runReaderT a (Thread workermCh workerpCh mC pC outC hand writeR rdr getId) |
|
|
|
s <- get |
|
|
|
|
|
|
|
liftIO . putStrLn $ "starting application" |
|
|
|
|
|
|
|
liftIO $ runReaderT a (Thread workermCh workerpCh mC pC outC hand writeR rdr getId conS) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- | Sends a blank space every 30 seconds to keep the connection alive |
|
|
|
-- | Sends a blank space every 30 seconds to keep the connection alive |
|
|
|
connPersist :: TMVar (BS.ByteString -> IO ()) -> IO () |
|
|
|
connPersist :: TMVar (BS.ByteString -> IO ()) -> IO () |
|
|
|
|