net.server: Add watchfd, a simple API for watching file descriptors
authorKim Alvefur <zash@zash.se>
Wed, 09 May 2018 16:15:40 +0200
changeset 8784 53178b6ba589
parent 8783 4cab4ee5dfcc
child 8785 daa518a22c34
net.server: Add watchfd, a simple API for watching file descriptors
doc/net.server.lua
net/server_epoll.lua
net/server_event.lua
net/server_select.lua
--- a/doc/net.server.lua	Mon May 07 22:10:29 2018 +0200
+++ b/doc/net.server.lua	Wed May 09 16:15:40 2018 +0200
@@ -229,6 +229,18 @@
 local function hook_signal(signal_id, handler)
 end
 
+--[[ Adds a low-level FD watcher
+Arguments:
+-   fd_number: A non-negative integer representing a file descriptor or
+    object with a :getfd() method returning one
+-   on_readable: Optional callback for when the FD is readable
+-   on_writable: Optional callback for when the FD is writable
+
+Returns:
+-   net.server handle
+]]
+local function watchfd(fd_number, on_readable, on_writable)
+end
 
 return {
 	get_backend = get_backend;
@@ -240,4 +252,5 @@
 	addclient = addclient;
 	closeall = closeall;
 	hook_signal = hook_signal;
+	watchfd = watchfd;
 }
--- a/net/server_epoll.lua	Mon May 07 22:10:29 2018 +0200
+++ b/net/server_epoll.lua	Wed May 09 16:15:40 2018 +0200
@@ -15,6 +15,7 @@
 local setmetatable = setmetatable;
 local tostring = tostring;
 local pcall = pcall;
+local type = type;
 local next = next;
 local pairs = pairs;
 local log = require "util.logger".init("server_epoll");
@@ -586,6 +587,25 @@
 	return client, conn;
 end
 
+local function watchfd(fd, onreadable, onwriteable)
+	local conn = setmetatable({
+		conn = fd;
+		onreadable = onreadable;
+		onwriteable = onwriteable;
+		close = function (self)
+			self:setflags(false, false);
+		end
+	}, interface_mt);
+	if type(fd) == "number" then
+		conn.getfd = function ()
+			return fd;
+		end;
+		-- Otherwise it'll need to be something LuaSocket-compatible
+	end
+	conn:setflags(onreadable, onwriteable);
+	return conn;
+end;
+
 -- Dump all data from one connection into another
 local function link(from, to)
 	from.listeners = setmetatable({
@@ -663,6 +683,7 @@
 	closeall = closeall;
 	setquitting = setquitting;
 	wrapclient = wrapclient;
+	watchfd = watchfd;
 	link = link;
 	set_config = function (newconfig)
 		cfg = setmetatable(newconfig, default_config);
--- a/net/server_event.lua	Mon May 07 22:10:29 2018 +0200
+++ b/net/server_event.lua	Wed May 09 16:15:40 2018 +0200
@@ -834,6 +834,34 @@
 	return event_handle;
 end
 
+local function watchfd(fd, onreadable, onwriteable)
+	local handle = {};
+	function handle:setflags(r,w)
+		if r ~= nil then
+			if r and not self.wantread then
+				self.wantread = base:addevent(fd, EV_READ, function ()
+					onreadable(self);
+				end);
+			elseif not r and self.wantread then
+				self.wantread:close();
+				self.wantread = nil;
+			end
+		end
+		if w ~= nil then
+			if w and not self.wantwrite then
+				self.wantwrite = base:addevent(fd, EV_WRITE, function ()
+					onwriteable(self);
+				end);
+			elseif not r and self.wantread then
+				self.wantwrite:close();
+				self.wantwrite = nil;
+			end
+		end
+	end
+	handle:setflags(onreadable, onwriteable);
+	return handle;
+end
+
 return {
 	cfg = cfg,
 	base = base,
@@ -850,6 +878,7 @@
 	get_backend = get_backend,
 	hook_signal = hook_signal,
 	add_task = add_task,
+	watchfd = watchfd,
 
 	__NAME = SCRIPT_NAME,
 	__DATE = LAST_MODIFIED,
--- a/net/server_select.lua	Mon May 07 22:10:29 2018 +0200
+++ b/net/server_select.lua	Wed May 09 16:15:40 2018 +0200
@@ -1034,6 +1034,48 @@
 	end
 end
 
+local closewatcher = function (handler)
+	local socket = handler.conn;
+	_sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
+	_readlistlen = removesocket( _readlist, socket, _readlistlen )
+	_socketlist[ socket ] = nil
+end;
+
+local addremove = function (handler, read, send)
+	local socket = handler.conn
+	_socketlist[ socket ] = handler
+	if read ~= nil then
+		if read then
+			_readlistlen = addsocket( _readlist, socket, _readlistlen )
+		else
+			_sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
+		end
+	end
+	if send ~= nil then
+		if send then
+			_sendlistlen = addsocket( _sendlist, socket, _sendlistlen )
+		else
+			_readlistlen = removesocket( _readlist, socket, _readlistlen )
+		end
+	end
+end
+
+local watchfd = function ( fd, onreadable, onwriteable )
+	local socket = fd
+	if type(fd) == "number" then
+		socket = { getfd = function () return fd; end }
+	end
+	local handler = {
+		conn = socket;
+		readbuffer = onreadable or id;
+		sendbuffer = onwriteable or id;
+		close = closewatcher;
+		setflags = addremove;
+	};
+	addremove( handler, onreadable, onwriteable )
+	return handler
+end
+
 ----------------------------------// BEGIN //--
 
 use "setmetatable" ( _socketlist, { __mode = "k" } )
@@ -1058,6 +1100,7 @@
 
 	addclient = addclient,
 	wrapclient = wrapclient,
+	watchfd = watchfd,
 
 	loop = loop,
 	link = link,