irc-fun-bot 0.2.0.0 → 0.3.0.0
raw patch · 11 files changed
+123/−36 lines, 11 filesdep +json-statedep −settingsdep ~irc-fun-clientPVP ok
version bump matches the API change (PVP)
Dependencies added: json-state
Dependencies removed: settings
Dependency ranges changed: irc-fun-client
API changes (from Hackage documentation)
- Network.IRC.Fun.Bot.Types: botEventLogFile :: Config -> FilePath
- Network.IRC.Fun.Bot.Types: channels :: Config -> [String]
- Network.IRC.Fun.Bot.Types: commandSets :: Behavior e s -> [CommandSet e s]
- Network.IRC.Fun.Bot.Types: commands :: CommandSet e s -> [Command e s]
- Network.IRC.Fun.Bot.Types: connection :: Config -> Connection
- Network.IRC.Fun.Bot.Types: handleBotMsg :: Behavior e s -> String -> String -> String -> Session e s ()
- Network.IRC.Fun.Bot.Types: handleJoin :: Behavior e s -> String -> String -> Session e s ()
- Network.IRC.Fun.Bot.Types: handleMsg :: Behavior e s -> String -> String -> String -> Bool -> Session e s ()
- Network.IRC.Fun.Bot.Types: handleNames :: Behavior e s -> String -> ChannelPrivacy -> [(Privilege, String)] -> Session e s ()
- Network.IRC.Fun.Bot.Types: handlePart :: Behavior e s -> String -> String -> Maybe String -> Session e s ()
- Network.IRC.Fun.Bot.Types: handlePersonalMsg :: Behavior e s -> String -> String -> Session e s ()
- Network.IRC.Fun.Bot.Types: handleQuit :: Behavior e s -> String -> Maybe String -> Session e s ()
- Network.IRC.Fun.Bot.Types: handleTopicChange :: Behavior e s -> String -> String -> String -> Session e s ()
- Network.IRC.Fun.Bot.Types: help :: Command e s -> String
- Network.IRC.Fun.Bot.Types: logDir :: Config -> FilePath
- Network.IRC.Fun.Bot.Types: names :: Command e s -> [String]
- Network.IRC.Fun.Bot.Types: nick :: Connection -> String
- Network.IRC.Fun.Bot.Types: password :: Connection -> Maybe String
- Network.IRC.Fun.Bot.Types: port :: Connection -> Int
- Network.IRC.Fun.Bot.Types: prefix :: CommandSet e s -> Char
- Network.IRC.Fun.Bot.Types: respond :: Command e s -> String -> String -> [String] -> Session e s ()
- Network.IRC.Fun.Bot.Types: saveInterval :: Config -> TimeInterval
- Network.IRC.Fun.Bot.Types: server :: Connection -> String
- Network.IRC.Fun.Bot.Types: stateFile :: Config -> FilePath
- Network.IRC.Fun.Bot.Types: tls :: Connection -> Bool
+ Network.IRC.Fun.Bot.Chat: failBack :: Maybe String -> String -> Failure -> Session e s ()
+ Network.IRC.Fun.Bot.Chat: sendBack :: Maybe String -> String -> String -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [botEventLogFile] :: Config -> FilePath
+ Network.IRC.Fun.Bot.Types: [channels] :: Config -> [String]
+ Network.IRC.Fun.Bot.Types: [commandSets] :: Behavior e s -> [CommandSet e s]
+ Network.IRC.Fun.Bot.Types: [commands] :: CommandSet e s -> [Command e s]
+ Network.IRC.Fun.Bot.Types: [connection] :: Config -> Connection
+ Network.IRC.Fun.Bot.Types: [handleBotMsg] :: Behavior e s -> String -> String -> String -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [handleJoin] :: Behavior e s -> String -> String -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [handleMsg] :: Behavior e s -> String -> String -> String -> Bool -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [handleNames] :: Behavior e s -> String -> ChannelPrivacy -> [(Privilege, String)] -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [handleNickChange] :: Behavior e s -> String -> String -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [handlePart] :: Behavior e s -> String -> String -> Maybe String -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [handlePersonalMsg] :: Behavior e s -> String -> String -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [handleQuit] :: Behavior e s -> String -> Maybe String -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [handleTopicChange] :: Behavior e s -> String -> String -> String -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [help] :: Command e s -> String
+ Network.IRC.Fun.Bot.Types: [logDir] :: Config -> FilePath
+ Network.IRC.Fun.Bot.Types: [names] :: Command e s -> [String]
+ Network.IRC.Fun.Bot.Types: [nick] :: Connection -> String
+ Network.IRC.Fun.Bot.Types: [password] :: Connection -> Maybe String
+ Network.IRC.Fun.Bot.Types: [port] :: Connection -> Int
+ Network.IRC.Fun.Bot.Types: [prefix] :: CommandSet e s -> Char
+ Network.IRC.Fun.Bot.Types: [respond] :: Command e s -> Maybe String -> String -> [String] -> (String -> Session e s ()) -> Session e s ()
+ Network.IRC.Fun.Bot.Types: [saveInterval] :: Config -> TimeInterval
+ Network.IRC.Fun.Bot.Types: [server] :: Connection -> String
+ Network.IRC.Fun.Bot.Types: [stateFile] :: Config -> FilePath
+ Network.IRC.Fun.Bot.Types: [stateRepo] :: Config -> Maybe FilePath
+ Network.IRC.Fun.Bot.Types: [tls] :: Connection -> Bool
- Network.IRC.Fun.Bot.Types: Behavior :: (String -> String -> Session e s ()) -> (String -> String -> Maybe String -> Session e s ()) -> (String -> Maybe String -> Session e s ()) -> (String -> String -> String -> Bool -> Session e s ()) -> (String -> String -> String -> Session e s ()) -> [CommandSet e s] -> (String -> String -> Session e s ()) -> (String -> String -> String -> Session e s ()) -> (String -> ChannelPrivacy -> [(Privilege, String)] -> Session e s ()) -> Behavior e s
+ Network.IRC.Fun.Bot.Types: Behavior :: (String -> String -> Session e s ()) -> (String -> String -> Maybe String -> Session e s ()) -> (String -> Maybe String -> Session e s ()) -> (String -> String -> String -> Bool -> Session e s ()) -> (String -> String -> String -> Session e s ()) -> [CommandSet e s] -> (String -> String -> Session e s ()) -> (String -> String -> Session e s ()) -> (String -> String -> String -> Session e s ()) -> (String -> ChannelPrivacy -> [(Privilege, String)] -> Session e s ()) -> Behavior e s
- Network.IRC.Fun.Bot.Types: Command :: [String] -> (String -> String -> [String] -> Session e s ()) -> String -> Command e s
+ Network.IRC.Fun.Bot.Types: Command :: [String] -> (Maybe String -> String -> [String] -> (String -> Session e s ()) -> Session e s ()) -> String -> Command e s
- Network.IRC.Fun.Bot.Types: Config :: Connection -> [String] -> FilePath -> FilePath -> TimeInterval -> FilePath -> Config
+ Network.IRC.Fun.Bot.Types: Config :: Connection -> [String] -> FilePath -> Maybe FilePath -> FilePath -> TimeInterval -> FilePath -> Config
- Network.IRC.Fun.Bot.Types: type EventSource e s a = Config -> e -> (a -> IO ()) -> ([a] -> IO ()) -> (FilePath -> IO Logger) -> IO ()
+ Network.IRC.Fun.Bot.Types: type EventSource e s a = Config The bot configuration. The event source may find this useful. -> e The bot's custom environment. The event source may find this useful. -> (a -> IO ()) A non-blocking 'IO' action which sends a given event to the processing queue. -> ([a] -> IO ()) A non-blocking 'IO' action which sends a given list of events to the processing queue. -> (FilePath -> IO Logger) An 'IO' action which creates a logger with a given target filename. An event source can use it to log events, errors, debug into, etc. into files efficiently. -> IO ()
Files
- ChangeLog +1/−1
- NEWS +27/−0
- irc-fun-bot.cabal +3/−3
- src/Network/IRC/Fun/Bot/Behavior.hs +1/−0
- src/Network/IRC/Fun/Bot/Chat.hs +3/−1
- src/Network/IRC/Fun/Bot/Internal/Chat.hs +13/−0
- src/Network/IRC/Fun/Bot/Internal/Event.hs +26/−13
- src/Network/IRC/Fun/Bot/Internal/Failure.hs +16/−10
- src/Network/IRC/Fun/Bot/Internal/Nicks.hs +8/−0
- src/Network/IRC/Fun/Bot/Internal/Persist.hs +6/−4
- src/Network/IRC/Fun/Bot/Internal/Types.hs +19/−4
ChangeLog view
@@ -3,7 +3,7 @@ $ darcs changes --repo http://dev.rel4tion.org/fr33domlover/irc-fun-bot -There is also a web interface at <http://darcs.rel4tion.org> which, among other+There is also a web interface at <http://dev.rel4tion.org> which, among other things, can display the history log. To see the log in a local clone, first get a copy of the repository if you
NEWS view
@@ -3,6 +3,33 @@ +irc-fun-bot 0.3.0.0 -- 2015-09-22+=================================++General, build and documentation changes:++* (None)++New APIs, features and enhancements:++* Allow sending commands in private messages+* Version control support (via Git) for state file+* Nick change event available, and new nick tracker action: changeNick+* New config option, stateRepo, to specify the git repo for state file++Bug fixes:++* (None)++Dependency changes:++* Add json-state+* Require irc-fun-client >= 0.2.0.0+++++ irc-fun-bot 0.2.0.0 -- 2015-09-10 =================================
irc-fun-bot.cabal view
@@ -1,5 +1,5 @@ name: irc-fun-bot-version: 0.2.0.0+version: 0.3.0.0 synopsis: Library for writing fun IRC bots. description: One day an idea came up on the #freepost IRC channel: We didn't need much of@@ -52,9 +52,9 @@ build-depends: aeson , base >=4.7 && <5 , fast-logger- , irc-fun-client >=0.1.1.0+ , irc-fun-client >=0.2.0.0 , irc-fun-messages- , settings+ , json-state , time , time-interval , time-units
src/Network/IRC/Fun/Bot/Behavior.hs view
@@ -54,6 +54,7 @@ , handleBotMsg = \ _ _ _ -> return () , commandSets = [] , handlePersonalMsg = \ _ _ -> return ()+ , handleNickChange = \ _ _ -> return () , handleTopicChange = \ _ _ _ -> return () , handleNames = \ _ _ _ -> return () }
src/Network/IRC/Fun/Bot/Chat.hs view
@@ -34,12 +34,14 @@ -- * Sending Messages , sendToChannel , sendToUser+ , sendBack , failToChannel , failToUser+ , failBack -- * Other Utilities , putIrc ) where import Network.IRC.Fun.Bot.Internal.Chat-import Network.IRC.Fun.Bot.Internal.Failure (failToChannel, failToUser)+import Network.IRC.Fun.Bot.Internal.Failure
src/Network/IRC/Fun/Bot/Internal/Chat.hs view
@@ -28,6 +28,7 @@ , partAll , sendToUser , sendToChannel+ , sendBack , putIrc ) where@@ -200,6 +201,18 @@ sendToUser nick msg = do h <- askHandle liftIO $ mapM_ (ircSendToUser h nick) $ lines msg++-- | Send a message back to the sender. If a channel is specified, send to the+-- channel. If not, send a private message.+sendBack :: Maybe String -- ^ Channel name, specify if replying to a message+ -- sent in a channel. Otherwise pass 'Nothing'.+ -> String -- ^ The sender user's nickname+ -> String -- ^ The message to send. It may contain newlines, in+ -- which case it will be split into multiple+ -- messages and sent sequentially.+ -> Session e s ()+sendBack (Just chan) _nick msg = sendToChannel chan msg+sendBack Nothing nick msg = sendToUser nick msg ------------------------------------------------------------------------------- -- Other Utilities
src/Network/IRC/Fun/Bot/Internal/Event.hs view
@@ -46,8 +46,8 @@ import qualified Data.HashMap.Lazy as M import Data.Maybe (catMaybes, fromMaybe, maybeToList) import Data.List (stripPrefix)-import Network.IRC.Fun.Bot.Internal.Chat (pong)-import Network.IRC.Fun.Bot.Internal.Failure (defaultRespondToChan)+import Network.IRC.Fun.Bot.Internal.Chat (pong, sendBack)+import Network.IRC.Fun.Bot.Internal.Failure import Network.IRC.Fun.Bot.Internal.Nicks import Network.IRC.Fun.Bot.Internal.State (askBehavior, askBehaviorS) import Network.IRC.Fun.Bot.Internal.Types hiding (Logger)@@ -304,6 +304,7 @@ C.ChannelMessage channel nick msg False -> Just $ Message channel nick msg $ msg `mentions` bnick C.PrivateMessage nick msg False -> Just $ PersonalMessage nick msg+ C.NickChange oldnick newnick -> Just $ NickChange oldnick newnick C.Topic channel nick topic -> Just $ TopicChange channel nick topic C.Names priv chan pnicks -> Just $ Names chan priv pnicks _ -> Nothing@@ -344,21 +345,29 @@ -- Run the command with the given prefix character, command name and list of -- parameters. If a command with the given prefix and name isn't found, the bot -- sends a default friendly response.-runCommand :: Maybe Char -- Command prefix, 'Nothing' picks the default prefix- -> String -- Command name- -> [String] -- List of parameters- -> String -- Channel in which the command was triggered- -> String -- Nickname of user who triggered the command+runCommand :: Maybe Char -- Command prefix, 'Nothing' picks the default prefix+ -> String -- Command name+ -> [String] -- List of parameters+ -> Maybe String -- Channel in which the command was triggered+ -> String -- Nickname of user who triggered the command -> Session e s ()-runCommand cpref cname cparams channel sender = do+runCommand cpref cname cparams mchan sender = do csets <- askBehaviorS commandSets case findCommand cpref cname csets of Nothing ->- defaultRespondToChan channel cpref cname Nothing+ case mchan of+ Just chan -> defaultRespondToChan chan cpref cname Nothing+ Nothing -> defaultRespondToUser sender cpref cname Nothing Just (Left cset) ->- defaultRespondToChan channel (Just $ prefix cset) cname (Just cset)+ case mchan of+ Just chan ->+ defaultRespondToChan+ chan (Just $ prefix cset) cname (Just cset)+ Nothing ->+ defaultRespondToUser+ sender (Just $ prefix cset) cname (Just cset) Just (Right cmd) ->- respond cmd channel sender cparams+ respond cmd mchan sender cparams (sendBack mchan sender) -- React to a bot event. handleBotEvent :: Event -> Session e s ()@@ -383,9 +392,13 @@ Notice mchan sender msg -> return () BotMessage chan sender msg -> handleBotMsg b chan sender msg BotCommand (Channel chan sender) cpref cname cargs ->- runCommand cpref cname cargs chan sender- BotCommand _ _ _ _ -> return ()+ runCommand cpref cname cargs (Just chan) sender+ BotCommand (User sender) cpref cname cargs ->+ runCommand cpref cname cargs Nothing sender PersonalMessage sender msg -> handlePersonalMsg b sender msg+ NickChange oldnick newnick -> do+ changeNick oldnick newnick+ handleNickChange b oldnick newnick TopicChange chan nick topic -> handleTopicChange b chan nick topic Names chan priv pnicks -> do tracked <- channelIsTracked chan
src/Network/IRC/Fun/Bot/Internal/Failure.hs view
@@ -18,12 +18,13 @@ , defaultRespondToUser , failToChannel , failToUser+ , failBack ) where import Data.Char (toLower) import Data.List (intercalate)-import Network.IRC.Fun.Bot.Internal.Chat (sendToChannel, sendToUser)+import Network.IRC.Fun.Bot.Internal.Chat (sendToChannel, sendToUser, sendBack) import Network.IRC.Fun.Bot.Internal.State (askBehaviorS) import Network.IRC.Fun.Bot.Internal.Types import Text.Printf (printf)@@ -58,7 +59,7 @@ :: String -- Target channel -> Maybe Char -- Command prefix that was triggered -> String -- Command name that was triggered- -> Maybe (CommandSet e s) -- The command set matching the prefix, is one+ -> Maybe (CommandSet e s) -- The command set matching the prefix, if one -- was found -> Session e s () defaultRespondToChan chan cpref cname cset = do@@ -110,24 +111,29 @@ printf "The %v%v argument is invalid: ‘%v’" pos (suffix pos) param OtherFail s -> "Command failed: " ++ s --- | Send message explaining a failure to an IRC channel+-- | Send message explaining a failure to an IRC channel. failToChannel :: String -- ^ Target channel -> String -- ^ User to whom to refer--- -> Char -- ^ Command prefix that was triggered--- -> String -- ^ Command name that was triggered -> Failure -- ^ Problem indication -> Session e s ()-failToChannel chan nick {-_cpref _cname-} failure =+failToChannel chan nick failure = let lowerc [] = [] lowerc (c:cs) = toLower c : cs in sendToChannel chan $ nick ++ ", " ++ lowerc (failureDescription failure) --- | Send message explaining a failure to an IRC user+-- | Send message explaining a failure to an IRC user. failToUser :: String -- ^ Target user--- -> Char -- ^ Command prefix that was triggered--- -> String -- ^ Command name that was triggered -> Failure -- ^ Problem indication -> Session e s ()-failToUser nick {-_cpref _cname-} failure =+failToUser nick failure = sendToUser nick $ failureDescription failure++-- | Send message explaining a failure back to the sender.+failBack :: Maybe String -- ^ Optional target channel, 'Nothing' means private+ -- message+ -> String -- ^ Target user nickname+ -> Failure -- ^ Problem indication+ -> Session e s ()+failBack (Just chan) nick failure = failToChannel chan nick failure+failBack Nothing nick failure = failToUser nick failure
src/Network/IRC/Fun/Bot/Internal/Nicks.hs view
@@ -24,6 +24,7 @@ , isInChannel , presence , addMember+ , changeNick , addChannel , removeMemberOnce , removeMember@@ -134,6 +135,13 @@ addMember chan nick = modify $ \ s -> s { tracker = f $ tracker s } where f = NT.addToChannel chan nick++-- | Record a nickname change. Remove old nickname from the channels in which+-- it's present, and add the new nickname to them.+changeNick :: String -> String -> Session e s ()+changeNick old new = modify $ \ s -> s { tracker = f $ tracker s }+ where+ f = NT.changeNick old new -- | Record a channel with the given present nicknames. addChannel :: String -> [String] -> Session e s ()
src/Network/IRC/Fun/Bot/Internal/Persist.hs view
@@ -24,13 +24,13 @@ where import Control.Applicative-import Control.Monad (mzero)+import Control.Monad (liftM, mzero) import Control.Monad.IO.Class (liftIO) import Control.Monad.Trans.RWS import Data.Aeson import qualified Data.HashMap.Lazy as M import Data.Maybe (isJust)-import Data.Settings.Persist+import Data.JsonState import Data.Time.Interval import Data.Time.Units (Microsecond) import Network.IRC.Fun.Bot.Internal.IrcLog (makeLogger)@@ -89,7 +89,8 @@ loadBotState :: BotEnv e s -> s -> IO (BotState s) loadBotState env pub = do- r <- loadSettings $ stateFile $ config env+ let conf = config env+ r <- loadState $ stateFilePath (stateFile conf) (stateRepo conf) case r of Left (False, e) -> error $ "Failed to read state file: " ++ e Left (True, e) -> error $ "Failed to parse state file: " ++ e@@ -98,7 +99,8 @@ mkSaveBotState :: Config -> IO (BotState s -> IO ()) mkSaveBotState conf = let iv = fromInteger $ microseconds $ saveInterval conf :: Microsecond- in mkSaveSettings iv (stateFile conf)+ msg = "auto commit by irc-fun-bot"+ in mkSaveStateChoose iv (stateFile conf) (stateRepo conf) msg saveBotState :: Session e s () saveBotState = do
src/Network/IRC/Fun/Bot/Internal/Types.hs view
@@ -55,9 +55,15 @@ -- | Directory path under which IRC log files will be placed. Relative to -- the bot process working directory, or absolute. , logDir :: FilePath+ -- | Directory path for the state file. This enables Git commits of the+ -- state file. A relative (to the bot process working dir) or absolute+ -- path to the Git repository. You must create the directory yourself if+ -- it doesn't exist, but repo will be auto-created for you if needed.+ , stateRepo :: Maybe FilePath -- | Filename into the bot state managed by this library will be stored.- -- The custom part of the state isn't handled. Path relative to the bot- -- process working directory, or absolute.+ -- The custom part of the state isn't handled. If 'stateDir' is+ -- 'Nothing', this is a path relative to the bot process working+ -- directory, or absolute. Otherwise, it's relative to the 'stateDir'. , stateFile :: FilePath -- | Minimal time interval between state saves. For example, to say -- \"don't write state to file more than once per three seconds\", set@@ -118,10 +124,16 @@ -- -- Parameters: --- -- (1) Channel in which the command was triggered+ -- (1) Channel in which the command was triggered, if any -- (2) Nickname of user who triggered the command -- (3) Command parameters given- , respond :: String -> String -> [String] -> Session e s ()+ -- (4) Action for sending a message back to the sender, same as using+ -- @sendBack@ with the channel and nickname+ , respond :: Maybe String+ -> String+ -> [String]+ -> (String -> Session e s ())+ -> Session e s () -- | Help string for the command, explaining it purpose, its parameters -- and its usage, possibly giving an example. May contain newlines.@@ -215,6 +227,8 @@ -- given nickname (1st parameter) and with the given content (2nd -- parameter). | PersonalMessage String String+ -- | Old nick, new nick.+ | NickChange String String -- | Channel, nickname, topic | TopicChange String String String -- | The server sent a list of nicknames present in a channel. Parameters:@@ -238,6 +252,7 @@ , handleBotMsg :: String -> String -> String -> Session e s () , commandSets :: [CommandSet e s] , handlePersonalMsg :: String -> String -> Session e s ()+ , handleNickChange :: String -> String -> Session e s () , handleTopicChange :: String -> String -> String -> Session e s () -- | Handle a channel member list received. Parameters: --