Archived
1
0
Fork 0

Added the quote module.

This commit is contained in:
Julien Dessaux 2010-04-25 17:46:13 +02:00
parent b6d119cf5b
commit c20cfe88b3
3 changed files with 127 additions and 21 deletions

View file

@ -5,49 +5,154 @@ module Plugins.Quote
import Control.Concurrent.Chan import Control.Concurrent.Chan
import Control.Exception import Control.Exception
import Control.Monad.State import Control.Monad.State
import qualified Data.Map as M
import Data.Maybe(fromMaybe)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO
import Data.Time
import IO hiding (catch)
import Prelude hiding (catch) import Prelude hiding (catch)
import System.Time (ClockTime) import System.Random(randomRIO)
import Hsbot.IRCPlugin import Hsbot.IRCPlugin
import Hsbot.Types import Hsbot.Types
import Hsbot.Utils import Hsbot.Utils
-- | A quote element
data QuoteElt = QuoteElt
{ eltQuoter :: String
, eltQuote :: String
} deriving (Read, Show)
-- | A quote object -- | A quote object
data Quote = Quote data Quote = Quote
{ quoter :: String { quoter :: String
, quote :: [String] , quote :: [QuoteElt]
, quoteTime :: ClockTime , quoteTime :: UTCTime
, votes :: Int , votes :: Int
} deriving (Show) } deriving (Read, Show)
-- | A QuoteBot state -- | A QuoteBot state
type QuoteDB = [Quote] data QuoteBotState = QuoteBotState
{ nextQuoteId :: Integer
, quoteBotDB :: M.Map Integer Quote
, quotesInProgress :: M.Map Integer Quote
} deriving (Read, Show)
-- | The QuoteBot monad -- | The QuoteBot monad
type QuoteBot a = StateT QuoteDB IO a type QuoteBot a = StateT QuoteBotState (StateT PluginState IO) a
-- | The plugin's main entry point -- | The plugin's main entry point
mainQuote :: Chan BotMsg -> Chan BotMsg -> IO () mainQuote :: Chan BotMsg -> Chan BotMsg -> IO ()
mainQuote serverChan chan = do mainQuote serverChan chan = do
-- First of all we restore the database
txtQuoteBot <- TIO.readFile $ "quotedb.txt"
let quoteBot = read (T.unpack txtQuoteBot) :: QuoteBotState
-- The plugin main loop
let plugin = PluginState "Quote" serverChan chan let plugin = PluginState "Quote" serverChan chan
evalStateT (mapM_ sendRegisterCommand ["quote"]) plugin evalStateT (mapM_ sendRegisterCommand ["quote"]) plugin
_ <- (evalStateT (run quoteBot) plugin) `catch` (\(_ :: AsyncException) -> return quoteBot) _ <- (evalStateT (run quoteBot) plugin) `catch` (\(_ :: AsyncException) -> return quoteBot)
evalStateT (mapM_ sendUnregisterCommand ["quote"]) plugin evalStateT (mapM_ sendUnregisterCommand ["quote"]) plugin
-- | The IrcPlugin monad main function -- | The IrcPlugin monad main function
run :: IrcPlugin () run :: QuoteBotState -> IrcPlugin (QuoteBotState)
run = forever $ do run quoteBot = do
msg <- readMsg msg <- readMsg
eval msg quoteBot' <- eval msg
run quoteBot'
where where
eval :: BotMsg -> IrcPlugin () -- | evaluate what we just received
eval (InternalCmd intCmd) = do eval :: BotMsg -> IrcPlugin (QuoteBotState)
case intCmdCmd intCmd of eval (InternalCmd intCmd)
"RUN" -> let stuff = words $ intCmdMsg intCmd | intCmdCmd intCmd == "RUN" = do
in case head stuff of quoteBot' <- execStateT (runCommand intCmd) quoteBot
"quote" -> lift $ trace $ "Quote module has been invoked for: " ++ (show intCmd) return quoteBot'
_ -> lift $ trace $ show intCmd -- TODO : help message | otherwise = do
_ -> lift $ trace $ show intCmd lift . trace $ show intCmd
eval (InputMsg msg) = return () return quoteBot
eval _ = return () eval (InputMsg _) = return (quoteBot)
eval _ = return (quoteBot)
-- | run a command we received
runCommand :: IntCmd -> QuoteBot ()
runCommand intCmd
| theCommand == "quote" = runQuoteCommand
| otherwise = do
lift . lift . trace $ show intCmd -- TODO : help message
where
-- | the message is a quote command
runQuoteCommand :: QuoteBot ()
| length args == 0 = do
quoteDB <- gets quoteBotDB
x <- liftIO $ randomRIO (0, (length $ M.keys quoteDB) - 1)
mapM_ (lift . answerMsg request) (formatQuote (M.keys quoteDB !! x) (M.elems quoteDB !! x))
| otherwise = do
dispatchQuoteCmd $ head args
-- | quote command dispatcher
dispatchQuoteCmd :: String -> QuoteBot ()
dispatchQuoteCmd cmd
| cmd == "start" = do
quoteBot <- get
now <- liftIO $ getCurrentTime
let sender = takeWhile (/= '!') $ fromMaybe "ARGH" (prefix request)
newQuote = Quote sender [(quoteElt stuff)] now 0
quoteId = nextQuoteId quoteBot
quotesInProgress' = M.insert quoteId newQuote (quotesInProgress quoteBot)
put $ quoteBot { nextQuoteId = quoteId + 1, quotesInProgress = quotesInProgress' }
lift $ answerMsg request ("New quoteId : " ++ show quoteId)
syncQuoteBot
| cmd == "append" = do
quoteBot <- get
case reads (head stuff) of
[(quoteId :: Integer,"")] -> do
case M.lookup quoteId (quotesInProgress quoteBot) of
Just theQuote -> do
let newQuote = theQuote { quote = (quoteElt $ tail stuff) : (quote theQuote) }
quotesInProgress' = M.insert quoteId newQuote (quotesInProgress quoteBot)
put $ quoteBot { quotesInProgress = quotesInProgress' }
syncQuoteBot
Nothing -> lift $ answerMsg request ("quoteId not found : " ++ (show quoteId))
_ -> lift $ answerMsg request ("Invalid quoteId : " ++ (head stuff))
| cmd == "commit" = do
quoteBot <- get
case reads (head stuff) of
[(quoteId :: Integer,"")] -> do
case M.lookup quoteId (quotesInProgress quoteBot) of
Just theQuote -> do
let quoteBotDB' = M.insert quoteId theQuote (quoteBotDB quoteBot)
quotesInProgress' = M.delete quoteId (quotesInProgress quoteBot)
put $ quoteBot { quoteBotDB = quoteBotDB', quotesInProgress = quotesInProgress' }
syncQuoteBot
Nothing -> lift $ answerMsg request ("quoteId not found : " ++ (show quoteId))
_ -> lift $ answerMsg request ("Invalid quoteId : " ++ (head stuff))
-- | cmd == "abort" =
| otherwise = lift $ answerMsg request ("Invalid command : " ++ cmd)
-- | Gets the new QuoteElt
quoteElt :: [String] -> QuoteElt
quoteElt msg = do
let budy = head $ msg
theQuote = unwords . tail $ msg
QuoteElt budy theQuote
-- | utilities
params = words . intCmdMsg $ intCmd
theCommand = head params
args = tail params
stuff = tail args
request = intCmdBotMsg intCmd
-- | The function that sync the quoteDB on disk
syncQuoteBot :: QuoteBot ()
syncQuoteBot = do
quoteBot <- get
file' <- liftIO $ openFile "quotedb.txt" WriteMode
liftIO . hPutStr file' $ show quoteBot
liftIO $ hClose file'
formatQuote :: Integer -> Quote -> [String]
formatQuote quoteId theQuote =
("+---| " ++ (show quoteId) ++ " |-- Reported by " ++ (quoter theQuote) ++ " on " ++ (show $ quoteTime theQuote)) :
foldl (\acc x -> formatQuoteElt x : acc) ["`------------------------------------------"] (quote theQuote)
where
formatQuoteElt :: QuoteElt -> String
formatQuoteElt quoteElt = "| <" ++ (eltQuoter quoteElt) ++ "> " ++ (eltQuote quoteElt)

2
README
View file

@ -1,5 +1,5 @@
Dependances : Dependances :
------------- -------------
hs-plugin hs-plugin
haskell-irc text

3
TODO
View file

@ -1,6 +1,5 @@
:julien!~julien@ogu21.corp PRIVMSG #shbot :@quote graou snif :julien!~julien@ogu21.corp PRIVMSG #shbot :@quote graou snif
* Write the quote module
* write the vote system for the quote module * write the vote system for the quote module
* only the quote reporter should be able to edit it * only the quote reporter should be able to edit it
* detect too identical quoting in a raw, or implement quote abort * detect too identical quoting in a raw, or implement quote abort
@ -23,4 +22,6 @@
* Make the bot auto-reconnect (/!\ admin plugin!) * Make the bot auto-reconnect (/!\ admin plugin!)
* discard all trace with a color param and replace those with functions info/warn/error/debug * discard all trace with a color param and replace those with functions info/warn/error/debug
* write a safe reload : try reload before unloading * write a safe reload : try reload before unloading
* remove from Types.hs what can be removed from it