eufon/socket-repl.fnl

65 lines
2.0 KiB
Fennel

(local { : fdopen } (require "posix.stdio"))
(local fcntl (require "posix.fcntl"))
(local unistd (require "posix.unistd"))
(local socket (require "posix.sys.socket"))
(local { : repl } (require :fennel))
(fn watch-fd [fd mode handler]
(kiwmi:event_loop_add_fd fd mode handler))
(fn unix-socket-listener [pathname on-connected]
(let [sa {:family socket.AF_UNIX
:path pathname
}
fd (socket.socket socket.AF_UNIX socket.SOCK_STREAM 0)]
(socket.bind fd sa)
(socket.listen fd 5)
(watch-fd
fd fcntl.O_RDWR
#(let [connected-fd (socket.accept $1)]
(on-connected connected-fd)))
))
(fn get-input [fd]
(let [buf (unistd.read fd 1024)]
(if (and buf (> (# buf) 0))
buf
"\n,exit")))
(fn start [pathname]
(unistd.unlink pathname)
(unix-socket-listener
pathname
(fn [fd]
(let [sock (fdopen fd "w+")
repl-coro (coroutine.create repl)]
(watch-fd fd fcntl.O_RDONLY
(fn [fd]
(coroutine.resume repl-coro (get-input fd))
(if (= (coroutine.status repl-coro) :dead)
(do
(sock:write "bye!\n")
(sock:close)
false)
true
)))
(coroutine.resume repl-coro
{:readChunk
(fn [{: stack-size}]
(sock:write
(if (> stack-size 0) ".." ">> "))
(sock:flush)
(coroutine.yield))
:onValues
(fn [vals]
(sock:write (table.concat vals "\t"))
(sock:write "\n"))
:onError
(fn [errtype err]
(sock:write
(.. errtype " error: " (tostring err) "\n")))
})))))
{ : start }