marvin 0.2.2 → 0.2.3
raw patch · 3 files changed
+50/−5 lines, 3 filesdep ~aesonPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson
API changes (from Hackage documentation)
Files
- CHANGELOG.md +7/−0
- marvin.cabal +1/−1
- src/Marvin/Adapter/IRC.hs +42/−4
CHANGELOG.md view
@@ -1,3 +1,10 @@+# 0.2.3 - 05.03.2017++- A big thanks to @lubomir for testing the IRC adapter and contributing the following changes+ - Better command recognition in IRC adapter+ - Bot now properly registers in IRC+ - Added config setting to IRC for channels which the bot should join+ # 0.2.2 - 05.03.2017 - Removed the integration tests from the cabal package config
marvin.cabal view
@@ -1,5 +1,5 @@ name: marvin-version: 0.2.2+version: 0.2.3 synopsis: A framework for modular, portable chat bots. description: A framework for writing portable chat bots. Inspired by hubot. .
src/Marvin/Adapter/IRC.hs view
@@ -11,6 +11,7 @@ -} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE Rank2Types #-}+{-# LANGUAGE ViewPatterns #-} module Marvin.Adapter.IRC ( IRCAdapter, IRCChannel ) where@@ -26,6 +27,7 @@ import Data.ByteString (ByteString) import Data.Conduit import Data.Maybe+import Data.Monoid ((<>)) import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.Lazy as L@@ -74,8 +76,13 @@ User nick -> (nick, Direct nick) Channel chan user -> (user, RealChannel chan) case _message ev of- Privmsg _ (Right msg) ->- runHandler $ CommandEvent user channel msg ts+ Privmsg target (Right msg) -> do+ -- Privmsg can either be a private message directly to+ -- the user, or it could be a message going to a+ -- channel.+ botname <- getBotname+ let (cmd, msg') = isMention botname target msg+ runHandler $ cmd user channel msg' ts Notice target (Right msg) -> do botname <- getBotname -- Check if bot is addressed@@ -86,13 +93,40 @@ Topic channel' t -> runHandler $ TopicChangeEvent user (RealChannel channel') t ts Ping a b -> writeChan msgOutChan $ Pong $ fromMaybe a b Invite chan _ -> writeChan msgOutChan $ Join chan- _ -> logDebugN $(isT "Unhadeled event #{rawEv}")+ _ -> logDebugN $(isT "Unhandled event #{rawEv}") forever $ handleOneMessage `catch` (\e -> logErrorN $(isT "UserError: #{e :: ErrorCall}")) where runHandler = void . async . liftIO . handler +-- If the bot is the target of the message, it's a command. Also we should+-- treat the message as a command if the message starts with the name of the+-- bot followed by a colon or a comma.+--+-- For such message we strip off the name, separator and whitespace and return+-- just the important bit.+--+-- * "marvin: hello" returns (CommandEvent, "hello")+-- * "hey everyone" returns (MessageEvent, "hey everyone")+isMention :: IsAdapter a+ => L.Text -- ^Bot name+ -> L.Text -- ^Target of message+ -> L.Text -- ^The actual message text+ -> (User a -> Channel a -> L.Text -> TimeStamp -> MT.Event a, L.Text)+isMention botname target msg+ | L.head target /= '#' = (CommandEvent, msg)+ | otherwise = case msg of+ (L.stripPrefix (botname <> ", ") -> Just msg') -> (CommandEvent, L.stripStart msg')+ (L.stripPrefix (botname <> ": ") -> Just msg') -> (CommandEvent, L.stripStart msg')+ _ -> (MessageEvent, msg) ++setUp :: Chan MarvinIRCMsg -> L.Text -> [L.Text] -> IO ()+setUp chan username channels = do+ writeChan chan (Nick username)+ writeChan chan (RawMsg $ "User " <> username <> " 0 * :" <> username)+ writeList2Chan chan $ map Join channels+ instance IsAdapter IRCAdapter where -- | Stores the username type User IRCAdapter = L.Text@@ -119,7 +153,11 @@ runWithAdapter handler = do port <- fromMaybe 7000 <$> lookupFromAdapterConfig "port" host <- requireFromAdapterConfig "host"+ user <- getBotname+ channels <- requireFromAdapterConfig "channels" IRCAdapter{msgOutChan} <- getAdapter inChan <- newChan async $ processor inChan handler- liftIO $ ircClient port host (return ()) (consumer inChan) (producer msgOutChan)+ liftIO $ do + setUp msgOutChan user channels+ ircClient port host (return ()) (consumer inChan) (producer msgOutChan)