{-# LANGUAGE TemplateHaskell #-} module Lambdabot.Main ( lambdabotVersion , Config , DSum(..) , lambdabotMain , Modules , modules , module Lambdabot.Plugin.Core , Priority(..) ) where import Lambdabot.Bot import Lambdabot.Config import Lambdabot.Logging import Lambdabot.Module import Lambdabot.Monad import Lambdabot.Plugin.Core import Lambdabot.State import Lambdabot.Util import Lambdabot.Util.Signals import Control.Exception.Lifted as E import Data.Dependent.Sum import Data.List import Data.Typeable import Data.Version import Language.Haskell.TH import Paths_lambdabot_core (version) import System.Exit import System.Log.Formatter import qualified System.Log.Logger as L import System.Log.Handler.Simple import Network (withSocketsDo) lambdabotVersion :: Version lambdabotVersion = version setupLogging :: LB () setupLogging = do stream <- getConfig consoleLogHandle level <- getConfig consoleLogLevel format <- getConfig consoleLogFormat unformattedHandler <- io (streamHandler stream level) let consoleHandler = unformattedHandler { formatter = simpleLogFormatter format } setRoot <- getConfig replaceRootLogger io $ if setRoot then L.updateGlobalLogger L.rootLoggerName (L.setLevel level . L.setHandlers [consoleHandler]) else L.updateGlobalLogger "Lambdabot" (L.setLevel level . L.addHandler consoleHandler) -- | The Lambdabot entry point. -- Initialise plugins, connect, and run the bot in the LB monad -- -- Also, handle any fatal exceptions (such as non-recoverable signals), -- (i.e. print a message and exit). Non-fatal exceptions should be dealt -- with in the mainLoop or further down. lambdabotMain :: LB () -> [DSum Config] -> IO ExitCode lambdabotMain initialise cfg = withSocketsDo . withIrcSignalCatch $ do rost <- initRoState cfg r <- try $ evalLB (do setupLogging noticeM "Initialising plugins" initialise noticeM "Done loading plugins" reportInitDone rost mainLoop return ExitSuccess) rost initRwState -- clean up and go home case r of Left (SomeException er) -> do case cast er of Just code -> return code Nothing -> do putStrLn "exception:" print er return (ExitFailure 1) Right code -> return code -- Actually, this isn't a loop anymore. TODO: better name. mainLoop :: LB () mainLoop = do waitForQuit `E.catch` (\e@SomeException{} -> errorM (show e)) -- catch anything, print informative message, and clean up withAllModules moduleExit flushModuleState ------------------------------------------------------------------------ type Modules = LB () modules :: [String] -> Q Exp modules xs = [| sequence_ $(listE $ map instalify (nub xs)) |] where instalify x = let module' = varE $ mkName (x ++ "Plugin") in [| ircLoadModule $module' x |]