项目文件夹

文件
2026-07-13 12:32:21 +08:00

144 行
2.4 KiB
Lua

local semaphore = require "ngx.semaphore"
local semaphore_new = semaphore.new
local remove = table.remove
local insert = table.insert
-- buffer
local recv_buf = {}
local recv_buf_mt = { __index = recv_buf }
local default_timeout = 5
function recv_buf.new()
return setmetatable({ smph = semaphore_new() }, recv_buf_mt)
end
function recv_buf:push(obj)
insert(self, obj)
if #self == 1 then
self.smph:post()
end
return true
end
function recv_buf:pop_no_wait()
return remove(self)
end
function recv_buf:pop(timeout)
if #self == 0 then
local ok, err = self.smph:wait(timeout or default_timeout)
if not ok then
return nil, err
end
end
return remove(self)
end
-- end buffer
local unpack = unpack
local _M = {}
local mt = { __index = _M }
local empty = {}
-- we ignore mask problems and most of error handling
function _M:new(opts)
opts = opts or empty
local new_peer = setmetatable({
timeout = opts.timeout,
buf = recv_buf.new(),
}, mt)
return new_peer
end
function _M:set_timeout(time)
self.timeout = time
return true
end
local types = {
[0x0] = "continuation",
[0x1] = "text",
[0x2] = "binary",
[0x8] = "close",
[0x9] = "ping",
[0xa] = "pong",
}
function _M:translate_frame(fin, op, payload)
payload = payload or ""
local payload_len = #payload
op = types[op]
if op == "close" then
-- being a close frame
if payload_len > 0 then
return payload[2], "close", payload[1]
end
return "", "close", nil
end
return payload, op, not fin and "again" or nil
end
function _M:recv_frame()
local buf = self.buf
local obj, err = buf:pop(self.timeout)
if not obj then
return nil, nil, err
end
return self:translate_frame(unpack(obj)) -- data, typ, err
end
local function send_frame(self, fin, op, payload)
local message = { fin, op, payload }
return self.peer.buf:push(message)
end
_M.send_frame = send_frame
function _M:send_text(data)
return self:send_frame(true, 0x1, data)
end
function _M:send_binary(data)
return self:send_frame(true, 0x2, data)
end
function _M:send_close(code, msg)
local payload
if code then
payload = {code, msg}
end
return self:send_frame(true, 0x8, payload)
end
function _M:send_ping(data)
return self:send_frame(true, 0x9, data)
end
function _M:send_pong(data)
return self:send_frame(true, 0xa, data)
end
-- for clients
function _M.connect()
end
function _M.set_keepalive()
end
function _M.close()
end
return _M