Switched to hslogger based logging
parent
13154a254a
commit
cb40b9c4d3
17
Main.hs
17
Main.hs
|
@ -6,12 +6,17 @@ module Main (main) where
|
||||||
|
|
||||||
import qualified Data.Configurator as CF
|
import qualified Data.Configurator as CF
|
||||||
|
|
||||||
import ClassyPrelude hiding (try, getArgs)
|
import ClassyPrelude hiding (getArgs)
|
||||||
import Control.Concurrent.Lifted (myThreadId)
|
import Control.Concurrent.Lifted (myThreadId)
|
||||||
import Control.Exception.Lifted (try, throwTo, AsyncException (UserInterrupt))
|
import Control.Exception.Lifted (throwTo, AsyncException (UserInterrupt))
|
||||||
import Data.Configurator.Types (Configured (..), Value (List), ConfigError (..), KeyError (..))
|
import Data.Configurator.Types (Configured (..), Value (List), ConfigError (..), KeyError (..))
|
||||||
import System.Environment (getArgs, getProgName)
|
import System.Environment (getArgs, getProgName)
|
||||||
import System.Exit (exitFailure)
|
import System.Exit (exitFailure)
|
||||||
|
import System.Log.Formatter (tfLogFormatter)
|
||||||
|
import System.Log.Handler (setFormatter)
|
||||||
|
import System.Log.Handler.Simple (streamHandler)
|
||||||
|
import System.Log.Logger (Priority (..), updateGlobalLogger, rootLoggerName,
|
||||||
|
setHandlers, setLevel)
|
||||||
import System.Posix.Signals (installHandler, sigINT, sigTERM, Handler (Catch))
|
import System.Posix.Signals (installHandler, sigINT, sigTERM, Handler (Catch))
|
||||||
|
|
||||||
import Network.IRC.Types
|
import Network.IRC.Types
|
||||||
|
@ -23,6 +28,7 @@ instance Configured a => Configured [a] where
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
-- get args
|
||||||
args <- getArgs
|
args <- getArgs
|
||||||
prog <- getProgName
|
prog <- getProgName
|
||||||
|
|
||||||
|
@ -30,10 +36,17 @@ main = do
|
||||||
putStrLn $ "Usage: " ++ pack prog ++ " <config file path>"
|
putStrLn $ "Usage: " ++ pack prog ++ " <config file path>"
|
||||||
exitFailure
|
exitFailure
|
||||||
|
|
||||||
|
-- setup signal handling
|
||||||
mainThreadId <- myThreadId
|
mainThreadId <- myThreadId
|
||||||
installHandler sigINT (Catch $ throwTo mainThreadId UserInterrupt) Nothing
|
installHandler sigINT (Catch $ throwTo mainThreadId UserInterrupt) Nothing
|
||||||
installHandler sigTERM (Catch $ throwTo mainThreadId UserInterrupt) Nothing
|
installHandler sigTERM (Catch $ throwTo mainThreadId UserInterrupt) Nothing
|
||||||
|
|
||||||
|
-- setup logging
|
||||||
|
stderrHandler <- streamHandler stderr DEBUG >>= \lh -> return $
|
||||||
|
setFormatter lh $ tfLogFormatter "%F %T" "[$utcTime] $loggername $prio $msg"
|
||||||
|
updateGlobalLogger rootLoggerName (setHandlers [stderrHandler] . setLevel DEBUG)
|
||||||
|
|
||||||
|
-- load config and start the bot
|
||||||
let configFile = headEx args
|
let configFile = headEx args
|
||||||
loadBotConfig configFile >>= runBot
|
loadBotConfig configFile >>= runBot
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,22 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
module Network.IRC.Bot where
|
module Network.IRC.Bot
|
||||||
|
( Line (..)
|
||||||
|
, sendCommand
|
||||||
|
, sendMessage
|
||||||
|
, sendEvent
|
||||||
|
, readLine
|
||||||
|
, sendCommandLoop
|
||||||
|
, readLineLoop
|
||||||
|
, messageProcessLoop
|
||||||
|
, eventProcessLoop )
|
||||||
|
where
|
||||||
|
|
||||||
import qualified Data.Text.Format as TF
|
import qualified Data.Text.Format as TF
|
||||||
import qualified Data.Text.Format.Params as TF
|
import qualified System.Log.Logger as HSL
|
||||||
|
|
||||||
import ClassyPrelude
|
import ClassyPrelude
|
||||||
import Control.Concurrent.Lifted (fork, Chan, readChan, writeChan, threadDelay)
|
import Control.Concurrent.Lifted (fork, Chan, readChan, writeChan, threadDelay)
|
||||||
|
@ -16,11 +27,14 @@ import Control.Monad.Reader (ask)
|
||||||
import Control.Monad.State (get, put)
|
import Control.Monad.State (get, put)
|
||||||
import System.IO (hIsEOF)
|
import System.IO (hIsEOF)
|
||||||
import System.Timeout (timeout)
|
import System.Timeout (timeout)
|
||||||
|
import System.Log.Logger.TH (deriveLoggers)
|
||||||
|
|
||||||
import Network.IRC.Protocol
|
import Network.IRC.Protocol
|
||||||
import Network.IRC.Types
|
import Network.IRC.Types
|
||||||
import Network.IRC.Util
|
import Network.IRC.Util
|
||||||
|
|
||||||
|
$(deriveLoggers "HSL" [HSL.DEBUG, HSL.INFO, HSL.ERROR])
|
||||||
|
|
||||||
data Line = Timeout | EOF | Line !Message deriving (Show, Eq)
|
data Line = Timeout | EOF | Line !Message deriving (Show, Eq)
|
||||||
|
|
||||||
sendCommand :: Chan Command -> Command -> IO ()
|
sendCommand :: Chan Command -> Command -> IO ()
|
||||||
|
@ -38,16 +52,17 @@ readLine = readChan
|
||||||
sendCommandLoop :: Channel Command -> Bot -> IO ()
|
sendCommandLoop :: Channel Command -> Bot -> IO ()
|
||||||
sendCommandLoop (commandChan, latch) bot@Bot { .. } = do
|
sendCommandLoop (commandChan, latch) bot@Bot { .. } = do
|
||||||
cmd <- readChan commandChan
|
cmd <- readChan commandChan
|
||||||
time <- getCurrentTime
|
|
||||||
let mline = lineFromCommand botConfig cmd
|
let mline = lineFromCommand botConfig cmd
|
||||||
case mline of
|
handle (\(e :: SomeException) ->
|
||||||
Nothing -> return ()
|
errorM ("Error while writing to connection: " ++ show e) >> latchIt latch) $ do
|
||||||
Just line -> do
|
case mline of
|
||||||
TF.hprint socket "{}\r\n" $ TF.Only line
|
Nothing -> return ()
|
||||||
TF.print "[{}] > {}\n" $ TF.buildParams (formatTime defaultTimeLocale "%F %T" time, line)
|
Just line -> do
|
||||||
case cmd of
|
TF.hprint socket "{}\r\n" $ TF.Only line
|
||||||
QuitCmd -> latchIt latch
|
infoM . unpack $ "> " ++ line
|
||||||
_ -> sendCommandLoop (commandChan, latch) bot
|
case cmd of
|
||||||
|
QuitCmd -> latchIt latch
|
||||||
|
_ -> sendCommandLoop (commandChan, latch) bot
|
||||||
|
|
||||||
readLineLoop :: MVar BotStatus -> Channel Line -> Bot -> Int -> IO ()
|
readLineLoop :: MVar BotStatus -> Channel Line -> Bot -> Int -> IO ()
|
||||||
readLineLoop mvBotStatus (lineChan, latch) bot@Bot { .. } timeoutDelay = do
|
readLineLoop mvBotStatus (lineChan, latch) bot@Bot { .. } timeoutDelay = do
|
||||||
|
@ -55,10 +70,13 @@ readLineLoop mvBotStatus (lineChan, latch) bot@Bot { .. } timeoutDelay = do
|
||||||
case botStatus of
|
case botStatus of
|
||||||
Disconnected -> latchIt latch
|
Disconnected -> latchIt latch
|
||||||
_ -> do
|
_ -> do
|
||||||
mLine <- timeout timeoutDelay readLine'
|
mLine <- try $ timeout timeoutDelay readLine'
|
||||||
case mLine of
|
case mLine of
|
||||||
Nothing -> writeChan lineChan Timeout
|
Left (e :: SomeException) -> do
|
||||||
Just line -> writeChan lineChan line
|
errorM $ "Error while reading from connection: " ++ show e
|
||||||
|
writeChan lineChan EOF
|
||||||
|
Right Nothing -> writeChan lineChan Timeout
|
||||||
|
Right (Just line) -> writeChan lineChan line
|
||||||
readLineLoop mvBotStatus (lineChan, latch) bot timeoutDelay
|
readLineLoop mvBotStatus (lineChan, latch) bot timeoutDelay
|
||||||
where
|
where
|
||||||
readLine' = do
|
readLine' = do
|
||||||
|
@ -67,7 +85,7 @@ readLineLoop mvBotStatus (lineChan, latch) bot@Bot { .. } timeoutDelay = do
|
||||||
then return EOF
|
then return EOF
|
||||||
else do
|
else do
|
||||||
line <- map initEx $ hGetLine socket
|
line <- map initEx $ hGetLine socket
|
||||||
debug $ "< " ++ line
|
infoM . unpack $ "< " ++ line
|
||||||
now <- getCurrentTime
|
now <- getCurrentTime
|
||||||
return . Line $ msgFromLine botConfig now line
|
return . Line $ msgFromLine botConfig now line
|
||||||
|
|
||||||
|
@ -79,7 +97,7 @@ messageProcessLoop lineChan commandChan !idleFor = do
|
||||||
|
|
||||||
nStatus <- liftIO . mask_ $
|
nStatus <- liftIO . mask_ $
|
||||||
if idleFor >= (oneSec * botTimeout botConfig)
|
if idleFor >= (oneSec * botTimeout botConfig)
|
||||||
then debug "Timeout" >> return Disconnected
|
then infoM "Timeout" >> return Disconnected
|
||||||
else do
|
else do
|
||||||
when (status == Kicked) $
|
when (status == Kicked) $
|
||||||
threadDelay (5 * oneSec) >> sendCommand commandChan JoinCmd
|
threadDelay (5 * oneSec) >> sendCommand commandChan JoinCmd
|
||||||
|
@ -87,13 +105,13 @@ messageProcessLoop lineChan commandChan !idleFor = do
|
||||||
mLine <- readLine lineChan
|
mLine <- readLine lineChan
|
||||||
case mLine of
|
case mLine of
|
||||||
Timeout -> getCurrentTime >>= dispatchHandlers bot . IdleMsg >> return Idle
|
Timeout -> getCurrentTime >>= dispatchHandlers bot . IdleMsg >> return Idle
|
||||||
EOF -> debug "Connection closed" >> return Disconnected
|
EOF -> infoM "Connection closed" >> return Disconnected
|
||||||
Line message -> do
|
Line message -> do
|
||||||
nStatus <- case message of
|
nStatus <- case message of
|
||||||
JoinMsg { .. } | userNick user == nick -> debug "Joined" >> return Joined
|
JoinMsg { .. } | userNick user == nick -> infoM "Joined" >> return Joined
|
||||||
KickMsg { .. } | kickedNick == nick -> debug "Kicked" >> return Kicked
|
KickMsg { .. } | kickedNick == nick -> infoM "Kicked" >> return Kicked
|
||||||
NickInUseMsg { .. } ->
|
NickInUseMsg { .. } ->
|
||||||
debug "Nick already in use" >> return NickNotAvailable
|
infoM "Nick already in use" >> return NickNotAvailable
|
||||||
ModeMsg { user = Self, .. } ->
|
ModeMsg { user = Self, .. } ->
|
||||||
sendCommand commandChan JoinCmd >> return Connected
|
sendCommand commandChan JoinCmd >> return Connected
|
||||||
_ -> return Connected
|
_ -> return Connected
|
||||||
|
@ -112,7 +130,7 @@ messageProcessLoop lineChan commandChan !idleFor = do
|
||||||
dispatchHandlers Bot { .. } message =
|
dispatchHandlers Bot { .. } message =
|
||||||
forM_ (mapToList msgHandlers) $ \(_, msgHandler) -> fork $
|
forM_ (mapToList msgHandlers) $ \(_, msgHandler) -> fork $
|
||||||
handle (\(e :: SomeException) ->
|
handle (\(e :: SomeException) ->
|
||||||
debug $ "Exception while processing message: " ++ pack (show e)) $ do
|
errorM $ "Exception while processing message: " ++ show e) $ do
|
||||||
mCmd <- handleMessage msgHandler botConfig message
|
mCmd <- handleMessage msgHandler botConfig message
|
||||||
case mCmd of
|
case mCmd of
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
|
@ -124,10 +142,10 @@ eventProcessLoop (eventChan, latch) lineChan commandChan bot@Bot {.. } = do
|
||||||
case fromEvent event of
|
case fromEvent event of
|
||||||
Just (QuitEvent, _) -> latchIt latch
|
Just (QuitEvent, _) -> latchIt latch
|
||||||
_ -> do
|
_ -> do
|
||||||
debug $ "Event: " ++ pack (show event)
|
debugM $ "Event: " ++ show event
|
||||||
forM_ (mapToList msgHandlers) $ \(_, msgHandler) -> fork $
|
forM_ (mapToList msgHandlers) $ \(_, msgHandler) -> fork $
|
||||||
handle (\(ex :: SomeException) ->
|
handle (\(ex :: SomeException) ->
|
||||||
debug $ "Exception while processing event: " ++ pack (show ex)) $ do
|
errorM $ "Exception while processing event: " ++ show ex) $ do
|
||||||
resp <- handleEvent msgHandler botConfig event
|
resp <- handleEvent msgHandler botConfig event
|
||||||
case resp of
|
case resp of
|
||||||
RespMessage message -> sendMessage lineChan message
|
RespMessage message -> sendMessage lineChan message
|
||||||
|
|
|
@ -2,26 +2,32 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
module Network.IRC.Client (runBot) where
|
module Network.IRC.Client (runBot) where
|
||||||
|
|
||||||
|
import qualified System.Log.Logger as HSL
|
||||||
|
|
||||||
import ClassyPrelude
|
import ClassyPrelude
|
||||||
import Control.Concurrent.Lifted (fork, newChan, threadDelay)
|
import Control.Concurrent.Lifted (fork, newChan, threadDelay)
|
||||||
import Control.Exception.Lifted (AsyncException (UserInterrupt))
|
import Control.Exception.Lifted (AsyncException (UserInterrupt))
|
||||||
import Network (PortID (PortNumber), connectTo, withSocketsDo)
|
import Network (PortID (PortNumber), connectTo, withSocketsDo)
|
||||||
import System.IO (hSetBuffering, BufferMode(..))
|
import System.IO (hSetBuffering, BufferMode(..))
|
||||||
|
import System.Log.Logger.TH (deriveLoggers)
|
||||||
|
|
||||||
import Network.IRC.Bot
|
import Network.IRC.Bot
|
||||||
import Network.IRC.Handlers
|
import Network.IRC.Handlers
|
||||||
import Network.IRC.Types
|
import Network.IRC.Types
|
||||||
import Network.IRC.Util
|
import Network.IRC.Util
|
||||||
|
|
||||||
|
$(deriveLoggers "HSL" [HSL.DEBUG, HSL.ERROR])
|
||||||
|
|
||||||
connect :: BotConfig -> IO (Bot, MVar BotStatus, Channel Line, Channel Command, Channel SomeEvent)
|
connect :: BotConfig -> IO (Bot, MVar BotStatus, Channel Line, Channel Command, Channel SomeEvent)
|
||||||
connect botConfig@BotConfig { .. } = do
|
connect botConfig@BotConfig { .. } = do
|
||||||
debug "Connecting ..."
|
debugM "Connecting ..."
|
||||||
socket <- connectToWithRetry
|
socket <- connectToWithRetry
|
||||||
hSetBuffering socket LineBuffering
|
hSetBuffering socket LineBuffering
|
||||||
debug "Connected"
|
debugM "Connected"
|
||||||
|
|
||||||
lineChan <- newChannel
|
lineChan <- newChannel
|
||||||
commandChan <- newChannel
|
commandChan <- newChannel
|
||||||
|
@ -33,22 +39,24 @@ connect botConfig@BotConfig { .. } = do
|
||||||
where
|
where
|
||||||
connectToWithRetry = connectTo (unpack server) (PortNumber (fromIntegral port))
|
connectToWithRetry = connectTo (unpack server) (PortNumber (fromIntegral port))
|
||||||
`catch` (\(e :: SomeException) -> do
|
`catch` (\(e :: SomeException) -> do
|
||||||
debug ("Error while connecting: " ++ pack (show e) ++ ". Waiting.")
|
errorM ("Error while connecting: " ++ show e ++ ". Waiting.")
|
||||||
threadDelay (5 * oneSec)
|
threadDelay (5 * oneSec)
|
||||||
connectToWithRetry)
|
connectToWithRetry)
|
||||||
|
|
||||||
newChannel = (,) <$> newChan <*> newEmptyMVar
|
newChannel = (,) <$> newChan <*> newEmptyMVar
|
||||||
|
|
||||||
loadMsgHandlers eventChan = flip (`foldM` mempty) msgHandlerNames $ \hMap msgHandlerName -> do
|
loadMsgHandlers eventChan = flip (`foldM` mempty) msgHandlerNames $ \hMap msgHandlerName -> do
|
||||||
debug $ "Loading msg handler: " ++ msgHandlerName
|
debugM . unpack $ "Loading msg handler: " ++ msgHandlerName
|
||||||
mMsgHandler <- mkMsgHandler botConfig eventChan msgHandlerName
|
mMsgHandler <- mkMsgHandler botConfig eventChan msgHandlerName
|
||||||
case mMsgHandler of
|
case mMsgHandler of
|
||||||
Nothing -> debug ("No msg handler found with name: " ++ msgHandlerName) >> return hMap
|
Nothing -> do
|
||||||
|
debugM . unpack $ "No msg handler found with name: " ++ msgHandlerName
|
||||||
|
return hMap
|
||||||
Just msgHandler -> return $ insertMap msgHandlerName msgHandler hMap
|
Just msgHandler -> return $ insertMap msgHandlerName msgHandler hMap
|
||||||
|
|
||||||
disconnect :: (Bot, MVar BotStatus, Channel Line, Channel Command, Channel SomeEvent) -> IO ()
|
disconnect :: (Bot, MVar BotStatus, Channel Line, Channel Command, Channel SomeEvent) -> IO ()
|
||||||
disconnect (Bot { .. }, mvBotStatus, (_, readLatch), (commandChan, sendLatch), (eventChan, eventLatch)) = do
|
disconnect (Bot { .. }, mvBotStatus, (_, readLatch), (commandChan, sendLatch), (eventChan, eventLatch)) = do
|
||||||
debug "Disconnecting ..."
|
debugM "Disconnecting ..."
|
||||||
sendCommand commandChan QuitCmd
|
sendCommand commandChan QuitCmd
|
||||||
awaitLatch sendLatch
|
awaitLatch sendLatch
|
||||||
swapMVar mvBotStatus Disconnected
|
swapMVar mvBotStatus Disconnected
|
||||||
|
@ -57,22 +65,22 @@ disconnect (Bot { .. }, mvBotStatus, (_, readLatch), (commandChan, sendLatch), (
|
||||||
awaitLatch eventLatch
|
awaitLatch eventLatch
|
||||||
|
|
||||||
unloadMsgHandlers
|
unloadMsgHandlers
|
||||||
hClose socket
|
handle (\(_ :: SomeException) -> return ()) $ hClose socket
|
||||||
debug "Disconnected"
|
debugM "Disconnected"
|
||||||
where
|
where
|
||||||
unloadMsgHandlers = forM_ (mapToList msgHandlers) $ \(msgHandlerName, msgHandler) -> do
|
unloadMsgHandlers = forM_ (mapToList msgHandlers) $ \(msgHandlerName, msgHandler) -> do
|
||||||
debug $ "Unloading msg handler: " ++ msgHandlerName
|
debugM . unpack $ "Unloading msg handler: " ++ msgHandlerName
|
||||||
stopMsgHandler msgHandler botConfig
|
stopMsgHandler msgHandler botConfig
|
||||||
|
|
||||||
runBot :: BotConfig -> IO ()
|
runBot :: BotConfig -> IO ()
|
||||||
runBot botConfig' = withSocketsDo $ do
|
runBot botConfig' = withSocketsDo $ do
|
||||||
hSetBuffering stdout LineBuffering
|
hSetBuffering stdout LineBuffering
|
||||||
debug "Running with config:"
|
debugM "Running with config:"
|
||||||
print botConfig
|
print botConfig
|
||||||
status <- runBot_
|
status <- runBot_
|
||||||
case status of
|
case status of
|
||||||
Disconnected -> debug "Restarting .." >> runBot botConfig
|
Disconnected -> debugM "Restarting .." >> runBot botConfig
|
||||||
Errored -> debug "Restarting .." >> runBot botConfig
|
Errored -> debugM "Restarting .." >> runBot botConfig
|
||||||
Interrupted -> return ()
|
Interrupted -> return ()
|
||||||
NickNotAvailable -> return ()
|
NickNotAvailable -> return ()
|
||||||
_ -> error "Unsupported status"
|
_ -> error "Unsupported status"
|
||||||
|
@ -81,8 +89,8 @@ runBot botConfig' = withSocketsDo $ do
|
||||||
|
|
||||||
handleErrors :: SomeException -> IO BotStatus
|
handleErrors :: SomeException -> IO BotStatus
|
||||||
handleErrors e = case fromException e of
|
handleErrors e = case fromException e of
|
||||||
Just UserInterrupt -> debug "User interrupt" >> return Interrupted
|
Just UserInterrupt -> debugM "User interrupt" >> return Interrupted
|
||||||
_ -> debug ("Exception! " ++ pack (show e)) >> return Errored
|
_ -> debugM ("Exception! " ++ show e) >> return Errored
|
||||||
|
|
||||||
runBot_ = bracket (connect botConfig) disconnect $
|
runBot_ = bracket (connect botConfig) disconnect $
|
||||||
\(bot, mvBotStatus, (lineChan, readLatch), (commandChan, sendLatch), eventChannel) ->
|
\(bot, mvBotStatus, (lineChan, readLatch), (commandChan, sendLatch), eventChannel) ->
|
||||||
|
|
|
@ -10,7 +10,7 @@ import qualified Data.Configurator as C
|
||||||
import qualified Data.Text.Format as TF
|
import qualified Data.Text.Format as TF
|
||||||
import qualified Data.Text.Format.Params as TF
|
import qualified Data.Text.Format.Params as TF
|
||||||
|
|
||||||
import ClassyPrelude hiding (try, (</>), (<.>), FilePath, log)
|
import ClassyPrelude hiding ((</>), (<.>), FilePath, log)
|
||||||
import Control.Concurrent.Lifted (Chan)
|
import Control.Concurrent.Lifted (Chan)
|
||||||
import Control.Exception.Lifted (mask_)
|
import Control.Exception.Lifted (mask_)
|
||||||
import Control.Monad.Reader (ask)
|
import Control.Monad.Reader (ask)
|
||||||
|
|
|
@ -3,23 +3,27 @@
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE RecordWildCards #-}
|
{-# LANGUAGE RecordWildCards #-}
|
||||||
{-# LANGUAGE ScopedTypeVariables #-}
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
|
|
||||||
module Network.IRC.Handlers.SongSearch (mkMsgHandler) where
|
module Network.IRC.Handlers.SongSearch (mkMsgHandler) where
|
||||||
|
|
||||||
import qualified Data.Configurator as CF
|
import qualified Data.Configurator as CF
|
||||||
|
import qualified System.Log.Logger as HSL
|
||||||
|
|
||||||
import ClassyPrelude hiding (try)
|
import ClassyPrelude
|
||||||
import Control.Concurrent.Lifted (Chan)
|
import Control.Concurrent.Lifted (Chan)
|
||||||
import Control.Exception.Lifted (try, evaluate)
|
import Control.Exception.Lifted (evaluate)
|
||||||
import Control.Monad.Reader (ask)
|
import Control.Monad.Reader (ask)
|
||||||
import Data.Aeson (FromJSON, parseJSON, Value (..), (.:))
|
import Data.Aeson (FromJSON, parseJSON, Value (..), (.:))
|
||||||
import Data.Aeson.Types (emptyArray)
|
import Data.Aeson.Types (emptyArray)
|
||||||
import Data.Text (strip)
|
import Data.Text (strip)
|
||||||
import Network.Curl.Aeson (curlAesonGet, CurlAesonException)
|
import Network.Curl.Aeson (curlAesonGet, CurlAesonException)
|
||||||
import Network.HTTP.Base (urlEncode)
|
import Network.HTTP.Base (urlEncode)
|
||||||
|
import System.Log.Logger.TH (deriveLoggers)
|
||||||
|
|
||||||
import Network.IRC.Types
|
import Network.IRC.Types
|
||||||
import Network.IRC.Util
|
|
||||||
|
$(deriveLoggers "HSL" [HSL.ERROR])
|
||||||
|
|
||||||
mkMsgHandler :: BotConfig -> Chan SomeEvent -> MsgHandlerName -> IO (Maybe MsgHandler)
|
mkMsgHandler :: BotConfig -> Chan SomeEvent -> MsgHandlerName -> IO (Maybe MsgHandler)
|
||||||
mkMsgHandler _ _ "songsearch" = return . Just $ newMsgHandler { onMessage = songSearch }
|
mkMsgHandler _ _ "songsearch" = return . Just $ newMsgHandler { onMessage = songSearch }
|
||||||
|
@ -42,7 +46,7 @@ songSearch ChannelMsg { .. }
|
||||||
mApiKey <- CF.lookup config "songsearch.tinysong_apikey"
|
mApiKey <- CF.lookup config "songsearch.tinysong_apikey"
|
||||||
map (Just . ChannelMsgReply) $ case mApiKey of
|
map (Just . ChannelMsgReply) $ case mApiKey of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
debug "tinysong api key not found in config"
|
errorM "tinysong api key not found in config"
|
||||||
return $ "Error while searching for " ++ query
|
return $ "Error while searching for " ++ query
|
||||||
Just apiKey -> do
|
Just apiKey -> do
|
||||||
let apiUrl = "http://tinysong.com/b/" ++ urlEncode (unpack query)
|
let apiUrl = "http://tinysong.com/b/" ++ urlEncode (unpack query)
|
||||||
|
|
|
@ -28,7 +28,7 @@ module Network.IRC.Types
|
||||||
, newMsgHandler
|
, newMsgHandler
|
||||||
, handleMessage
|
, handleMessage
|
||||||
, handleEvent
|
, handleEvent
|
||||||
, stopMsgHandler)
|
, stopMsgHandler )
|
||||||
where
|
where
|
||||||
|
|
||||||
import ClassyPrelude
|
import ClassyPrelude
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
module Network.IRC.Util where
|
module Network.IRC.Util where
|
||||||
|
|
||||||
import qualified Data.Text.Format as TF
|
--import qualified Data.Text.Format as TF
|
||||||
import qualified Data.Text.Format.Params as TF
|
--import qualified Data.Text.Format.Params as TF
|
||||||
|
|
||||||
import ClassyPrelude
|
import ClassyPrelude
|
||||||
import Control.Concurrent.Lifted (Chan)
|
import Control.Concurrent.Lifted (Chan)
|
||||||
|
@ -13,11 +13,6 @@ import Control.Concurrent.Lifted (Chan)
|
||||||
oneSec :: Int
|
oneSec :: Int
|
||||||
oneSec = 1000000
|
oneSec = 1000000
|
||||||
|
|
||||||
debug :: Text -> IO ()
|
|
||||||
debug msg = do
|
|
||||||
time <- getCurrentTime
|
|
||||||
TF.print "[{}] {}\n" $ TF.buildParams (formatTime defaultTimeLocale "%F %T" time, msg)
|
|
||||||
|
|
||||||
type Latch = MVar ()
|
type Latch = MVar ()
|
||||||
|
|
||||||
latchIt :: Latch -> IO ()
|
latchIt :: Latch -> IO ()
|
||||||
|
|
|
@ -51,23 +51,25 @@ cabal-version: >=1.10
|
||||||
library
|
library
|
||||||
other-extensions: Safe
|
other-extensions: Safe
|
||||||
|
|
||||||
build-depends: base >=4.5 && <4.8,
|
build-depends: base >=4.5 && <4.8,
|
||||||
text >=0.11 && <0.12,
|
text >=0.11 && <0.12,
|
||||||
mtl >=2.1 && <2.2,
|
mtl >=2.1 && <2.2,
|
||||||
network >=2.3 && <2.5,
|
network >=2.3 && <2.5,
|
||||||
configurator >= 0.2,
|
configurator >= 0.2,
|
||||||
time >=1.4.0,
|
time >=1.4.0,
|
||||||
curl-aeson ==0.0.3,
|
curl-aeson ==0.0.3,
|
||||||
aeson >=0.6.0.0,
|
aeson >=0.6.0.0,
|
||||||
HTTP >=4000,
|
HTTP >=4000,
|
||||||
transformers >=0.3,
|
transformers >=0.3,
|
||||||
classy-prelude ==0.9.1,
|
classy-prelude ==0.9.1,
|
||||||
text-format >= 0.3.1,
|
text-format >= 0.3.1,
|
||||||
filepath >=1.3,
|
filepath >=1.3,
|
||||||
directory >=1.2,
|
directory >=1.2,
|
||||||
lifted-base >=0.2,
|
lifted-base >=0.2,
|
||||||
unix >=2.7,
|
unix >=2.7,
|
||||||
convertible >=1.1
|
convertible >=1.1,
|
||||||
|
hslogger >=1.2.4,
|
||||||
|
hslogger-template >=2.0
|
||||||
|
|
||||||
exposed-modules: Network.IRC.Types, Network.IRC.Protocol,
|
exposed-modules: Network.IRC.Types, Network.IRC.Protocol,
|
||||||
Network.IRC.Handlers, Network.IRC.Client
|
Network.IRC.Handlers, Network.IRC.Client
|
||||||
|
@ -88,23 +90,25 @@ executable hask-irc
|
||||||
other-extensions: Safe
|
other-extensions: Safe
|
||||||
|
|
||||||
-- Other library packages from which modules are imported.
|
-- Other library packages from which modules are imported.
|
||||||
build-depends: base >=4.5 && <4.8,
|
build-depends: base >=4.5 && <4.8,
|
||||||
text >=0.11 && <0.12,
|
text >=0.11 && <0.12,
|
||||||
mtl >=2.1 && <2.2,
|
mtl >=2.1 && <2.2,
|
||||||
network >=2.3 && <2.5,
|
network >=2.3 && <2.5,
|
||||||
configurator >= 0.2,
|
configurator >= 0.2,
|
||||||
time >=1.4.0,
|
time >=1.4.0,
|
||||||
curl-aeson ==0.0.3,
|
curl-aeson ==0.0.3,
|
||||||
aeson >=0.6.0.0,
|
aeson >=0.6.0.0,
|
||||||
HTTP >=4000,
|
HTTP >=4000,
|
||||||
transformers >=0.3,
|
transformers >=0.3,
|
||||||
classy-prelude ==0.9.1,
|
classy-prelude ==0.9.1,
|
||||||
text-format >= 0.3.1,
|
text-format >= 0.3.1,
|
||||||
filepath >=1.3,
|
filepath >=1.3,
|
||||||
directory >=1.2,
|
directory >=1.2,
|
||||||
lifted-base >=0.2,
|
lifted-base >=0.2,
|
||||||
unix >=2.7,
|
unix >=2.7,
|
||||||
convertible >=1.1
|
convertible >=1.1,
|
||||||
|
hslogger >=1.2.4,
|
||||||
|
hslogger-template >=2.0
|
||||||
|
|
||||||
-- Directories containing source files.
|
-- Directories containing source files.
|
||||||
-- hs-source-dirs:
|
-- hs-source-dirs:
|
||||||
|
|
Loading…
Reference in New Issue