-----------------------------------------------------------------------------
-- |
-- Module      :  Plugins.Monitors.Net
-- Copyright   :  (c) 2011, 2012, 2013, 2014, 2017 Jose Antonio Ortega Ruiz
--                (c) 2007-2010 Andrea Rossato
-- License     :  BSD-style (see LICENSE)
--
-- Maintainer  :  Jose A. Ortega Ruiz <jao@gnu.org>
-- Stability   :  unstable
-- Portability :  unportable
--
-- A net device monitor for Xmobar
--
-----------------------------------------------------------------------------

{-# LANGUAGE OverloadedStrings #-}

module Xmobar.Plugins.Monitors.Net (
                        startNet
                      , startDynNet
                      ) where

import Xmobar.Plugins.Monitors.Common

import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Monoid ((<>))
import Data.Time.Clock (UTCTime, getCurrentTime, diffUTCTime)
import Data.Word (Word64)
import Control.Monad (forM, filterM)
import System.Directory (getDirectoryContents, doesFileExist)
import System.FilePath ((</>))
import System.Console.GetOpt
import System.IO.Error (catchIOError)
import System.IO.Unsafe (unsafeInterleaveIO)

import qualified Data.ByteString.Char8 as B

type DevList = [String]

parseDevList :: String -> DevList
parseDevList :: String -> DevList
parseDevList = String -> DevList
splitOnComma
  where splitOnComma :: String -> DevList
splitOnComma [] = [[]]
        splitOnComma (Char
',':String
xs) = [] String -> DevList -> DevList
forall a. a -> [a] -> [a]
: String -> DevList
splitOnComma String
xs
        splitOnComma (Char
x:String
xs) =
           let rest :: DevList
rest = String -> DevList
splitOnComma String
xs
           in (Char
x Char -> String -> String
forall a. a -> [a] -> [a]
: DevList -> String
forall a. [a] -> a
head DevList
rest) String -> DevList -> DevList
forall a. a -> [a] -> [a]
: DevList -> DevList
forall a. [a] -> [a]
tail DevList
rest

data NetOpts = NetOpts
  { NetOpts -> Maybe IconPattern
rxIconPattern :: Maybe IconPattern
  , NetOpts -> Maybe IconPattern
txIconPattern :: Maybe IconPattern
  , NetOpts -> Maybe DevList
onlyDevList :: Maybe DevList
  }

defaultOpts :: NetOpts
defaultOpts :: NetOpts
defaultOpts = NetOpts :: Maybe IconPattern -> Maybe IconPattern -> Maybe DevList -> NetOpts
NetOpts
  { rxIconPattern :: Maybe IconPattern
rxIconPattern = Maybe IconPattern
forall a. Maybe a
Nothing
  , txIconPattern :: Maybe IconPattern
txIconPattern = Maybe IconPattern
forall a. Maybe a
Nothing
  , onlyDevList :: Maybe DevList
onlyDevList = Maybe DevList
forall a. Maybe a
Nothing
  }

options :: [OptDescr (NetOpts -> NetOpts)]
options :: [OptDescr (NetOpts -> NetOpts)]
options =
  [ String
-> DevList
-> ArgDescr (NetOpts -> NetOpts)
-> String
-> OptDescr (NetOpts -> NetOpts)
forall a. String -> DevList -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"rx-icon-pattern"] ((String -> NetOpts -> NetOpts)
-> String -> ArgDescr (NetOpts -> NetOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x NetOpts
o ->
     NetOpts
o { rxIconPattern :: Maybe IconPattern
rxIconPattern = IconPattern -> Maybe IconPattern
forall a. a -> Maybe a
Just (IconPattern -> Maybe IconPattern)
-> IconPattern -> Maybe IconPattern
forall a b. (a -> b) -> a -> b
$ String -> IconPattern
parseIconPattern String
x }) String
"") String
""
  , String
-> DevList
-> ArgDescr (NetOpts -> NetOpts)
-> String
-> OptDescr (NetOpts -> NetOpts)
forall a. String -> DevList -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"tx-icon-pattern"] ((String -> NetOpts -> NetOpts)
-> String -> ArgDescr (NetOpts -> NetOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x NetOpts
o ->
     NetOpts
o { txIconPattern :: Maybe IconPattern
txIconPattern = IconPattern -> Maybe IconPattern
forall a. a -> Maybe a
Just (IconPattern -> Maybe IconPattern)
-> IconPattern -> Maybe IconPattern
forall a b. (a -> b) -> a -> b
$ String -> IconPattern
parseIconPattern String
x }) String
"") String
""
  , String
-> DevList
-> ArgDescr (NetOpts -> NetOpts)
-> String
-> OptDescr (NetOpts -> NetOpts)
forall a. String -> DevList -> ArgDescr a -> String -> OptDescr a
Option String
"" [String
"devices"] ((String -> NetOpts -> NetOpts)
-> String -> ArgDescr (NetOpts -> NetOpts)
forall a. (String -> a) -> String -> ArgDescr a
ReqArg (\String
x NetOpts
o ->
     NetOpts
o { onlyDevList :: Maybe DevList
onlyDevList = DevList -> Maybe DevList
forall a. a -> Maybe a
Just (DevList -> Maybe DevList) -> DevList -> Maybe DevList
forall a b. (a -> b) -> a -> b
$ String -> DevList
parseDevList String
x }) String
"") String
""
  ]

data UnitPerSec = Bs | KBs | MBs | GBs deriving (UnitPerSec -> UnitPerSec -> Bool
(UnitPerSec -> UnitPerSec -> Bool)
-> (UnitPerSec -> UnitPerSec -> Bool) -> Eq UnitPerSec
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: UnitPerSec -> UnitPerSec -> Bool
$c/= :: UnitPerSec -> UnitPerSec -> Bool
== :: UnitPerSec -> UnitPerSec -> Bool
$c== :: UnitPerSec -> UnitPerSec -> Bool
Eq,Int -> UnitPerSec
UnitPerSec -> Int
UnitPerSec -> [UnitPerSec]
UnitPerSec -> UnitPerSec
UnitPerSec -> UnitPerSec -> [UnitPerSec]
UnitPerSec -> UnitPerSec -> UnitPerSec -> [UnitPerSec]
(UnitPerSec -> UnitPerSec)
-> (UnitPerSec -> UnitPerSec)
-> (Int -> UnitPerSec)
-> (UnitPerSec -> Int)
-> (UnitPerSec -> [UnitPerSec])
-> (UnitPerSec -> UnitPerSec -> [UnitPerSec])
-> (UnitPerSec -> UnitPerSec -> [UnitPerSec])
-> (UnitPerSec -> UnitPerSec -> UnitPerSec -> [UnitPerSec])
-> Enum UnitPerSec
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: UnitPerSec -> UnitPerSec -> UnitPerSec -> [UnitPerSec]
$cenumFromThenTo :: UnitPerSec -> UnitPerSec -> UnitPerSec -> [UnitPerSec]
enumFromTo :: UnitPerSec -> UnitPerSec -> [UnitPerSec]
$cenumFromTo :: UnitPerSec -> UnitPerSec -> [UnitPerSec]
enumFromThen :: UnitPerSec -> UnitPerSec -> [UnitPerSec]
$cenumFromThen :: UnitPerSec -> UnitPerSec -> [UnitPerSec]
enumFrom :: UnitPerSec -> [UnitPerSec]
$cenumFrom :: UnitPerSec -> [UnitPerSec]
fromEnum :: UnitPerSec -> Int
$cfromEnum :: UnitPerSec -> Int
toEnum :: Int -> UnitPerSec
$ctoEnum :: Int -> UnitPerSec
pred :: UnitPerSec -> UnitPerSec
$cpred :: UnitPerSec -> UnitPerSec
succ :: UnitPerSec -> UnitPerSec
$csucc :: UnitPerSec -> UnitPerSec
Enum,Eq UnitPerSec
Eq UnitPerSec
-> (UnitPerSec -> UnitPerSec -> Ordering)
-> (UnitPerSec -> UnitPerSec -> Bool)
-> (UnitPerSec -> UnitPerSec -> Bool)
-> (UnitPerSec -> UnitPerSec -> Bool)
-> (UnitPerSec -> UnitPerSec -> Bool)
-> (UnitPerSec -> UnitPerSec -> UnitPerSec)
-> (UnitPerSec -> UnitPerSec -> UnitPerSec)
-> Ord UnitPerSec
UnitPerSec -> UnitPerSec -> Bool
UnitPerSec -> UnitPerSec -> Ordering
UnitPerSec -> UnitPerSec -> UnitPerSec
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: UnitPerSec -> UnitPerSec -> UnitPerSec
$cmin :: UnitPerSec -> UnitPerSec -> UnitPerSec
max :: UnitPerSec -> UnitPerSec -> UnitPerSec
$cmax :: UnitPerSec -> UnitPerSec -> UnitPerSec
>= :: UnitPerSec -> UnitPerSec -> Bool
$c>= :: UnitPerSec -> UnitPerSec -> Bool
> :: UnitPerSec -> UnitPerSec -> Bool
$c> :: UnitPerSec -> UnitPerSec -> Bool
<= :: UnitPerSec -> UnitPerSec -> Bool
$c<= :: UnitPerSec -> UnitPerSec -> Bool
< :: UnitPerSec -> UnitPerSec -> Bool
$c< :: UnitPerSec -> UnitPerSec -> Bool
compare :: UnitPerSec -> UnitPerSec -> Ordering
$ccompare :: UnitPerSec -> UnitPerSec -> Ordering
$cp1Ord :: Eq UnitPerSec
Ord)
data NetValue = NetValue Float UnitPerSec deriving (NetValue -> NetValue -> Bool
(NetValue -> NetValue -> Bool)
-> (NetValue -> NetValue -> Bool) -> Eq NetValue
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NetValue -> NetValue -> Bool
$c/= :: NetValue -> NetValue -> Bool
== :: NetValue -> NetValue -> Bool
$c== :: NetValue -> NetValue -> Bool
Eq,Int -> NetValue -> String -> String
[NetValue] -> String -> String
NetValue -> String
(Int -> NetValue -> String -> String)
-> (NetValue -> String)
-> ([NetValue] -> String -> String)
-> Show NetValue
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [NetValue] -> String -> String
$cshowList :: [NetValue] -> String -> String
show :: NetValue -> String
$cshow :: NetValue -> String
showsPrec :: Int -> NetValue -> String -> String
$cshowsPrec :: Int -> NetValue -> String -> String
Show)

instance Show UnitPerSec where
    show :: UnitPerSec -> String
show UnitPerSec
Bs  = String
"B/s"
    show UnitPerSec
KBs = String
"KB/s"
    show UnitPerSec
MBs = String
"MB/s"
    show UnitPerSec
GBs = String
"GB/s"

data NetDev num = N String (NetDevInfo num) | NA deriving (NetDev num -> NetDev num -> Bool
(NetDev num -> NetDev num -> Bool)
-> (NetDev num -> NetDev num -> Bool) -> Eq (NetDev num)
forall num. Eq num => NetDev num -> NetDev num -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NetDev num -> NetDev num -> Bool
$c/= :: forall num. Eq num => NetDev num -> NetDev num -> Bool
== :: NetDev num -> NetDev num -> Bool
$c== :: forall num. Eq num => NetDev num -> NetDev num -> Bool
Eq,Int -> NetDev num -> String -> String
[NetDev num] -> String -> String
NetDev num -> String
(Int -> NetDev num -> String -> String)
-> (NetDev num -> String)
-> ([NetDev num] -> String -> String)
-> Show (NetDev num)
forall num. Show num => Int -> NetDev num -> String -> String
forall num. Show num => [NetDev num] -> String -> String
forall num. Show num => NetDev num -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [NetDev num] -> String -> String
$cshowList :: forall num. Show num => [NetDev num] -> String -> String
show :: NetDev num -> String
$cshow :: forall num. Show num => NetDev num -> String
showsPrec :: Int -> NetDev num -> String -> String
$cshowsPrec :: forall num. Show num => Int -> NetDev num -> String -> String
Show,ReadPrec [NetDev num]
ReadPrec (NetDev num)
Int -> ReadS (NetDev num)
ReadS [NetDev num]
(Int -> ReadS (NetDev num))
-> ReadS [NetDev num]
-> ReadPrec (NetDev num)
-> ReadPrec [NetDev num]
-> Read (NetDev num)
forall num. Read num => ReadPrec [NetDev num]
forall num. Read num => ReadPrec (NetDev num)
forall num. Read num => Int -> ReadS (NetDev num)
forall num. Read num => ReadS [NetDev num]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [NetDev num]
$creadListPrec :: forall num. Read num => ReadPrec [NetDev num]
readPrec :: ReadPrec (NetDev num)
$creadPrec :: forall num. Read num => ReadPrec (NetDev num)
readList :: ReadS [NetDev num]
$creadList :: forall num. Read num => ReadS [NetDev num]
readsPrec :: Int -> ReadS (NetDev num)
$creadsPrec :: forall num. Read num => Int -> ReadS (NetDev num)
Read)
data NetDevInfo num = NI | ND num num deriving (NetDevInfo num -> NetDevInfo num -> Bool
(NetDevInfo num -> NetDevInfo num -> Bool)
-> (NetDevInfo num -> NetDevInfo num -> Bool)
-> Eq (NetDevInfo num)
forall num. Eq num => NetDevInfo num -> NetDevInfo num -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: NetDevInfo num -> NetDevInfo num -> Bool
$c/= :: forall num. Eq num => NetDevInfo num -> NetDevInfo num -> Bool
== :: NetDevInfo num -> NetDevInfo num -> Bool
$c== :: forall num. Eq num => NetDevInfo num -> NetDevInfo num -> Bool
Eq,Int -> NetDevInfo num -> String -> String
[NetDevInfo num] -> String -> String
NetDevInfo num -> String
(Int -> NetDevInfo num -> String -> String)
-> (NetDevInfo num -> String)
-> ([NetDevInfo num] -> String -> String)
-> Show (NetDevInfo num)
forall num. Show num => Int -> NetDevInfo num -> String -> String
forall num. Show num => [NetDevInfo num] -> String -> String
forall num. Show num => NetDevInfo num -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [NetDevInfo num] -> String -> String
$cshowList :: forall num. Show num => [NetDevInfo num] -> String -> String
show :: NetDevInfo num -> String
$cshow :: forall num. Show num => NetDevInfo num -> String
showsPrec :: Int -> NetDevInfo num -> String -> String
$cshowsPrec :: forall num. Show num => Int -> NetDevInfo num -> String -> String
Show,ReadPrec [NetDevInfo num]
ReadPrec (NetDevInfo num)
Int -> ReadS (NetDevInfo num)
ReadS [NetDevInfo num]
(Int -> ReadS (NetDevInfo num))
-> ReadS [NetDevInfo num]
-> ReadPrec (NetDevInfo num)
-> ReadPrec [NetDevInfo num]
-> Read (NetDevInfo num)
forall num. Read num => ReadPrec [NetDevInfo num]
forall num. Read num => ReadPrec (NetDevInfo num)
forall num. Read num => Int -> ReadS (NetDevInfo num)
forall num. Read num => ReadS [NetDevInfo num]
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
readListPrec :: ReadPrec [NetDevInfo num]
$creadListPrec :: forall num. Read num => ReadPrec [NetDevInfo num]
readPrec :: ReadPrec (NetDevInfo num)
$creadPrec :: forall num. Read num => ReadPrec (NetDevInfo num)
readList :: ReadS [NetDevInfo num]
$creadList :: forall num. Read num => ReadS [NetDevInfo num]
readsPrec :: Int -> ReadS (NetDevInfo num)
$creadsPrec :: forall num. Read num => Int -> ReadS (NetDevInfo num)
Read)

type NetDevRawTotal = NetDev Word64
type NetDevRate = NetDev Float

type NetDevRef = IORef (NetDevRawTotal, UTCTime)

-- The more information available, the better.
-- Note that names don't matter. Therefore, if only the names differ,
-- a compare evaluates to EQ while (==) evaluates to False.
instance Ord num => Ord (NetDev num) where
    compare :: NetDev num -> NetDev num -> Ordering
compare NetDev num
NA NetDev num
NA             = Ordering
EQ
    compare NetDev num
NA NetDev num
_              = Ordering
LT
    compare NetDev num
_  NetDev num
NA             = Ordering
GT
    compare (N String
_ NetDevInfo num
i1) (N String
_ NetDevInfo num
i2) = NetDevInfo num
i1 NetDevInfo num -> NetDevInfo num -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` NetDevInfo num
i2

instance Ord num => Ord (NetDevInfo num) where
    compare :: NetDevInfo num -> NetDevInfo num -> Ordering
compare NetDevInfo num
NI NetDevInfo num
NI                 = Ordering
EQ
    compare NetDevInfo num
NI ND {}              = Ordering
LT
    compare ND {} NetDevInfo num
NI              = Ordering
GT
    compare (ND num
x1 num
y1) (ND num
x2 num
y2) = num
x1 num -> num -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` num
x2 Ordering -> Ordering -> Ordering
forall a. Semigroup a => a -> a -> a
<> num
y1 num -> num -> Ordering
forall a. Ord a => a -> a -> Ordering
`compare` num
y2

netConfig :: IO MConfig
netConfig :: IO MConfig
netConfig = String -> DevList -> IO MConfig
mkMConfig
    String
"<dev>: <rx>KB|<tx>KB"      -- template
    [String
"dev", String
"rx", String
"tx", String
"rxbar", String
"rxvbar", String
"rxipat", String
"txbar", String
"txvbar", String
"txipat"]     -- available replacements

operstateDir :: String -> FilePath
operstateDir :: String -> String
operstateDir String
d = String
"/sys/class/net" String -> String -> String
</> String
d String -> String -> String
</> String
"operstate"

existingDevs :: IO [String]
existingDevs :: IO DevList
existingDevs = String -> IO DevList
getDirectoryContents String
"/sys/class/net" IO DevList -> (DevList -> IO DevList) -> IO DevList
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (String -> IO Bool) -> DevList -> IO DevList
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
isDev
  where isDev :: String -> IO Bool
isDev String
d | String
d String -> DevList -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` DevList
excludes = Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                | Bool
otherwise = String -> IO Bool
doesFileExist (String -> String
operstateDir String
d)
        excludes :: DevList
excludes = [String
".", String
"..", String
"lo"]

isUp :: String -> IO Bool
isUp :: String -> IO Bool
isUp String
d = (IO Bool -> (IOError -> IO Bool) -> IO Bool)
-> (IOError -> IO Bool) -> IO Bool -> IO Bool
forall a b c. (a -> b -> c) -> b -> a -> c
flip IO Bool -> (IOError -> IO Bool) -> IO Bool
forall a. IO a -> (IOError -> IO a) -> IO a
catchIOError (IO Bool -> IOError -> IO Bool
forall a b. a -> b -> a
const (IO Bool -> IOError -> IO Bool) -> IO Bool -> IOError -> IO Bool
forall a b. (a -> b) -> a -> b
$ Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False) (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ do
  ByteString
operstate <- String -> IO ByteString
B.readFile (String -> String
operstateDir String
d)
  Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool -> IO Bool) -> Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$! ([ByteString] -> ByteString
forall a. [a] -> a
head ([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
B.lines) ByteString
operstate ByteString -> [ByteString] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ByteString
"up", ByteString
"unknown"]

readNetDev :: [String] -> IO NetDevRawTotal
readNetDev :: DevList -> IO NetDevRawTotal
readNetDev ~[String
d, String
x, String
y] = do
  Bool
up <- IO Bool -> IO Bool
forall a. IO a -> IO a
unsafeInterleaveIO (IO Bool -> IO Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> a -> b
$ String -> IO Bool
isUp String
d
  NetDevRawTotal -> IO NetDevRawTotal
forall (m :: * -> *) a. Monad m => a -> m a
return (NetDevRawTotal -> IO NetDevRawTotal)
-> NetDevRawTotal -> IO NetDevRawTotal
forall a b. (a -> b) -> a -> b
$ String -> NetDevInfo Word64 -> NetDevRawTotal
forall num. String -> NetDevInfo num -> NetDev num
N String
d (if Bool
up then Word64 -> Word64 -> NetDevInfo Word64
forall num. num -> num -> NetDevInfo num
ND (String -> Word64
forall p. (Num p, Read p) => String -> p
r String
x) (String -> Word64
forall p. (Num p, Read p) => String -> p
r String
y) else NetDevInfo Word64
forall num. NetDevInfo num
NI)
    where r :: String -> p
r String
s | String
s String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
"" = p
0
              | Bool
otherwise = String -> p
forall a. Read a => String -> a
read String
s

netParser :: B.ByteString -> IO [NetDevRawTotal]
netParser :: ByteString -> IO [NetDevRawTotal]
netParser = (ByteString -> IO NetDevRawTotal)
-> [ByteString] -> IO [NetDevRawTotal]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (DevList -> IO NetDevRawTotal
readNetDev (DevList -> IO NetDevRawTotal)
-> (ByteString -> DevList) -> ByteString -> IO NetDevRawTotal
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> DevList
splitDevLine) ([ByteString] -> IO [NetDevRawTotal])
-> (ByteString -> [ByteString])
-> ByteString
-> IO [NetDevRawTotal]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
readDevLines
  where readDevLines :: ByteString -> [ByteString]
readDevLines = Int -> [ByteString] -> [ByteString]
forall a. Int -> [a] -> [a]
drop Int
2 ([ByteString] -> [ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
B.lines
        splitDevLine :: ByteString -> DevList
splitDevLine = (ByteString -> String) -> [ByteString] -> DevList
forall a b. (a -> b) -> [a] -> [b]
map ByteString -> String
B.unpack ([ByteString] -> DevList)
-> (ByteString -> [ByteString]) -> ByteString -> DevList
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [ByteString]
forall a. [a] -> [a]
selectCols ([ByteString] -> [ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Bool) -> [ByteString] -> [ByteString]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (ByteString -> Bool) -> ByteString -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Bool
B.null) ([ByteString] -> [ByteString])
-> (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ByteString -> [ByteString]
B.splitWith (Char -> String -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char
' ',Char
':'])
        selectCols :: [b] -> [b]
selectCols [b]
cols = (Int -> b) -> [Int] -> [b]
forall a b. (a -> b) -> [a] -> [b]
map ([b]
cols[b] -> Int -> b
forall a. [a] -> Int -> a
!!) [Int
0,Int
1,Int
9]

findNetDev :: String -> IO NetDevRawTotal
findNetDev :: String -> IO NetDevRawTotal
findNetDev String
dev = do
  [NetDevRawTotal]
nds <- String -> IO ByteString
B.readFile String
"/proc/net/dev" IO ByteString
-> (ByteString -> IO [NetDevRawTotal]) -> IO [NetDevRawTotal]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ByteString -> IO [NetDevRawTotal]
netParser
  case (NetDevRawTotal -> Bool) -> [NetDevRawTotal] -> [NetDevRawTotal]
forall a. (a -> Bool) -> [a] -> [a]
filter NetDevRawTotal -> Bool
forall num. NetDev num -> Bool
isDev [NetDevRawTotal]
nds of
    NetDevRawTotal
x:[NetDevRawTotal]
_ -> NetDevRawTotal -> IO NetDevRawTotal
forall (m :: * -> *) a. Monad m => a -> m a
return NetDevRawTotal
x
    [NetDevRawTotal]
_ -> NetDevRawTotal -> IO NetDevRawTotal
forall (m :: * -> *) a. Monad m => a -> m a
return NetDevRawTotal
forall num. NetDev num
NA
  where isDev :: NetDev num -> Bool
isDev (N String
d NetDevInfo num
_) = String
d String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
dev
        isDev NetDev num
NA = Bool
False

formatNet :: Maybe IconPattern -> Float -> Monitor (String, String, String, String)
formatNet :: Maybe IconPattern
-> Float -> Monitor (String, String, String, String)
formatNet Maybe IconPattern
mipat Float
d = do
    Bool
s <- Selector Bool -> Monitor Bool
forall a. Selector a -> Monitor a
getConfigValue Selector Bool
useSuffix
    Int
dd <- Selector Int -> Monitor Int
forall a. Selector a -> Monitor a
getConfigValue Selector Int
decDigits
    let str :: Bool -> Float -> String
str Bool
True Float
v = Int -> Float -> String
forall a. RealFloat a => Int -> a -> String
showDigits Int
dd Float
d' String -> String -> String
forall a. [a] -> [a] -> [a]
++ UnitPerSec -> String
forall a. Show a => a -> String
show UnitPerSec
u
            where (NetValue Float
d' UnitPerSec
u) = Float -> NetValue
byteNetVal Float
v
        str Bool
False Float
v = Int -> Float -> String
forall a. RealFloat a => Int -> a -> String
showDigits Int
dd (Float -> String) -> Float -> String
forall a b. (a -> b) -> a -> b
$ Float
v Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
1024
    String
b <- Float -> Float -> Monitor String
showLogBar Float
0.9 Float
d
    String
vb <- Float -> Float -> Monitor String
showLogVBar Float
0.9 Float
d
    String
ipat <- Maybe IconPattern -> Float -> Float -> Monitor String
showLogIconPattern Maybe IconPattern
mipat Float
0.9 Float
d
    String
x <- (Float -> String) -> Float -> Monitor String
forall a. (Num a, Ord a) => (a -> String) -> a -> Monitor String
showWithColors (Bool -> Float -> String
str Bool
s) Float
d
    (String, String, String, String)
-> Monitor (String, String, String, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (String
x, String
b, String
vb, String
ipat)

printNet :: NetOpts -> NetDevRate -> Monitor String
printNet :: NetOpts -> NetDevRate -> Monitor String
printNet NetOpts
opts NetDevRate
nd =
  case NetDevRate
nd of
    N String
d (ND Float
r Float
t) -> do
        (String
rx, String
rb, String
rvb, String
ripat) <- Maybe IconPattern
-> Float -> Monitor (String, String, String, String)
formatNet (NetOpts -> Maybe IconPattern
rxIconPattern NetOpts
opts) Float
r
        (String
tx, String
tb, String
tvb, String
tipat) <- Maybe IconPattern
-> Float -> Monitor (String, String, String, String)
formatNet (NetOpts -> Maybe IconPattern
txIconPattern NetOpts
opts) Float
t
        DevList -> Monitor String
parseTemplate [String
d,String
rx,String
tx,String
rb,String
rvb,String
ripat,String
tb,String
tvb,String
tipat]
    N String
_ NetDevInfo Float
NI -> String -> Monitor String
forall (m :: * -> *) a. Monad m => a -> m a
return String
""
    NetDevRate
NA -> Selector String -> Monitor String
forall a. Selector a -> Monitor a
getConfigValue Selector String
naString

parseNet :: NetDevRef -> String -> IO NetDevRate
parseNet :: NetDevRef -> String -> IO NetDevRate
parseNet NetDevRef
nref String
nd = do
  (NetDevRawTotal
n0, UTCTime
t0) <- NetDevRef -> IO (NetDevRawTotal, UTCTime)
forall a. IORef a -> IO a
readIORef NetDevRef
nref
  NetDevRawTotal
n1 <- String -> IO NetDevRawTotal
findNetDev String
nd
  UTCTime
t1 <- IO UTCTime
getCurrentTime
  NetDevRef -> (NetDevRawTotal, UTCTime) -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef NetDevRef
nref (NetDevRawTotal
n1, UTCTime
t1)
  let scx :: Float
scx = NominalDiffTime -> Float
forall a b. (Real a, Fractional b) => a -> b
realToFrac (UTCTime -> UTCTime -> NominalDiffTime
diffUTCTime UTCTime
t1 UTCTime
t0)
      scx' :: Float
scx' = if Float
scx Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
> Float
0 then Float
scx else Float
1
      rate :: a -> a -> Float
rate a
da a
db = Int -> Float -> Float
takeDigits Int
2 (Float -> Float) -> Float -> Float
forall a b. (a -> b) -> a -> b
$ a -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
db a -> a -> a
forall a. Num a => a -> a -> a
- a
da) Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
scx'
      diffRate :: NetDev a -> NetDev a -> NetDevRate
diffRate (N String
d (ND a
ra a
ta)) (N String
_ (ND a
rb a
tb)) = String -> NetDevInfo Float -> NetDevRate
forall num. String -> NetDevInfo num -> NetDev num
N String
d (Float -> Float -> NetDevInfo Float
forall num. num -> num -> NetDevInfo num
ND (a -> a -> Float
forall a. Integral a => a -> a -> Float
rate a
ra a
rb) (a -> a -> Float
forall a. Integral a => a -> a -> Float
rate a
ta a
tb))
      diffRate (N String
d NetDevInfo a
NI) NetDev a
_ = String -> NetDevInfo Float -> NetDevRate
forall num. String -> NetDevInfo num -> NetDev num
N String
d NetDevInfo Float
forall num. NetDevInfo num
NI
      diffRate NetDev a
_ (N String
d NetDevInfo a
NI) = String -> NetDevInfo Float -> NetDevRate
forall num. String -> NetDevInfo num -> NetDev num
N String
d NetDevInfo Float
forall num. NetDevInfo num
NI
      diffRate NetDev a
_ NetDev a
_ = NetDevRate
forall num. NetDev num
NA
  NetDevRate -> IO NetDevRate
forall (m :: * -> *) a. Monad m => a -> m a
return (NetDevRate -> IO NetDevRate) -> NetDevRate -> IO NetDevRate
forall a b. (a -> b) -> a -> b
$ NetDevRawTotal -> NetDevRawTotal -> NetDevRate
forall a. Integral a => NetDev a -> NetDev a -> NetDevRate
diffRate NetDevRawTotal
n0 NetDevRawTotal
n1

runNet :: NetDevRef -> String -> [String] -> Monitor String
runNet :: NetDevRef -> String -> DevList -> Monitor String
runNet NetDevRef
nref String
i DevList
argv = do
  NetDevRate
dev <- IO NetDevRate -> Monitor NetDevRate
forall a. IO a -> Monitor a
io (IO NetDevRate -> Monitor NetDevRate)
-> IO NetDevRate -> Monitor NetDevRate
forall a b. (a -> b) -> a -> b
$ NetDevRef -> String -> IO NetDevRate
parseNet NetDevRef
nref String
i
  NetOpts
opts <- IO NetOpts -> Monitor NetOpts
forall a. IO a -> Monitor a
io (IO NetOpts -> Monitor NetOpts) -> IO NetOpts -> Monitor NetOpts
forall a b. (a -> b) -> a -> b
$ [OptDescr (NetOpts -> NetOpts)] -> NetOpts -> DevList -> IO NetOpts
forall opts.
[OptDescr (opts -> opts)] -> opts -> DevList -> IO opts
parseOptsWith [OptDescr (NetOpts -> NetOpts)]
options NetOpts
defaultOpts DevList
argv
  NetOpts -> NetDevRate -> Monitor String
printNet NetOpts
opts NetDevRate
dev

parseNets :: [(NetDevRef, String)] -> IO [NetDevRate]
parseNets :: [(NetDevRef, String)] -> IO [NetDevRate]
parseNets = ((NetDevRef, String) -> IO NetDevRate)
-> [(NetDevRef, String)] -> IO [NetDevRate]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (((NetDevRef, String) -> IO NetDevRate)
 -> [(NetDevRef, String)] -> IO [NetDevRate])
-> ((NetDevRef, String) -> IO NetDevRate)
-> [(NetDevRef, String)]
-> IO [NetDevRate]
forall a b. (a -> b) -> a -> b
$ (NetDevRef -> String -> IO NetDevRate)
-> (NetDevRef, String) -> IO NetDevRate
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry NetDevRef -> String -> IO NetDevRate
parseNet

runNets :: [(NetDevRef, String)] -> [String] -> Monitor String
runNets :: [(NetDevRef, String)] -> DevList -> Monitor String
runNets [(NetDevRef, String)]
refs DevList
argv = do
  NetOpts
opts <- IO NetOpts -> Monitor NetOpts
forall a. IO a -> Monitor a
io (IO NetOpts -> Monitor NetOpts) -> IO NetOpts -> Monitor NetOpts
forall a b. (a -> b) -> a -> b
$ [OptDescr (NetOpts -> NetOpts)] -> NetOpts -> DevList -> IO NetOpts
forall opts.
[OptDescr (opts -> opts)] -> opts -> DevList -> IO opts
parseOptsWith [OptDescr (NetOpts -> NetOpts)]
options NetOpts
defaultOpts DevList
argv
  NetDevRate
dev <- IO NetDevRate -> Monitor NetDevRate
forall a. IO a -> Monitor a
io (IO NetDevRate -> Monitor NetDevRate)
-> IO NetDevRate -> Monitor NetDevRate
forall a b. (a -> b) -> a -> b
$ [(NetDevRef, String)] -> IO NetDevRate
parseActive ([(NetDevRef, String)] -> IO NetDevRate)
-> [(NetDevRef, String)] -> IO NetDevRate
forall a b. (a -> b) -> a -> b
$ NetOpts -> [(NetDevRef, String)] -> [(NetDevRef, String)]
forall a. NetOpts -> [(a, String)] -> [(a, String)]
filterRefs NetOpts
opts [(NetDevRef, String)]
refs
  NetOpts -> NetDevRate -> Monitor String
printNet NetOpts
opts NetDevRate
dev
    where parseActive :: [(NetDevRef, String)] -> IO NetDevRate
parseActive [(NetDevRef, String)]
refs' = ([NetDevRate] -> NetDevRate) -> IO [NetDevRate] -> IO NetDevRate
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [NetDevRate] -> NetDevRate
selectActive ([(NetDevRef, String)] -> IO [NetDevRate]
parseNets [(NetDevRef, String)]
refs')
          refInDevList :: NetOpts -> (a, String) -> Bool
refInDevList NetOpts
opts' (a
_, String
refname') = case NetOpts -> Maybe DevList
onlyDevList NetOpts
opts' of
            Just DevList
theList -> String
refname' String -> DevList -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` DevList
theList
            Maybe DevList
Nothing -> Bool
True
          filterRefs :: NetOpts -> [(a, String)] -> [(a, String)]
filterRefs NetOpts
opts' [(a, String)]
refs' = case ((a, String) -> Bool) -> [(a, String)] -> [(a, String)]
forall a. (a -> Bool) -> [a] -> [a]
filter (NetOpts -> (a, String) -> Bool
forall a. NetOpts -> (a, String) -> Bool
refInDevList NetOpts
opts') [(a, String)]
refs' of
            [] -> [(a, String)]
refs'
            [(a, String)]
xs -> [(a, String)]
xs
          selectActive :: [NetDevRate] -> NetDevRate
selectActive = [NetDevRate] -> NetDevRate
forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
maximum

startNet :: String -> [String] -> Int -> (String -> IO ()) -> IO ()
startNet :: String -> DevList -> Int -> (String -> IO ()) -> IO ()
startNet String
i DevList
a Int
r String -> IO ()
cb = do
  UTCTime
t0 <- IO UTCTime
getCurrentTime
  NetDevRef
nref <- (NetDevRawTotal, UTCTime) -> IO NetDevRef
forall a. a -> IO (IORef a)
newIORef (NetDevRawTotal
forall num. NetDev num
NA, UTCTime
t0)
  NetDevRate
_ <- NetDevRef -> String -> IO NetDevRate
parseNet NetDevRef
nref String
i
  DevList
-> IO MConfig
-> (DevList -> Monitor String)
-> Int
-> (String -> IO ())
-> IO ()
runM DevList
a IO MConfig
netConfig (NetDevRef -> String -> DevList -> Monitor String
runNet NetDevRef
nref String
i) Int
r String -> IO ()
cb

startDynNet :: [String] -> Int -> (String -> IO ()) -> IO ()
startDynNet :: DevList -> Int -> (String -> IO ()) -> IO ()
startDynNet DevList
a Int
r String -> IO ()
cb = do
  DevList
devs <- IO DevList
existingDevs
  [(NetDevRef, String)]
refs <- DevList
-> (String -> IO (NetDevRef, String)) -> IO [(NetDevRef, String)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM DevList
devs ((String -> IO (NetDevRef, String)) -> IO [(NetDevRef, String)])
-> (String -> IO (NetDevRef, String)) -> IO [(NetDevRef, String)]
forall a b. (a -> b) -> a -> b
$ \String
d -> do
            UTCTime
t <- IO UTCTime
getCurrentTime
            NetDevRef
nref <- (NetDevRawTotal, UTCTime) -> IO NetDevRef
forall a. a -> IO (IORef a)
newIORef (NetDevRawTotal
forall num. NetDev num
NA, UTCTime
t)
            NetDevRate
_ <- NetDevRef -> String -> IO NetDevRate
parseNet NetDevRef
nref String
d
            (NetDevRef, String) -> IO (NetDevRef, String)
forall (m :: * -> *) a. Monad m => a -> m a
return (NetDevRef
nref, String
d)
  DevList
-> IO MConfig
-> (DevList -> Monitor String)
-> Int
-> (String -> IO ())
-> IO ()
runM DevList
a IO MConfig
netConfig ([(NetDevRef, String)] -> DevList -> Monitor String
runNets [(NetDevRef, String)]
refs) Int
r String -> IO ()
cb

byteNetVal :: Float -> NetValue
byteNetVal :: Float -> NetValue
byteNetVal Float
v
    | Float
v Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
1024Float -> Float -> Float
forall a. Floating a => a -> a -> a
**Float
1 = Float -> UnitPerSec -> NetValue
NetValue Float
v UnitPerSec
Bs
    | Float
v Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
1024Float -> Float -> Float
forall a. Floating a => a -> a -> a
**Float
2 = Float -> UnitPerSec -> NetValue
NetValue (Float
vFloat -> Float -> Float
forall a. Fractional a => a -> a -> a
/Float
1024Float -> Float -> Float
forall a. Floating a => a -> a -> a
**Float
1) UnitPerSec
KBs
    | Float
v Float -> Float -> Bool
forall a. Ord a => a -> a -> Bool
< Float
1024Float -> Float -> Float
forall a. Floating a => a -> a -> a
**Float
3 = Float -> UnitPerSec -> NetValue
NetValue (Float
vFloat -> Float -> Float
forall a. Fractional a => a -> a -> a
/Float
1024Float -> Float -> Float
forall a. Floating a => a -> a -> a
**Float
2) UnitPerSec
MBs
    | Bool
otherwise   = Float -> UnitPerSec -> NetValue
NetValue (Float
vFloat -> Float -> Float
forall a. Fractional a => a -> a -> a
/Float
1024Float -> Float -> Float
forall a. Floating a => a -> a -> a
**Float
3) UnitPerSec
GBs