irc-fun-client 0.1.0.0 → 0.1.1.0
raw patch · 6 files changed
+347/−11 lines, 6 filesdep +auto-updatedep +fast-loggerdep +timePVP ok
version bump matches the API change (PVP)
Dependencies added: auto-update, fast-logger, time, time-units, unordered-containers
API changes (from Hackage documentation)
+ Network.IRC.Fun.Client.ChannelLogger: Enter :: NickName -> ChannelName -> LogEvent
+ Network.IRC.Fun.Client.ChannelLogger: EnterChan :: NickName -> ChanLogEvent
+ Network.IRC.Fun.Client.ChannelLogger: Leave :: NickName -> ChannelName -> LogEvent
+ Network.IRC.Fun.Client.ChannelLogger: LeaveAll :: NickName -> LogEvent
+ Network.IRC.Fun.Client.ChannelLogger: LeaveChan :: NickName -> ChanLogEvent
+ Network.IRC.Fun.Client.ChannelLogger: Message :: NickName -> ChannelName -> String -> LogEvent
+ Network.IRC.Fun.Client.ChannelLogger: MessageChan :: NickName -> String -> ChanLogEvent
+ Network.IRC.Fun.Client.ChannelLogger: Rename :: NickName -> NickName -> LogEvent
+ Network.IRC.Fun.Client.ChannelLogger: RenameInChan :: NickName -> NickName -> ChanLogEvent
+ Network.IRC.Fun.Client.ChannelLogger: data ChanLogEvent
+ Network.IRC.Fun.Client.ChannelLogger: data LogEvent
+ Network.IRC.Fun.Client.ChannelLogger: data Logger
+ Network.IRC.Fun.Client.ChannelLogger: fromClientEvent :: Event -> Maybe LogEvent
+ Network.IRC.Fun.Client.ChannelLogger: instance Show ChanLogEvent
+ Network.IRC.Fun.Client.ChannelLogger: instance Show LogEvent
+ Network.IRC.Fun.Client.ChannelLogger: logEvent :: Logger -> ChanLogEvent -> IO ()
+ Network.IRC.Fun.Client.ChannelLogger: logFilePath :: FilePath -> String -> ChannelName -> FilePath
+ Network.IRC.Fun.Client.ChannelLogger: newLogger :: IO String -> FilePath -> IO Logger
+ Network.IRC.Fun.Client.ChannelLogger: removeLogger :: Logger -> IO ()
+ Network.IRC.Fun.Client.NickTracker: ChannelTracker :: (HashSet NickName) -> ChannelTracker
+ Network.IRC.Fun.Client.NickTracker: NetworkTracker :: (HashMap ChannelName ChannelTracker) -> NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: addChannel :: ChannelName -> [NickName] -> NetworkTracker -> NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: addMember :: NickName -> ChannelTracker -> ChannelTracker
+ Network.IRC.Fun.Client.NickTracker: addToChannel :: ChannelName -> NickName -> NetworkTracker -> NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: isInChannel :: NickName -> ChannelName -> NetworkTracker -> Bool
+ Network.IRC.Fun.Client.NickTracker: isMemberOf :: NickName -> ChannelTracker -> Bool
+ Network.IRC.Fun.Client.NickTracker: newChannel :: [NickName] -> ChannelTracker
+ Network.IRC.Fun.Client.NickTracker: newNetwork :: NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: newtype ChannelTracker
+ Network.IRC.Fun.Client.NickTracker: newtype NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: presence :: NickName -> NetworkTracker -> [ChannelName]
+ Network.IRC.Fun.Client.NickTracker: removeChannel :: ChannelName -> NetworkTracker -> NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: removeChannels :: [ChannelName] -> NetworkTracker -> NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: removeFromChannel :: ChannelName -> NickName -> NetworkTracker -> NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: removeFromNetwork :: NickName -> NetworkTracker -> NetworkTracker
+ Network.IRC.Fun.Client.NickTracker: removeMember :: NickName -> ChannelTracker -> ChannelTracker
+ Network.IRC.Fun.Client.Time: currentTimeGetter :: IO (IO (UTCTime, String))
Files
- NEWS +29/−0
- irc-fun-client.cabal +11/−3
- src/Network/IRC/Fun/Client.hs +19/−8
- src/Network/IRC/Fun/Client/ChannelLogger.hs +116/−0
- src/Network/IRC/Fun/Client/NickTracker.hs +126/−0
- src/Network/IRC/Fun/Client/Time.hs +46/−0
NEWS view
@@ -3,6 +3,35 @@ +irc-fun-client 0.1.1.0 -- 2015-09-10+====================================++General, build and documentation changes:++* (None)++New APIs, features and enhancements:++* Basic channel logger API+* Efficient and scalable time getter+* Channel member tracker++Bug fixes:++* (None)++Dependency changes:++* Add dependency: auto-update+* Add dependency: fast-logger+* Add dependency: time+* Add dependency: time-units+* Add dependency: unordered-containers+++++ irc-fun-client 0.1.0.0 -- 2015-08-09 ====================================
irc-fun-client.cabal view
@@ -1,5 +1,5 @@ name: irc-fun-client-version: 0.1.0.0+version: 0.1.1.0 synopsis: Another library for writing IRC clients. description: This is an IRC client library that uses @irc-fun-messages@ library package@@ -24,14 +24,22 @@ library exposed-modules: Network.IRC.Fun.Client+ , Network.IRC.Fun.Client.ChannelLogger , Network.IRC.Fun.Client.Commands , Network.IRC.Fun.Client.Events , Network.IRC.Fun.Client.IO+ , Network.IRC.Fun.Client.NickTracker+ , Network.IRC.Fun.Client.Time , Network.IRC.Fun.Client.Util -- other-modules: -- other-extensions: - build-depends: base >=4.7 && <5+ build-depends: auto-update+ , base >=4.7 && <5 , irc-fun-messages- , network >=2.3+ , fast-logger >=2.4.1+ , network >=2.3+ , time >=1.5+ , time-units >=1+ , unordered-containers >=0.2.5 hs-source-dirs: src default-language: Haskell2010
src/Network/IRC/Fun/Client.hs view
@@ -20,6 +20,11 @@ -- * "Commands": Provides functions for sending IRC commands to the server. -- * "Events": Provides an Event type and functions for receiving IRC events. -- These events are an abstraction on top of IRC messages.+-- * "ChannelLogger": Provides a system for logging IRC channel activity into a+-- file.+-- * "Time": Provides an efficient scalable way to get the current time, and a+-- formatted time string for use in the logger.+-- * "NickTracker": Provides functions for tracking channels and their members -- * "Util": Miscellaneous helper functions which could be useful to clients -- -- If you're writing an IRC client, here is a suggestion for how to begin:@@ -32,14 +37,20 @@ -- need to receive IRC messages directly, use functions from the "IO" -- module. module Network.IRC.Fun.Client- ( module Network.IRC.Fun.Client.Commands- , module Network.IRC.Fun.Client.Events- , module Network.IRC.Fun.Client.IO- , module Network.IRC.Fun.Client.Util+ ( module ChannelLogger+ , module Commands+ , module Events+ , module IO+ , module NickTracker+ , module Util+ , module Time ) where -import Network.IRC.Fun.Client.Commands-import Network.IRC.Fun.Client.Events-import Network.IRC.Fun.Client.IO-import Network.IRC.Fun.Client.Util+import qualified Network.IRC.Fun.Client.ChannelLogger as ChannelLogger+import qualified Network.IRC.Fun.Client.Commands as Commands+import qualified Network.IRC.Fun.Client.Events as Events+import qualified Network.IRC.Fun.Client.IO as IO+import qualified Network.IRC.Fun.Client.NickTracker as NickTracker+import qualified Network.IRC.Fun.Client.Util as Util+import qualified Network.IRC.Fun.Client.Time as Time
+ src/Network/IRC/Fun/Client/ChannelLogger.hs view
@@ -0,0 +1,116 @@+{- This file is part of irc-fun-client.+ -+ - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++{-# LANGUAGE OverloadedStrings #-}++module Network.IRC.Fun.Client.ChannelLogger+ ( Logger ()+ , ChanLogEvent (..)+ , LogEvent (..)+ , logFilePath+ , newLogger+ , removeLogger+ , logEvent+ , fromClientEvent+ )+where++import Control.Monad (liftM)+import Data.Monoid ((<>))+import Network.IRC.Fun.Client.Events (Event (..))+import Network.IRC.Fun.Messages.TypeAliases (NickName, ChannelName)+import System.Log.FastLogger++data Logger = Logger+ { loggerSet :: LoggerSet+ , loggerGetTime :: IO String+ }++data ChanLogEvent+ = EnterChan NickName+ | LeaveChan NickName+ | MessageChan NickName String+ | RenameInChan NickName NickName+ deriving Show++data LogEvent+ = Enter NickName ChannelName+ | Leave NickName ChannelName+ | LeaveAll NickName+ | Message NickName ChannelName String+ | Rename NickName NickName+ deriving Show++-- | Utility for constructing a log file path.+logFilePath :: FilePath -- ^ Directory in which to place log files. Relative+ -- to the program's working directory, or absolute.+ -> String -- ^ Server label, e.g. @\"freenode\"@+ -> ChannelName -- ^ IRC channel name, e.g. @\"#freepost\"@+ -> FilePath+logFilePath dir server chan = dir ++ "/" ++ server ++ "." ++ chan ++ ".irc"++-- | Create a logger for a given IRC channel.+newLogger :: IO String -- ^ Action which returns a formatted time string. You+ -- can use "Network.IRC.Fun.Client.Time" to create such+ -- an action.+ -> FilePath -- ^ Path of the log file+ -> IO Logger+newLogger getTime path = do+ lset <- newFileLoggerSet defaultBufSize path+ return $ Logger+ { loggerSet = lset+ , loggerGetTime = getTime+ }++-- | Flush buffers and release resources.+--+-- When the logger is paused for a long period of time (i.e. not momentarily -+-- e.g. by a user disabling channel logging via UI), you can use this to+-- release resources. Later, when logging is needed again, create a fresh new+-- logger.+--+-- If your client joins many channels but log few of them, you can save+-- resources by keeping open loggers only for the few logged channels.+removeLogger :: Logger -> IO ()+removeLogger logger = rmLoggerSet $ loggerSet logger++formatEvent :: ChanLogEvent -> LogStr+formatEvent e = case e of+ EnterChan nick -> "|-->| " <> toLogStr nick <> " has joined"+ LeaveChan nick -> "|<--| " <> toLogStr nick <> " has left"+ MessageChan nick msg -> "<" <> toLogStr nick <> "> " <> toLogStr msg+ RenameInChan old new -> "|---| " <> toLogStr old <> " is now known as "+ <> toLogStr new++formatLine :: IO String -> ChanLogEvent -> IO LogStr+formatLine getTime event = do+ t <- getTime+ return $ toLogStr t <> " " <> formatEvent event++-- | Write a log message corresponding to a given event.+logEvent :: Logger -> ChanLogEvent -> IO ()+logEvent logger event = do+ line <- formatLine (loggerGetTime logger) event+ pushLogStrLn (loggerSet logger) line++-- | If an IRC client event can be logged, return a matching log event and the+-- channel in which the event has occured.+fromClientEvent :: Event -> Maybe LogEvent+fromClientEvent event = case event of+ Join chan nick -> Just $ Enter nick chan+ Part chan nick _reason -> Just $ Leave nick chan+ Quit nick _reason -> Just $ LeaveAll nick+ ChannelMessage chan nick msg _notice -> Just $ Message nick chan msg+ _ -> Nothing
+ src/Network/IRC/Fun/Client/NickTracker.hs view
@@ -0,0 +1,126 @@+{- This file is part of irc-fun-client.+ -+ - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++-- | Using the tools provided here, you can track which users are members of+-- which channels. This functionality has a veriety of uses, e.g. displaying+-- user lists in client UI and logging/displaying quit messages in the correct+-- channel logs/buffers.+module Network.IRC.Fun.Client.NickTracker+ ( ChannelTracker (..)+ , NetworkTracker (..)+ , isMemberOf+ , isInChannel+ , presence+ , newChannel+ , newNetwork+ , addMember+ , addToChannel+ , addChannel+ , removeMember+ , removeFromChannel+ , removeFromNetwork+ , removeChannel+ , removeChannels+ )+where++import qualified Data.HashMap.Lazy as M+import qualified Data.HashSet as S+import Network.IRC.Fun.Messages.TypeAliases++newtype ChannelTracker = ChannelTracker (S.HashSet NickName)++newtype NetworkTracker = NetworkTracker (M.HashMap ChannelName ChannelTracker)++-- | Check whether a nickname is present in a channel.+isMemberOf :: NickName -> ChannelTracker -> Bool+nick `isMemberOf` (ChannelTracker nicks) = nick `S.member` nicks++-- | Check whether a nickname is present in a channel.+isInChannel :: NickName -> ChannelName -> NetworkTracker -> Bool+isInChannel nick chan (NetworkTracker cts) =+ case M.lookup chan cts of+ Nothing -> False+ Just ct -> nick `isMemberOf` ct++applySnd :: (b -> c) -> (a, b) -> (a, c)+applySnd f (x, y) = (x, f y)++-- | Check in which channels a nickname is present.+presence :: NickName -> NetworkTracker -> [ChannelName]+presence nick (NetworkTracker cts) =+ [ chan | (chan, True) <- map (applySnd (nick `isMemberOf`)) $ M.toList cts]++-- | Record a channel with the given present nicknames.+newChannel :: [NickName] -> ChannelTracker+newChannel nicks = ChannelTracker $ S.fromList nicks++-- | Create new tracker.+newNetwork :: NetworkTracker+newNetwork = NetworkTracker $ M.empty++-- | Record a nickname being present in a channel.+addMember :: NickName -> ChannelTracker -> ChannelTracker+addMember nick (ChannelTracker nicks) = ChannelTracker $ S.insert nick nicks++-- | Record a nickname being present in a channel.+addToChannel :: ChannelName -> NickName -> NetworkTracker -> NetworkTracker+addToChannel chan nick (NetworkTracker cts) = NetworkTracker $ f cts+ where+ f chans =+ case M.lookup chan chans of+ Nothing ->+ let ct = ChannelTracker $ S.singleton nick+ in M.insert chan ct chans+ Just (ChannelTracker nicks) ->+ let ct = ChannelTracker $ S.insert nick nicks+ in M.insert chan ct chans++-- | Record a channel with the given present nicknames.+addChannel :: ChannelName -> [NickName] -> NetworkTracker -> NetworkTracker+addChannel chan nicks (NetworkTracker cts) = NetworkTracker $ f cts+ where+ f = M.insert chan $ newChannel nicks++-- | Record a channel not having a given nickname anymore.+removeMember :: NickName -> ChannelTracker -> ChannelTracker+removeMember nick (ChannelTracker nicks) = ChannelTracker $ S.delete nick nicks++-- | Record a channel not having a given nickname anymore.+removeFromChannel :: ChannelName+ -> NickName+ -> NetworkTracker+ -> NetworkTracker+removeFromChannel chan nick (NetworkTracker cts) = NetworkTracker $ f cts+ where+ f chans = M.adjust (removeMember nick) chan chans++-- | Record a nickname not being present in any channel anymore.+removeFromNetwork :: NickName -> NetworkTracker -> NetworkTracker+removeFromNetwork nick (NetworkTracker cts) = NetworkTracker $ f cts+ where+ f = M.map (removeMember nick)++-- | Remove a channel from the tracker.+removeChannel :: ChannelName -> NetworkTracker -> NetworkTracker+removeChannel chan (NetworkTracker cts) = NetworkTracker $ f cts+ where+ f = M.delete chan++-- | Remove channels from the tracker.+removeChannels :: [ChannelName] -> NetworkTracker -> NetworkTracker+removeChannels chans (NetworkTracker cts) = NetworkTracker $ f cts+ where+ f ts = ts `M.difference` M.fromList (zip chans (repeat ()))
+ src/Network/IRC/Fun/Client/Time.hs view
@@ -0,0 +1,46 @@+{- This file is part of irc-fun-client.+ -+ - Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.+ -+ - ♡ Copying is an act of love. Please copy, reuse and share.+ -+ - The author(s) have dedicated all copyright and related and neighboring+ - rights to this software to the public domain worldwide. This software is+ - distributed without any warranty.+ -+ - You should have received a copy of the CC0 Public Domain Dedication along+ - with this software. If not, see+ - <http://creativecommons.org/publicdomain/zero/1.0/>.+ -}++-- | Get the current UTC time and formatted time strings, using auto-update to+-- run the actual action periodically and by demand. In other words, these+-- functions can safely be used at high frequency.+--+-- Intended use: Create a single getter in the main thread and pass as needed+-- to other threads for their own use.+module Network.IRC.Fun.Client.Time+ ( currentTimeGetter+ )+where++import Control.AutoUpdate+import Data.Time.Clock (UTCTime, getCurrentTime)+import Data.Time.Format (defaultTimeLocale, formatTime)+import Data.Time.Units (Second, toMicroseconds)++format = formatTime defaultTimeLocale "%F %T"++action = do+ t <- getCurrentTime+ return (t, format t)++settings = defaultUpdateSettings+ { updateFreq = fromInteger $ toMicroseconds (1 :: Second)+ , updateAction = action+ }++-- | Make a getter which returns the current time, and a formatted time string+-- for use in IRC logs.+currentTimeGetter :: IO (IO (UTCTime, String))+currentTimeGetter = mkAutoUpdate settings