{-# LANGUAGE TemplateHaskell #-}
module Matterhorn.LastRunState
( LastRunState
, lrsHost
, lrsPort
, lrsUserId
, lrsSelectedChannelId
, writeLastRunState
, readLastRunState
, isValidLastRunState
)
where
import Prelude ()
import Matterhorn.Prelude
import Control.Monad.Trans.Except
import qualified Data.Aeson as A
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Lens.Micro.Platform ( makeLenses )
import System.Directory ( createDirectoryIfMissing )
import System.FilePath ( dropFileName )
import qualified System.Posix.Files as P
import qualified System.Posix.Types as P
import Network.Mattermost.Lenses
import Network.Mattermost.Types
import Matterhorn.FilePaths
import Matterhorn.IOUtil
import Matterhorn.Types
data LastRunState = LastRunState
{ _lrsHost :: Hostname
, _lrsPort :: Port
, _lrsUserId :: UserId
, _lrsSelectedChannelId :: ChannelId
}
instance A.ToJSON LastRunState where
toJSON lrs = A.object [ "host" A..= _lrsHost lrs
, "port" A..= _lrsPort lrs
, "user_id" A..= _lrsUserId lrs
, "sel_channel_id" A..= _lrsSelectedChannelId lrs
]
instance A.FromJSON LastRunState where
parseJSON = A.withObject "LastRunState" $ \v ->
LastRunState
<$> v A..: "host"
<*> v A..: "port"
<*> v A..: "user_id"
<*> v A..: "sel_channel_id"
makeLenses ''LastRunState
toLastRunState :: ChatState -> LastRunState
toLastRunState cs = LastRunState
{ _lrsHost = cs^.csResources.crConn.cdHostnameL
, _lrsPort = cs^.csResources.crConn.cdPortL
, _lrsUserId = myUserId cs
, _lrsSelectedChannelId = cs^.csCurrentChannelId
}
lastRunStateFileMode :: P.FileMode
lastRunStateFileMode = P.unionFileModes P.ownerReadMode P.ownerWriteMode
writeLastRunState :: ChatState -> IO ()
writeLastRunState cs =
when (cs^.csCurrentChannel.ccInfo.cdType `elem` [Ordinary, Private]) $ do
let runState = toLastRunState cs
tId = myTeamId cs
lastRunStateFile <- lastRunStateFilePath $ unId $ toId tId
createDirectoryIfMissing True $ dropFileName lastRunStateFile
BS.writeFile lastRunStateFile $ LBS.toStrict $ A.encode runState
P.setFileMode lastRunStateFile lastRunStateFileMode
readLastRunState :: TeamId -> IO (Either String LastRunState)
readLastRunState tId = runExceptT $ do
contents <- convertIOException $
lastRunStateFilePath (unId $ toId tId) >>= BS.readFile
case A.eitherDecodeStrict' contents of
Right val -> return val
Left err -> throwE $ "Failed to parse lastRunState file: " ++ err
isValidLastRunState :: ChatResources -> User -> LastRunState -> Bool
isValidLastRunState cr me rs =
rs^.lrsHost == cr^.crConn.cdHostnameL
&& rs^.lrsPort == cr^.crConn.cdPortL
&& rs^.lrsUserId == me^.userIdL