module Needles.Bot.Trigger (
MessageInfo(..)
, MessageType(..)
, Trigger
, TriggerAct
, mkTrigger
, mkTrigger_
, send
, printLn
, getVar
, storeVar
, duraGet
, duraStore
, sendChat
, sendPm
, command
, clusterTrigger
) where
import Control.Applicative
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Trans.State.Strict
import Data.Text (Text, append)
import qualified Data.Text as T
import qualified Data.Text.IO as TIO (putStrLn)
import Needles.Bot.Types
mkTrigger :: (MessageInfo -> Bool) -> (MessageInfo -> TriggerAct a b c)
-> a -> Trigger
mkTrigger p action s = Trigger p actFun
where actFun mi = do
let baked = bakeAction (action mi) s
(_, s') <- baked
return (mkTrigger p action s')
mkTrigger_ :: (MessageInfo -> Bool) -> (MessageInfo -> TriggerAct () b c)
-> Trigger
mkTrigger_ p action = mkTrigger p action ()
bakeAction :: TriggerAct a b c -> a -> StateT BotState IO (c, a)
bakeAction (Send text) a = do
sender <- bMessChan <$> get
liftIO $ mapM_ sender (T.lines text)
return ((), a)
bakeAction (PrintLn text) a = liftIO $ TIO.putStrLn text >> return ((), a)
bakeAction GetVar a = return (a, a)
bakeAction (StoreVar a') _ = return ((), a')
bakeAction DuraGet _ = error "Durable storage not implemented yet"
bakeAction (DuraStore _) _ = error "Durable storage not implemented yet"
bakeAction (DoIO io) a = flip (,) a <$> liftIO io
bakeAction (Bind ma k) a = do
(res, a') <- firstAct
let secondAct = k res
bakeAction secondAct a'
where firstAct = bakeAction ma a
bakeAction (Pure c) a = return (c, a)
send :: Text -> TriggerAct a b ()
send = Send
printLn :: Text -> TriggerAct a b ()
printLn = PrintLn
getVar :: TriggerAct a b a
getVar = GetVar
storeVar :: a -> TriggerAct a b ()
storeVar = StoreVar
duraGet :: TriggerAct a b b
duraGet = DuraGet
duraStore :: b -> TriggerAct a b ()
duraStore = DuraStore
sendChat :: Text -> Text -> TriggerAct a b ()
sendChat r m = mapM_ send roomMessages
where roomMessages = map (append roomPrefix) (T.lines m)
roomPrefix = T.snoc r '|'
sendPm :: Text -> Text -> TriggerAct a b ()
sendPm u m = mapM_ send userMessages
where userMessages = map (append userPrefix) (T.lines m)
userPrefix = T.snoc (append "|/pm " u) ','
command :: Text -> Text -> TriggerAct a b ()
command r c = send (append roomPrefix c)
where roomPrefix = T.snoc r '|'
clusterTrigger :: forall a b. [(MessageInfo -> Bool, MessageInfo -> TriggerAct a b ())] -> a -> Trigger
clusterTrigger triggers initState = mkTrigger clusterPred clusterAction initState
where clusterPred mi = any ($mi) . map fst $ triggers
clusterAction :: MessageInfo -> TriggerAct a b ()
clusterAction mi = mapM_ (checkAndDo mi) triggers
checkAndDo mi (p, act) = if p mi then act mi else return ()