refactoring

This commit is contained in:
Er2 2022-03-07 17:53:29 +03:00
parent d4b070754a
commit 1e05869bd8
5 changed files with 258 additions and 60 deletions

11
http.lua Normal file
View file

@ -0,0 +1,11 @@
local function _loop(b, v)
writeln(v, 'HTTP/1.1 200 OK', '')
write(v, 'Please use telnet to use this service.')
close(v)
end
return {
-- submodule
_loop = _loop,
}

148
main.lua
View file

@ -1,8 +1,5 @@
local socket = require 'socket'
local tcp = socket.bind('*', 8080)
tcp:settimeout(0)
motd = { local motd = {
' __ ' , ' __ ' ,
' ___________/__\\___________ ', ' ___________/__\\___________ ',
' / _ _ -__ - ___ - \\', ' / _ _ -__ - ___ - \\',
@ -21,48 +18,70 @@ motd = {
local cls = {} local cls = {}
local tmp = {} local tmp = {}
local function get(v) utf8 = require '.utf8'
v.buf = v.buf or ''
local l, err
while not err do
l, err = v.cli:receive(1)
if l == '\r' or l == '\n' then
if v.le then v.cli:send '\r\n' end
l, v.buf = v.buf, nil
break
elseif l == '\127'
then v.cli:send '\008'
v.buf = v.buf:sub(1, -2)
elseif l then
v.buf = v.buf.. l
if v.le then v.cli:send(l) end
end
end
return l, err
end
while true do local back = {
local cli = tcp:accept() tcp = require '.tcp',
if cli then http = require '.http',
cli:settimeout(0) -- ws = require '.ws',
if (cli:receive() or ''):match 'GET /.* HTTP.*' }
then cli:send('HTTP/1.1 200 OK\r\n\r\nPlease use telnet to use this service.')
cli:close() local main = {
else cli:send(table.concat(motd, '\r\n')..'\r\n') 'tcp',
table.insert(tmp, { -- 'ws',
}
function get(v, ...) return back[v.back].get(v, ...) end
function close(v, ...) return back[v.back].close(v, ...) end
function write(v, ...) return back[v.back].write(v, ...) end
function writeln(v, ...) return back[v.back].writeln(v, ...) end
function makev(cli, back)
if not cli then return end
return {
cli = cli, cli = cli,
st = 0, st = 0,
}) back = back,
}
end
function init(v)
writeln(v, table.unpack(motd))
writeln(v, '')
table.insert(tmp, v)
end
function forc(fn, t, c)
if c == nil or c == true then
for k, v in pairs(cls) do
fn(v, k)
if v.closed then table.remove(cls, k) end
end end
end end
if t then
for k, v in pairs(tmp) do for k, v in pairs(tmp) do
fn(v, k)
if v.closed then table.remove(tmp, k) end
end
end
end
local runs = true
while runs do
for _, v in pairs(main) do
local p, w = back[v]._loop(v)
if p and back[p]
then back[p]._loop(v, w) end
end
forc(function(v, k)
if v.reads then -- nothing if v.reads then -- nothing
elseif v.st == 0 then v.cli:send('Do you need input echo? [YNQ] ') elseif v.st == 0 then write (v, 'Do you need input echo? [YNHQ] ')
elseif v.st == 1 then v.cli:send('Username: ') elseif v.st == 1 then write (v, 'Username: ')
elseif v.st == 2 then v.cli:send('Password: ') elseif v.st == 2 then write (v, 'Password: ')
elseif v.st == 3 then v.cli:send('Welcome, '.. v.user ..'!\r\n') elseif v.st == 3 then writeln(v, 'Welcome, '.. v.user ..'!')
for _, w in pairs(cls) do for _, w in pairs(cls) do
w.cli:send('\r\n-- '.. v.user ..' joined --\r\n') writeln(w, '', '-- '.. v.user ..' joined --')
end end
v.st, v.reads = nil, nil v.st, v.reads = nil, nil
table.remove(tmp, k) table.remove(tmp, k)
@ -71,30 +90,47 @@ while true do
if v.st then v.reads = true if v.st then v.reads = true
local l, err = get(v) local l, err = get(v)
if err == 'timeout' then -- nothing if err == 'timeout' then -- nothing
elseif err then table.remove(tmp, k) elseif err then close(v)
elseif (l or ''):match '^%s*$' then v.reads = false --elseif (l or ''):match '^%s*$' then v.reads = false
elseif v.st == 0 then v.st, v.reads = 1, false elseif v.st == 0 then v.st, v.reads = 1, false
if l:match 'y' if l:match '[Yy]'
then v.le = true; v.cli:send(l.. '\r\n') then v.le = true; writeln(v, l)
elseif l:match 'q' elseif l:match '[QqEe]' then close(v)
then v.cli:close(); table.remove(tmp, k) elseif l:match '[Nn]' then -- nothing
else v.st = 0
writeln(v, l,
'Say N if you see your input twice.',
'Say Y if not.',
'Say Q to exit.')
end
elseif v.st == 1 then v.reads = false
if #(l:match '^%S+' or '') >= 3
then v.user, v.st = l:match '^%S+', 3
else writeln(v, 'Provide username with length >= 3 symbols')
end end
elseif v.st == 1 then v.st, v.user, v.reads = 3, l:match '^%S+', false
elseif v.st == 2 then v.st, v.reads = 1, false elseif v.st == 2 then v.st, v.reads = 1, false
end end
end end
end end, true, false)
for k, v in pairs(cls) do
forc(function(v, k)
local l, err = get(v) local l, err = get(v)
if l == '/leave' then v.cli:close(); err = 'closed'
end
if err and err ~= 'timeout' then table.remove(cls, k) end
for j, w in pairs(cls) do
if err and err ~= 'timeout' if err and err ~= 'timeout'
then w.cli:send('\r\n-- '.. v.user ..' leaved --\r\n') then close(v) end
elseif (l or ''):match '^%s*$' then -- nothing if l == '/help' then writeln(v, '-- HELP --',
elseif k ~= j then w.cli:send('\r\n'.. v.user ..': '.. l ..'\r\n') '/leave - Close chat'
end )
end elseif l == '/leave' then close(v)
elseif (l or ''):sub(1, 1) == '/'
then writeln(v, 'Unknown command')
elseif not (l or ''):match '^%s*$'
then forc(function(w)
if w == v then -- ignore yourself
elseif v.closed
then writeln(w, '', '-- '.. v.user ..' leaves --')
else writeln(w, '', v.user ..': '.. l)
end end
end) end
end, false, true)
end end

View file

@ -12,7 +12,7 @@ ___|___|____/____\_____|___|___
Welcome to Er2Chat! Welcome to Er2Chat!
You need to login to continue You need to login to continue
Do you need input echo? [YNQ] Do you need input echo? [YNHQ]
``` ```
--- ---

62
tcp.lua Normal file
View file

@ -0,0 +1,62 @@
local socket = require 'socket'
local tcp = socket.bind('*', 8080)
tcp:settimeout(0)
local function get(v)
v.buf = v.buf or ''
local l, err
while not err do
l, err = v.cli:receive(1)
if l == '\r' or l == '\n' then
if v.le then writeln(v, '') end
local n = v.cli:receive(1)
if not n or n == '\n' or n == '\r'
then l, v.buf = v.buf, nil
else l = n end
end
if v.buf == nil then break
elseif l == '\127'
then write(v, '\008')
v.buf = utf8.sub(v.buf, 1, -2)
elseif l then
v.buf = v.buf.. l
if v.le then write(v, l) end
end
end
return l, err
end
local function write(v, ...)
v.cli:send(table.concat({...}, '\r\n'))
end
local function writeln(v, ...)
write(v, ...)
write(v, '\r\n')
end
local function close(v)
v.cli:close()
v.closed = true
end
local function _loop(b)
local v = makev(tcp:accept(), b)
if v then
v.cli:settimeout(0)
local l = v.cli:receive()
if (l or ''):match 'GET /.* HTTP.*' then
return 'http', v
else init(v)
end
end
end
return {
get = get,
write = write,
writeln = writeln,
close = close,
_loop = _loop,
tcp = tcp,
}

89
utf8.lua Normal file
View file

@ -0,0 +1,89 @@
-- Unicode library
local pattern = '[%z\1-\127\194-\244][\128-\191]*'
-- helper function
local function posrelat(pos, len)
if pos < 0 then
pos = len + pos + 1
end
return pos
end
local utf8 = {}
-- THE MEAT
function utf8.map(s, f, no_subs)
local i = 0
if no_subs then
for b, e in s:gmatch('()' .. pattern .. '()') do
i = i + 1
local c = e - b
f(i, c, b)
end
else
for b, c in s:gmatch('()(' .. pattern .. ')') do
i = i + 1
f(i, c, b)
end
end
end
-- THE REST
function utf8.chars(s, no_subs)
return coroutine.wrap(function()
return utf8.map(s, coroutine.yield, no_subs)
end)
end
function utf8.len(s)
return select(2, s:gsub('[^\128-\193]', ''))
end
function utf8.replace(s, map)
return s:gsub(pattern, map)
end
function utf8.reverse(s)
s = s:gsub(pattern, function(c)
return #c > 1 and c:reverse()
end)
return s:reverse()
end
function utf8.strip(s)
return s:gsub(pattern, function(c)
return #c > 1 and ''
end)
end
function utf8.sub(s, i, j)
local l = utf8.len(s)
i = posrelat(i, l)
j = j and posrelat(j, l) or l
if i < 1 then i = 1 end
if j > l then j = l end
if i > j then return '' end
local diff = j - i
local iter = utf8.chars(s, true)
for _ = 1, i - 1 do iter() end
local c, b = select(2, iter())
if diff == 0
then return s:sub(b, b + c - 1) end
i = b
for _ = 1, diff - 1 do iter() end
local c, b = select(2, iter())
return s:sub(i, b + c - 1)
end
return utf8