socket-repl.fnl (2234B)
1 (local { : fdopen } (require "posix.stdio")) 2 (local fcntl (require "posix.fcntl")) 3 (local unistd (require "posix.unistd")) 4 (local socket (require "posix.sys.socket")) 5 (local lgi (require :lgi)) 6 7 (local { : GLib } lgi) 8 9 (local { : repl } (require :fennel)) 10 11 12 (fn watch-fd [fd mode handler] 13 (let [events [ GLib.IOCondition.IN GLib.IOCondition.HUP] 14 channel (GLib.IOChannel.unix_new fd)] 15 (GLib.io_add_watch channel 0 events #(handler fd)))) 16 17 (fn unix-socket-listener [pathname on-connected] 18 (let [sa {:family socket.AF_UNIX 19 :path pathname 20 } 21 fd (socket.socket socket.AF_UNIX socket.SOCK_STREAM 0)] 22 (socket.bind fd sa) 23 (socket.listen fd 5) 24 (watch-fd 25 fd fcntl.O_RDWR 26 #(let [connected-fd (socket.accept $1)] 27 (on-connected connected-fd))) 28 )) 29 30 (fn get-input [fd] 31 (let [buf (unistd.read fd 1024)] 32 (if (and buf (> (# buf) 0)) 33 buf 34 "\n,exit"))) 35 36 (fn start [pathname] 37 (unistd.unlink pathname) 38 (unix-socket-listener 39 pathname 40 (fn [fd] 41 (let [sock (fdopen fd "w+") 42 repl-coro (coroutine.create repl)] 43 (watch-fd fd fcntl.O_RDONLY 44 (fn [fd] 45 (coroutine.resume repl-coro (get-input fd)) 46 (if (= (coroutine.status repl-coro) :dead) 47 (do 48 (sock:write "bye!\n") 49 (sock:close) 50 false) 51 true 52 ))) 53 (coroutine.resume repl-coro 54 {:readChunk 55 (fn [{: stack-size}] 56 (sock:write 57 (if (> stack-size 0) ".." ">> ")) 58 (sock:flush) 59 (coroutine.yield)) 60 :onValues 61 (fn [vals] 62 (sock:write (table.concat vals "\t")) 63 (sock:write "\n")) 64 :onError 65 (fn [errtype err] 66 (sock:write 67 (.. errtype " error: " (tostring err) "\n"))) 68 }))))) 69 70 71 { : start }