{-# LANGUAGE TupleSections #-}
-----------------------------------------------------------------------------
-- |
-- Module      : System.Taffybar.Information.CPU2
-- Copyright   : (c) José A. Romero L.
-- License     : BSD3-style (see LICENSE)
--
-- Maintainer  : José A. Romero L. <escherdragon@gmail.com>
-- Stability   : unstable
-- Portability : unportable
--
-- Provides information about used CPU times, obtained from parsing the
-- @\/proc\/stat@ file using some of the facilities included in the
-- "System.Taffybar.Information.StreamInfo" module.
-- And also provides information about the temperature of cores.
-- (Now supports only physical cpu).
--
-----------------------------------------------------------------------------

module System.Taffybar.Information.CPU2 where

import Control.Monad
import Data.List
import Data.Maybe
import Safe
import System.Directory
import System.FilePath
import System.Taffybar.Information.StreamInfo

-- | Returns a list of 5 to 7 elements containing all the values available for
-- the given core (or all of them aggregated, if "cpu" is passed).
getCPUInfo :: String -> IO [Int]
getCPUInfo :: [Char] -> IO [Int]
getCPUInfo = [Char] -> ([Char] -> [([Char], [Int])]) -> [Char] -> IO [Int]
forall a. [Char] -> ([Char] -> [([Char], [a])]) -> [Char] -> IO [a]
getParsedInfo [Char]
"/proc/stat" [Char] -> [([Char], [Int])]
parse

parse :: String -> [(String, [Int])]
parse :: [Char] -> [([Char], [Int])]
parse = ([Char] -> Maybe ([Char], [Int])) -> [[Char]] -> [([Char], [Int])]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ([[Char]] -> Maybe ([Char], [Int])
tuplize ([[Char]] -> Maybe ([Char], [Int]))
-> ([Char] -> [[Char]]) -> [Char] -> Maybe ([Char], [Int])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]]
words) ([[Char]] -> [([Char], [Int])])
-> ([Char] -> [[Char]]) -> [Char] -> [([Char], [Int])]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char] -> Bool) -> [[Char]] -> [[Char]]
forall a. (a -> Bool) -> [a] -> [a]
filter (\[Char]
x -> Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
take Int
3 [Char]
x [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char]
"cpu") ([[Char]] -> [[Char]])
-> ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]]
lines

tuplize :: [String] -> Maybe (String, [Int])
tuplize :: [[Char]] -> Maybe ([Char], [Int])
tuplize [[Char]]
s = do
  [Char]
cpu <- [[Char]]
s [[Char]] -> Int -> Maybe [Char]
forall a. [a] -> Int -> Maybe a
`atMay` Int
0
  ([Char], [Int]) -> Maybe ([Char], [Int])
forall (m :: * -> *) a. Monad m => a -> m a
return ([Char]
cpu, ([Char] -> Int) -> [[Char]] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> [Char] -> Int
forall a. Read a => a -> [Char] -> a
readDef (-Int
1)) ([[Char]] -> [[Char]]
forall a. [a] -> [a]
tailSafe [[Char]]
s))

-- | Returns a two-element list containing relative system and user times
-- calculated using two almost simultaneous samples of the @\/proc\/stat@ file
-- for the given core (or all of them aggregated, if \"cpu\" is passed).
getCPULoad :: String -> IO [Double]
getCPULoad :: [Char] -> IO [Double]
getCPULoad [Char]
cpu = do
  [Double]
load <- Double -> IO [Int] -> IO [Double]
forall a b. (Integral a, RealFloat b) => b -> IO [a] -> IO [b]
getLoad Double
0.05 (IO [Int] -> IO [Double]) -> IO [Int] -> IO [Double]
forall a b. (a -> b) -> a -> b
$ [Char] -> IO [Int]
getCPUInfo [Char]
cpu
  case [Double]
load of
    Double
l0:Double
l1:Double
l2:[Double]
_ -> [Double] -> IO [Double]
forall (m :: * -> *) a. Monad m => a -> m a
return [ Double
l0 Double -> Double -> Double
forall a. Num a => a -> a -> a
+ Double
l1, Double
l2 ]
    [Double]
_ -> [Double] -> IO [Double]
forall (m :: * -> *) a. Monad m => a -> m a
return []

-- | Get the directory in which core temperature files are kept.
getCPUTemperatureDirectory :: IO FilePath
getCPUTemperatureDirectory :: IO [Char]
getCPUTemperatureDirectory =
  ([Char]
baseDir [Char] -> [Char] -> [Char]
</>) ([Char] -> [Char]) -> ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Maybe [Char] -> [Char]
forall a. a -> Maybe a -> a
fromMaybe [Char]
"hwmon0" (Maybe [Char] -> [Char])
-> ([[Char]] -> Maybe [Char]) -> [[Char]] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  ([Char] -> Bool) -> [[Char]] -> Maybe [Char]
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find ([Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf [Char]
"hwmon")
  ([[Char]] -> [Char]) -> IO [[Char]] -> IO [Char]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Char] -> IO [[Char]]
listDirectory [Char]
baseDir
  where baseDir :: [Char]
baseDir =
          [Char]
"/"  [Char] -> [Char] -> [Char]
</> [Char]
"sys" [Char] -> [Char] -> [Char]
</> [Char]
"bus" [Char] -> [Char] -> [Char]
</> [Char]
"platform" [Char] -> [Char] -> [Char]
</>
          [Char]
"devices" [Char] -> [Char] -> [Char]
</> [Char]
"coretemp.0" [Char] -> [Char] -> [Char]
</> [Char]
"hwmon"

readCPUTempFile :: FilePath -> IO Double
readCPUTempFile :: [Char] -> IO Double
readCPUTempFile [Char]
cpuTempFilePath = (Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Double
1000) (Double -> Double) -> ([Char] -> Double) -> [Char] -> Double
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Double
forall a. Read a => [Char] -> a
read ([Char] -> Double) -> IO [Char] -> IO Double
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Char] -> IO [Char]
readFile [Char]
cpuTempFilePath

getAllTemperatureFiles :: FilePath -> IO [FilePath]
getAllTemperatureFiles :: [Char] -> IO [[Char]]
getAllTemperatureFiles [Char]
temperaturesDirectory =
  ([Char] -> Bool) -> [[Char]] -> [[Char]]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Bool -> Bool -> Bool)
-> ([Char] -> Bool) -> ([Char] -> Bool) -> [Char] -> Bool
forall (m :: * -> *) a1 a2 r.
Monad m =>
(a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 Bool -> Bool -> Bool
(&&) ([Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isPrefixOf [Char]
"temp") ([Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isSuffixOf [Char]
"input")) ([[Char]] -> [[Char]]) -> IO [[Char]] -> IO [[Char]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
         [Char] -> IO [[Char]]
listDirectory [Char]
temperaturesDirectory

getCPUTemperatures :: IO [(String, Double)]
getCPUTemperatures :: IO [([Char], Double)]
getCPUTemperatures = do
  [Char]
dir <- IO [Char]
getCPUTemperatureDirectory
  let mkPair :: [Char] -> IO ([Char], Double)
mkPair [Char]
filename = ([Char]
filename,) (Double -> ([Char], Double)) -> IO Double -> IO ([Char], Double)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Char] -> IO Double
readCPUTempFile ([Char]
dir [Char] -> [Char] -> [Char]
</> [Char]
filename)
  [Char] -> IO [[Char]]
getAllTemperatureFiles [Char]
dir IO [[Char]]
-> ([[Char]] -> IO [([Char], Double)]) -> IO [([Char], Double)]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ([Char] -> IO ([Char], Double))
-> [[Char]] -> IO [([Char], Double)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM [Char] -> IO ([Char], Double)
mkPair