hask-irc/Network/IRC/Client.hs

106 lines
3.2 KiB
Haskell
Raw Normal View History

2014-05-04 04:28:08 +05:30
{-# LANGUAGE RecordWildCards, ScopedTypeVariables #-}
2014-05-04 07:43:37 +05:30
module Network.IRC.Client (run) where
import qualified Data.Text as T
2014-05-04 04:28:08 +05:30
import Control.Exception
2014-05-04 04:28:08 +05:30
import Control.Concurrent
import Control.Monad
2014-05-04 04:28:08 +05:30
import Control.Monad.Reader
import Control.Monad.State
2014-05-04 04:28:08 +05:30
import Network
2014-05-04 08:44:54 +05:30
import Prelude hiding (log, catch)
2014-05-04 04:28:08 +05:30
import System.IO
import System.Time
import System.Timeout
2014-05-04 04:28:08 +05:30
import Text.Printf
import Network.IRC.Handlers
import Network.IRC.Protocol
import Network.IRC.Types
oneSec = 1000000
2014-05-04 08:44:54 +05:30
log msg = getClockTime >>= \t -> printf "[%s] ** %s\n" (show 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 = T.unpack $ lineFromCommand botConfig reply
2014-05-04 04:28:08 +05:30
hPrintf socket "%s\r\n" line >> printf "> %s\n" line
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
mLine <- fmap (fmap init) . timeout (oneSec * botTimeout botConfig) . hGetLine $ socket
case mLine of
Nothing -> return Disconnected
Just line -> do
time <- getClockTime
printf "[%s] %s\n" (show time) line
let message = msgFromLine botConfig time (T.pack line)
case message of
JoinMsg { .. } | userNick user == nick -> log "Joined" >> return Joined
KickMsg { .. } -> log "Kicked" >> return Kicked
_ -> do
forkIO $ case message of
Ping { .. } -> sendCommand bot $ Pong msg
ModeMsg { user = Self, .. } -> sendCommand bot JoinCmd
msg -> forM_ (handlers botConfig) $ \handler -> forkIO $ do
cmd <- runHandler (getHandler handler) botConfig msg
case cmd 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 ..."
handle <- connectToWithRetry
2014-05-04 04:28:08 +05:30
hSetBuffering handle LineBuffering
hSetBuffering stdout LineBuffering
log "Connected"
2014-05-04 04:28:08 +05:30
return $ Bot botConfig handle
where
connectToWithRetry = connectTo server (PortNumber (fromIntegral port))
`catch` (\(e :: SomeException) -> do
log ("Error: " ++ 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 ()
where
run_ = bracket (connect botConfig) disconnect $ \bot ->
go bot `catch` \(e :: SomeException) -> do
log $ "Exception! " ++ show e
return Errored
go bot = do
sendCommand bot NickCmd
sendCommand bot UserCmd
runIRC bot Connected listen