2014-10-04 21:22:24 +05:30
|
|
|
{-# LANGUAGE ExistentialQuantification #-}
|
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
|
|
{-# LANGUAGE RankNTypes #-}
|
|
|
|
|
|
|
|
module Network.IRC.MessageBus
|
|
|
|
( MessageBus
|
|
|
|
, newMessageBus
|
|
|
|
, MessageChannel
|
|
|
|
, newMessageChannel
|
|
|
|
, sendMessage
|
|
|
|
, receiveMessage
|
2014-10-05 13:12:49 +05:30
|
|
|
, receiveMessageEither
|
2014-10-04 21:22:24 +05:30
|
|
|
, closeMessageChannel
|
2015-06-21 18:18:59 +05:30
|
|
|
, awaitMessageChannel
|
|
|
|
, isClosedMessageChannel ) where
|
2014-10-04 21:22:24 +05:30
|
|
|
|
|
|
|
import ClassyPrelude
|
|
|
|
|
|
|
|
newtype Latch = Latch (MVar ())
|
|
|
|
|
|
|
|
newLatch :: IO Latch
|
|
|
|
newLatch = liftM Latch newEmptyMVar
|
|
|
|
|
|
|
|
doLatch :: Latch -> IO ()
|
|
|
|
doLatch (Latch mv) = putMVar mv ()
|
|
|
|
|
|
|
|
awaitLatch :: Latch -> IO ()
|
|
|
|
awaitLatch (Latch mv) = void $ takeMVar mv
|
|
|
|
|
2015-06-21 18:18:59 +05:30
|
|
|
latched :: Latch -> IO Bool
|
|
|
|
latched (Latch mv) = map isJust . tryReadMVar $ mv
|
|
|
|
|
2014-10-04 21:22:24 +05:30
|
|
|
newtype MessageBus a = MessageBus (TChan a)
|
|
|
|
|
|
|
|
newMessageBus :: IO (MessageBus a)
|
|
|
|
newMessageBus = MessageBus <$> newBroadcastTChanIO
|
|
|
|
|
2014-10-13 11:21:08 +05:30
|
|
|
-- | A channel through which messages are sent and received.
|
2014-10-04 21:22:24 +05:30
|
|
|
data MessageChannel a = MessageChannel Latch (TChan a) (TChan a)
|
|
|
|
|
|
|
|
newMessageChannel ::MessageBus a -> IO (MessageChannel a)
|
|
|
|
newMessageChannel (MessageBus wChan) = do
|
|
|
|
latch <- newLatch
|
|
|
|
rChan <- atomically $ dupTChan wChan
|
|
|
|
return $ MessageChannel latch rChan wChan
|
|
|
|
|
|
|
|
sendMessageSTM :: MessageChannel a -> a -> STM ()
|
|
|
|
sendMessageSTM (MessageChannel _ _ wChan) = writeTChan wChan
|
|
|
|
|
|
|
|
receiveMessageSTM :: MessageChannel a -> STM a
|
|
|
|
receiveMessageSTM (MessageChannel _ rChan _) = readTChan rChan
|
|
|
|
|
2015-06-21 19:44:39 +05:30
|
|
|
-- | Sends a message through a message channel.
|
2014-10-13 11:21:08 +05:30
|
|
|
sendMessage :: MessageChannel a -- ^ The channel
|
|
|
|
-> a -- ^ The message to send
|
|
|
|
-> IO ()
|
2014-10-04 21:22:24 +05:30
|
|
|
sendMessage chan = atomically . sendMessageSTM chan
|
|
|
|
|
|
|
|
receiveMessage :: MessageChannel a -> IO a
|
|
|
|
receiveMessage = atomically . receiveMessageSTM
|
|
|
|
|
|
|
|
closeMessageChannel :: MessageChannel a -> IO ()
|
|
|
|
closeMessageChannel (MessageChannel latch _ _) = doLatch latch
|
|
|
|
|
|
|
|
awaitMessageChannel :: MessageChannel a -> IO ()
|
|
|
|
awaitMessageChannel (MessageChannel latch _ _) = awaitLatch latch
|
2014-10-05 13:12:49 +05:30
|
|
|
|
2015-06-21 18:18:59 +05:30
|
|
|
isClosedMessageChannel :: MessageChannel a -> IO Bool
|
|
|
|
isClosedMessageChannel (MessageChannel latch _ _) = latched latch
|
|
|
|
|
2014-10-05 13:12:49 +05:30
|
|
|
receiveMessageEither :: MessageChannel a -> MessageChannel b -> IO (Either a b)
|
|
|
|
receiveMessageEither chan1 chan2 = atomically $
|
|
|
|
map Left (receiveMessageSTM chan1) `orElseSTM` map Right (receiveMessageSTM chan2)
|