sane-scripts: sane-ip-reconnect: port to python & only connect to networks we *know*
This commit is contained in:
parent
aa8c3affcd
commit
ae78f2b6c2
|
@ -95,12 +95,11 @@ let
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
patchPhase = ''
|
# remove python scripts (we package them further below)
|
||||||
# remove python scripts (we package them further below)
|
patchPhase = builtins.concatStringsSep
|
||||||
rm sane-bt-search
|
"\n"
|
||||||
rm sane-date-math
|
(lib.mapAttrsToList (name: pkg: "rm ${pkg.pname}") py-scripts)
|
||||||
rm sane-reclaim-boot-space
|
;
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
|
@ -108,24 +107,29 @@ let
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
bt-search = static-nix-shell.mkPython3Bin {
|
py-scripts = {
|
||||||
pname = "sane-bt-search";
|
bt-search = static-nix-shell.mkPython3Bin {
|
||||||
src = ./src;
|
pname = "sane-bt-search";
|
||||||
pyPkgs = [ "natsort" "requests" ];
|
src = ./src;
|
||||||
|
pyPkgs = [ "natsort" "requests" ];
|
||||||
|
};
|
||||||
|
date-math = static-nix-shell.mkPython3Bin {
|
||||||
|
pname = "sane-date-math";
|
||||||
|
src = ./src;
|
||||||
|
};
|
||||||
|
reclaim-boot-space = static-nix-shell.mkPython3Bin {
|
||||||
|
pname = "sane-reclaim-boot-space";
|
||||||
|
src = ./src;
|
||||||
|
};
|
||||||
|
ip-reconnect = static-nix-shell.mkPython3Bin {
|
||||||
|
pname = "sane-ip-reconnect";
|
||||||
|
src = ./src;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
date-math = static-nix-shell.mkPython3Bin {
|
|
||||||
pname = "sane-date-math";
|
|
||||||
src = ./src;
|
|
||||||
};
|
|
||||||
reclaim-boot-space = static-nix-shell.mkPython3Bin {
|
|
||||||
pname = "sane-reclaim-boot-space";
|
|
||||||
src = ./src;
|
|
||||||
};
|
|
||||||
|
|
||||||
in
|
in
|
||||||
symlinkJoin {
|
symlinkJoin {
|
||||||
name = "sane-scripts";
|
name = "sane-scripts";
|
||||||
paths = [ shell-scripts bt-search date-math reclaim-boot-space ];
|
paths = [ shell-scripts ] ++ lib.attrValues py-scripts;
|
||||||
meta = {
|
meta = {
|
||||||
description = "collection of scripts associated with uninsane systems";
|
description = "collection of scripts associated with uninsane systems";
|
||||||
homepage = "https://git.uninsane.org";
|
homepage = "https://git.uninsane.org";
|
||||||
|
|
|
@ -1,20 +1,96 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env nix-shell
|
||||||
|
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])"
|
||||||
|
|
||||||
# reconnect to best wifi network.
|
import re
|
||||||
# lappy frequently DCs from the ideal network
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
set -ex
|
def rm_color(stdout: str) -> str:
|
||||||
|
" remove terminal control codes -- used by iwctl to colorize the output "
|
||||||
|
return re.sub("\\[[0-9;]*m", "", stdout)
|
||||||
|
|
||||||
sudo iwctl station wlan0 scan
|
def rm_heading(stdout: str) -> str:
|
||||||
sleep 5
|
return "\n".join(stdout.split("\n")[4:])
|
||||||
|
|
||||||
# get networks. remove control characters (colors), then leading info, then take the top-rated network
|
def extract_columns(stdout: str) -> list:
|
||||||
networks=$(iwctl station wlan0 get-networks rssi-dbms | sed 's/\[[0-9;]*m//g' | sed 's/ [ >]*/ /g' | sed 's/^ //' | tail -n +5)
|
" split each line into two fields "
|
||||||
|
lines = stdout.split("\n")
|
||||||
|
items = []
|
||||||
|
for l in lines:
|
||||||
|
# XXX: this will fail for non-psk networks
|
||||||
|
# but i don't split on space because that would fail for networks that have names with spaces
|
||||||
|
if " psk " not in l: continue
|
||||||
|
split_at = l.find(" psk ")
|
||||||
|
first, second = l[:split_at], l[split_at+5:]
|
||||||
|
first, second = first.strip(), second.strip()
|
||||||
|
if first.startswith('> '):
|
||||||
|
# the `>` is formatting, indicating that it's the active network
|
||||||
|
first = first[2:].strip()
|
||||||
|
items.append((first, second))
|
||||||
|
return items
|
||||||
|
|
||||||
strengths=$(echo "$networks" | grep -o '\-[0-9][0-9]* *$')
|
def iwctl(args: list, sudo: bool = False) -> str:
|
||||||
best_strength=$(echo "$strengths" | sort -h | tail -n 1)
|
cmd = [ "iwctl" ] + args
|
||||||
best_line=$(echo "$networks" | grep -- "$best_strength$")
|
if sudo:
|
||||||
# network names could have spaces in them if someone's evil, so rather than `cut`, we trim the `psk` and `db` columnds
|
cmd = [ "sudo" ] + cmd
|
||||||
best_network=$(echo "$best_line" | sed 's/ [a-z][a-z]* -[0-9][0-9]* *$//g')
|
res = subprocess.run(cmd, capture_output=True)
|
||||||
|
if res.returncode != 0:
|
||||||
|
print(f"iwctl failed:\n{res.stderr}")
|
||||||
|
res.check_returncode() # raise
|
||||||
|
return res.stdout.decode()
|
||||||
|
|
||||||
sudo iwctl station wlan0 connect "$best_network"
|
def scan():
|
||||||
|
iwctl(["station", "wlan0", "scan"], sudo=True)
|
||||||
|
time.sleep(5) # give time for adapter to see networks
|
||||||
|
|
||||||
|
def get_known() -> list:
|
||||||
|
stdout = iwctl(["known-networks", "list"])
|
||||||
|
stdout = rm_color(stdout)
|
||||||
|
stdout = rm_heading(stdout)
|
||||||
|
return [name for (name, date) in extract_columns(stdout)]
|
||||||
|
|
||||||
|
def get_visible() -> list:
|
||||||
|
stdout = iwctl(["station", "wlan0", "get-networks", "rssi-dbms"])
|
||||||
|
stdout = rm_color(stdout)
|
||||||
|
stdout = rm_heading(stdout)
|
||||||
|
return [(name, int(strength)) for (name, strength) in extract_columns(stdout)]
|
||||||
|
|
||||||
|
def choose_best(visible: list, known: list) -> str:
|
||||||
|
candidates = [(name, strength) for (name, strength) in visible if name in known]
|
||||||
|
# the least-negative RSSI is the best
|
||||||
|
return max(candidates, key=lambda c: c[1])[0]
|
||||||
|
|
||||||
|
def connect(network: str) -> str:
|
||||||
|
return iwctl(["station", "wlan0", "connect", network], sudo=True)
|
||||||
|
|
||||||
|
def restart() -> str:
|
||||||
|
return subprocess.check_output([
|
||||||
|
"sudo",
|
||||||
|
"systemctl",
|
||||||
|
"restart",
|
||||||
|
"iwd",
|
||||||
|
])
|
||||||
|
|
||||||
|
print("scanning for networks... ", end="", flush=True)
|
||||||
|
scan()
|
||||||
|
print("done")
|
||||||
|
print()
|
||||||
|
|
||||||
|
known = get_known()
|
||||||
|
print("known networks:", "".join(f"\n\t{name}" for name in known))
|
||||||
|
print()
|
||||||
|
|
||||||
|
visible = get_visible()
|
||||||
|
print("visible networks:", "".join(f"\n\t{name}: {rss}" for (name, rss) in visible))
|
||||||
|
print()
|
||||||
|
|
||||||
|
best = choose_best(visible, known)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print(f"connecting to {best}")
|
||||||
|
result = connect(best)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print("restarting iwd daemon")
|
||||||
|
restart()
|
||||||
|
else:
|
||||||
|
print("success", result)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user