Add network ping and speed test sections
This commit is contained in:
Executable
+90
@@ -0,0 +1,90 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# omarchy:summary=Measure live internet speed for one direction
|
||||||
|
# omarchy:group=network
|
||||||
|
# omarchy:args=[down|up]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
direction="${1:-}"
|
||||||
|
probe=1.1.1.1
|
||||||
|
download_bytes=25000000
|
||||||
|
upload_blocks=64
|
||||||
|
|
||||||
|
case "$direction" in
|
||||||
|
down | up)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: omarchy-network-speedtest [down|up]" >&2
|
||||||
|
exit 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
format_mbps() {
|
||||||
|
awk -v value="$1" 'BEGIN {
|
||||||
|
if (value <= 0) print "0.0"
|
||||||
|
else if (value < 10) printf "%.1f\n", value
|
||||||
|
else printf "%.0f\n", value
|
||||||
|
}'
|
||||||
|
}
|
||||||
|
|
||||||
|
iface=$(ip route get "$probe" 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i == "dev") { print $(i + 1); exit } }')
|
||||||
|
|
||||||
|
if [[ -z $iface || ! -r /sys/class/net/$iface/statistics/rx_bytes || ! -r /sys/class/net/$iface/statistics/tx_bytes ]]; then
|
||||||
|
echo "No active network interface" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! omarchy-cmd-present curl; then
|
||||||
|
echo "curl is required" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
traffic_pid=""
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n $traffic_pid ]]; then
|
||||||
|
pkill -TERM -P "$traffic_pid" 2>/dev/null || true
|
||||||
|
kill "$traffic_pid" 2>/dev/null || true
|
||||||
|
wait "$traffic_pid" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
if [[ $direction == "down" ]]; then
|
||||||
|
while true; do
|
||||||
|
curl -fsS -o /dev/null "https://speed.cloudflare.com/__down?bytes=$download_bytes" 2>/dev/null || exit
|
||||||
|
done &
|
||||||
|
else
|
||||||
|
while true; do
|
||||||
|
dd if=/dev/zero bs=1M count="$upload_blocks" 2>/dev/null | curl -fsS -o /dev/null -X POST --data-binary @- "https://speed.cloudflare.com/__up" 2>/dev/null || exit
|
||||||
|
done &
|
||||||
|
fi
|
||||||
|
traffic_pid=$!
|
||||||
|
|
||||||
|
rx_before=$(cat "/sys/class/net/$iface/statistics/rx_bytes")
|
||||||
|
tx_before=$(cat "/sys/class/net/$iface/statistics/tx_bytes")
|
||||||
|
|
||||||
|
while kill -0 "$traffic_pid" 2>/dev/null; do
|
||||||
|
sleep 1
|
||||||
|
rx_after=$(cat "/sys/class/net/$iface/statistics/rx_bytes")
|
||||||
|
tx_after=$(cat "/sys/class/net/$iface/statistics/tx_bytes")
|
||||||
|
|
||||||
|
if [[ $direction == "down" ]]; then
|
||||||
|
rate=$(awk -v before="$rx_before" -v after="$rx_after" 'BEGIN {
|
||||||
|
if (after < before) print 0
|
||||||
|
else print (after - before) * 8 / 1000000
|
||||||
|
}')
|
||||||
|
else
|
||||||
|
rate=$(awk -v before="$tx_before" -v after="$tx_after" 'BEGIN {
|
||||||
|
if (after < before) print 0
|
||||||
|
else print (after - before) * 8 / 1000000
|
||||||
|
}')
|
||||||
|
fi
|
||||||
|
|
||||||
|
format_mbps "$rate"
|
||||||
|
rx_before=$rx_after
|
||||||
|
tx_before=$tx_after
|
||||||
|
done
|
||||||
|
|
||||||
|
wait "$traffic_pid" 2>/dev/null || true
|
||||||
@@ -112,12 +112,13 @@ function appendPingSample(samples, raw, limit) {
|
|||||||
return values
|
return values
|
||||||
}
|
}
|
||||||
|
|
||||||
function averagePingLatency(samples) {
|
function averagePingLatency(samples, limit) {
|
||||||
var values = Array.isArray(samples) ? samples : []
|
var values = Array.isArray(samples) ? samples : []
|
||||||
|
var sampleLimit = Math.max(1, parseInt(limit, 10) || values.length || 1)
|
||||||
var total = 0
|
var total = 0
|
||||||
var count = 0
|
var count = 0
|
||||||
|
|
||||||
for (var i = 0; i < values.length; i++) {
|
for (var i = Math.max(0, values.length - sampleLimit); i < values.length; i++) {
|
||||||
var value = values[i]
|
var value = values[i]
|
||||||
if (typeof value !== "number" || !isFinite(value) || value < 0) continue
|
if (typeof value !== "number" || !isFinite(value) || value < 0) continue
|
||||||
total += value
|
total += value
|
||||||
@@ -127,11 +128,30 @@ function averagePingLatency(samples) {
|
|||||||
return count > 0 ? total / count : -1
|
return count > 0 ? total / count : -1
|
||||||
}
|
}
|
||||||
|
|
||||||
function pingLatencyState(previous, next, limit) {
|
function pingPacketLossPercent(samples) {
|
||||||
|
var values = Array.isArray(samples) ? samples : []
|
||||||
|
if (values.length === 0) return 0
|
||||||
|
|
||||||
|
var lost = 0
|
||||||
|
for (var i = 0; i < values.length; i++) {
|
||||||
|
if (values[i] === null) lost++
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.round((lost / values.length) * 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPacketLoss(percent) {
|
||||||
|
var value = parseInt(percent, 10)
|
||||||
|
if (!value || value < 0) return "0%"
|
||||||
|
return value + "%"
|
||||||
|
}
|
||||||
|
|
||||||
|
function pingLatencyState(previous, next, limit, averageLimit) {
|
||||||
var prev = previous || {}
|
var prev = previous || {}
|
||||||
var sample = next || {}
|
var sample = next || {}
|
||||||
var iface = sample.iface || ""
|
var iface = sample.iface || ""
|
||||||
var window = Math.max(1, parseInt(limit, 10) || 5)
|
var window = Math.max(1, parseInt(limit, 10) || 5)
|
||||||
|
var averageWindow = Math.max(1, parseInt(averageLimit, 10) || window)
|
||||||
var reset = iface === "" || iface !== (prev.pingIface || "")
|
var reset = iface === "" || iface !== (prev.pingIface || "")
|
||||||
var routerSamples = reset ? [] : prev.routerPingSamples
|
var routerSamples = reset ? [] : prev.routerPingSamples
|
||||||
var internetSamples = reset ? [] : prev.internetPingSamples
|
var internetSamples = reset ? [] : prev.internetPingSamples
|
||||||
@@ -143,8 +163,9 @@ function pingLatencyState(previous, next, limit) {
|
|||||||
pingIface: iface,
|
pingIface: iface,
|
||||||
routerPingSamples: routerSamples,
|
routerPingSamples: routerSamples,
|
||||||
internetPingSamples: internetSamples,
|
internetPingSamples: internetSamples,
|
||||||
routerPingLatency: averagePingLatency(routerSamples),
|
routerPingLatency: averagePingLatency(routerSamples, averageWindow),
|
||||||
internetPingLatency: averagePingLatency(internetSamples)
|
internetPingLatency: averagePingLatency(internetSamples, averageWindow),
|
||||||
|
internetPingPacketLoss: pingPacketLossPercent(internetSamples)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +182,12 @@ function formatRate(bytesPerSec) {
|
|||||||
return formatBytes(bytesPerSec) + "/s"
|
return formatBytes(bytesPerSec) + "/s"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatSpeedMbps(mbps) {
|
||||||
|
var value = parseFloat(mbps)
|
||||||
|
if (!isFinite(value) || value <= 0) return "--"
|
||||||
|
return value.toFixed(value > 0 && value < 10 ? 1 : 0) + " Mbps"
|
||||||
|
}
|
||||||
|
|
||||||
function formatPingLatency(ms) {
|
function formatPingLatency(ms) {
|
||||||
var value = parseFloat(ms)
|
var value = parseFloat(ms)
|
||||||
if (!isFinite(value) || value < 0) return "Timeout"
|
if (!isFinite(value) || value < 0) return "Timeout"
|
||||||
@@ -226,8 +253,11 @@ if (typeof module !== "undefined") {
|
|||||||
parseKeyValue: parseKeyValue,
|
parseKeyValue: parseKeyValue,
|
||||||
throughputState: throughputState,
|
throughputState: throughputState,
|
||||||
pingLatencyState: pingLatencyState,
|
pingLatencyState: pingLatencyState,
|
||||||
|
pingPacketLossPercent: pingPacketLossPercent,
|
||||||
|
formatPacketLoss: formatPacketLoss,
|
||||||
formatBytes: formatBytes,
|
formatBytes: formatBytes,
|
||||||
formatRate: formatRate,
|
formatRate: formatRate,
|
||||||
|
formatSpeedMbps: formatSpeedMbps,
|
||||||
formatPingLatency: formatPingLatency,
|
formatPingLatency: formatPingLatency,
|
||||||
wifiRow: wifiRow,
|
wifiRow: wifiRow,
|
||||||
sortWifiRows: sortWifiRows,
|
sortWifiRows: sortWifiRows,
|
||||||
|
|||||||
@@ -37,13 +37,10 @@ Panel {
|
|||||||
property var internetPingSamples: []
|
property var internetPingSamples: []
|
||||||
property real routerPingLatency: -1
|
property real routerPingLatency: -1
|
||||||
property real internetPingLatency: -1
|
property real internetPingLatency: -1
|
||||||
readonly property int pingWindow: 5
|
property int internetPingPacketLoss: 0
|
||||||
readonly property bool hasRouterPing: routerPingSamples.length > 0
|
readonly property int pingHistoryWindow: 24
|
||||||
|
readonly property int pingAverageWindow: 5
|
||||||
readonly property bool hasInternetPing: internetPingSamples.length > 0
|
readonly property bool hasInternetPing: internetPingSamples.length > 0
|
||||||
readonly property bool hasPing: hasRouterPing || hasInternetPing
|
|
||||||
readonly property bool hasSecondPing: hasRouterPing && hasInternetPing
|
|
||||||
readonly property string primaryPingLabel: hasRouterPing ? "Router Ping" : (hasInternetPing ? "Internet Ping" : "")
|
|
||||||
readonly property real primaryPingLatency: hasRouterPing ? routerPingLatency : internetPingLatency
|
|
||||||
property int connectionPhraseIndex: 0
|
property int connectionPhraseIndex: 0
|
||||||
readonly property var connectionPhrases: [
|
readonly property var connectionPhrases: [
|
||||||
"Wiring bits",
|
"Wiring bits",
|
||||||
@@ -65,6 +62,14 @@ Panel {
|
|||||||
property bool wifiStationAvailable: false
|
property bool wifiStationAvailable: false
|
||||||
property string dnsProvider: ""
|
property string dnsProvider: ""
|
||||||
property string pendingDnsProvider: ""
|
property string pendingDnsProvider: ""
|
||||||
|
property bool speedTestRunning: false
|
||||||
|
property bool speedTestHasRun: false
|
||||||
|
property bool speedTestExpectedStop: false
|
||||||
|
property string speedTestPhase: ""
|
||||||
|
property string speedTestStderr: ""
|
||||||
|
property string speedTestDownloadMbps: ""
|
||||||
|
property string speedTestUploadMbps: ""
|
||||||
|
property string speedTestError: ""
|
||||||
|
|
||||||
// Per-row in-flight state. `actionSsid` flips on for the row whose action
|
// Per-row in-flight state. `actionSsid` flips on for the row whose action
|
||||||
// is currently running so it can render "Connecting…" / "Disconnecting…" /
|
// is currently running so it can render "Connecting…" / "Disconnecting…" /
|
||||||
@@ -158,6 +163,7 @@ Panel {
|
|||||||
internetPingSamples = []
|
internetPingSamples = []
|
||||||
routerPingLatency = -1
|
routerPingLatency = -1
|
||||||
internetPingLatency = -1
|
internetPingLatency = -1
|
||||||
|
internetPingPacketLoss = 0
|
||||||
if (wifiDevice) wifiDevice.scannerEnabled = false
|
if (wifiDevice) wifiDevice.scannerEnabled = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -322,13 +328,14 @@ Panel {
|
|||||||
pingIface: pingIface,
|
pingIface: pingIface,
|
||||||
routerPingSamples: routerPingSamples,
|
routerPingSamples: routerPingSamples,
|
||||||
internetPingSamples: internetPingSamples
|
internetPingSamples: internetPingSamples
|
||||||
}, next, pingWindow)
|
}, next, pingHistoryWindow, pingAverageWindow)
|
||||||
|
|
||||||
pingIface = state.pingIface
|
pingIface = state.pingIface
|
||||||
routerPingSamples = state.routerPingSamples
|
routerPingSamples = state.routerPingSamples
|
||||||
internetPingSamples = state.internetPingSamples
|
internetPingSamples = state.internetPingSamples
|
||||||
routerPingLatency = state.routerPingLatency
|
routerPingLatency = state.routerPingLatency
|
||||||
internetPingLatency = state.internetPingLatency
|
internetPingLatency = state.internetPingLatency
|
||||||
|
internetPingPacketLoss = state.internetPingPacketLoss
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatBytes(bytes) {
|
function formatBytes(bytes) {
|
||||||
@@ -339,10 +346,18 @@ Panel {
|
|||||||
return Model.formatRate(bytesPerSec)
|
return Model.formatRate(bytesPerSec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatSpeedMbps(mbps) {
|
||||||
|
return Model.formatSpeedMbps(mbps)
|
||||||
|
}
|
||||||
|
|
||||||
function formatPingLatency(ms) {
|
function formatPingLatency(ms) {
|
||||||
return Model.formatPingLatency(ms)
|
return Model.formatPingLatency(ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function formatPacketLoss(percent) {
|
||||||
|
return Model.formatPacketLoss(percent)
|
||||||
|
}
|
||||||
|
|
||||||
function findDevice(type) {
|
function findDevice(type) {
|
||||||
var devices = networkDevices || []
|
var devices = networkDevices || []
|
||||||
for (var i = 0; i < devices.length; i++) {
|
for (var i = 0; i < devices.length; i++) {
|
||||||
@@ -388,6 +403,53 @@ Panel {
|
|||||||
dnsProvider = value || "DHCP"
|
dnsProvider = value || "DHCP"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSpeedTestLine(line) {
|
||||||
|
var value = parseFloat(line)
|
||||||
|
if (!isFinite(value) || value < 0) return
|
||||||
|
|
||||||
|
if (speedTestPhase === "down") speedTestDownloadMbps = String(value)
|
||||||
|
else if (speedTestPhase === "up") speedTestUploadMbps = String(value)
|
||||||
|
speedTestError = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function runSpeedTest() {
|
||||||
|
if (speedTestProc.running) return
|
||||||
|
speedTestError = ""
|
||||||
|
speedTestHasRun = true
|
||||||
|
speedTestRunning = true
|
||||||
|
startSpeedTestPhase("down")
|
||||||
|
}
|
||||||
|
|
||||||
|
function startSpeedTestPhase(phase) {
|
||||||
|
speedTestExpectedStop = false
|
||||||
|
speedTestPhase = phase
|
||||||
|
speedTestStderr = ""
|
||||||
|
speedTestProc.command = ["omarchy-network-speedtest", phase]
|
||||||
|
speedTestProc.running = true
|
||||||
|
speedTestPhaseTimer.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopSpeedTestPhase() {
|
||||||
|
speedTestPhaseTimer.stop()
|
||||||
|
if (speedTestProc.running) {
|
||||||
|
speedTestExpectedStop = true
|
||||||
|
speedTestProc.running = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
finishSpeedTestPhase()
|
||||||
|
}
|
||||||
|
|
||||||
|
function finishSpeedTestPhase() {
|
||||||
|
if (speedTestPhase === "down") {
|
||||||
|
startSpeedTestPhase("up")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
speedTestPhase = ""
|
||||||
|
speedTestRunning = false
|
||||||
|
speedTestExpectedStop = false
|
||||||
|
}
|
||||||
|
|
||||||
function dnsCommand(provider) {
|
function dnsCommand(provider) {
|
||||||
var command = "omarchy-dns"
|
var command = "omarchy-dns"
|
||||||
if (provider) command += " " + Util.shellQuote(provider)
|
if (provider) command += " " + Util.shellQuote(provider)
|
||||||
@@ -541,6 +603,35 @@ Panel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: speedTestProc
|
||||||
|
stdout: SplitParser { onRead: function(line) { root.updateSpeedTestLine(line) } }
|
||||||
|
stderr: StdioCollector {
|
||||||
|
waitForEnd: true
|
||||||
|
onStreamFinished: root.speedTestStderr = String(text || "").trim()
|
||||||
|
}
|
||||||
|
onExited: function(exitCode) {
|
||||||
|
speedTestPhaseTimer.stop()
|
||||||
|
|
||||||
|
if (!root.speedTestExpectedStop && exitCode !== 0) {
|
||||||
|
root.speedTestError = root.speedTestStderr || "Speed test failed"
|
||||||
|
root.speedTestPhase = ""
|
||||||
|
root.speedTestRunning = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root.speedTestExpectedStop = false
|
||||||
|
root.finishSpeedTestPhase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: speedTestPhaseTimer
|
||||||
|
interval: 5000
|
||||||
|
repeat: false
|
||||||
|
onTriggered: root.stopSpeedTestPhase()
|
||||||
|
}
|
||||||
|
|
||||||
// Action runner for DNS provider changes. Wi-Fi actions use the
|
// Action runner for DNS provider changes. Wi-Fi actions use the
|
||||||
// Quickshell.Networking NetworkManager backend directly.
|
// Quickshell.Networking NetworkManager backend directly.
|
||||||
Process {
|
Process {
|
||||||
@@ -838,21 +929,17 @@ Panel {
|
|||||||
columnSpacing: Style.space(20)
|
columnSpacing: Style.space(20)
|
||||||
rowSpacing: Style.spacing.labelGap
|
rowSpacing: Style.spacing.labelGap
|
||||||
|
|
||||||
InfoLabel {
|
InfoLabel { visible: root.hasInternetPing; text: "Ping" }
|
||||||
visible: root.hasPing
|
|
||||||
text: root.primaryPingLabel
|
|
||||||
}
|
|
||||||
DetailValue {
|
DetailValue {
|
||||||
visible: root.hasPing
|
visible: root.hasInternetPing
|
||||||
text: root.formatPingLatency(root.primaryPingLatency)
|
text: root.formatPingLatency(root.internetPingLatency)
|
||||||
}
|
color: root.internetPingPacketLoss > 0 ? root.bar.urgent : root.bar.foreground
|
||||||
InfoLabel {
|
|
||||||
visible: root.hasPing
|
|
||||||
text: root.hasSecondPing ? "Internet Ping" : ""
|
|
||||||
}
|
}
|
||||||
|
InfoLabel { visible: root.hasInternetPing; text: "Packet Loss" }
|
||||||
DetailValue {
|
DetailValue {
|
||||||
visible: root.hasPing
|
visible: root.hasInternetPing
|
||||||
text: root.hasSecondPing ? root.formatPingLatency(root.internetPingLatency) : ""
|
text: root.formatPacketLoss(root.internetPingPacketLoss)
|
||||||
|
color: root.internetPingPacketLoss > 0 ? root.bar.urgent : root.bar.foreground
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoLabel { visible: root.info.rx_bytes !== undefined; text: "Receiving" }
|
InfoLabel { visible: root.info.rx_bytes !== undefined; text: "Receiving" }
|
||||||
@@ -888,6 +975,73 @@ Panel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PanelSeparator {
|
||||||
|
visible: !!root.info.iface
|
||||||
|
foreground: root.bar.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
visible: !!root.info.iface
|
||||||
|
width: parent.width
|
||||||
|
spacing: Style.space(12)
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Style.space(8)
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width
|
||||||
|
implicitHeight: Math.max(speedTestHeader.implicitHeight, speedRunButton.implicitHeight)
|
||||||
|
|
||||||
|
PanelSectionHeader {
|
||||||
|
id: speedTestHeader
|
||||||
|
text: "SPEED TEST"
|
||||||
|
foreground: root.bar.foreground
|
||||||
|
fontFamily: root.bar.fontFamily
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: speedRunButton
|
||||||
|
text: root.speedTestRunning ? "Running..." : "Run"
|
||||||
|
enabled: !root.speedTestRunning
|
||||||
|
foreground: root.bar.foreground
|
||||||
|
fontFamily: root.bar.fontFamily
|
||||||
|
fontSize: Style.font.bodySmall
|
||||||
|
horizontalPadding: Style.spacing.controlPaddingX
|
||||||
|
verticalPadding: Style.spacing.controlPaddingY
|
||||||
|
bordered: true
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: root.runSpeedTest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: speedTestValues
|
||||||
|
visible: root.speedTestHasRun
|
||||||
|
width: parent.width
|
||||||
|
spacing: Style.space(20)
|
||||||
|
|
||||||
|
readonly property real cellWidth: Math.max(0, (width - spacing * 3) / 4)
|
||||||
|
|
||||||
|
InfoLabel { width: speedTestValues.cellWidth; text: "Download" }
|
||||||
|
DetailValue { width: speedTestValues.cellWidth; text: root.formatSpeedMbps(root.speedTestDownloadMbps) }
|
||||||
|
InfoLabel { width: speedTestValues.cellWidth; text: "Upload" }
|
||||||
|
DetailValue { width: speedTestValues.cellWidth; text: root.formatSpeedMbps(root.speedTestUploadMbps) }
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoValue {
|
||||||
|
visible: root.speedTestError !== ""
|
||||||
|
text: root.speedTestError
|
||||||
|
color: root.bar.urgent
|
||||||
|
width: parent.width
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DNS provider selection.
|
// DNS provider selection.
|
||||||
PanelSeparator {
|
PanelSeparator {
|
||||||
foreground: root.bar.foreground
|
foreground: root.bar.foreground
|
||||||
|
|||||||
@@ -44,34 +44,37 @@ let ping = network.pingLatencyState(
|
|||||||
)
|
)
|
||||||
assertDeepEqual(
|
assertDeepEqual(
|
||||||
ping,
|
ping,
|
||||||
{ pingIface: 'wlan0', routerPingSamples: [2], internetPingSamples: [20], routerPingLatency: 2, internetPingLatency: 20 },
|
{ pingIface: 'wlan0', routerPingSamples: [2], internetPingSamples: [20], routerPingLatency: 2, internetPingLatency: 20, internetPingPacketLoss: 0 },
|
||||||
'network seeds ping latency samples'
|
'network seeds ping latency samples'
|
||||||
)
|
)
|
||||||
|
|
||||||
ping = network.pingLatencyState(ping, { iface: 'wlan0', router_ping_ms: '4.0', internet_ping_ms: '' }, 4)
|
ping = network.pingLatencyState(ping, { iface: 'wlan0', router_ping_ms: '4.0', internet_ping_ms: '' }, 4)
|
||||||
assertDeepEqual(
|
assertDeepEqual(
|
||||||
ping,
|
ping,
|
||||||
{ pingIface: 'wlan0', routerPingSamples: [2, 4], internetPingSamples: [20, null], routerPingLatency: 3, internetPingLatency: 20 },
|
{ pingIface: 'wlan0', routerPingSamples: [2, 4], internetPingSamples: [20, null], routerPingLatency: 3, internetPingLatency: 20, internetPingPacketLoss: 50 },
|
||||||
'network averages recent successful ping samples'
|
'network averages recent successful ping samples'
|
||||||
)
|
)
|
||||||
|
|
||||||
assertDeepEqual(
|
assertDeepEqual(
|
||||||
network.pingLatencyState(ping, { iface: 'eth0', router_ping_ms: '1.5', internet_ping_ms: '10.0' }, 4),
|
network.pingLatencyState(ping, { iface: 'eth0', router_ping_ms: '1.5', internet_ping_ms: '10.0' }, 4),
|
||||||
{ pingIface: 'eth0', routerPingSamples: [1.5], internetPingSamples: [10], routerPingLatency: 1.5, internetPingLatency: 10 },
|
{ pingIface: 'eth0', routerPingSamples: [1.5], internetPingSamples: [10], routerPingLatency: 1.5, internetPingLatency: 10, internetPingPacketLoss: 0 },
|
||||||
'network resets ping samples when interface changes'
|
'network resets ping samples when interface changes'
|
||||||
)
|
)
|
||||||
|
|
||||||
assertDeepEqual(
|
assertDeepEqual(
|
||||||
network.pingLatencyState(ping, { iface: 'wlan0', internet_ping_ms: '22.0' }, 4),
|
network.pingLatencyState(ping, { iface: 'wlan0', internet_ping_ms: '22.0' }, 4),
|
||||||
{ pingIface: 'wlan0', routerPingSamples: [], internetPingSamples: [20, null, 22], routerPingLatency: -1, internetPingLatency: 21 },
|
{ pingIface: 'wlan0', routerPingSamples: [], internetPingSamples: [20, null, 22], routerPingLatency: -1, internetPingLatency: 21, internetPingPacketLoss: 33 },
|
||||||
'network clears ping samples when a target is unavailable'
|
'network clears ping samples when a target is unavailable'
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEqual(network.formatBytes(1536), '1.5 KB', 'network formats bytes')
|
assertEqual(network.formatBytes(1536), '1.5 KB', 'network formats bytes')
|
||||||
assertEqual(network.formatRate(1536), '1.5 KB/s', 'network formats rates')
|
assertEqual(network.formatRate(1536), '1.5 KB/s', 'network formats rates')
|
||||||
|
assertEqual(network.formatSpeedMbps('250.4'), '250 Mbps', 'network formats speed test results')
|
||||||
assertEqual(network.formatPingLatency('2.54'), '2.5 ms', 'network formats low ping with precision')
|
assertEqual(network.formatPingLatency('2.54'), '2.5 ms', 'network formats low ping with precision')
|
||||||
assertEqual(network.formatPingLatency('25.4'), '25 ms', 'network formats ping')
|
assertEqual(network.formatPingLatency('25.4'), '25 ms', 'network formats ping')
|
||||||
assertEqual(network.formatPingLatency(''), 'Timeout', 'network formats missing ping as timeout')
|
assertEqual(network.formatPingLatency(''), 'Timeout', 'network formats missing ping as timeout')
|
||||||
|
assertEqual(network.formatPacketLoss(2), '2%', 'network formats packet loss')
|
||||||
|
assertEqual(network.formatPacketLoss(0), '0%', 'network formats zero packet loss')
|
||||||
|
|
||||||
const rows = network.sortWifiRows([
|
const rows = network.sortWifiRows([
|
||||||
{ ssid: 'Open', connected: false, known: false, signal: 95 },
|
{ ssid: 'Open', connected: false, known: false, signal: 95 },
|
||||||
|
|||||||
Reference in New Issue
Block a user