hask-irc/Network/IRC/Client.hs

111 lines
3.6 KiB
Haskell
Raw Normal View History

{-# LANGUAGE RecordWildCards, ScopedTypeVariables, NoImplicitPrelude, OverloadedStrings #-}
2014-05-04 04:28:08 +05:30
2014-05-04 07:43:37 +05:30
module Network.IRC.Client (run) where
import qualified Data.Text.Format as TF
import qualified Data.Text.Format.Params as TF
2014-05-04 04:28:08 +05:30
2014-05-10 21:45:16 +05:30
import ClassyPrelude hiding (log)
2014-05-04 04:28:08 +05:30
import Control.Concurrent
2014-05-10 21:45:16 +05:30
import Control.Monad.Reader hiding (forM_)
import Control.Monad.State hiding (forM_)
2014-05-04 04:28:08 +05:30
import Network
2014-05-10 21:45:16 +05:30
import System.IO (hSetBuffering, BufferMode(..))
import System.Timeout
2014-05-04 04:28:08 +05:30
import Network.IRC.Handlers
import Network.IRC.Protocol
import Network.IRC.Types
2014-05-07 14:35:25 +05:30
oneSec :: Int
oneSec = 1000000
log :: Text -> IO ()
2014-05-10 21:45:16 +05:30
log msg = getCurrentTime >>= \t -> TF.print "[{}] ** {}\n" $ TF.buildParams (t, msg)
2014-05-04 04:28:08 +05:30
sendCommand :: Bot -> Command -> IO ()
2014-05-04 07:43:37 +05:30
sendCommand Bot { .. } reply = do
let line = lineFromCommand botConfig reply
TF.hprint socket "{}\r\n" $ TF.Only line
TF.print "> {}\n" $ TF.Only line
2014-05-04 04:28:08 +05:30
listen :: IRC ()
listen = do
status <- get
2014-05-04 07:43:37 +05:30
bot@Bot { .. } <- ask
let nick = botNick botConfig
2014-05-04 04:28:08 +05:30
nStatus <- liftIO $ do
when (status == Kicked) $
threadDelay (5 * oneSec) >> sendCommand bot JoinCmd
2014-05-10 21:45:16 +05:30
mLine <- map (map initEx) . timeout (oneSec * botTimeout botConfig) . hGetLine $ socket
case mLine of
Nothing -> return Disconnected
Just line -> do
2014-05-10 21:45:16 +05:30
now <- getCurrentTime
TF.print "[{}] {}\n" $ TF.buildParams (now, line)
2014-05-10 21:45:16 +05:30
let message = msgFromLine botConfig now line
case message of
JoinMsg { .. } | userNick user == nick -> log "Joined" >> return Joined
2014-05-06 03:08:09 +05:30
KickMsg { .. } | kicked == nick -> log "Kicked" >> return Kicked
_ -> do
forkIO $ case message of
Ping { .. } -> sendCommand bot $ Pong msg
ModeMsg { user = Self, .. } -> sendCommand bot JoinCmd
2014-05-07 14:35:25 +05:30
msg -> forM_ (handlers botConfig) $ \handlerName -> forkIO $ do
let mHandler = getHandler handlerName
case mHandler of
Nothing -> log $ "No handler found with name: " ++ handlerName
2014-05-07 14:35:25 +05:30
Just handler -> do
mCmd <- runHandler handler botConfig msg
case mCmd of
Nothing -> return ()
Just cmd -> sendCommand bot cmd
return status
put nStatus
when (nStatus /= Disconnected) listen
2014-05-04 04:28:08 +05:30
connect :: BotConfig -> IO Bot
2014-05-04 07:43:37 +05:30
connect botConfig@BotConfig { .. } = do
log "Connecting ..."
2014-05-07 14:35:25 +05:30
socket <- connectToWithRetry
hSetBuffering socket LineBuffering
2014-05-04 04:28:08 +05:30
hSetBuffering stdout LineBuffering
log "Connected"
2014-05-07 14:35:25 +05:30
return $ Bot botConfig socket
where
connectToWithRetry = connectTo server (PortNumber (fromIntegral port))
`catch` (\(e :: SomeException) -> do
2014-05-10 21:45:16 +05:30
log ("Error while connecting: " ++ pack (show e) ++ ". Waiting.")
threadDelay (5 * oneSec)
connectToWithRetry)
2014-05-04 04:28:08 +05:30
disconnect :: Bot -> IO ()
disconnect bot = do
log "Disconnecting ..."
2014-05-04 04:28:08 +05:30
hClose . socket $ bot
log "Disconnected"
2014-05-04 04:28:08 +05:30
run :: BotConfig -> IO ()
run botConfig = withSocketsDo $ do
log "Running with config:"
print botConfig
status <- run_
case status of
2014-05-04 08:44:54 +05:30
Disconnected -> log "Connection timed out" >> run botConfig
Errored -> return ()
2014-05-07 14:35:25 +05:30
_ -> error "Unsupported status"
where
run_ = bracket (connect botConfig) disconnect $ \bot ->
go bot `catch` \(e :: SomeException) -> do
2014-05-10 21:45:16 +05:30
log $ "Exception! " ++ pack (show e)
return Errored
go bot = do
sendCommand bot NickCmd
sendCommand bot UserCmd
runIRC bot Connected listen