[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: A Batteries API specification (was Re: LuaDEAL - Lua DEad Alive Libraries)
- From: Sean Conner <sean@...>
- Date: Sat, 8 Feb 2020 17:10:21 -0500
It was thus said that the Great Philipp Janda once stated:
> Am 06.02.20 um 18:26 schröbte Pierre Chapuis:
> >On Thu, Feb 6, 2020, at 18:23, Pierre Chapuis wrote:
> >
> >>Yes. I remember reading an explanation along those lines by Ryan Dahl
> >>somewhere.
> >
> >Found it: https://tinyclouds.org/iocp-links.html
>
>
> Very interesting read. Thanks for the link!
>
> It appears to me that if we want portable (meaning also Windows) event
> handling in your standard library, there currently is no way around
> libuv.
The problem with libuv is that it's a framework, not a library [1]. And
thus, you have to buy into its framework for how things should work. And oh
boy, does it have opinions on how things should work. It supports:
Full-featured event loop backed by epoll, kqueue, IOCP, event ports.
Asynchronous TCP and UDP sockets
Asynchronous DNS resolution
Asynchronous file and file system operations
File system events
ANSI escape code controlled TTY
IPC with socket sharing, using Unix domain sockets or named pipes (Windows)
Child processes
Thread pool
Signal handling
High resolution clock
Threading and synchronization primitives
That's a *huge surface area*, but it almost has to support all those. It
needs threads to deal with reading/writing files [2], and if you have
thrads, you need signal handling [3]. And if you are doing non-blocking
socket operations, of course you'll need DNS resolution [4].
> The good news is that there already are Lua bindings to libuv, so
> we have a starting point for our Lua extended standard library.
Yes there are. I looked at two, and neither one looks inviting to me.
Both of them give an example of usage in a echo service. Using my own
framework [6], the echo example is:
local nfl = require "org.conman.nfl"
local tcp = require "org.conman.nfl.tcp"
local function echo(ios)
for line in ios:lines() do
ios:write(line,'\n')
end
ios:close()
end
tcp.listen('localhost',1337,echo)
nfl.server_eventloop()
or, if you want TLS [7]:
local nfl = require "org.conman.nfl"
local tls = require "org.conman.nfl.tls"
local function echo(ios)
for line in ios:lines() do
ios:write(line,'\n')
end
ios:close()
end
tls.listen('localhost',1337,echo,function(conf)
return conf:cert_file('certfile')
and conf:key_file ('keyfile')
and conf:protocols("all")
end)
nfl.server_eventloop()
But this is a framework, and as I've said above, you *have* to buy into
how it works to use it. I have some other examples of how it works [8], but
again, org.conman.nfl is a *framework*, not a library. And keep those two
examples in mind, because in my mind, those are the simplest examples you'll
see.
I also have a non-event version of the above API (mostly for client side)
that presents a similar (but not identical) interface.
Anyway, I'll start with the simpler of the two Lua bindings to libuv, lluv
[9]. It's available via LuaRocks, which is good, and it seems like a very
straightforward binding (with all the implications, good and bad), and the
sample echo server:
local uv = require "lluv"
local ut = require "lluv.utils"
local socket = require "lluv.luasocket"
local function echo(cli)
while true do
local msg, err = cli:receive("*r")
if not msg then break end
cli:send(msg)
end
cli:close()
end
local function server(host, port, fn)
local srv = socket.tcp()
srv:bind(host, port)
while true do
local cli = srv:accept()
ut.corun(function()
-- attach socket to current coroutine
fn(cli:attach())
end)
end
end
ut.corun(server, "127.0.0.1", 1337, echo)
uv.run()
There is support for TLS [10] but it's not as easy as mine to use, and I'm
having a hard time figuring out how to integrate the scant examples on the
SSL page with the echo server above. I'm sure it's possible.
Then there's luv [11]. It too, is available via LuaRocks, but it appears
to be its own echosystem, with it's own package manager [12] and everything.
And the sample echo server is nothing to write home about either:
local uv = require('luv')
local function create_server(host, port, on_connection)
local server = uv.new_tcp()
server:bind(host, port)
server:listen(128, function(err)
-- Make sure there was no problem setting up listen
assert(not err, err)
-- Accept the client
local client = uv.new_tcp()
server:accept(client)
on_connection(client)
end)
return server
end
local server = create_server("0.0.0.0", 1337, function (client)
client:read_start(function (err, chunk)
-- Crash on errors
assert(not err, err)
if chunk then
-- Echo anything heard
client:write(chunk)
else
-- When the stream ends, close the socket
client:close()
end
end)
end)
print("TCP Echo server listening on port " .. server:getsockname().port)
uv.run()
They do seem to have wrappers for OpenSSL, but no examples that I can see
about how to use them.
> I don't
> know how the current state of the binding is. Maybe we have to add CI
> for the three target OSes and the common Lua versions/implementations,
> maybe add valgrind, clang-tidy etc. to the mix, add missing pieces to
> binding code and/or unit tests, do code reviews, the usual stuff. But we
> can continue from there. I believe there also is a Lua distribution
> based on libuv with some batteries included. It probably deserves a
> closer look as well as a possible starting point.
Yeah. Javascript wins the world.
-spc
[1] Well, *technically* it's a library.
[2] Because on POSIX, you *can't* use select(), poll(), epoll(), et. al
with files because they're always "ready" even if they might block.
[3] Because some signals are delivered to a specific thread (say,
SIGSEGV) and some will be sent to any thread in a process (say,
SIGUSR1).
[4] Which for me is big flashing red alert sign. Years ago at work,
some cow-orkers were trying to use an existing DNS library and it
was just a mess because it was hard to integrate into the existing
framework they were using. It was a nightmare for integrate and
debug and they were still trying to work it when I suggested my own
DNS library [5]. One day later they had it integrated and working,
because my DNS library *did not do the networking!*
[5] https://github.com/spc476/SPCDNS
[6] https://github.com/spc476/lua-conmanorg/blob/master/lua/nfl.lua
https://github.com/spc476/lua-conmanorg/tree/master/lua/nfl
[7] I'm using libtls, which comes with libressl. Sadly, it doesn't seem
to be used outside of OpenBSD. It's a shame, because libtls makes
it very easy to use TLS.
[8] https://github.com/spc476/port70
https://github.com/spc476/GLV-1.12556
[9] https://github.com/moteus/lua-lluv
[10] https://github.com/moteus/lua-lluv-ssl
[11] https://github.com/luvit/luv
[12] https://github.com/luvit/lit