irc-fun-bot-0.2.0.0: src/Network/IRC/Fun/Bot/Internal/Persist.hs
{- This file is part of irc-fun-bot.
-
- Written in 2015 by fr33domlover <fr33domlover@rel4tion.org>.
-
- ♡ Copying is an act of love. Please copy, reuse and share.
-
- The author(s) have dedicated all copyright and related and neighboring
- rights to this software to the public domain worldwide. This software is
- distributed without any warranty.
-
- You should have received a copy of the CC0 Public Domain Dedication along
- with this software. If not, see
- <http://creativecommons.org/publicdomain/zero/1.0/>.
-}
-- For JSON field names
{-# LANGUAGE OverloadedStrings #-}
module Network.IRC.Fun.Bot.Internal.Persist
( loadBotState
, mkSaveBotState
, saveBotState
)
where
import Control.Applicative
import Control.Monad (mzero)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.RWS
import Data.Aeson
import qualified Data.HashMap.Lazy as M
import Data.Maybe (isJust)
import Data.Settings.Persist
import Data.Time.Interval
import Data.Time.Units (Microsecond)
import Network.IRC.Fun.Bot.Internal.IrcLog (makeLogger)
import Network.IRC.Fun.Bot.Internal.Types
import Network.IRC.Fun.Client.NickTracker (newNetwork)
data ChannelStateJ = ChannelStateJ Bool Bool
data BotStateJ = BotStateJ (M.HashMap String ChannelStateJ)
toJ :: BotState s -> BotStateJ
toJ bstate = BotStateJ $ M.map f $ chanstate bstate
where
f (ChannelState track mlogger) = ChannelStateJ track (isJust mlogger)
fromJ :: BotStateJ -> BotEnv e s -> s -> IO (BotState s)
fromJ (BotStateJ chansJ) env pub = do
let f chan (ChannelStateJ tracking logging) = do
mlogger <-
if logging
then fmap Just $ makeLogger env chan
else return Nothing
return $ ChannelState tracking mlogger
defstate = ChannelStateJ False False
chansConf = M.fromList $ zip (channels $ config env) (repeat defstate)
chansAll = chansJ `M.union` chansConf
chans <- M.traverseWithKey f chansAll
return $ BotState newNetwork chans pub
instance FromJSON ChannelStateJ where
parseJSON (Object o) =
ChannelStateJ <$>
o .: "track" <*>
o .: "log"
parseJSON _ = mzero
instance ToJSON ChannelStateJ where
toJSON (ChannelStateJ tracking logging) = object
[ "track" .= tracking
, "log" .= logging
]
instance FromJSON BotStateJ where
parseJSON (Object o) =
BotStateJ <$>
o .: "channels"
parseJSON _ = mzero
instance ToJSON BotStateJ where
toJSON (BotStateJ chans) = object
[ "channels" .= chans
]
instance ToJSON (BotState s) where
toJSON bstate = toJSON $ toJ bstate
loadBotState :: BotEnv e s -> s -> IO (BotState s)
loadBotState env pub = do
r <- loadSettings $ stateFile $ config env
case r of
Left (False, e) -> error $ "Failed to read state file: " ++ e
Left (True, e) -> error $ "Failed to parse state file: " ++ e
Right sj -> fromJ sj env pub
mkSaveBotState :: Config -> IO (BotState s -> IO ())
mkSaveBotState conf =
let iv = fromInteger $ microseconds $ saveInterval conf :: Microsecond
in mkSaveSettings iv (stateFile conf)
saveBotState :: Session e s ()
saveBotState = do
bstate <- get
save <- asks saveState
liftIO $ save bstate