# HG changeset patch # User bsw # Date 1428703845 -7200 # Node ID 4997e742c81ccb2dd2969fd878ca4de01cc0ee66 # Parent 74ec80b721b9a0e6506d7113478e62837e290ccd Added multiuser chat to example diff -r 74ec80b721b9 -r 4997e742c81c example_application.lua --- a/example_application.lua Fri Apr 10 13:17:29 2015 +0200 +++ b/example_application.lua Sat Apr 11 00:10:45 2015 +0200 @@ -7,18 +7,159 @@ -- preparation before forking: local documents = {} -for i, document_name in ipairs{"example_webpage.html", "example_webpage.css"} do +for i, document_name in ipairs{"example_webpage.html", "example_chat.html", "example_webpage.css"} do local file = assert(io.open(document_name)) documents[document_name] = file:read("*a") -- store file contents in memory file:close() end +local function chat_server(request) + + + local listener = assert(moonbridge_io.tcplisten("localhost", 8081)) + local clients = {} + local io_listener = { [listener] = true } + local io_writer = {} + local sessions = {} + local msgs = {} + local last_msg = 0 + + while true do + + local new_conn = listener:accept_nb() + + if new_conn then + clients[new_conn] = { + read_buffer = "" + } + io_listener[new_conn] = true + end + + for conn, client in pairs(clients) do + + repeat + local line = conn:read_nb(nil, "\n") + if not line then + clients[conn] = nil + io_listener[conn] = nil + + elseif line ~= "" then + local line, terminator = line:match("([^\n]*)(\n?)") + + if terminator ~= "\n" then + client.read_buffer = client.read_buffer .. line + else + local line = client.read_buffer .. line + client.read_buffer = "" + + if not client.type then + if line == "events" then + client.type = "events" + client.session = "sesam" .. math.random(10000000,99999999) + client.name = "user".. math.random(10000000,99999999) + client.last_msg = 0 + client.send_session = true + client.send_name = true + client.last_msg = #msgs + sessions[client.session] = conn + io_listener[conn] = nil + else + client.type = "chat" + if sessions[line] then + client.session = line + io_listener[conn] = true + else + conn:close() + clients[conn] = nil + end + end + else + if client.type == "chat" then + local event_client = clients[sessions[client.session]] + local command, arg = line:match("([^:]+):(.*)") + if not command then + elseif command == "NAME" then + local name = arg + local success + repeat + success = true + for conn2, client2 in pairs(clients) do + if client2.name == name then + name = name .. math.random(0,9) + success = false + break + end + end + until success + last_msg = last_msg + 1 + msgs[last_msg] = { + name = event_client.name, + msg = "is now known as " .. name + } + event_client.name = name + event_client.send_name = true + elseif command == "MSG" then + if #arg > 0 then + last_msg = last_msg + 1 + msgs[last_msg] = { + name = event_client.name, + msg = arg + } + end + end + end + + end + end + end + until not line or line == "" + end + + for conn, client in pairs(clients) do + if client.type == "events" then + if client.send_session then + assert(conn:write_nb("SESSION:" .. client.session .. "\n")) + client.send_session = false + end + if client.send_name then + assert(conn:write_nb("NAME:" .. client.name .. "\n")) + client.send_name = false + end + if client.last_msg < last_msg then + for i = client.last_msg + 1, last_msg do + assert(conn:write_nb("MSG:" .. msgs[i].name .. " " .. msgs[i].msg .. "\n")) + end + client.last_msg = last_msg + end + assert(conn:write_nb("TIME:" .. os.time() .. "\n")) + local bytes_left = assert(conn:flush_nb()) + if bytes_left > 0 then + io_writer[conn] = true + else + io_writer[conn] = false + end + end + + end + + moonbridge_io.poll(io_listener, io_writer) + + end + +end + +listen{ + { proto = "interval", delay = 1 }, + connect = chat_server, + max_fork = 1 +} + listen{ -- listen to a tcp version 4 socket - { proto = "tcp4", port = 8080, localhost = true }, + { proto = "tcp4", port = 8080, localhost = false }, -- listen to a tcp version 6 socket - { proto = "tcp6", port = 8080, localhost = true }, + --{ proto = "tcp6", port = 8080, localhost = false }, -- listen to a unix domain socket --{ proto = "local", path = 'socket' }, @@ -30,7 +171,7 @@ pre_fork = 1, -- number of forks -- minimum number of processes - min_fork = 2, -- number of forks + min_fork = 4, -- number of forks -- maximum number of processes (hard limit) max_fork = 16, -- number of forks @@ -79,6 +220,22 @@ request:send_status("303 See Other") request:send_header("Location", "http://" .. request.headers_value.host .. "/example_webpage.html") + elseif request.path == "chat" then + request:send_status("200 OK") + request:send_header("Content-Type", "text/chat; charset=UTF-8") + request:send_data("MULTIUSERCHAT:protocol version 1\n") + + local conn = assert(moonbridge_io.tcpconnect("localhost", 8081)) + + conn:write("events\n") + conn:flush() + + while true do + local line = conn:read(nil, "\n") + request:send_data(line) + request:flush() + end + else local document_name = request.path local document_extension = string.match(document_name, "%.([^.])$") @@ -139,6 +296,37 @@ request:send_data("
Submitted comment: ", http.encode_html(request.post_params.comment), "
\n") request:send_data("