1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
|
local ev = require 'luxio.event'
local sio = require 'luxio.simple'
local clients = {}
local clientnr = 0
local listener = assert(sio.bind("localhost", 1234))
local function client_say(client, str)
client.sendbuf[#client.sendbuf+1] = str
ev.set_events(client.socket, nil, true)
end
local function client_send(client)
if #client.sendbuf > 1 then
client.sendbuf = { table.concat(client.sendbuf) ; _ = client.sendbuf._}
end
local written, err = client.socket:write(client.sendbuf[1] or "", client.sendbuf._)
if written >= 0 then
client.sendbuf._ = (client.sendbuf._ or 0) + written
else
print("Erm?", err)
return false
end
if client.sendbuf._ and (client.sendbuf._ == #(client.sendbuf[1] or "")) then
client.sendbuf = {}
end
if client.quitting and not client.sendbuf._ then
ev.unregister_fd(client.socket)
client.socket:close()
clients[client.socket] = nil
return false
end
return client.sendbuf._
end
local function do_line(client, line)
local cmd = line:match("^%.(.-)\r?\n$")
if cmd then
if cmd == "quit" then
client:say("S: bye\n");
client.quitting = true
for sock, _client in pairs(clients) do
if client ~= _client then
_client:say(("S: Client %d is quitting\n"):format(client.nr))
end
end
return
end
client:say(("S: Unknown command: %s\n"):format(cmd))
else
for sock, _client in pairs(clients) do
_client:say(("%d: %s"):format(client.nr, line))
end
end
end
local function client_recv(client)
local s, err = client.socket:read(1024)
if (s == "") then
-- client has closed
for sock, _client in pairs(clients) do
if client ~= _client then
_client:say(("S: Client %d disconnected\n"):format(_client.nr))
end
end
clients[client.socket] = nil
ev.unregister_fd(client.socket)
client.socket:close()
return
end
if (s == -1) then
print("Erm?", err)
return false
end
client.recvbuf[#client.recvbuf+1] = s
if (s:match("\n")) then
-- At least one newline, so process lines
local full_s = table.concat(client.recvbuf)
local line = full_s:match("^(.-\n)")
full_s = full_s:match(".-\n(.*)$")
while line do
do_line(client, line)
line = full_s:match("^(.-\n)")
full_s = full_s:match(".-\n(.*)$")
end
client.recvbuf = { full_s }
end
-- Always want to read more
return true
end
function new_client()
local newsock, addr = listener:accept()
clientnr = clientnr + 1
for sock, client in pairs(clients) do
client:say(("S: New client %d from %s\n"):format(clientnr, addr))
end
clients[newsock] = {
socket = newsock,
sendbuf = {},
recvbuf = {},
say = client_say,
nr = clientnr
}
ev.register_fd(newsock, clients[newsock], client_recv, client_send, client_err)
ev.set_events(newsock, true)
clients[newsock]:say("S: Welcome, say something\n")
-- And tell us about more clients
return true
end
ev.register_fd(listener, nil, new_client)
ev.set_events(listener, true)
function show_time()
for sock, client in pairs(clients) do
client:say(("S: The time, sponsored by luxio, is %s\n"):format(os.date()))
end
return os.time() + 30
end
ev.alarm(os.time() + 30, show_time)
ev.run()
|