devout: add event loop and main run function

This commit is contained in:
Daniel Barlow 2024-04-23 20:15:02 +01:00
parent 52eb283a26
commit 97a8ae1c84
3 changed files with 130 additions and 5 deletions

View file

@ -1,3 +1,9 @@
(local sock (require :minisock))
(local { : view } (require :fennel))
(fn trace [expr]
(doto expr (print :TRACE (view expr))))
(fn parse-uevent [s]
(let [at (string.find s "@" 1 true)
(nl nxt) (string.find s "\0" 1 true)]
@ -42,8 +48,80 @@
:subscribe (fn [_ id callback terms]
(tset subscribers id {: callback : terms }))
:unsubscribe (fn [_ id] (tset subscribers id nil))
}))
;; #define POLLIN 0x0001
;; #define POLLPRI 0x0002
;; #define POLLOUT 0x0004
;; #define POLLERR 0x0008
;; #define POLLHUP 0x0010
;; #define POLLNVAL 0x0020
{ : database }
(fn unix-socket [name]
(let [addr (.. "\1\0" name "\0\0\0\0\0")
(sock err) (sock.bind addr)]
(assert sock err)))
(fn pollfds-for [fds]
(table.concat (icollect [_ v (ipairs fds)] (string.pack "iHH" v 1 0))))
(fn unpack-pollfds [pollfds]
(var i 1)
(let [fds {}]
(while (< i (# pollfds))
(let [(fd _ revents i_) (string.unpack "iHH" pollfds i)]
(if (> revents 0) (tset fds fd revents))
(set i i_)))
fds))
(fn parse-terms [str]
(print :terms str)
(collect [n (string.gmatch str "([^ ]+)")]
(string.match n "(.-)=(.+)")))
(fn handle-client [db client]
(match (trace (sock.read client))
"" (do
(db:unsubscribe client)
false)
s (do
(db:subscribe
client
(fn [e]
(sock.write client (view e)))
(parse-terms s))
true)
(nil err) (do (print err) false)))
(fn event-loop []
(let [fds {}]
{
:register #(tset fds $2 $3)
:feed (fn [_ revents]
(each [fd revent (pairs revents)]
(when (not ((. fds fd) fd))
(tset fds fd nil)
(sock.close fd))))
:fds #(icollect [fd _ (pairs fds)] fd)
:_tbl #(do fds) ;exposed for tests
}))
(fn run []
(let [[sockname] arg
s (unix-socket sockname)
db (database)
loop (event-loop)]
(loop:register
s
#(match (sock.accept s)
(client addr)
(do
(loop:register client (partial handle-client db))
true)))
(while true
(let [pollfds (pollfds-for (loop:fds))
(rpollfds numfds) (sock.poll pollfds 1000)]
(when (> numfds 0)
(loop:feed (unpack-pollfds rpollfds)))))))
{ : database : run : event-loop }