irc-client 0.2.4.0 → 0.2.5.0
raw patch · 6 files changed
+94/−68 lines, 6 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Network.IRC.Client.Types: _channels :: InstanceConfig -> [Text]
- Network.IRC.Client.Types: _connectionConfig :: IRCState -> ConnectionConfig
- Network.IRC.Client.Types: _ctcpVer :: InstanceConfig -> Text
- Network.IRC.Client.Types: _description :: EventHandler -> Text
- Network.IRC.Client.Types: _disconnect :: ConnectionConfig -> IRC ()
- Network.IRC.Client.Types: _eventFunc :: EventHandler -> UnicodeEvent -> IRC ()
- Network.IRC.Client.Types: _eventHandlers :: InstanceConfig -> [EventHandler]
- Network.IRC.Client.Types: _flood :: ConnectionConfig -> NominalDiffTime
- Network.IRC.Client.Types: _func :: ConnectionConfig -> Int -> ByteString -> IO () -> Consumer (Either ByteString IrcEvent) IO () -> Producer IO IrcMessage -> IO ()
- Network.IRC.Client.Types: _ignore :: InstanceConfig -> [(Text, Maybe Text)]
- Network.IRC.Client.Types: _instanceConfig :: IRCState -> TVar InstanceConfig
- Network.IRC.Client.Types: _logfunc :: ConnectionConfig -> Origin -> ByteString -> IO ()
- Network.IRC.Client.Types: _matchType :: EventHandler -> EventType
- Network.IRC.Client.Types: _message :: Event a -> Message a
- Network.IRC.Client.Types: _nick :: InstanceConfig -> Text
- Network.IRC.Client.Types: _port :: ConnectionConfig -> Int
- Network.IRC.Client.Types: _raw :: Event a -> ByteString
- Network.IRC.Client.Types: _realname :: InstanceConfig -> Text
- Network.IRC.Client.Types: _sendqueue :: ConnectionConfig -> TBMChan IrcMessage
- Network.IRC.Client.Types: _server :: ConnectionConfig -> ByteString
- Network.IRC.Client.Types: _source :: Event a -> Source a
- Network.IRC.Client.Types: _username :: InstanceConfig -> Text
- Network.IRC.Client.Types: instance Eq EventType
- Network.IRC.Client.Types: instance Eq Origin
- Network.IRC.Client.Types: instance Read Origin
- Network.IRC.Client.Types: instance Show EventType
- Network.IRC.Client.Types: instance Show Origin
+ Network.IRC.Client: startStateful :: MonadIO m => ConnectionConfig s -> InstanceConfig s -> s -> m ()
+ Network.IRC.Client.Types: [_channels] :: InstanceConfig s -> [Text]
+ Network.IRC.Client.Types: [_connectionConfig] :: IRCState s -> ConnectionConfig s
+ Network.IRC.Client.Types: [_ctcpVer] :: InstanceConfig s -> Text
+ Network.IRC.Client.Types: [_description] :: EventHandler s -> Text
+ Network.IRC.Client.Types: [_disconnect] :: ConnectionConfig s -> StatefulIRC s ()
+ Network.IRC.Client.Types: [_eventFunc] :: EventHandler s -> UnicodeEvent -> StatefulIRC s ()
+ Network.IRC.Client.Types: [_eventHandlers] :: InstanceConfig s -> [EventHandler s]
+ Network.IRC.Client.Types: [_flood] :: ConnectionConfig s -> NominalDiffTime
+ Network.IRC.Client.Types: [_func] :: ConnectionConfig s -> Int -> ByteString -> IO () -> Consumer (Either ByteString IrcEvent) IO () -> Producer IO IrcMessage -> IO ()
+ Network.IRC.Client.Types: [_ignore] :: InstanceConfig s -> [(Text, Maybe Text)]
+ Network.IRC.Client.Types: [_instanceConfig] :: IRCState s -> TVar (InstanceConfig s)
+ Network.IRC.Client.Types: [_logfunc] :: ConnectionConfig s -> Origin -> ByteString -> IO ()
+ Network.IRC.Client.Types: [_matchType] :: EventHandler s -> EventType
+ Network.IRC.Client.Types: [_message] :: Event a -> Message a
+ Network.IRC.Client.Types: [_nick] :: InstanceConfig s -> Text
+ Network.IRC.Client.Types: [_port] :: ConnectionConfig s -> Int
+ Network.IRC.Client.Types: [_raw] :: Event a -> ByteString
+ Network.IRC.Client.Types: [_realname] :: InstanceConfig s -> Text
+ Network.IRC.Client.Types: [_sendqueue] :: ConnectionConfig s -> TBMChan IrcMessage
+ Network.IRC.Client.Types: [_server] :: ConnectionConfig s -> ByteString
+ Network.IRC.Client.Types: [_source] :: Event a -> Source a
+ Network.IRC.Client.Types: [_userState] :: IRCState s -> TVar s
+ Network.IRC.Client.Types: [_username] :: InstanceConfig s -> Text
+ Network.IRC.Client.Types: getUserState :: IRCState s -> TVar s
+ Network.IRC.Client.Types: instance GHC.Classes.Eq Network.IRC.Client.Types.EventType
+ Network.IRC.Client.Types: instance GHC.Classes.Eq Network.IRC.Client.Types.Origin
+ Network.IRC.Client.Types: instance GHC.Read.Read Network.IRC.Client.Types.Origin
+ Network.IRC.Client.Types: instance GHC.Show.Show Network.IRC.Client.Types.EventType
+ Network.IRC.Client.Types: instance GHC.Show.Show Network.IRC.Client.Types.Origin
+ Network.IRC.Client.Types: putState :: s -> StatefulIRC s ()
+ Network.IRC.Client.Types: state :: StatefulIRC s s
+ Network.IRC.Client.Types: stateTVar :: StatefulIRC s (TVar s)
+ Network.IRC.Client.Types: type StatefulIRC s a = ReaderT (IRCState s) IO a
- Network.IRC.Client: connect :: MonadIO m => ByteString -> Int -> NominalDiffTime -> m ConnectionConfig
+ Network.IRC.Client: connect :: MonadIO m => ByteString -> Int -> NominalDiffTime -> m (ConnectionConfig s)
- Network.IRC.Client: connect' :: MonadIO m => (Origin -> ByteString -> IO ()) -> ByteString -> Int -> NominalDiffTime -> m ConnectionConfig
+ Network.IRC.Client: connect' :: MonadIO m => (Origin -> ByteString -> IO ()) -> ByteString -> Int -> NominalDiffTime -> m (ConnectionConfig s)
- Network.IRC.Client: connectWithTLS :: MonadIO m => ByteString -> Int -> NominalDiffTime -> m ConnectionConfig
+ Network.IRC.Client: connectWithTLS :: MonadIO m => ByteString -> Int -> NominalDiffTime -> m (ConnectionConfig s)
- Network.IRC.Client: connectWithTLS' :: MonadIO m => (Origin -> ByteString -> IO ()) -> ByteString -> Int -> NominalDiffTime -> m ConnectionConfig
+ Network.IRC.Client: connectWithTLS' :: MonadIO m => (Origin -> ByteString -> IO ()) -> ByteString -> Int -> NominalDiffTime -> m (ConnectionConfig s)
- Network.IRC.Client: defaultDisconnectHandler :: IRC ()
+ Network.IRC.Client: defaultDisconnectHandler :: StatefulIRC s ()
- Network.IRC.Client: defaultEventHandlers :: [EventHandler]
+ Network.IRC.Client: defaultEventHandlers :: [EventHandler s]
- Network.IRC.Client: defaultIRCConf :: Text -> InstanceConfig
+ Network.IRC.Client: defaultIRCConf :: Text -> InstanceConfig s
- Network.IRC.Client: disconnect :: IRC ()
+ Network.IRC.Client: disconnect :: StatefulIRC s ()
- Network.IRC.Client: send :: UnicodeMessage -> IRC ()
+ Network.IRC.Client: send :: UnicodeMessage -> StatefulIRC s ()
- Network.IRC.Client: sendBS :: IrcMessage -> IRC ()
+ Network.IRC.Client: sendBS :: IrcMessage -> StatefulIRC s ()
- Network.IRC.Client: start :: MonadIO m => ConnectionConfig -> InstanceConfig -> m ()
+ Network.IRC.Client: start :: MonadIO m => ConnectionConfig () -> InstanceConfig () -> m ()
- Network.IRC.Client: start' :: MonadIO m => IRCState -> m ()
+ Network.IRC.Client: start' :: MonadIO m => IRCState s -> m ()
- Network.IRC.Client.Handlers: ctcpPingHandler :: UnicodeEvent -> IRC ()
+ Network.IRC.Client.Handlers: ctcpPingHandler :: UnicodeEvent -> StatefulIRC s ()
- Network.IRC.Client.Handlers: ctcpTimeHandler :: UnicodeEvent -> IRC ()
+ Network.IRC.Client.Handlers: ctcpTimeHandler :: UnicodeEvent -> StatefulIRC s ()
- Network.IRC.Client.Handlers: ctcpVersionHandler :: UnicodeEvent -> IRC ()
+ Network.IRC.Client.Handlers: ctcpVersionHandler :: UnicodeEvent -> StatefulIRC s ()
- Network.IRC.Client.Handlers: defaultDisconnectHandler :: IRC ()
+ Network.IRC.Client.Handlers: defaultDisconnectHandler :: StatefulIRC s ()
- Network.IRC.Client.Handlers: defaultEventHandlers :: [EventHandler]
+ Network.IRC.Client.Handlers: defaultEventHandlers :: [EventHandler s]
- Network.IRC.Client.Handlers: nickMangler :: UnicodeEvent -> IRC ()
+ Network.IRC.Client.Handlers: nickMangler :: UnicodeEvent -> StatefulIRC s ()
- Network.IRC.Client.Handlers: pingHandler :: UnicodeEvent -> IRC ()
+ Network.IRC.Client.Handlers: pingHandler :: UnicodeEvent -> StatefulIRC s ()
- Network.IRC.Client.Handlers: welcomeNick :: UnicodeEvent -> IRC ()
+ Network.IRC.Client.Handlers: welcomeNick :: UnicodeEvent -> StatefulIRC s ()
- Network.IRC.Client.Types: ConnectionConfig :: (Int -> ByteString -> IO () -> Consumer (Either ByteString IrcEvent) IO () -> Producer IO IrcMessage -> IO ()) -> TBMChan IrcMessage -> ByteString -> Int -> NominalDiffTime -> IRC () -> (Origin -> ByteString -> IO ()) -> ConnectionConfig
+ Network.IRC.Client.Types: ConnectionConfig :: (Int -> ByteString -> IO () -> Consumer (Either ByteString IrcEvent) IO () -> Producer IO IrcMessage -> IO ()) -> TBMChan IrcMessage -> ByteString -> Int -> NominalDiffTime -> StatefulIRC s () -> (Origin -> ByteString -> IO ()) -> ConnectionConfig s
- Network.IRC.Client.Types: EventHandler :: Text -> EventType -> (UnicodeEvent -> IRC ()) -> EventHandler
+ Network.IRC.Client.Types: EventHandler :: Text -> EventType -> (UnicodeEvent -> StatefulIRC s ()) -> EventHandler s
- Network.IRC.Client.Types: IRCState :: ConnectionConfig -> TVar InstanceConfig -> IRCState
+ Network.IRC.Client.Types: IRCState :: ConnectionConfig s -> TVar s -> TVar (InstanceConfig s) -> IRCState s
- Network.IRC.Client.Types: InstanceConfig :: Text -> Text -> Text -> [Text] -> Text -> [EventHandler] -> [(Text, Maybe Text)] -> InstanceConfig
+ Network.IRC.Client.Types: InstanceConfig :: Text -> Text -> Text -> [Text] -> Text -> [EventHandler s] -> [(Text, Maybe Text)] -> InstanceConfig s
- Network.IRC.Client.Types: connectionConfig :: IRC ConnectionConfig
+ Network.IRC.Client.Types: connectionConfig :: StatefulIRC s (ConnectionConfig s)
- Network.IRC.Client.Types: data ConnectionConfig
+ Network.IRC.Client.Types: data ConnectionConfig s
- Network.IRC.Client.Types: data EventHandler
+ Network.IRC.Client.Types: data EventHandler s
- Network.IRC.Client.Types: data IRCState
+ Network.IRC.Client.Types: data IRCState s
- Network.IRC.Client.Types: data InstanceConfig
+ Network.IRC.Client.Types: data InstanceConfig s
- Network.IRC.Client.Types: getConnectionConfig :: IRCState -> ConnectionConfig
+ Network.IRC.Client.Types: getConnectionConfig :: IRCState s -> ConnectionConfig s
- Network.IRC.Client.Types: getInstanceConfig :: IRCState -> TVar InstanceConfig
+ Network.IRC.Client.Types: getInstanceConfig :: IRCState s -> TVar (InstanceConfig s)
- Network.IRC.Client.Types: getInstanceConfig' :: MonadIO m => IRCState -> m InstanceConfig
+ Network.IRC.Client.Types: getInstanceConfig' :: MonadIO m => IRCState s -> m (InstanceConfig s)
- Network.IRC.Client.Types: instanceConfig :: IRC InstanceConfig
+ Network.IRC.Client.Types: instanceConfig :: StatefulIRC s (InstanceConfig s)
- Network.IRC.Client.Types: instanceConfigTVar :: IRC (TVar InstanceConfig)
+ Network.IRC.Client.Types: instanceConfigTVar :: StatefulIRC s (TVar (InstanceConfig s))
- Network.IRC.Client.Types: ircState :: IRC IRCState
+ Network.IRC.Client.Types: ircState :: StatefulIRC s (IRCState s)
- Network.IRC.Client.Types: newIRCState :: MonadIO m => ConnectionConfig -> InstanceConfig -> m IRCState
+ Network.IRC.Client.Types: newIRCState :: MonadIO m => ConnectionConfig s -> InstanceConfig s -> s -> m (IRCState s)
- Network.IRC.Client.Types: putInstanceConfig :: InstanceConfig -> IRC ()
+ Network.IRC.Client.Types: putInstanceConfig :: InstanceConfig s -> StatefulIRC s ()
- Network.IRC.Client.Types: type IRC a = ReaderT IRCState IO a
+ Network.IRC.Client.Types: type IRC a = StatefulIRC () a
- Network.IRC.Client.Utils: delChan :: TVar InstanceConfig -> Text -> STM ()
+ Network.IRC.Client.Utils: delChan :: TVar (InstanceConfig s) -> Text -> STM ()
- Network.IRC.Client.Utils: leaveChannel :: Text -> Maybe Text -> IRC ()
+ Network.IRC.Client.Utils: leaveChannel :: Text -> Maybe Text -> StatefulIRC s ()
- Network.IRC.Client.Utils: reply :: UnicodeEvent -> Text -> IRC ()
+ Network.IRC.Client.Utils: reply :: UnicodeEvent -> Text -> StatefulIRC s ()
- Network.IRC.Client.Utils: setNick :: Text -> IRC ()
+ Network.IRC.Client.Utils: setNick :: Text -> StatefulIRC s ()
Files
- Network/IRC/Client.hs +15/−10
- Network/IRC/Client/Handlers.hs +12/−12
- Network/IRC/Client/Internal.hs +14/−15
- Network/IRC/Client/Types.hs +48/−25
- Network/IRC/Client/Utils.hs +4/−4
- irc-client.cabal +1/−2
Network/IRC/Client.hs view
@@ -6,7 +6,7 @@ -- > run host port nick = do -- > conn <- connect host port 1 -- > let cfg = defaultIRCConf nick--- > let cfg' = cfg { _handlers = yourCustomEventHandlers : _handlers cfg }+-- > let cfg' = cfg { _eventHandlers = yourCustomEventHandlers : _eventHandlers cfg } -- > start conn cfg' -- -- You shouldn't really need to tweak anything other than the event@@ -18,6 +18,7 @@ , connectWithTLS , start , start'+ , startStateful -- * Logging , Origin (..)@@ -67,7 +68,7 @@ -- ^ The port -> NominalDiffTime -- ^ The flood cooldown- -> m ConnectionConfig+ -> m (ConnectionConfig s) connect = connect' noopLogger -- | Connect to a server with TLS.@@ -78,7 +79,7 @@ -- ^ The port -> NominalDiffTime -- ^ The flood cooldown- -> m ConnectionConfig+ -> m (ConnectionConfig s) connectWithTLS = connectWithTLS' noopLogger -- | Connect to a server without TLS, with the provided logging@@ -92,7 +93,7 @@ -- ^ The port -> NominalDiffTime -- ^ The flood cooldown- -> m ConnectionConfig+ -> m (ConnectionConfig s) connect' = connectInternal ircClient defaultDisconnectHandler -- | Connect to a server with TLS, with the provided logging function.@@ -105,7 +106,7 @@ -- ^ The port -> NominalDiffTime -- ^ The flood cooldown- -> m ConnectionConfig+ -> m (ConnectionConfig s) connectWithTLS' = connectInternal ircTLSClient defaultDisconnectHandler -- * Starting@@ -113,23 +114,27 @@ -- | Run the event loop for a server, receiving messages and handing -- them off to handlers as appropriate. Messages will be logged to -- stdout.-start :: MonadIO m => ConnectionConfig -> InstanceConfig -> m ()-start cconf iconf = newIRCState cconf iconf >>= start'+start :: MonadIO m => ConnectionConfig () -> InstanceConfig () -> m ()+start cconf iconf = startStateful cconf iconf () +-- | like 'start' but for clients with state.+startStateful :: MonadIO m => ConnectionConfig s -> InstanceConfig s -> s -> m ()+startStateful cconf iconf ustate = newIRCState cconf iconf ustate >>= start'+ -- | Like 'start', but use the provided initial state.-start' :: MonadIO m => IRCState -> m ()+start' :: MonadIO m => IRCState s -> m () start' = liftIO . runReaderT runner -- * Default configuration -- | Construct a default IRC configuration from a nick-defaultIRCConf :: Text -> InstanceConfig+defaultIRCConf :: Text -> InstanceConfig s defaultIRCConf n = InstanceConfig { _nick = n , _username = n , _realname = n , _channels = []- , _ctcpVer = "irc-client-0.2.3.0"+ , _ctcpVer = "irc-client-0.2.5.0" , _eventHandlers = defaultEventHandlers , _ignore = [] }
Network/IRC/Client/Handlers.hs view
@@ -60,7 +60,7 @@ -- -- If you are building a bot, you may want to write an event handler -- to process messages representing commands.-defaultEventHandlers :: [EventHandler]+defaultEventHandlers :: [EventHandler s] defaultEventHandlers = [ EventHandler "Respond to server PING requests" EPing pingHandler , EventHandler "Respond to CTCP PING requests" ECTCP ctcpPingHandler@@ -73,24 +73,24 @@ ] -- | Respond to server @PING@ messages with a @PONG@.-pingHandler :: UnicodeEvent -> IRC ()+pingHandler :: UnicodeEvent -> StatefulIRC s () pingHandler ev = case _message ev of Ping s1 s2 -> send . Pong $ fromMaybe s1 s2 _ -> return () -- | Respond to CTCP @PING@ requests with a CTCP @PONG@.-ctcpPingHandler :: UnicodeEvent -> IRC ()+ctcpPingHandler :: UnicodeEvent -> StatefulIRC s () ctcpPingHandler = ctcpHandler [("PING", return)] -- | Respond to CTCP @VERSION@ requests with the version string.-ctcpVersionHandler :: UnicodeEvent -> IRC ()+ctcpVersionHandler :: UnicodeEvent -> StatefulIRC s () ctcpVersionHandler = ctcpHandler [("VERSION", go)] where go _ = do ver <- _ctcpVer <$> instanceConfig return [ver] -- | Respond to CTCP @TIME@ requests with the system time.-ctcpTimeHandler :: UnicodeEvent -> IRC ()+ctcpTimeHandler :: UnicodeEvent -> StatefulIRC s () ctcpTimeHandler = ctcpHandler [("TIME", go)] where go _ = do now <- liftIO getCurrentTime@@ -98,7 +98,7 @@ -- | Update the nick upon welcome (numeric reply 001), as it may not -- be what we requested (eg, in the case of a nick too long).-welcomeNick :: UnicodeEvent -> IRC ()+welcomeNick :: UnicodeEvent -> StatefulIRC s () welcomeNick = numHandler [(001, go)] where go (srvNick:_) = do tvarI <- instanceConfigTVar@@ -110,7 +110,7 @@ -- | Mangle the nick if there's a collision (numeric replies 432, 433, -- and 436) when we set it-nickMangler :: UnicodeEvent -> IRC ()+nickMangler :: UnicodeEvent -> StatefulIRC s () nickMangler = numHandler [ (432, go fresh) , (433, go mangle) , (436, go mangle)@@ -165,7 +165,7 @@ -- | Upon receiving a channel topic (numeric reply 332), add the -- channel to the list (if not already present).-joinHandler :: UnicodeEvent -> IRC ()+joinHandler :: UnicodeEvent -> StatefulIRC s () joinHandler = numHandler [(332, go)] where go (c:_) = do tvarI <- instanceConfigTVar@@ -178,7 +178,7 @@ go _ = return () -- | Update the channel list upon being kicked.-kickHandler :: UnicodeEvent -> IRC ()+kickHandler :: UnicodeEvent -> StatefulIRC s () kickHandler ev = do theNick <- _nick <$> instanceConfig tvarI <- instanceConfigTVar@@ -192,13 +192,13 @@ -- | The default disconnect handler: do nothing. You might want to -- override this with one which reconnects.-defaultDisconnectHandler :: IRC ()+defaultDisconnectHandler :: StatefulIRC s () defaultDisconnectHandler = return () -- *Utils -- | Match and handle a named CTCP-ctcpHandler :: [(Text, [Text] -> IRC [Text])] -> UnicodeEvent -> IRC ()+ctcpHandler :: [(Text, [Text] -> StatefulIRC s [Text])] -> UnicodeEvent -> StatefulIRC s () ctcpHandler hs ev = case (_source ev, _message ev) of (User n, Privmsg _ (Left ctcpbs)) -> let (verb, xs) = first toUpper $ fromCTCP ctcpbs@@ -210,7 +210,7 @@ _ -> return () -- | Match and handle a numeric reply-numHandler :: [(Int, [Text] -> IRC ())] -> UnicodeEvent -> IRC ()+numHandler :: [(Int, [Text] -> StatefulIRC s ())] -> UnicodeEvent -> StatefulIRC s () numHandler hs ev = case _message ev of Numeric num xs -> maybe (return ()) ($xs) $ lookup num hs _ -> return ()
Network/IRC/Client/Internal.hs view
@@ -33,12 +33,12 @@ -- | Connect to a server using the supplied connection function. connectInternal :: MonadIO m => (Int -> ByteString -> IO () -> Consumer (Either ByteString IrcEvent) IO () -> Producer IO IrcMessage -> IO ())- -> IRC ()+ -> StatefulIRC s () -> (Origin -> ByteString -> IO ()) -> ByteString -> Int -> NominalDiffTime- -> m ConnectionConfig+ -> m (ConnectionConfig s) connectInternal f dcHandler logf host port flood = liftIO $ do queueS <- newTBMChanIO 16 @@ -55,7 +55,7 @@ -- * Event loop -- | The event loop.-runner :: IRC ()+runner :: StatefulIRC s () runner = do state <- ircState @@ -68,8 +68,7 @@ let initialise = flip runReaderT state $ do sendBS $ rawMessage "USER" [encodeUtf8 theUser, "-", "-", encodeUtf8 theReal] send $ Nick theNick- mapM_ (send . Join) . _channels <$> instanceConfig- return ()+ instanceConfig >>= mapM_ (send . Join) . _channels -- Run the event loop, and call the disconnect handler if the remote -- end closes the socket.@@ -84,8 +83,8 @@ dchandler <- _disconnect <$> connectionConfig - let source = toProducer $ sourceTBMChan queue $= antiflood $= logConduit (logf FromServer . toByteString)- let sink = forgetful =$= logConduit (logf FromClient . _raw) =$ eventSink state+ let source = toProducer $ sourceTBMChan queue $= antiflood $= logConduit (logf FromClient . toByteString)+ let sink = forgetful =$= logConduit (logf FromServer . _raw) =$ eventSink state liftIO $ func port server initialise sink source @@ -100,7 +99,7 @@ -- | Block on receiving a message and invoke all matching handlers -- concurrently.-eventSink :: MonadIO m => IRCState -> Consumer IrcEvent m ()+eventSink :: MonadIO m => IRCState s -> Consumer IrcEvent m () eventSink ircstate = awaitForever $ \event -> do let event' = decodeUtf8 <$> event ignored <- isIgnored ircstate event'@@ -109,7 +108,7 @@ liftIO $ mapM_ (\h -> forkIO $ runReaderT (h event') ircstate) handlers -- | Check if an event is ignored or not.-isIgnored :: MonadIO m => IRCState -> UnicodeEvent -> m Bool+isIgnored :: MonadIO m => IRCState s -> UnicodeEvent -> m Bool isIgnored ircstate ev = do iconf <- liftIO . atomically . readTVar . _instanceConfig $ ircstate let ignoreList = _ignore iconf@@ -121,7 +120,7 @@ Server _ -> False -- |Get the event handlers for an event.-getHandlersFor :: Event a -> [EventHandler] -> [UnicodeEvent -> IRC ()]+getHandlersFor :: Event a -> [EventHandler s] -> [UnicodeEvent -> StatefulIRC s ()] getHandlersFor e ehs = [_eventFunc eh | eh <- ehs, _matchType eh `elem` [EEverything, eventType e]] -- |A conduit which logs everything which goes through it.@@ -151,7 +150,7 @@ appendFile fp $ unwords [ formatTime defaultTimeLocale "%c" now- , if origin == FromServer then "<---" else "--->"+ , if origin == FromServer then "--->" else "<---" , init . tail $ show x ] @@ -163,12 +162,12 @@ -- | Send a message as UTF-8, using TLS if enabled. This blocks if -- messages are sent too rapidly.-send :: UnicodeMessage -> IRC ()+send :: UnicodeMessage -> StatefulIRC s () send = sendBS . fmap encodeUtf8 -- | Send a message, using TLS if enabled. This blocks if messages are -- sent too rapidly.-sendBS :: IrcMessage -> IRC ()+sendBS :: IrcMessage -> StatefulIRC s () sendBS msg = do queue <- _sendqueue <$> connectionConfig liftIO . atomically $ writeTBMChan queue msg@@ -177,7 +176,7 @@ -- | Disconnect from the server, properly tearing down the TLS session -- (if there is one).-disconnect :: IRC ()+disconnect :: StatefulIRC s () disconnect = do queueS <- _sendqueue <$> connectionConfig @@ -190,7 +189,7 @@ disconnectNow -- | Disconnect immediately, without waiting for messages to be sent.-disconnectNow :: IRC ()+disconnectNow :: StatefulIRC s () disconnectNow = do queueS <- _sendqueue <$> connectionConfig liftIO . atomically $ closeTBMChan queueS
Network/IRC/Client/Types.hs view
@@ -31,64 +31,87 @@ -- *State -- | The IRC monad.-type IRC a = ReaderT IRCState IO a+type IRC a = StatefulIRC () a -data IRCState = IRCState { _connectionConfig :: ConnectionConfig- -- ^Read-only connection configuration- , _instanceConfig :: TVar InstanceConfig- -- ^Mutable instance configuration in STM- }+-- | The IRC monad, with state.+type StatefulIRC s a = ReaderT (IRCState s) IO a +data IRCState s = IRCState { _connectionConfig :: ConnectionConfig s+ -- ^Read-only connection configuration+ , _userState :: TVar s+ -- ^Mutable user state+ , _instanceConfig :: TVar (InstanceConfig s)+ -- ^Mutable instance configuration in STM+ }+ -- | Construct a new IRC state-newIRCState :: MonadIO m => ConnectionConfig -> InstanceConfig -> m IRCState-newIRCState cconf iconf = do- tvar <- liftIO . atomically . newTVar $ iconf+newIRCState :: MonadIO m => ConnectionConfig s -> InstanceConfig s -> s -> m (IRCState s)+newIRCState cconf iconf ustate = do+ ustvar <- liftIO . atomically . newTVar $ ustate+ ictvar <- liftIO . atomically . newTVar $ iconf return IRCState { _connectionConfig = cconf- , _instanceConfig = tvar+ , _userState = ustvar+ , _instanceConfig = ictvar } --- | Access the entire state.-ircState :: IRC IRCState+-- | Access the client state.+ircState :: StatefulIRC s (IRCState s) ircState = ask -- | Extract the connection configuration from an IRC state-getConnectionConfig :: IRCState -> ConnectionConfig+getConnectionConfig :: IRCState s -> ConnectionConfig s getConnectionConfig = _connectionConfig -- | Extract the instance configuration from an IRC state-getInstanceConfig :: IRCState -> TVar InstanceConfig+getInstanceConfig :: IRCState s -> TVar (InstanceConfig s) getInstanceConfig = _instanceConfig +-- | Extract the user state from an IRC state+getUserState :: IRCState s -> TVar s+getUserState = _userState+ -- | Extract the current snapshot of the instance configuration from -- an IRC state-getInstanceConfig' :: MonadIO m => IRCState -> m InstanceConfig+getInstanceConfig' :: MonadIO m => IRCState s -> m (InstanceConfig s) getInstanceConfig' = liftIO . atomically . readTVar . _instanceConfig -- | Access the connection config-connectionConfig :: IRC ConnectionConfig+connectionConfig :: StatefulIRC s (ConnectionConfig s) connectionConfig = _connectionConfig <$> ask -- | Access the instance config TVar-instanceConfigTVar :: IRC (TVar InstanceConfig)+instanceConfigTVar :: StatefulIRC s (TVar (InstanceConfig s)) instanceConfigTVar = _instanceConfig <$> ask -- | Access the instance config as it is right now.-instanceConfig :: IRC InstanceConfig+instanceConfig :: StatefulIRC s (InstanceConfig s) instanceConfig = instanceConfigTVar >>= liftIO . atomically . readTVar -- | Overwrite the instance config, even if it has changed since we -- looked at it.-putInstanceConfig :: InstanceConfig -> IRC ()+putInstanceConfig :: InstanceConfig s -> StatefulIRC s () putInstanceConfig iconf = instanceConfigTVar >>= liftIO . atomically . flip writeTVar iconf +-- | Access the user state.+stateTVar :: StatefulIRC s (TVar s)+stateTVar = _userState <$> ask++-- | Access the user state as it is right now.+state :: StatefulIRC s s+state = stateTVar >>= liftIO . atomically . readTVar++-- | Set the user state.+putState :: s -> StatefulIRC s ()+putState s = stateTVar >>= liftIO . atomically . flip writeTVar s+ -- | The origin of a message. data Origin = FromServer | FromClient deriving (Eq, Read, Show) -- | The static state of an IRC server connection.-data ConnectionConfig = ConnectionConfig+data ConnectionConfig s = ConnectionConfig { _func :: Int -> ByteString -> IO () -> Consumer (Either ByteString IrcEvent) IO () -> Producer IO IrcMessage -> IO () -- ^ Function to connect and start the conduits. , _sendqueue :: TBMChan IrcMessage@@ -99,14 +122,14 @@ -- ^ The server port. , _flood :: NominalDiffTime -- ^ The minimum time between two adjacent messages.- , _disconnect :: IRC ()+ , _disconnect :: StatefulIRC s () -- ^ Action to run if the remote server closes the connection. , _logfunc :: Origin -> ByteString -> IO () -- ^ Function to log messages sent to and received from the server. } -- | The updateable state of an IRC connection.-data InstanceConfig = InstanceConfig+data InstanceConfig s = InstanceConfig { _nick :: Text -- ^ Client nick , _username :: Text@@ -117,7 +140,7 @@ -- ^ Current channels , _ctcpVer :: Text -- ^ Response to CTCP VERSION- , _eventHandlers :: [EventHandler]+ , _eventHandlers :: [EventHandler s] -- ^ The registered event handlers , _ignore :: [(Text, Maybe Text)] -- ^ List of nicks (optionally restricted to channels) to ignore@@ -136,12 +159,12 @@ deriving (Eq, Show) -- | A function which handles an event.-data EventHandler = EventHandler+data EventHandler s = EventHandler { _description :: Text -- ^ A description of the event handler. , _matchType :: EventType -- ^ Which type to be triggered by- , _eventFunc :: UnicodeEvent -> IRC ()+ , _eventFunc :: UnicodeEvent -> StatefulIRC s () -- ^ The function to call. }
Network/IRC/Client/Utils.hs view
@@ -13,7 +13,7 @@ -- | Update the nick in the instance configuration and also send an -- update message to the server. This doesn't attempt to resolve nick -- collisions, that's up to the event handlers.-setNick :: Text -> IRC ()+setNick :: Text -> StatefulIRC s () setNick new = do tvarI <- instanceConfigTVar @@ -25,7 +25,7 @@ -- | Update the channel list in the instance configuration and also -- part the channel.-leaveChannel :: Text -> Maybe Text -> IRC ()+leaveChannel :: Text -> Maybe Text -> StatefulIRC s () leaveChannel chan reason = do tvarI <- instanceConfigTVar liftIO . atomically $ delChan tvarI chan@@ -35,13 +35,13 @@ -- | Remove a channel from the list without sending a part command (be -- careful not to let the channel list get out of sync with the -- real-world state if you use it for anything!)-delChan :: TVar InstanceConfig -> Text -> STM ()+delChan :: TVar (InstanceConfig s) -> Text -> STM () delChan tvarI chan = do iconf <- readTVar tvarI writeTVar tvarI iconf { _channels = filter (/=chan) $ _channels iconf } -- | Send a message to the source of an event.-reply :: UnicodeEvent -> Text -> IRC ()+reply :: UnicodeEvent -> Text -> StatefulIRC s () reply ev txt = case _source ev of Channel c _ -> mapM_ (send . Privmsg c . Right) $ T.lines txt User n -> mapM_ (send . Privmsg n . Right) $ T.lines txt
irc-client.cabal view
@@ -10,7 +10,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change-version: 0.2.4.0+version: 0.2.5.0 -- A short (one-line) description of the package. synopsis: An IRC client library.@@ -77,7 +77,6 @@ -- Compile with -Wall by default ghc-options: -Wall- -fno-warn-unused-do-bind -- LANGUAGE extensions used by modules in this package. -- other-extensions: