-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Minor changes - [X] netspeed: auto-detect interface if undefined - [X] netspeed: new widget icons for device class and state - [X] netspeed: detect interface type (wired/wireless) - [X] netspeed: detect interface online state - [X] netspeed: show IPv4 address with the `@tokyo-night-tmux_netspeed_showip` option - [X] netspeed: vary the refresh rate with the `@tokyo-night-tmux_netspeed_refresh` option ## Bug & security fixes - [X] netspeed: improve accuracy and performance of netspeed calculations with `bc` - [X] netspeed: handle - [X] netspeed: handle VPN devices on macOS using the primary interface
- Loading branch information
Showing
6 changed files
with
238 additions
and
56 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
#!/usr/bin/env bash | ||
|
||
# Get network transmit data | ||
function get_bytes() { | ||
local interface="$1" | ||
if [[ "$(uname)" == "Linux" ]]; then | ||
awk -v interface="$interface" '$1 == interface ":" {print $2, $10}' /proc/net/dev | ||
elif [[ "$(uname)" == "Darwin" ]]; then | ||
netstat -ib | awk -v interface="$interface" '/^'"${interface}"'/ {print $7, $10}' | head -n1 | ||
else | ||
# Unsupported operating system | ||
exit 1 | ||
fi | ||
} | ||
|
||
# Convert into readable format | ||
function readable_format() { | ||
local bytes=$1 | ||
local secs=${2:-1} | ||
|
||
if [[ $bytes -lt 1048576 ]]; then | ||
echo "$(bc -l <<<"scale=1; $bytes / 1024 / $secs")KB/s" | ||
else | ||
echo "$(bc -l <<<"scale=1; $bytes / 1048576 / $secs")MB/s" | ||
fi | ||
} | ||
|
||
# Auto-determine interface | ||
function find_interface() { | ||
local interface | ||
if [[ $(uname) == "Linux" ]]; then | ||
interface=$(awk '$2 == 00000000 {print $1}' /proc/net/route) | ||
elif [[ $(uname) == "Darwin" ]]; then | ||
interface=$(route get default 2>/dev/null | grep interface | awk '{print $2}') | ||
# If VPN, fallback to en0 | ||
[[ ${interface:0:4} == "utun" ]] && interface="en0" | ||
fi | ||
echo "$interface" | ||
} | ||
|
||
# Detect interface IPv4 and status | ||
function interface_ipv4() { | ||
local interface="$1" | ||
local ipv4_addr | ||
local status="up" # Default assumption | ||
if [[ $(uname) == "Darwin" ]]; then | ||
# Check for an IPv4 on macOS | ||
ipv4_addr=$(ipconfig getifaddr "$interface") | ||
[[ -z $ipv4_addr ]] && status="down" | ||
elif [[ $(uname) == "Linux" ]]; then | ||
# Use 'ip' command to check for IPv4 address | ||
if command -v ip >/dev/null 2>&1; then | ||
ipv4_addr=$(ip addr show dev "$interface" 2>/dev/null | grep "inet\b" | awk '{sub("/.*", "", $2); print $2}') | ||
[[ -z $ipv4_addr ]] && status="down" | ||
# Use 'ifconfig' command to check for IPv4 address | ||
elif command -v ifconfig >/dev/null 2>&1; then | ||
ipv4_addr=$(ifconfig "$interface" 2>/dev/null | grep "inet\b" | awk '{print $2}') | ||
[[ -z $ipv4_addr ]] && status="down" | ||
# Fallback to operstate on Linux | ||
elif [[ $(cat "/sys/class/net/$interface/operstate" 2>/dev/null) != "up" ]]; then | ||
status="down" | ||
fi | ||
fi | ||
echo "$ipv4_addr" | ||
[[ $status == "up" ]] && return 0 || return 1 | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,70 +4,71 @@ | |
# email : [email protected] | ||
#<------------------------------------------------------------------------------------------> | ||
|
||
# Check if enabled | ||
ENABLED=$(tmux show-option -gv @tokyo-night-tmux_show_netspeed 2>/dev/null) | ||
[[ ${ENABLED} -ne 1 ]] && exit 0 | ||
|
||
# Imports | ||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.." | ||
. "${ROOT_DIR}/lib/coreutils-compat.sh" | ||
|
||
# Check the global value | ||
SHOW_NETSPEED=$(tmux show-option -gv @tokyo-night-tmux_show_netspeed) | ||
if [ "$SHOW_NETSPEED" != "1" ]; then | ||
exit 0 | ||
fi | ||
|
||
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
source $CURRENT_DIR/themes.sh | ||
source "$ROOT_DIR/src/themes.sh" | ||
source "$ROOT_DIR/lib/netspeed.sh" | ||
|
||
# Get network interface | ||
INTERFACE=$(tmux show-option -gv @tokyo-night-tmux_netspeed_iface 2>/dev/null) | ||
# Show IP address | ||
SHOW_IP=$(tmux show-option -gv @tokyo-night-tmux_netspeed_showip 2>/dev/null) | ||
# Time between refresh | ||
TIME_DIFF=$(tmux show-option -gv @tokyo-night-tmux_netspeed_refresh 2>/dev/null) | ||
TIME_DIFF=${TIME_DIFF:-1} | ||
|
||
# Get network transmit data from /proc/net/dev | ||
get_bytes() { | ||
local interface="$1" | ||
if [[ "$(uname)" == "Linux" ]]; then | ||
awk -v interface="$interface" '$1 == interface ":" {print $2, $10}' /proc/net/dev | ||
elif [[ "$(uname)" == "Darwin" ]]; then | ||
netstat -ib | awk -v interface="$interface" '/^'${interface}'/ {print $7, $10}' | ||
else | ||
# Unsupported operating system | ||
exit 1 | ||
fi | ||
} | ||
|
||
# Convert into readable format | ||
readable_format() { | ||
local bytes=$1 | ||
# Icons | ||
declare -A NET_ICONS | ||
NET_ICONS[wifi_up]="#[fg=${THEME[foreground]}]\U000f05a9" # nf-md-wifi | ||
NET_ICONS[wifi_down]="#[fg=${THEME[red]}]\U000f05aa" # nf-md-wifi_off | ||
NET_ICONS[wired_up]="#[fg=${THEME[foreground]}]\U000f0318" # nf-md-lan_connect | ||
NET_ICONS[wired_down]="#[fg=${THEME[red]}]\U000f0319" # nf-md-lan_disconnect | ||
NET_ICONS[traffic_tx]="#[fg=${THEME[bblue]}]\U000f06f6" # nf-md-upload_network | ||
NET_ICONS[traffic_rx]="#[fg=${THEME[bgreen]}]\U000f06f4" # nf-md-download_network | ||
NET_ICONS[ip]="#[fg=${THEME[foreground]}]\U000f0a5f" # nf-md-ip | ||
|
||
# Convert bytes to KBps, 'bc' is dependency, 'pacman -S bc' | ||
local kbps=$(echo "scale=1; $bytes / 1024" | bc) | ||
if (($(echo "$kbps < 1" | bc -l))); then | ||
echo "0.0B" | ||
elif (($(echo "$kbps >= 1024" | bc -l))); then | ||
# Convert KBps to MBps | ||
local mbps=$(echo "scale=1; $kbps / 1024" | bc) | ||
echo "${mbps}MB/s" | ||
else | ||
echo "${kbps}KB/s" | ||
fi | ||
} | ||
# Determine interface if not set | ||
if [[ -z $INTERFACE ]]; then | ||
INTERFACE=$(find_interface) | ||
[[ -z $INTERFACE ]] && exit 1 | ||
# Update tmux option for this session | ||
tmux set-option -g @tokyo-night-tmux_netspeed_iface "$INTERFACE" | ||
fi | ||
|
||
# Echo network speed | ||
read RX1 TX1 < <(get_bytes "$INTERFACE") | ||
sleep 1 | ||
read RX2 TX2 < <(get_bytes "$INTERFACE") | ||
read -r RX1 TX1 < <(get_bytes "$INTERFACE") | ||
sleep "$TIME_DIFF" | ||
read -r RX2 TX2 < <(get_bytes "$INTERFACE") | ||
|
||
RX_DIFF=$((RX2 - RX1)) | ||
TX_DIFF=$((TX2 - TX1)) | ||
|
||
TIME_DIFF=1 | ||
RX_SPEED="#[fg=${THEME[foreground]}]$(readable_format "$RX_DIFF" "$TIME_DIFF")" | ||
TX_SPEED="#[fg=${THEME[foreground]}]$(readable_format "$TX_DIFF" "$TIME_DIFF")" | ||
|
||
# Interface icon | ||
if [[ ${INTERFACE} == "en0" ]] || [[ -d /sys/class/net/${INTERFACE}/wireless ]]; then | ||
IFACE_TYPE="wifi" | ||
else | ||
IFACE_TYPE="wired" | ||
fi | ||
|
||
RX_SPEED=$(readable_format "$((RX_DIFF / TIME_DIFF))") | ||
TX_SPEED=$(readable_format "$((TX_DIFF / TIME_DIFF))") | ||
# Detect interface IPv4 and state | ||
if IPV4_ADDR=$(interface_ipv4 "$INTERFACE"); then | ||
IFACE_STATUS="up" | ||
else | ||
IFACE_STATUS="down" | ||
fi | ||
|
||
NETWORK_ICON="" | ||
NETWORK_ICON=${NET_ICONS[${IFACE_TYPE}_${IFACE_STATUS}]} | ||
|
||
# TODO: Use a more sophisticated method to detect iface type (wifi, ethernet, etc) | ||
if [ ${INTERFACE:0:1} == "w" ]; then | ||
NETWORK_ICON="" | ||
OUTPUT="${RESET}░ ${NET_ICONS[traffic_rx]} $RX_SPEED ${NET_ICONS[traffic_tx]} $TX_SPEED $NETWORK_ICON #[dim]$INTERFACE " | ||
if [[ ${SHOW_IP} -ne 0 ]] && [[ -n $IPV4_ADDR ]]; then | ||
OUTPUT+="${NET_ICONS[ip]} #[dim]$IPV4_ADDR " | ||
fi | ||
|
||
echo "${RESET}░ #[fg=${THEME[bgreen]}]${RESET} $RX_SPEED #[fg=${THEME[bblue]}]${RESET} $TX_SPEED ${NETWORK_ICON} #[dim]$INTERFACE " | ||
echo -e "$OUTPUT" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
#!/usr/bin/env bats | ||
|
||
setup() { | ||
if [[ $(uname) == "Darwin" ]]; then | ||
HOMEBREW_PREFIX=$(brew --prefix) | ||
load "${HOMEBREW_PREFIX}/lib/bats-mock/stub.bash" | ||
else | ||
load /usr/lib/bats-mock/stub.bash | ||
fi | ||
# shellcheck source=lib/netspeed.sh | ||
source "${BATS_TEST_DIRNAME}/../lib/netspeed.sh" | ||
|
||
# macOS stubs | ||
if [[ $(uname) == "Darwin" ]]; then | ||
stub route \ | ||
"get default : echo -e ' gateway: 192.168.0.1\n interface: en0\n flags: <UP,GATEWAY,DONE,STATIC,PRCLONING,GLOBAL>'" \ | ||
"get default : echo -e ' gateway: 192.168.1.1\n interface: en1\n flags: <UP,GATEWAY,DONE,STATIC,PRCLONING,GLOBAL>'" \ | ||
"get default : echo -e ' gateway: 10.23.45.67\n interface: utun4\n flags: <UP,GATEWAY,DONE,STATIC,PRCLONING,GLOBAL>'" | ||
stub ipconfig \ | ||
"getifaddr en0 : echo 172.17.0.2" | ||
stub netstat \ | ||
"-ib : echo -e 'en0 1500 <Link#15> 49:2f:d3:60:03:33 79545944 0 67521187295 39466094 0 14135888609 0\nen0 1500 fake-host. fe80:f::123:beef: 79545944 - 67521187295 39466094 - 14135888609 -'" | ||
elif [[ $(uname) == "Linux" ]]; then | ||
stub ip \ | ||
"addr show dev eth0 : echo -e '18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65535 qdisc noqueue state UP group default\n link/ether 49:2f:d3:60:03:33 brd ff:ff:ff:ff:ff:ff link-netnsid 0\n inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0\n valid_lft forever preferred_lft forever\n inet6 fe80::b576:50dc:d0a6:8d9a/64 scope link\n valid_lft forever preferred_lft forever'" | ||
stub ifconfig \ | ||
"eth0 : echo -e 'eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 65535\n inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255\n inet6 fe80::b576:50dc:d0a6:8d9a prefixlen 64 scopeid 0x20<link>\n ether 49:2f:d3:60:03:33 txqueuelen 0 (Ethernet)\n RX packets 3609 bytes 11565908 (11.0 MiB)\n RX errors 0 dropped 0 overruns 0 frame 0\n TX packets 2716 bytes 182918 (178.6 KiB)\n TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0'" | ||
fi | ||
} | ||
|
||
teardown() { | ||
if [[ $(uname) == "Darwin" ]]; then | ||
run unstub route | ||
run unstub ipconfig | ||
run unstub netstat | ||
elif [[ $(uname) == "Linux" ]]; then | ||
run unstub ip | ||
run unstub ifconfig | ||
fi | ||
} | ||
|
||
@test "Test get_bytes (macOS)" { | ||
# Skip test if not on macOS | ||
if [[ $(uname) != "Darwin" ]]; then | ||
skip | ||
fi | ||
run get_bytes en0 | ||
[[ $output == "67521187295 14135888609" ]] | ||
} | ||
|
||
@test "Test readable_format" { | ||
run readable_format 1024 | ||
[[ $output == "1.0KB/s" ]] | ||
run readable_format 1048576 | ||
[[ $output == "1.0MB/s" ]] | ||
run readable_format 34829287 | ||
[[ $output == "33.2MB/s" ]] | ||
} | ||
|
||
@test "Test readable_format with delay" { | ||
run readable_format 34829287 1.0 | ||
[[ $output == "33.2MB/s" ]] | ||
run readable_format 19578465 3 | ||
[[ $output == "6.2MB/s" ]] | ||
run readable_format 29584754 2.5 | ||
[[ $output == "11.2MB/s" ]] | ||
} | ||
|
||
@test "Test find_interface (macOS)" { | ||
# Skip test if not on macOS | ||
if [[ $(uname) != "Darwin" ]]; then | ||
skip | ||
fi | ||
|
||
# en0 wifi | ||
run find_interface | ||
[[ $output == "en0" ]] | ||
# en1 wired | ||
run find_interface | ||
[[ $output == "en1" ]] | ||
# utun4 vpn | ||
run find_interface | ||
[[ $output == "en0" ]] # should fallback to en0 | ||
} | ||
|
||
@test "Test interface_ipv4 (Linux)" { | ||
# Skip test if not on Linux | ||
if [[ $(uname) != "Linux" ]]; then | ||
skip | ||
fi | ||
|
||
# Test docker local IP | ||
run interface_ipv4 eth0 | ||
[[ $output == "172.17.0.2" ]] | ||
[[ $status == 0 ]] | ||
|
||
# Test non-existing interface | ||
run interface_ipv4 eth69 | ||
[[ $output == "" ]] | ||
[[ $status == 1 ]] | ||
} | ||
|
||
@test "Test interface_ipv4 (macOS)" { | ||
# Skip test if not on Linux | ||
if [[ $(uname) != "Darwin" ]]; then | ||
skip | ||
fi | ||
|
||
# Test docker local IP | ||
run interface_ipv4 en0 | ||
[[ $output == "172.17.0.2" ]] | ||
[[ $status == 0 ]] | ||
|
||
# Test non-existing interface | ||
run interface_ipv4 en69 | ||
[[ $output == "" ]] | ||
[[ $status == 1 ]] | ||
} |
This file was deleted.
Oops, something went wrong.