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
|
|
|
|
2014-05-04 07:03:23 +05:30
|
|
|
import Control.Exception
|
2014-05-04 04:28:08 +05:30
|
|
|
import Control.Concurrent
|
|
|
|
import Control.Monad.Reader
|
|
|
|
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
|
2014-05-04 07:03:23 +05:30
|
|
|
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
|
|
|
|
|
2014-05-04 07:03:23 +05:30
|
|
|
data Status = Connected | Disconnected | Joined | Kicked | Errored
|
|
|
|
deriving (Show, Eq)
|
|
|
|
|
|
|
|
oneSec = 1000000
|
|
|
|
|
2014-05-04 04:28:08 +05:30
|
|
|
io = liftIO
|
|
|
|
|
2014-05-04 08:44:54 +05:30
|
|
|
log msg = getClockTime >>= \t -> printf "[%s] ** %s\n" (show t) msg
|
2014-05-04 07:03:23 +05:30
|
|
|
|
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
|
|
|
|
|
2014-05-04 07:03:23 +05:30
|
|
|
listen :: Status -> IRC Status
|
|
|
|
listen status = do
|
2014-05-04 07:43:37 +05:30
|
|
|
bot@Bot { .. } <- ask
|
2014-05-04 07:03:23 +05:30
|
|
|
let nick = botNick botConfig
|
2014-05-04 04:28:08 +05:30
|
|
|
|
2014-05-04 07:03:23 +05:30
|
|
|
when (status == Kicked) $
|
|
|
|
io $ threadDelay (5 * oneSec) >> sendCommand bot JoinCmd
|
2014-05-04 04:28:08 +05:30
|
|
|
|
2014-05-04 07:03:23 +05:30
|
|
|
mLine <- io . timeout (oneSec * botTimeout botConfig) . hGetLine $ socket
|
|
|
|
case mLine of
|
|
|
|
Nothing -> return Disconnected
|
|
|
|
Just l -> do
|
|
|
|
let line = init l
|
|
|
|
time <- io getClockTime
|
2014-05-04 04:28:08 +05:30
|
|
|
|
2014-05-04 07:03:23 +05:30
|
|
|
io $ printf "[%s] %s\n" (show time) line
|
|
|
|
|
2014-05-04 07:43:37 +05:30
|
|
|
let message = msgFromLine botConfig time (T.pack line)
|
2014-05-04 07:03:23 +05:30
|
|
|
nStatus <- io $ 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 -> do
|
|
|
|
cmd <- handleMessage handler botConfig msg
|
|
|
|
case cmd of
|
|
|
|
Nothing -> return ()
|
|
|
|
Just cmd -> sendCommand bot cmd
|
|
|
|
return status
|
|
|
|
|
|
|
|
listen nStatus
|
2014-05-04 04:28:08 +05:30
|
|
|
|
|
|
|
connect :: BotConfig -> IO Bot
|
2014-05-04 07:43:37 +05:30
|
|
|
connect botConfig@BotConfig { .. } = do
|
2014-05-04 07:03:23 +05:30
|
|
|
log "Connecting ..."
|
|
|
|
handle <- connectToWithRetry
|
2014-05-04 04:28:08 +05:30
|
|
|
hSetBuffering handle LineBuffering
|
|
|
|
hSetBuffering stdout LineBuffering
|
2014-05-04 07:03:23 +05:30
|
|
|
log "Connected"
|
2014-05-04 04:28:08 +05:30
|
|
|
return $ Bot botConfig handle
|
2014-05-04 07:03:23 +05:30
|
|
|
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
|
2014-05-04 07:03:23 +05:30
|
|
|
log "Disconnecting ..."
|
2014-05-04 04:28:08 +05:30
|
|
|
hClose . socket $ bot
|
2014-05-04 07:03:23 +05:30
|
|
|
log "Disconnected"
|
2014-05-04 04:28:08 +05:30
|
|
|
|
|
|
|
run :: BotConfig -> IO ()
|
2014-05-04 07:03:23 +05:30
|
|
|
run botConfig = withSocketsDo $ do
|
|
|
|
status <- run_
|
|
|
|
case status of
|
2014-05-04 08:44:54 +05:30
|
|
|
Disconnected -> log "Connection timed out" >> run botConfig
|
2014-05-04 07:03:23 +05:30
|
|
|
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
|
|
|
|
runReaderT (listen Connected) bot
|