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