eufon

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 229ba07b800072d51dc660efc613beb68fabc816
parent da00b8a3a520fd58828aa25e0ad70167fd25fd6f
Author: Daniel Barlow <dan@telent.net>
Date:   Sun,  3 Apr 2022 18:09:02 +0100

add "uplink" indicator

- currently shows ssid and signal strength, if wlan
- for lan, should show interface name (not tested)

plan to enhance with
- lan speed, for wired ethernet
- wwan support

Diffstat:
Mblinkenlicht/bl.fnl | 21++++++++++++++++++++-
Mblinkenlicht/iostream.fnl | 19+++++++++++++------
Dblinkenlicht/nl.fnl | 105-------------------------------------------------------------------------------
Ablinkenlicht/uplink.fnl | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 144 insertions(+), 112 deletions(-)

diff --git a/blinkenlicht/bl.fnl b/blinkenlicht/bl.fnl @@ -3,6 +3,7 @@ (local iostream (require :iostream)) (local metric (require :metric)) +(local uplink (require :uplink)) (stylesheet "licht.css") @@ -16,7 +17,6 @@ ; 0xf377 ; glyph not present in font-awesome free )) - (fn spawn [] true) @@ -41,6 +41,25 @@ {:text v}) })) + (let [uplink (uplink.new) + input (iostream.from-descriptor uplink.fd)] + (indicator { + :wait-for { + :input [input] + :interval (* 4 1000) + } + :refresh + #(let [status (uplink:status)] + (if status + {:text (.. (or status.ssid status.name "?") + " " + (if status.quality + (tostring (+ status.quality 100)) + ""))} + {:text "no internet"} + )) + })) + (let [f (iostream.open "/tmp/statuspipe" :r)] (indicator { ;; this is a guide to tell blinkenlicht when it might diff --git a/blinkenlicht/iostream.fnl b/blinkenlicht/iostream.fnl @@ -1,16 +1,23 @@ (local posix (require :posix)) (local fcntl (require :posix.fcntl)) +(fn from-descriptor [fd] + { + :read #(posix.unistd.read fd $2) ;XXX needs to check for eof + :close #(posix.unistd.close fd) + :fileno fd + }) + + (fn open [name direction] (let [flags (match direction :r posix.O_RDONLY :w (+ posix.O_WRONLY posix.O_CREAT)) fd (posix.open name flags)] (fcntl.fcntl fd fcntl.F_SETFL fcntl.O_NONBLOCK) - { - :read #(posix.unistd.read fd $2) ;XXX needs to check for eof - :close #(posix.unistd.close fd) - :fileno fd - })) + (from-descriptor fd))) -{: open } +{ + : open + : from-descriptor + } diff --git a/blinkenlicht/nl.fnl b/blinkenlicht/nl.fnl @@ -1,105 +0,0 @@ -(local nl (require :netlink)) -(local view (. (require :fennel) :view)) - -;; $ grep DEVTYPE /sys/class/net/*/uevent -;; /sys/class/net/docker0/uevent:DEVTYPE=bridge -;; /sys/class/net/wlp4s0/uevent:DEVTYPE=wlan -;; /sys/class/net/wwp0s20f0u2i12/uevent:DEVTYPE=wwan -;; (ethernet and loopback devices don't have DEVTYPE) - -(fn devtype [ifname] - (with-open [f (io.open (.. "/sys/class/net/" ifname "/uevent") :r)] - (accumulate [dtype nil - line #(f:read "*l") - :until dtype] - (let [(name value) (line:match "([^=]+)=(.+)")] - (if (= name "DEVTYPE") value dtype))))) - -;; if the type is wlan, we can get a signal strength indicator -;; from the "quality - link" column of /proc/net/wireless - -(fn wlan-link-quality [ifname] - (with-open [f (io.open "/proc/net/wireless" :r)] - (accumulate [strength nil - line #(f:read "*l") - :until strength] - ;; "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " - ;; "%6d %6d %6d\n", - ;; https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/wireless/wext-proc.c#n49 - - (let [(name status link level) - (line:match "(.-): +(%x+) +(%S-)[ .] +(%S-)[ .]")] - (if (= name ifname) - (tonumber level) - strength))))) - -(fn wlan-link-ssid [ifname] - ;; could do this directly using an ioctl - ;; http://papermint-designs.com/dmo-blog/2016-08-how-to-get-the-essid-of-the-wifi-network-you-are-connected-to-# - (with-open [f (io.popen (.. "iwgetid " ifname " --raw") :r)] - (f:read "*l"))) - -(fn get-network-info [event] - ;; augments a newlink event with relevant information, if it's - ;; sufficiently well-configured to have any - - ;; "up" => administratively up - ;; "running" => can actually exchange packets - (when (= event.running "yes") - (let [dtype (devtype event.name)] - (tset event :devtype dtype) - (when (= dtype "wlan") - (if (not event.ssid) - (tset event :ssid (wlan-link-ssid event.name))) - (tset event :quality (wlan-link-quality event.name))) - (when (= dtype "wwan") - ;; for wwan, need to determine how to get strength and carrier name - true) - )) - event) - - -(fn netlunk [] - (let [links {} - routes {} - sock (nl.socket)] - (fn handle-event [event] - (match event - {:event :newlink} - (tset links event.index - (match event.up - "yes" (get-network-info event) - "no" event)) - - {:event :newroute} - (tset routes (or event.dst "default") event) - - {} (print :unhandled event.event) - )) - (each [_ event (ipairs (sock:query ))] - (handle-event event)) - - { - :refresh #(each [_ event (ipairs (sock:event))] - (handle-event event)) - :fd (sock:fd) - :uplink (fn [self] - (let [defaultroute routes.default - interface (and defaultroute - (. links defaultroute.index))] - (and interface (= interface.running "yes") - (get-network-info interface)))) - :wait #(sock:poll 1000) - :interface (fn [self ifnum] (. links ifnum)) - } - )) - -(let [nl (netlunk)] - (while (or (nl:wait) true) - (nl:refresh) - (match (nl:uplink) - interface - (print "default route through " (view interface)) - nil - (print "no default route") - ))) diff --git a/blinkenlicht/uplink.fnl b/blinkenlicht/uplink.fnl @@ -0,0 +1,111 @@ +(local nl (require :netlink)) +(local view (. (require :fennel) :view)) + +;; $ grep DEVTYPE /sys/class/net/*/uevent +;; /sys/class/net/docker0/uevent:DEVTYPE=bridge +;; /sys/class/net/wlp4s0/uevent:DEVTYPE=wlan +;; /sys/class/net/wwp0s20f0u2i12/uevent:DEVTYPE=wwan +;; (ethernet and loopback devices don't have DEVTYPE) + +(fn devtype [ifname] + (with-open [f (io.open (.. "/sys/class/net/" ifname "/uevent") :r)] + (accumulate [dtype nil + line #(f:read "*l") + :until dtype] + (let [(name value) (line:match "([^=]+)=(.+)")] + (if (= name "DEVTYPE") value dtype))))) + +;; if the type is wlan, we can get a signal strength indicator +;; from the "quality - link" column of /proc/net/wireless + +(fn wlan-link-quality [ifname] + (with-open [f (io.open "/proc/net/wireless" :r)] + (accumulate [strength nil + line #(f:read "*l") + :until strength] + ;; "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d " + ;; "%6d %6d %6d\n", + ;; https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/wireless/wext-proc.c#n49 + + (let [(name status link level) + (line:match "(.-): +(%x+) +(%S-)[ .] +(%S-)[ .]")] + (if (= name ifname) + (tonumber level) + strength))))) + +(fn wlan-link-ssid [ifname] + ;; could do this directly using an ioctl + ;; http://papermint-designs.com/dmo-blog/2016-08-how-to-get-the-essid-of-the-wifi-network-you-are-connected-to-# + (with-open [f (io.popen (.. "iwgetid " ifname " --raw") :r)] + (f:read "*l"))) + +(fn get-network-info [event] + ;; augments a newlink event with relevant information, if it's + ;; sufficiently well-configured to have any + + ;; "up" => administratively up + ;; "running" => can actually exchange packets + (when (= event.running "yes") + (let [dtype (devtype event.name)] + (tset event :devtype dtype) + (when (= dtype "wlan") + (if (not event.ssid) + (tset event :ssid (wlan-link-ssid event.name))) + (tset event :quality (wlan-link-quality event.name))) + (when (= dtype "wwan") + ;; for wwan, need to determine how to get strength and carrier name + true) + )) + event) + +(fn uplink [] + (let [links {} + routes {} + sock (nl.socket)] + (fn handle-event [event] + (match event + {:event :newlink} + (tset links event.index + (match event.up + "yes" (get-network-info event) + "no" event)) + + {:event :newroute} + (tset routes (or event.dst "default") event) + + {} (print :unhandled event.event) + )) + (each [_ event (ipairs (sock:query ))] + (handle-event event)) + + { + :refresh #(each [_ event (ipairs (sock:event))] + (handle-event event)) + :fd (sock:fd) + :status (fn [self] + (self:refresh) + (let [defaultroute routes.default + interface (and defaultroute + (. links defaultroute.index))] + (and interface (= interface.running "yes") + (get-network-info interface)))) + :wait #(sock:poll 1000) + :interface (fn [self ifnum] + (. links ifnum)) + } + )) + +(comment +(let [nl (netlunk)] + (while (or (nl:wait) true) + (nl:refresh) + (match (nl:uplink) + interface + (print "default route through " (view interface)) + nil + (print "no default route") + )))) + +{ + :new uplink + }