clients.lua: Add client activity tracking

Mon, 04 Jan 2016 11:35:43 +0000

author
Matthew Wild <mwild1@gmail.com>
date
Mon, 04 Jan 2016 11:35:43 +0000
changeset 6
4e46ef3035ba
parent 5
4a3caf5d0f4b
child 7
59655d6c45b3

clients.lua: Add client activity tracking

clients.lua file | annotate | diff | comparison | revisions
--- a/clients.lua	Mon Jan 04 11:05:50 2016 +0000
+++ b/clients.lua	Mon Jan 04 11:35:43 2016 +0000
@@ -1,6 +1,7 @@
 local socket = require "socket";
 local server = require "net.server_select";
 local http_server = require"net.http.server";
+local new_uuid = require "util.uuid".generate;
 local log = require "util.logger".init("clients");
 
 local response_head = 	table.concat({
@@ -13,6 +14,7 @@
 	"Keep-Alive: timeout=5, max=99";
 	"Connection: Keep-Alive";
 	"Transfer-Encoding: chunked";
+	"Set-Cookie: COOKIE_STRING";
 	"";
 	"";	
 }, "\r\n");
@@ -21,15 +23,36 @@
 
 local last_chunk;
 
+local have_clients = false;
+
+-- [conn] = cookie
 local clients = {};
+-- [cookie] = conn
+local client_by_cookie = {};
+-- [conn] = last_active_timestamp
+local active_clients = {};
+
+local activity_timeout = 20;
+
+local function update_have_clients()
+	if have_clients and not next(active_clients) then
+		have_clients = false;
+		log("debug", "No more clients");
+		events.fire_event("no-clients");
+	elseif not have_clients and next(active_clients) then
+		have_clients = true;
+		log("debug", "Active clients");
+		events.fire_event("have-clients");
+	end
+end
+
 
 -- Called when a HTTP stream client closes
 function listener.ondisconnect(conn)
+	client_by_cookie[clients[conn]] = nil;
 	clients[conn] = nil;
-	if not next(clients) then
-		log("debug", "No more clients");
-		events.fire_event("no-clients");
-	end
+	active_clients[conn] = nil;
+	update_have_clients();
 end
 listener.ondetach = listener.ondisconnect;
 
@@ -38,16 +61,22 @@
 	if path ~= "/cam" then
 		return 404;
 	end
-	
-	if not next(clients) then
-		log("debug", "Have clients now");
-		events.fire_event("have-clients");
-	end
-	
+
 	local conn = event.response.conn;
 
-	conn:write(response_head);
-	clients[conn] = true;
+	local cookie = event.request.headers.cookie;
+	if cookie then
+		log("debug", "Client %s connected", cookie);
+	else
+		cookie = new_uuid();
+		log("debug", "New client connected, assigned %s", cookie);
+	end
+	conn:write((response_head:gsub("COOKIE_STRING", cookie)));
+	clients[conn] = cookie;
+	active_clients[conn] = os.time();
+	client_by_cookie[cookie] = conn;
+
+	update_have_clients();
 
 	if last_chunk then
 		conn:write(last_chunk);
@@ -58,6 +87,26 @@
 	return true;
 end
 
+local function mark_active(request)
+	local cookie = event.request.headers.cookie;
+	if not cookie then
+		log("warn", "Active client with no cookie");
+		return;
+	end
+	local conn = client_by_cookie[cookie];
+	if not conn then
+		log("warn", "Active client with no connection");
+		return;
+	end
+	active_clients[conn] = os.time();
+	update_have_clients();
+end
+
+function handle_active(event, path)
+	mark_active(event.request);
+	return "OK";
+end
+
 events.add_handler("image-changed", function (event)
 	log("debug", "New image");
 	local chunk_data = table.concat({
@@ -69,12 +118,20 @@
 	}, "\r\n");
 	last_chunk = ("%x\r\n%s\r\n"):format(#chunk_data, chunk_data);
 	
+	local time_now = os.time();
 	for client in pairs(clients) do
-		client:write(last_chunk);
+		local active_time = active_clients[client];
+		if active_time and time_now - active_time < activity_timeout then
+			client:write(last_chunk);
+		else
+			active_clients[client] = nil;
+		end
 	end
+	update_have_clients();
 end);
 
 http_server.add_host("localhost");
 http_server.set_default_host("localhost");
 http_server.add_handler("GET localhost/*", handle_request);
+http_server.add_handler("GET localhost/active", handle_active);
 http_server.listen_on(8006);

mercurial