hmonitors/src/Monitors/Net.hs

128 lines
3.8 KiB
Haskell

module Monitors.Net (queryNet) where
import Data.List
import Data.Maybe
import System.Process
import Text.Printf
import Text.Regex
import qualified Data.Map as M
import Monitors.Common
data DeviceType = Wifi | Ethernet | OtherDevice
data DeviceData = DeviceData
{ deviceName :: String
, deviceType :: DeviceType
, connected :: Bool
, signal :: Maybe Int
}
icons :: M.Map String String
icons = M.map buildIcon $ M.fromList
[ ( "wifi" , 64168 )
, ( "wifi-off" , 64169 )
, ( "ethernet" , 63231 )
]
offline :: String
offline = colorize (colors M.! "inactive") (icons M.! "wifi-off")
getConnectivity :: String -> IO String
getConnectivity cmd = head . lines <$> readProcess cmd args ""
where args = ["networking", "connectivity", "check"]
getDevStatus :: String -> IO [DeviceData]
getDevStatus cmd = readProcess cmd args "" >>= mapM (buildDeviceData cmd) . lines
where
args = ["--terse", "--fields", "device,type,state", "device", "status"]
buildDeviceData :: String -> String -> IO DeviceData
buildDeviceData cmd x =
let
[d,t,state] = splitFields x
deviceType = readDeviceType t
connected = state == "connected"
in do
signal <- getWifiSignal cmd deviceType d
return DeviceData
{ deviceName = d
, deviceType = deviceType
, connected = connected
, signal = signal
}
readDeviceType :: String -> DeviceType
readDeviceType "wifi" = Wifi
readDeviceType "ethernet" = Ethernet
readDeviceType _ = OtherDevice
splitFields :: String -> [String]
splitFields = splitRegex (mkRegex "[^\\]:")
getWifiSignal :: String -> DeviceType -> String -> IO (Maybe Int)
getWifiSignal cmd Wifi dev = parseStdout <$> readProcess cmd args ""
where
args =
[ "--terse"
, "--fields", "in-use,signal"
, "device", "wifi", "list"
, "ifname", dev
]
isActive = (=="*") . head . splitFields
readVal = read . (!! 1) . splitFields
parseStdout = fmap readVal . find isActive . lines
getWifiSignal _ _ _ = return Nothing
getActiveDevs :: String -> IO [DeviceData]
getActiveDevs cmd = filter activeDev <$> getDevStatus cmd
where
activeDev :: DeviceData -> Bool
activeDev DeviceData { deviceType = Wifi, connected = True } = True
activeDev DeviceData { deviceType = Ethernet, connected = True } = True
activeDev _ = False
getSignalColor :: Maybe Int -> String
getSignalColor x = fromMaybe (colors M.! def) (M.lookup (getKey x) colors)
where
def = "active"
getKey Nothing = def
getKey (Just x)
| x < 30 = "red"
| x >= 30 && x < 60 = "yellow"
| x >= 60 && x <= 100 = "green"
| otherwise = def
makeDevIcon :: DeviceData -> String
makeDevIcon DeviceData { deviceType = Ethernet } =
colorize (colors M.! "active") (icons M.! "ethernet")
makeDevIcon DeviceData { deviceType = Wifi, signal = signal@(Just s) } =
let
colorIcon = colorize (getSignalColor signal) (icons M.! "wifi")
txt = colorize (colors M.! "active") (show s)
in printf "%s %s" colorIcon txt
makeDevIcon DeviceData { deviceType = Wifi, signal = Nothing } =
colorize (getSignalColor Nothing) (icons M.! "wifi")
makeDevIcon _ = offline
getStatus :: [DeviceData] -> String
getStatus = intercalate separator . map makeDevIcon
queryNet :: String -> IO String
queryNet cmd = do
connectivity <- getConnectivity cmd
--icon <- if connectivity `elem` ["none", "limited"]
icon <- if connectivity == "none"
then return offline
else getStatus <$> getActiveDevs cmd
return $ separator ++ icon