125 lines
3.6 KiB
Haskell
125 lines
3.6 KiB
Haskell
|
module Monitors.Net (queryNet) where
|
||
|
|
||
|
import Data.List.Split
|
||
|
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 :: IO String
|
||
|
getConnectivity = head . lines <$> readProcess "nmcli" args ""
|
||
|
where args = ["networking", "connectivity", "check"]
|
||
|
|
||
|
getDevStatus :: IO [DeviceData]
|
||
|
getDevStatus = readProcess "nmcli" args "" >>= mapM buildDeviceData . lines
|
||
|
where
|
||
|
args = ["--terse", "--fields", "device,type,state", "device", "status"]
|
||
|
|
||
|
buildDeviceData :: String -> IO DeviceData
|
||
|
buildDeviceData x =
|
||
|
let
|
||
|
[d,t,state] = splitOn ":" x
|
||
|
deviceType = readDeviceType t
|
||
|
connected = state == "connected"
|
||
|
in do
|
||
|
signal <- getWifiSignal deviceType d
|
||
|
return DeviceData
|
||
|
{ deviceName = d
|
||
|
, deviceType = deviceType
|
||
|
, connected = connected
|
||
|
, signal = signal
|
||
|
}
|
||
|
|
||
|
readDeviceType :: String -> DeviceType
|
||
|
readDeviceType "wifi" = Wifi
|
||
|
readDeviceType "ethernet" = Ethernet
|
||
|
readDeviceType _ = OtherDevice
|
||
|
|
||
|
getWifiSignal :: DeviceType -> String -> IO (Maybe Int)
|
||
|
getWifiSignal Wifi dev = parseStdout <$> readProcess "nmcli" args ""
|
||
|
where
|
||
|
args =
|
||
|
[ "--terse"
|
||
|
, "--fields", "in-use,signal"
|
||
|
, "device", "wifi", "list"
|
||
|
, "ifname", dev
|
||
|
]
|
||
|
splt = splitOn ":"
|
||
|
isActive = (=="*") . head . splt
|
||
|
readVal = read . (!! 1) . splt
|
||
|
parseStdout = fmap readVal . find isActive . lines
|
||
|
getWifiSignal _ _ = return Nothing
|
||
|
|
||
|
getActiveDevs :: IO [DeviceData]
|
||
|
getActiveDevs = filter activeDev <$> getDevStatus
|
||
|
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 :: IO String
|
||
|
queryNet = do
|
||
|
connectivity <- getConnectivity
|
||
|
--icon <- if connectivity `elem` ["none", "limited"]
|
||
|
icon <- if connectivity == "none"
|
||
|
then return offline
|
||
|
else getStatus <$> getActiveDevs
|
||
|
return $ separator ++ icon
|