# HG changeset patch # User Matthew Wild # Date 1451907343 0 # Node ID 4e46ef3035bafbf5f4547a0dff48005ba5e053ed # Parent 4a3caf5d0f4b5ea5cb064d45a0bdd218edc0b943 clients.lua: Add client activity tracking diff -r 4a3caf5d0f4b -r 4e46ef3035ba clients.lua --- 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);