hask-irc/hask-irc-core/Network/IRC/Types.hs

223 lines
7.4 KiB
Haskell
Raw Normal View History

2014-06-01 02:11:20 +05:30
{-# LANGUAGE DeriveDataTypeable #-}
2014-05-13 00:00:33 +05:30
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
2014-06-01 02:11:20 +05:30
{-# LANGUAGE TemplateHaskell #-}
module Network.IRC.Types
2014-06-01 02:11:20 +05:30
( Nick (..)
2014-05-20 02:40:08 +05:30
, MsgHandlerName
, User (..)
, Message (..)
2014-05-25 01:09:31 +05:30
, MessageDetails (..)
2014-05-20 02:40:08 +05:30
, Command (..)
2014-05-21 00:06:37 +05:30
, Event (..)
, SomeEvent
, QuitEvent(..)
, EventResponse (..)
2014-05-20 02:40:08 +05:30
, BotConfig (..)
, BotStatus (..)
, Bot (..)
, IRC
, runIRC
, MsgHandler (..)
, MonadMsgHandler
, newMsgHandler
2014-05-21 00:06:37 +05:30
, handleMessage
, handleEvent
2014-05-22 20:59:02 +05:30
, stopMsgHandler
2014-06-01 23:14:19 +05:30
, getHelp
, MsgHandlerMaker (..))
where
2014-05-04 02:57:43 +05:30
2014-05-10 21:45:16 +05:30
import ClassyPrelude
2014-06-01 23:14:19 +05:30
import Control.Concurrent.Lifted (Chan)
import Control.Monad.Base (MonadBase)
import Control.Monad.Reader (ReaderT, MonadReader, runReaderT)
import Control.Monad.State (StateT, MonadState, execStateT)
import Data.Configurator.Types (Config)
import Data.Data (Data)
import Data.SafeCopy (base, deriveSafeCopy)
import Data.Typeable (cast)
2014-05-21 11:20:53 +05:30
2014-05-22 20:59:02 +05:30
import Network.IRC.Util
2014-05-21 11:20:53 +05:30
-- IRC related
2014-05-04 02:57:43 +05:30
2014-06-01 02:11:20 +05:30
newtype Nick = Nick { nickToText :: Text }
deriving (Eq, Ord, Data, Typeable, Hashable)
instance Show Nick where
show = unpack . nickToText
$(deriveSafeCopy 0 'base ''Nick)
data User = Self | User { userNick :: !Nick, userServer :: !Text }
2014-06-01 23:14:19 +05:30
deriving (Show, Eq, Ord)
2014-05-04 02:57:43 +05:30
2014-05-25 01:09:31 +05:30
data Message = Message { msgTime :: !UTCTime, msgLine :: !Text, msgDetails :: MessageDetails}
2014-06-01 23:14:19 +05:30
deriving (Show, Eq, Ord)
2014-05-25 01:09:31 +05:30
data MessageDetails =
IdleMsg
| NickInUseMsg
| PingMsg { msg :: !Text }
| PongMsg { msg :: !Text }
| NamesMsg { nicks :: ![Nick] }
| ChannelMsg { user :: !User, msg :: !Text }
| PrivMsg { user :: !User, msg :: !Text }
| ActionMsg { user :: !User, msg :: !Text }
| JoinMsg { user :: !User }
| QuitMsg { user :: !User, msg :: !Text }
| PartMsg { user :: !User, msg :: !Text }
| NickMsg { user :: !User, newNick :: !Nick }
| KickMsg { user :: !User, kickedNick :: !Nick, msg :: !Text }
| ModeMsg { user :: !User, msgTarget :: !Text, mode :: !Text , modeArgs :: ![Text] }
| OtherMsg { msgSource :: !Text, msgCommand :: !Text, msgTarget :: !Text , msg :: !Text }
2014-06-01 23:14:19 +05:30
deriving (Show, Eq, Ord)
2014-05-04 02:57:43 +05:30
data Command =
PingCmd { rmsg :: !Text }
| PongCmd { rmsg :: !Text }
| ChannelMsgReply { rmsg :: !Text }
| PrivMsgReply { ruser :: !User, rmsg :: !Text }
2014-05-04 02:57:43 +05:30
| NickCmd
| UserCmd
| JoinCmd
| QuitCmd
| NamesCmd
2014-06-01 23:14:19 +05:30
deriving (Show, Eq, Ord)
2014-05-04 02:57:43 +05:30
2014-06-01 23:14:19 +05:30
-- Events
2014-05-21 11:20:53 +05:30
2014-06-01 23:14:19 +05:30
class (Typeable e, Show e, Eq e) => Event e where
2014-05-21 00:06:37 +05:30
toEvent :: e -> IO SomeEvent
toEvent e = SomeEvent <$> pure e <*> getCurrentTime
fromEvent :: SomeEvent -> Maybe (e, UTCTime)
fromEvent (SomeEvent e time) = do
ev <- cast e
return (ev, time)
2014-06-01 23:14:19 +05:30
data SomeEvent = forall e. (Event e, Typeable e) => SomeEvent e UTCTime deriving (Typeable)
2014-05-21 00:06:37 +05:30
instance Show SomeEvent where
show (SomeEvent e time) = formatTime defaultTimeLocale "[%F %T] " time ++ show e
2014-06-01 23:14:19 +05:30
instance Eq SomeEvent where
SomeEvent e1 t1 == SomeEvent e2 t2 =
case cast e2 of
Just e2' -> e1 == e2' && t1 == t2
Nothing -> False
2014-05-21 00:06:37 +05:30
2014-06-01 23:14:19 +05:30
data QuitEvent = QuitEvent deriving (Show, Eq, Ord, Typeable)
2014-05-21 00:06:37 +05:30
instance Event QuitEvent
data EventResponse = RespNothing
| RespEvent SomeEvent
| RespMessage Message
| RespCommand Command
2014-06-01 23:14:19 +05:30
deriving (Show, Eq)
2014-05-21 00:06:37 +05:30
2014-05-21 11:20:53 +05:30
-- Bot
2014-06-01 02:11:20 +05:30
type MsgHandlerName = Text
2014-06-01 23:14:19 +05:30
data BotConfig = BotConfig { server :: !Text
, port :: !Int
, channel :: !Text
, botNick :: !Nick
, botTimeout :: !Int
, msgHandlerInfo :: !(Map MsgHandlerName (Map Text Text))
, msgHandlerMakers :: ![MsgHandlerMaker]
, config :: !Config }
instance Show BotConfig where
2014-05-25 01:09:31 +05:30
show BotConfig { .. } = "server = " ++ show server ++ "\n" ++
"port = " ++ show port ++ "\n" ++
"channel = " ++ show channel ++ "\n" ++
"nick = " ++ show botNick ++ "\n" ++
"timeout = " ++ show botTimeout ++ "\n" ++
2014-05-22 20:59:02 +05:30
"handlers = " ++ show (mapKeys msgHandlerInfo)
data Bot = Bot { botConfig :: !BotConfig
, socket :: !Handle
, msgHandlers :: !(Map MsgHandlerName MsgHandler) }
2014-05-04 02:57:43 +05:30
2014-06-01 23:14:19 +05:30
data BotStatus = Connected
| Disconnected
| Joined
| Kicked
| Errored
| Idle
| Interrupted
| NickNotAvailable
deriving (Show, Eq, Ord)
newtype IRC a = IRC { _runIRC :: StateT BotStatus (ReaderT Bot IO) a }
deriving ( Functor
, Applicative
, Monad
, MonadIO
, MonadReader Bot
, MonadState BotStatus )
runIRC :: Bot -> BotStatus -> IRC a -> IO BotStatus
2014-05-07 14:35:25 +05:30
runIRC bot botStatus = flip runReaderT bot . flip execStateT botStatus . _runIRC
2014-05-21 11:20:53 +05:30
-- Message handlers
newtype MsgHandlerT a = MsgHandlerT { _runMsgHandler :: ReaderT BotConfig IO a }
2014-05-25 01:09:31 +05:30
deriving ( Functor
, Applicative
, Monad
, MonadIO
2014-05-25 14:51:33 +05:30
, MonadBase IO
2014-05-25 01:09:31 +05:30
, MonadReader BotConfig )
2014-05-25 14:51:33 +05:30
class (MonadIO m, Applicative m, MonadReader BotConfig m, MonadBase IO m) => MonadMsgHandler m where
msgHandler :: MsgHandlerT a -> m a
instance MonadMsgHandler MsgHandlerT where
msgHandler = id
2014-06-01 06:48:24 +05:30
handleMessage :: MsgHandler -> BotConfig -> Message -> IO [Command]
2014-05-21 00:06:37 +05:30
handleMessage MsgHandler { .. } botConfig =
flip runReaderT botConfig . _runMsgHandler . onMessage
stopMsgHandler :: MsgHandler -> BotConfig -> IO ()
stopMsgHandler MsgHandler { .. } botConfig =
2014-05-21 00:06:37 +05:30
flip runReaderT botConfig . _runMsgHandler $ onStop
handleEvent :: MsgHandler -> BotConfig -> SomeEvent -> IO EventResponse
handleEvent MsgHandler { .. } botConfig =
flip runReaderT botConfig . _runMsgHandler . onEvent
2014-05-22 20:59:02 +05:30
getHelp :: MsgHandler -> BotConfig -> IO (Map Text Text)
getHelp MsgHandler { .. } botConfig =
flip runReaderT botConfig . _runMsgHandler $ onHelp
2014-05-21 00:06:37 +05:30
data MsgHandler = MsgHandler {
2014-06-01 06:48:24 +05:30
onMessage :: !(forall m . MonadMsgHandler m => Message -> m [Command]),
2014-05-21 00:06:37 +05:30
onStop :: !(forall m . MonadMsgHandler m => m ()),
2014-05-22 20:59:02 +05:30
onEvent :: !(forall m . MonadMsgHandler m => SomeEvent -> m EventResponse),
onHelp :: !(forall m . MonadMsgHandler m => m (Map Text Text))
2014-05-21 00:06:37 +05:30
}
newMsgHandler :: MsgHandler
2014-05-21 00:06:37 +05:30
newMsgHandler = MsgHandler {
2014-06-01 06:48:24 +05:30
onMessage = const $ return [],
2014-05-21 00:06:37 +05:30
onStop = return (),
2014-05-22 20:59:02 +05:30
onEvent = const $ return RespNothing,
onHelp = return mempty
2014-05-21 00:06:37 +05:30
}
2014-06-01 23:14:19 +05:30
data MsgHandlerMaker = MsgHandlerMaker {
msgHandlerName :: !MsgHandlerName,
msgHandlerMaker :: BotConfig -> Chan SomeEvent -> MsgHandlerName -> IO (Maybe MsgHandler)
}
instance Eq MsgHandlerMaker where
m1 == m2 = msgHandlerName m1 == msgHandlerName m2
instance Ord MsgHandlerMaker where
m1 `compare` m2 = msgHandlerName m1 `compare` msgHandlerName m2