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:
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
+ }