lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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