80 lines
2.3 KiB
TypeScript
80 lines
2.3 KiB
TypeScript
import Network from "gi://AstalNetwork";
|
|
import { bind, Variable } from "astal";
|
|
import { toHumanReadable } from "@/lib/utils";
|
|
|
|
type IpOutput = Array<{
|
|
ifname: string;
|
|
stats64: {
|
|
rx: { bytes: number };
|
|
tx: { bytes: number };
|
|
};
|
|
}>;
|
|
|
|
type Usage = {
|
|
initialRx: number | null;
|
|
initialTx: number | null;
|
|
totalRx: number;
|
|
totalTx: number;
|
|
};
|
|
|
|
const getConnection = (instance?: Network.Wifi | Network.Wired) => {
|
|
if (!instance) return null;
|
|
|
|
const addresses = (instance instanceof Network.Wifi
|
|
? instance?.activeConnection
|
|
: instance?.connection)
|
|
?.ip4Config?.get_addresses();
|
|
return addresses.map(addr => addr.get_address()).join(", ");
|
|
}
|
|
|
|
export default function NetworkInfo() {
|
|
const net = Network.get_default();
|
|
const wiredConn = bind(net, "wired");
|
|
const wifiConn = bind(net, "wifi");
|
|
|
|
const currentConn = Variable.derive([
|
|
wiredConn,
|
|
wifiConn
|
|
], (wired, wifi) => {
|
|
switch (net.primary) {
|
|
case Network.Primary.WIFI: return wifi;
|
|
case Network.Primary.WIRED: return wired;
|
|
default: return;
|
|
}
|
|
})
|
|
|
|
const networkInterface = net.primary == 1 ? "enp0s31f6" : "wlp4s0";
|
|
const networkUsage = Variable<Usage>({
|
|
initialRx: null,
|
|
initialTx: null,
|
|
totalRx: 0,
|
|
totalTx: 0,
|
|
}).poll(
|
|
5000,
|
|
['ip', '-s', '-j', 'link', 'show', networkInterface],
|
|
(out, prev) => {
|
|
const ipOutput = JSON.parse(out) as IpOutput;
|
|
const totalRx = ipOutput?.reduce((prev, item) => prev + item.stats64.rx.bytes, 0);
|
|
const totalTx = ipOutput?.reduce((prev, item) => prev + item.stats64.tx.bytes, 0);
|
|
|
|
return {
|
|
initialRx: prev.initialRx ?? totalRx,
|
|
initialTx: prev.initialTx ?? totalTx,
|
|
totalTx,
|
|
totalRx,
|
|
};
|
|
}
|
|
);
|
|
|
|
const dataBinding = bind(networkUsage);
|
|
const binding = bind(currentConn);
|
|
|
|
return binding.as(Boolean) ? <>
|
|
{binding.as(getConnection).as(data => data && <label label={data} />)}
|
|
{dataBinding.as(data => <>
|
|
<label label={`TX: ${toHumanReadable(data.totalTx / 4, "B/s")}`} />
|
|
<label label={`RX: ${toHumanReadable(data.totalRx / 4, "B/s")}`} />
|
|
</>)}
|
|
</> : <label>No network</label>
|
|
}
|