module Pakej.Widget.Memory
(
#ifdef TEST
Mem(..)
#else
Mem
#endif
, Query
, widget
, ratio
, total
, available
, used
, lookup
, getData
#ifdef TEST
, parseData
, parseLine
, memoryDataError
#endif
) where
import Control.Applicative
import Data.Int (Int64)
import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import qualified Data.Text.Read as Text
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Traversable (traverse)
import Prelude hiding (lookup)
import System.IO.Error (catchIOError)
import Pakej.Widget (PakejWidget, text)
newtype Mem = Mem { unMem :: HashMap Text Int64 } deriving (Show, Eq)
type Query a = Mem -> Maybe a
widget
:: Text
-> Query Text
-> PakejWidget Text
widget z q = text $ either (const z) (maybe z id . q) <$> getData "/proc/meminfo"
ratio :: Fractional a => Query a -> Query a -> Query a
ratio = (liftA2.liftA2) (/)
total :: Num a => Query a
total = lookup "MemTotal"
available :: Num a => Query a
available mem = lookup "MemAvailable" mem <|> availableApprox mem
availableApprox :: Num a => Query a
availableApprox mem = fmap sum (traverse (\k -> lookup k mem) ["MemFree", "Buffers", "Cached"])
used :: Num a => Query a
used = (liftA2.liftA2) () total available
lookup :: Num a => Text -> Query a
lookup k = fmap fromIntegral . HashMap.lookup k . unMem
getData :: FilePath -> IO (Either Text Mem)
getData = handleIOError (return . memoryDataError . Text.pack . show) . fmap parseData . Text.readFile
handleIOError :: (IOError -> IO a) -> IO a -> IO a
handleIOError = flip catchIOError
parseData :: Text -> Either Text Mem
parseData = fmap (Mem . HashMap.fromList) . parseFile
parseFile :: Text -> Either Text [(Text, Int64)]
parseFile = traverse parseLine . Text.lines
parseLine :: Text -> Either Text (Text, Int64)
parseLine l = case Text.words l of
(pre : n : _)
| Just pre' <- Text.stripSuffix ":" pre
, Right (n', _) <- Text.decimal n -> Right (pre', n')
_ -> memoryDataError $ "bad line: " <> l
memoryDataError :: Text -> Either Text a
memoryDataError x = Left $ "Pakej.Widget.Memory: " <> x