Add lenses to listing and use them in the example bot

This commit is contained in:
Joscha 2020-04-09 10:40:24 +00:00
parent 9a476d9371
commit 822bb9efad
2 changed files with 70 additions and 41 deletions

View file

@ -1,7 +1,13 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
-- | This module contains an example implementation of a small bot. It is a good
-- starting point if you want to create your own bot.
--
-- The example bot uses lenses for its state because they vastly reduce the
-- amount of code required to update the 'Listing' inside the state. It is
-- entirely possible to use haboli without lenses though, should you want to do
-- that.
module Haboli.Euphoria.ExampleBot
( exampleBot
@ -14,15 +20,19 @@ import Data.List
import qualified Data.Map.Strict as Map
import qualified Data.Text as T
import Data.Time
import Lens.Micro
import Lens.Micro.TH
import Haboli.Euphoria
import Haboli.Euphoria.Botrulez
data BotState = BotState
{ botStartTime :: UTCTime
, botListing :: Listing
{ _botStartTime :: UTCTime
, _botListing :: Listing
} deriving (Show)
makeLenses ''BotState
-- | A small example bot. Takes a room password as its first argument. You can
-- run this bot in [&test](https://euphoria.io/room/test) like this:
--
@ -33,27 +43,27 @@ exampleBot mPasswd = do
initialEvents <- untilConnected $
respondingToBounce mPasswd $
respondingToPing nextEvent
listing <- preferNick "ExampleBot" $ newListing initialEvents
stateVar <- liftIO $ newMVar $ BotState startTime listing
let initialState = BotState startTime $ newListing initialEvents
stateVar <- liftIO $ newMVar initialState
preferNickVia botListing stateVar "ExampleBot"
botMain stateVar
botMain :: MVar BotState -> Client T.Text ()
botMain stateVar = forever $ do
event <- respondingToCommands (getCommands stateVar) $
respondingToPing nextEvent
-- Update the listing
liftIO $ modifyMVar_ stateVar $ \state ->
pure state{botListing = updateFromEvent event $ botListing state}
updateFromEventVia botListing stateVar event
getCommands :: MVar BotState -> Client e [Command T.Text]
getCommands stateVar = do
state <- liftIO $ readMVar stateVar
let name = svNick $ self $ botListing state
let name = state ^. botListing . lsSelfL . svNickL
pure
[ botrulezPingGeneral
, botrulezPingSpecific name
, botrulezHelpSpecific name "I am an example bot for https://github.com/Garmelon/haboli/."
, botrulezUptimeSpecific name $ botStartTime state
, botrulezHelpSpecific name
"I am an example bot for https://github.com/Garmelon/haboli/."
, botrulezUptimeSpecific name $ state ^. botStartTime
, botrulezKillSpecific name
, cmdSpecific "hug" name $ \msg -> void $ reply msg "/me hugs back"
, cmdHello
@ -68,15 +78,12 @@ cmdHello = cmdGeneral "hello" $ \msg -> do
cmdNick :: MVar BotState -> T.Text -> Command e
cmdNick stateVar name = cmdSpecificArgs "nick" name $ \msg args -> do
-- Update the listing while updating the nick
state <- liftIO $ takeMVar stateVar
listing' <- preferNick args $ botListing state
liftIO $ putMVar stateVar state{botListing = listing'}
preferNickVia botListing stateVar args
void $ reply msg "Is this better?"
cmdWho :: MVar BotState -> Command e
cmdWho stateVar = cmdGeneral "who" $ \msg -> do
state <- liftIO $ readMVar stateVar
let people = others $ botListing state
let people = state ^. botListing . lsOthersL
nicks = sort $ map svNick $ Map.elems people
void $ reply msg $ T.intercalate "\n" nicks