mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-25 12:43:09 +00:00
Merge branch 'lua53'
This commit is contained in:
@@ -230,10 +230,10 @@ function mongo_collection:insert(doc)
|
||||
end
|
||||
|
||||
function mongo_collection:safe_insert(doc)
|
||||
return self.database:runCommand("insert", self.name, "documents", {bson_encode(doc)})
|
||||
return self.database:runCommand("insert", self.name, "documents", {bson_encode(doc)})
|
||||
end
|
||||
|
||||
function mongo_collection:batch_insert(docs)
|
||||
function mongo_collection:batch_insert(docs)
|
||||
for i=1,#docs do
|
||||
if docs[i]._id == nil then
|
||||
docs[i]._id = bson.objectid()
|
||||
@@ -279,9 +279,45 @@ function mongo_collection:find(query, selector)
|
||||
__cursor = nil,
|
||||
__document = {},
|
||||
__flags = 0,
|
||||
__skip = 0,
|
||||
__sortquery = nil,
|
||||
__limit = 0,
|
||||
} , cursor_meta)
|
||||
end
|
||||
|
||||
function mongo_cursor:sort(key_list)
|
||||
self.__sortquery = bson_encode {['$query'] = self.__query, ['$orderby'] = key_list}
|
||||
return self
|
||||
end
|
||||
|
||||
function mongo_cursor:skip(amount)
|
||||
self.__skip = amount
|
||||
return self
|
||||
end
|
||||
|
||||
function mongo_cursor:limit(amount)
|
||||
self.__limit = amount
|
||||
return self
|
||||
end
|
||||
|
||||
function mongo_cursor:count(with_limit_and_skip)
|
||||
local cmd = {
|
||||
'count', self.__collection.name,
|
||||
'query', self.__query,
|
||||
}
|
||||
if with_limit_and_skip then
|
||||
local len = #cmd
|
||||
cmd[len+1] = 'limit'
|
||||
cmd[len+2] = self.__limit
|
||||
cmd[len+3] = 'skip'
|
||||
cmd[len+4] = self.__skip
|
||||
end
|
||||
local ret = self.__collection.database:runCommand(table.unpack(cmd))
|
||||
assert(ret and ret.ok == 1)
|
||||
return ret.n
|
||||
end
|
||||
|
||||
|
||||
-- collection:createIndex({username = 1}, {unique = true})
|
||||
function mongo_collection:createIndex(keys, option)
|
||||
local name = option.name
|
||||
@@ -291,7 +327,7 @@ function mongo_collection:createIndex(keys, option)
|
||||
for k, v in pairs(keys) do
|
||||
name = (name == nil) and k or (name .. "_" .. k)
|
||||
name = name .. "_" .. v
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -319,13 +355,13 @@ end
|
||||
|
||||
-- collection:findAndModify({query = {name = "userid"}, update = {["$inc"] = {nextid = 1}}, })
|
||||
-- keys, value type
|
||||
-- query, table
|
||||
-- query, table
|
||||
-- sort, table
|
||||
-- remove, bool
|
||||
-- update, table
|
||||
-- new, bool
|
||||
-- fields, bool
|
||||
-- upsert, boolean
|
||||
-- remove, bool
|
||||
-- update, table
|
||||
-- new, bool
|
||||
-- fields, bool
|
||||
-- upsert, boolean
|
||||
function mongo_collection:findAndModify(doc)
|
||||
assert(doc.query)
|
||||
assert(doc.update or doc.remove)
|
||||
@@ -335,7 +371,7 @@ function mongo_collection:findAndModify(doc)
|
||||
table.insert(cmd, k)
|
||||
table.insert(cmd, v)
|
||||
end
|
||||
return self.database:runCommand(unpack(cmd))
|
||||
return self.database:runCommand(table.unpack(cmd))
|
||||
end
|
||||
|
||||
function mongo_cursor:hasNext()
|
||||
@@ -348,10 +384,11 @@ function mongo_cursor:hasNext()
|
||||
local sock = conn.__sock
|
||||
local pack
|
||||
if self.__data == nil then
|
||||
pack = driver.query(request_id, self.__flags, self.__collection.full_name,0,0,self.__query,self.__selector)
|
||||
local query = self.__sortquery or self.__query
|
||||
pack = driver.query(request_id, self.__flags, self.__collection.full_name, self.__skip, -self.__limit, query, self.__selector)
|
||||
else
|
||||
if self.__cursor then
|
||||
pack = driver.more(request_id, self.__collection.full_name,0,self.__cursor)
|
||||
pack = driver.more(request_id, self.__collection.full_name, -self.__limit, self.__cursor)
|
||||
else
|
||||
-- no more
|
||||
self.__document = nil
|
||||
|
||||
143
lualib/mysql.lua
143
lualib/mysql.lua
@@ -2,27 +2,22 @@
|
||||
-- Copyright (C) 2014 Chang Feng
|
||||
-- This file is modified version from https://github.com/openresty/lua-resty-mysql
|
||||
-- The license is under the BSD license.
|
||||
-- Modified by Cloud Wu (remove bit32 for lua 5.3)
|
||||
|
||||
local socketchannel = require "socketchannel"
|
||||
local bit = require "bit32"
|
||||
local mysqlaux = require "mysqlaux.c"
|
||||
local crypt = require "crypt"
|
||||
|
||||
|
||||
local sub = string.sub
|
||||
local strgsub = string.gsub
|
||||
local strformat = string.format
|
||||
local strbyte = string.byte
|
||||
local strchar = string.char
|
||||
local strfind = string.find
|
||||
local strrep = string.rep
|
||||
local null = nil
|
||||
local band = bit.band
|
||||
local bxor = bit.bxor
|
||||
local bor = bit.bor
|
||||
local lshift = bit.lshift
|
||||
local rshift = bit.rshift
|
||||
local strunpack = string.unpack
|
||||
local strpack = string.pack
|
||||
local sha1= crypt.sha1
|
||||
local concat = table.concat
|
||||
local unpack = unpack
|
||||
local setmetatable = setmetatable
|
||||
local error = error
|
||||
local tonumber = tonumber
|
||||
@@ -53,105 +48,53 @@ for i = 0x01, 0x05 do
|
||||
-- tiny, short, long, float, double
|
||||
converters[i] = tonumber
|
||||
end
|
||||
-- converters[0x08] = tonumber -- long long
|
||||
converters[0x08] = tonumber -- long long
|
||||
converters[0x09] = tonumber -- int24
|
||||
converters[0x0d] = tonumber -- year
|
||||
converters[0xf6] = tonumber -- newdecimal
|
||||
|
||||
|
||||
local function _get_byte2(data, i)
|
||||
local a, b = strbyte(data, i, i + 1)
|
||||
return bor(a, lshift(b, 8)), i + 2
|
||||
return strunpack("<I2",data,i)
|
||||
end
|
||||
|
||||
|
||||
local function _get_byte3(data, i)
|
||||
local a, b, c = strbyte(data, i, i + 2)
|
||||
return bor(a, lshift(b, 8), lshift(c, 16)), i + 3
|
||||
return strunpack("<I3",data,i)
|
||||
end
|
||||
|
||||
|
||||
local function _get_byte4(data, i)
|
||||
local a, b, c, d = strbyte(data, i, i + 3)
|
||||
return bor(a, lshift(b, 8), lshift(c, 16), lshift(d, 24)), i + 4
|
||||
return strunpack("<I4",data,i)
|
||||
end
|
||||
|
||||
|
||||
local function _get_byte8(data, i)
|
||||
local a, b, c, d, e, f, g, h = strbyte(data, i, i + 7)
|
||||
|
||||
-- XXX workaround for the lack of 64-bit support in bitop:
|
||||
local lo = bor(a, lshift(b, 8), lshift(c, 16), lshift(d, 24))
|
||||
local hi = bor(e, lshift(f, 8), lshift(g, 16), lshift(h, 24))
|
||||
return lo + hi * 4294967296, i + 8
|
||||
|
||||
-- return bor(a, lshift(b, 8), lshift(c, 16), lshift(d, 24), lshift(e, 32),
|
||||
-- lshift(f, 40), lshift(g, 48), lshift(h, 56)), i + 8
|
||||
return strunpack("<I8",data,i)
|
||||
end
|
||||
|
||||
|
||||
local function _set_byte2(n)
|
||||
return strchar(band(n, 0xff), band(rshift(n, 8), 0xff))
|
||||
return strpack("<I2", n)
|
||||
end
|
||||
|
||||
|
||||
local function _set_byte3(n)
|
||||
return strchar(band(n, 0xff),
|
||||
band(rshift(n, 8), 0xff),
|
||||
band(rshift(n, 16), 0xff))
|
||||
return strpack("<I3", n)
|
||||
end
|
||||
|
||||
|
||||
local function _set_byte4(n)
|
||||
return strchar(band(n, 0xff),
|
||||
band(rshift(n, 8), 0xff),
|
||||
band(rshift(n, 16), 0xff),
|
||||
band(rshift(n, 24), 0xff))
|
||||
return strpack("<I4", n)
|
||||
end
|
||||
|
||||
|
||||
local function _from_cstring(data, i)
|
||||
local last = strfind(data, "\0", i, true)
|
||||
if not last then
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
return sub(data, i, last), last + 1
|
||||
return strunpack("z", data, i)
|
||||
end
|
||||
|
||||
|
||||
local function _to_cstring(data)
|
||||
return data .. "\0"
|
||||
end
|
||||
|
||||
|
||||
local function _to_binary_coded_string(data)
|
||||
return strchar(#data) .. data
|
||||
end
|
||||
|
||||
|
||||
local function _dump(data)
|
||||
local len = #data
|
||||
local bytes = new_tab(len, 0)
|
||||
for i = 1, len do
|
||||
bytes[i] = strbyte(data, i)
|
||||
end
|
||||
return concat(bytes, " ")
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function _dumphex(bytes)
|
||||
local result ={}
|
||||
|
||||
for i = 1, string.len(bytes) do
|
||||
local charcode = tonumber(strbyte(bytes, i, i))
|
||||
local hexstr = string.format("%02X", charcode)
|
||||
result[i]=hexstr
|
||||
end
|
||||
|
||||
local res=table.concat(result, " ")
|
||||
return res
|
||||
return strgsub(bytes, ".", function(x) return strformat("%02x ", strbyte(x)) end)
|
||||
end
|
||||
|
||||
|
||||
@@ -159,19 +102,20 @@ local function _compute_token(password, scramble)
|
||||
if password == "" then
|
||||
return ""
|
||||
end
|
||||
--_dump(scramble)
|
||||
--_dumphex(scramble)
|
||||
|
||||
local stage1 = sha1(password)
|
||||
--print("stage1:", _dumphex(stage1) )
|
||||
local stage2 = sha1(stage1)
|
||||
local stage3 = sha1(scramble .. stage2)
|
||||
local n = #stage1
|
||||
local bytes = new_tab(n, 0)
|
||||
for i = 1, n do
|
||||
bytes[i] = strchar(bxor(strbyte(stage3, i), strbyte(stage1, i)))
|
||||
end
|
||||
|
||||
return concat(bytes)
|
||||
local i = 0
|
||||
return strgsub(stage3,".",
|
||||
function(x)
|
||||
i = i + 1
|
||||
-- ~ is xor in lua 5.3
|
||||
return strchar(strbyte(x) ~ strbyte(stage1, i))
|
||||
end)
|
||||
end
|
||||
|
||||
local function _compose_packet(self, req, size)
|
||||
@@ -253,7 +197,7 @@ local function _from_length_coded_bin(data, pos)
|
||||
end
|
||||
|
||||
if first == 251 then
|
||||
return null, pos + 1
|
||||
return nil, pos + 1
|
||||
end
|
||||
|
||||
if first == 252 then
|
||||
@@ -278,8 +222,8 @@ end
|
||||
local function _from_length_coded_str(data, pos)
|
||||
local len
|
||||
len, pos = _from_length_coded_bin(data, pos)
|
||||
if len == nil or len == null then
|
||||
return null, pos
|
||||
if len == nil then
|
||||
return nil, pos
|
||||
end
|
||||
|
||||
return sub(data, pos, pos + len - 1), pos + len
|
||||
@@ -401,7 +345,7 @@ local function _parse_row_data_packet(data, cols, compact)
|
||||
local typ = col.type
|
||||
local name = col.name
|
||||
|
||||
if value ~= null then
|
||||
if value ~= nil then
|
||||
local conv = converters[typ]
|
||||
if conv then
|
||||
value = conv(value)
|
||||
@@ -457,7 +401,7 @@ local function _recv_auth_resp(self)
|
||||
|
||||
if typ == 'ERR' then
|
||||
local errno, msg, sqlstate = _parse_err_packet(packet)
|
||||
error( string.format("errno:%d, msg:%s,sqlstate:%s",errno,msg,sqlstate))
|
||||
error( strformat("errno:%d, msg:%s,sqlstate:%s",errno,msg,sqlstate))
|
||||
--return nil, errno,msg, sqlstate
|
||||
end
|
||||
|
||||
@@ -484,7 +428,7 @@ local function _mysql_login(self,user,password,database)
|
||||
|
||||
if typ == "ERR" then
|
||||
local errno, msg, sqlstate = _parse_err_packet(packet)
|
||||
error( string.format("errno:%d, msg:%s,sqlstate:%s",errno,msg,sqlstate))
|
||||
error( strformat("errno:%d, msg:%s,sqlstate:%s",errno,msg,sqlstate))
|
||||
end
|
||||
|
||||
self.protocol_ver = strbyte(packet)
|
||||
@@ -517,9 +461,7 @@ local function _mysql_login(self,user,password,database)
|
||||
local more_capabilities
|
||||
more_capabilities, pos = _get_byte2(packet, pos)
|
||||
|
||||
self._server_capabilities = bor(self._server_capabilities,
|
||||
lshift(more_capabilities, 16))
|
||||
|
||||
self._server_capabilities = self._server_capabilities|more_capabilities<<16
|
||||
|
||||
local len = 21 - 8 - 1
|
||||
|
||||
@@ -536,16 +478,15 @@ local function _mysql_login(self,user,password,database)
|
||||
|
||||
local client_flags = 260047;
|
||||
|
||||
local req = _set_byte4(client_flags)
|
||||
.. _set_byte4(self._max_packet_size)
|
||||
.. "\0" -- TODO: add support for charset encoding
|
||||
.. strrep("\0", 23)
|
||||
.. _to_cstring(user)
|
||||
.. _to_binary_coded_string(token)
|
||||
.. _to_cstring(database)
|
||||
local req = strpack("<I4I4c24zs1z",
|
||||
client_flags,
|
||||
self._max_packet_size,
|
||||
strrep("\0", 24), -- TODO: add support for charset encoding
|
||||
user,
|
||||
token,
|
||||
database)
|
||||
|
||||
local packet_len = 4 + 4 + 1 + 23 + #user + 1
|
||||
+ #token + 1 + #database + 1
|
||||
local packet_len = #req
|
||||
|
||||
local authpacket=_compose_packet(self,req,packet_len)
|
||||
return sockchannel:request(authpacket,_recv_auth_resp(self))
|
||||
@@ -576,12 +517,12 @@ local function read_result(self, sock)
|
||||
if typ == "ERR" then
|
||||
local errno, msg, sqlstate = _parse_err_packet(packet)
|
||||
return nil, msg, errno, sqlstate
|
||||
--error( string.format("errno:%d, msg:%s,sqlstate:%s",errno,msg,sqlstate))
|
||||
--error( strformat("errno:%d, msg:%s,sqlstate:%s",errno,msg,sqlstate))
|
||||
end
|
||||
|
||||
if typ == 'OK' then
|
||||
local res = _parse_ok_packet(packet)
|
||||
if res and band(res.server_status, SERVER_MORE_RESULTS_EXISTS) ~= 0 then
|
||||
if res and res.server_status&SERVER_MORE_RESULTS_EXISTS ~= 0 then
|
||||
return res, "again"
|
||||
end
|
||||
return res
|
||||
@@ -601,7 +542,7 @@ local function read_result(self, sock)
|
||||
local col, err, errno, sqlstate = _recv_field_packet(self, sock)
|
||||
if not col then
|
||||
return nil, err, errno, sqlstate
|
||||
--error( string.format("errno:%d, msg:%s,sqlstate:%s",errno,msg,sqlstate))
|
||||
--error( strformat("errno:%d, msg:%s,sqlstate:%s",errno,msg,sqlstate))
|
||||
end
|
||||
|
||||
cols[i] = col
|
||||
@@ -634,7 +575,7 @@ local function read_result(self, sock)
|
||||
if typ == 'EOF' then
|
||||
local warning_count, status_flags = _parse_eof_packet(packet)
|
||||
|
||||
if band(status_flags, SERVER_MORE_RESULTS_EXISTS) ~= 0 then
|
||||
if status_flags&SERVER_MORE_RESULTS_EXISTS ~= 0 then
|
||||
return rows, "again"
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
local skynet = require "skynet"
|
||||
local socket = require "socket"
|
||||
local socketchannel = require "socketchannel"
|
||||
local int64 = require "int64"
|
||||
|
||||
local table = table
|
||||
local string = string
|
||||
@@ -102,12 +101,8 @@ local function pack_value(lines, v)
|
||||
return
|
||||
end
|
||||
|
||||
local t = type(v)
|
||||
if t == "number" then
|
||||
v = tostring(v)
|
||||
elseif t == "userdata" then
|
||||
v = int64.tostring(int64.new(v),10)
|
||||
end
|
||||
v = tostring(v)
|
||||
|
||||
table.insert(lines,"$"..#v)
|
||||
table.insert(lines,v)
|
||||
end
|
||||
|
||||
@@ -31,14 +31,14 @@ end
|
||||
local function update(root, cobj, gcobj)
|
||||
root.__obj = cobj
|
||||
root.__gcobj = gcobj
|
||||
-- don't use pairs
|
||||
for k,v in next, root do
|
||||
if type(v)=="table" and k~="__parent" then
|
||||
local children = root.__cache
|
||||
if children then
|
||||
for k,v in pairs(children) do
|
||||
local pointer = index(cobj, k)
|
||||
if type(pointer) == "userdata" then
|
||||
update(v, pointer, gcobj)
|
||||
else
|
||||
root[k] = nil
|
||||
children[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -74,13 +74,22 @@ function meta:__index(key)
|
||||
local obj = getcobj(self)
|
||||
local v = index(obj, key)
|
||||
if type(v) == "userdata" then
|
||||
local r = setmetatable({
|
||||
local children = self.__cache
|
||||
if children == nil then
|
||||
children = {}
|
||||
self.__cache = children
|
||||
end
|
||||
local r = children[key]
|
||||
if r then
|
||||
return r
|
||||
end
|
||||
r = setmetatable({
|
||||
__obj = v,
|
||||
__gcobj = self.__gcobj,
|
||||
__parent = self,
|
||||
__key = key,
|
||||
}, meta)
|
||||
self[key] = r
|
||||
children[key] = r
|
||||
return r
|
||||
else
|
||||
return v
|
||||
@@ -91,24 +100,6 @@ function meta:__len()
|
||||
return len(getcobj(self))
|
||||
end
|
||||
|
||||
local function conf_ipairs(self, index)
|
||||
local obj = getcobj(self)
|
||||
index = index + 1
|
||||
local value = rawget(self, index)
|
||||
if value then
|
||||
return index, value
|
||||
end
|
||||
local sz = len(obj)
|
||||
if sz < index then
|
||||
return
|
||||
end
|
||||
return index, self[index]
|
||||
end
|
||||
|
||||
function meta:__ipairs()
|
||||
return conf_ipairs, self, 0
|
||||
end
|
||||
|
||||
function meta:__pairs()
|
||||
return conf.next, self, nil
|
||||
end
|
||||
|
||||
69
lualib/sharemap.lua
Normal file
69
lualib/sharemap.lua
Normal file
@@ -0,0 +1,69 @@
|
||||
local stm = require "stm"
|
||||
local sprotoloader = require "sprotoloader"
|
||||
local sproto = require "sproto"
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local sharemap = {}
|
||||
|
||||
function sharemap.register(protofile)
|
||||
-- use global slot 0 for type define
|
||||
sprotoloader.register(protofile, 0)
|
||||
end
|
||||
|
||||
local sprotoobj
|
||||
local function loadsp()
|
||||
if sprotoobj == nil then
|
||||
sprotoobj = sprotoloader.load(0)
|
||||
end
|
||||
return sprotoobj
|
||||
end
|
||||
|
||||
function sharemap:commit()
|
||||
self.__obj(sprotoobj:encode(self.__typename, self.__data))
|
||||
end
|
||||
|
||||
function sharemap:copy()
|
||||
return stm.copy(self.__obj)
|
||||
end
|
||||
|
||||
function sharemap.writer(typename, obj)
|
||||
local sp = loadsp()
|
||||
obj = obj or {}
|
||||
local stmobj = stm.new(sp:encode(typename,obj))
|
||||
obj.__typename = typename
|
||||
obj.__obj = stmobj
|
||||
obj.__data = obj
|
||||
obj.commit = sharemap.commit
|
||||
obj.copy = sharemap.copy
|
||||
return setmetatable(obj, { __index = obj.__data, __newindex = obj.__data })
|
||||
end
|
||||
|
||||
local function decode(msg, sz, self)
|
||||
local data = self.__data
|
||||
for k in pairs(data) do
|
||||
data[k] = nil
|
||||
end
|
||||
return sprotoobj:decode(self.__typename, msg, sz, data)
|
||||
end
|
||||
|
||||
function sharemap:update()
|
||||
return self.__obj(decode, self)
|
||||
end
|
||||
|
||||
function sharemap.reader(typename, stmcpy)
|
||||
local sp = loadsp()
|
||||
local stmobj = stm.newcopy(stmcpy)
|
||||
local _, data = stmobj(function(msg, sz)
|
||||
return sp:decode(typename, msg, sz)
|
||||
end)
|
||||
|
||||
local obj = {
|
||||
__typename = typename,
|
||||
__obj = stmobj,
|
||||
__data = data,
|
||||
update = sharemap.update,
|
||||
}
|
||||
return setmetatable(obj, { __index = obj.__data, __newindex = error })
|
||||
end
|
||||
|
||||
return sharemap
|
||||
@@ -22,7 +22,7 @@ local skynet = {
|
||||
PTYPE_HARBOR = 5,
|
||||
PTYPE_SOCKET = 6,
|
||||
PTYPE_ERROR = 7,
|
||||
PTYPE_QUEUE = 8, -- use in deprecated mqueue, use skynet.queue instead
|
||||
PTYPE_QUEUE = 8, -- used in deprecated mqueue, use skynet.queue instead
|
||||
PTYPE_DEBUG = 9,
|
||||
PTYPE_LUA = 10,
|
||||
PTYPE_SNAX = 11,
|
||||
@@ -101,7 +101,6 @@ local coroutine_count = 0
|
||||
local function co_create(f)
|
||||
local co = table.remove(coroutine_pool)
|
||||
if co == nil then
|
||||
local print = print
|
||||
co = coroutine.create(function(...)
|
||||
f(...)
|
||||
while true do
|
||||
@@ -233,6 +232,9 @@ function suspend(co, result, command, param, size)
|
||||
elseif command == "QUIT" then
|
||||
-- service exit
|
||||
return
|
||||
elseif command == nil then
|
||||
-- debug trace
|
||||
return
|
||||
else
|
||||
error("Unknown command : " .. command .. "\n" .. debug.traceback(co))
|
||||
end
|
||||
@@ -339,7 +341,7 @@ end
|
||||
|
||||
function skynet.exit()
|
||||
fork_queue = {} -- no fork coroutine can be execute after skynet.exit
|
||||
skynet.send(".launcher","lua","REMOVE",skynet.self())
|
||||
skynet.send(".launcher","lua","REMOVE",skynet.self(), false)
|
||||
-- report the sources that call me
|
||||
for co, session in pairs(session_coroutine_id) do
|
||||
local address = session_coroutine_address[co]
|
||||
@@ -362,7 +364,7 @@ end
|
||||
|
||||
function skynet.kill(name)
|
||||
if type(name) == "number" then
|
||||
skynet.send(".launcher","lua","REMOVE",name)
|
||||
skynet.send(".launcher","lua","REMOVE",name, true)
|
||||
name = skynet.address(name)
|
||||
end
|
||||
c.command("KILL",name)
|
||||
@@ -461,7 +463,7 @@ function skynet.dispatch_unknown_request(unknown)
|
||||
end
|
||||
|
||||
local function unknown_response(session, address, msg, sz)
|
||||
print("Response message :" , c.tostring(msg,sz))
|
||||
skynet.error(string.format("Response message :" , c.tostring(msg,sz)))
|
||||
error(string.format("Unknown session : %d from %x", session, address))
|
||||
end
|
||||
|
||||
@@ -719,6 +721,7 @@ local debug = require "skynet.debug"
|
||||
debug(skynet, {
|
||||
dispatch = dispatch_message,
|
||||
clear = clear_pool,
|
||||
suspend = suspend,
|
||||
})
|
||||
|
||||
return skynet
|
||||
|
||||
@@ -58,6 +58,11 @@ function dbgcmd.TERM(service)
|
||||
skynet.term(service)
|
||||
end
|
||||
|
||||
function dbgcmd.REMOTEDEBUG(...)
|
||||
local remotedebug = require "skynet.remotedebug"
|
||||
remotedebug.start(export, ...)
|
||||
end
|
||||
|
||||
local function _debug_dispatch(session, address, cmd, ...)
|
||||
local f = dbgcmd[cmd]
|
||||
assert(f, cmd)
|
||||
|
||||
133
lualib/skynet/injectcode.lua
Normal file
133
lualib/skynet/injectcode.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
local debug = debug
|
||||
local table = table
|
||||
|
||||
local FUNC_TEMP=[[
|
||||
local $ARGS
|
||||
return function(...)
|
||||
$SOURCE
|
||||
end,
|
||||
function()
|
||||
return {$LOCALS}
|
||||
end
|
||||
]]
|
||||
|
||||
local temp = {}
|
||||
local function wrap_locals(co, source, level, ext_funcs)
|
||||
if co == coroutine.running() then
|
||||
level = level + 3
|
||||
end
|
||||
local f = debug.getinfo(co, level,"f").func
|
||||
if f == nil then
|
||||
return false, "Invalid level"
|
||||
end
|
||||
|
||||
local uv = {}
|
||||
local locals = {}
|
||||
local uv_id = {}
|
||||
local local_id = {}
|
||||
|
||||
if ext_funcs then
|
||||
for k,v in pairs(ext_funcs) do
|
||||
table.insert(uv, k)
|
||||
end
|
||||
end
|
||||
local i = 1
|
||||
while true do
|
||||
local name, value = debug.getlocal(co, level, i)
|
||||
if name == nil then
|
||||
break
|
||||
end
|
||||
if name:byte() ~= 40 then -- '('
|
||||
table.insert(uv, name)
|
||||
table.insert(locals, ("[%d]=%s,"):format(i,name))
|
||||
local_id[name] = value
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
local i = 1
|
||||
while true do
|
||||
local name = debug.getupvalue(f, i)
|
||||
if name == nil then
|
||||
break
|
||||
end
|
||||
uv_id[name] = i
|
||||
table.insert(uv, name)
|
||||
i = i + 1
|
||||
end
|
||||
temp.ARGS = table.concat(uv, ",")
|
||||
temp.SOURCE = source
|
||||
temp.LOCALS = table.concat(locals)
|
||||
local full_source = FUNC_TEMP:gsub("%$(%w+)",temp)
|
||||
local loader, err = load(full_source, "=(debug)")
|
||||
if loader == nil then
|
||||
return false, err
|
||||
end
|
||||
local func, update = loader()
|
||||
-- join func's upvalues
|
||||
local i = 1
|
||||
while true do
|
||||
local name = debug.getupvalue(func, i)
|
||||
if name == nil then
|
||||
break
|
||||
end
|
||||
if ext_funcs then
|
||||
local v = ext_funcs[name]
|
||||
if v then
|
||||
debug.setupvalue(func, i, v)
|
||||
end
|
||||
end
|
||||
|
||||
local local_value = local_id[name]
|
||||
if local_value then
|
||||
debug.setupvalue(func, i, local_value)
|
||||
end
|
||||
local upvalue_id = uv_id[name]
|
||||
if upvalue_id then
|
||||
debug.upvaluejoin(func, i, f, upvalue_id)
|
||||
end
|
||||
i=i+1
|
||||
end
|
||||
local vararg, v = debug.getlocal(co, level, -1)
|
||||
if vararg then
|
||||
local vargs = { v }
|
||||
local i = 2
|
||||
while true do
|
||||
local vararg,v = debug.getlocal(co, level, -i)
|
||||
if vararg then
|
||||
vargs[i] = v
|
||||
else
|
||||
break
|
||||
end
|
||||
i=i+1
|
||||
end
|
||||
return func, update, table.unpack(vargs)
|
||||
else
|
||||
return func, update
|
||||
end
|
||||
end
|
||||
|
||||
local function exec(co, level, func, update, ...)
|
||||
if not func then
|
||||
return false, update
|
||||
end
|
||||
if co == coroutine.running() then
|
||||
level = level + 2
|
||||
end
|
||||
local rets = table.pack(pcall(func, ...))
|
||||
if rets[1] then
|
||||
local needupdate = update()
|
||||
for k,v in pairs(needupdate) do
|
||||
debug.setlocal(co, level,k,v)
|
||||
end
|
||||
return table.unpack(rets, 1, rets.n)
|
||||
else
|
||||
return false, rets[2]
|
||||
end
|
||||
end
|
||||
|
||||
return function (source, co, level, ext_funcs)
|
||||
co = co or coroutine.running()
|
||||
level = level or 0
|
||||
return exec(co, level, wrap_locals(co, source, level, ext_funcs))
|
||||
end
|
||||
|
||||
263
lualib/skynet/remotedebug.lua
Normal file
263
lualib/skynet/remotedebug.lua
Normal file
@@ -0,0 +1,263 @@
|
||||
local skynet = require "skynet"
|
||||
local debugchannel = require "debugchannel"
|
||||
local socket = require "socket"
|
||||
local injectrun = require "skynet.injectcode"
|
||||
local table = table
|
||||
local debug = debug
|
||||
local coroutine = coroutine
|
||||
local sethook = debugchannel.sethook
|
||||
|
||||
|
||||
local M = {}
|
||||
|
||||
local HOOK_FUNC = "raw_dispatch_message"
|
||||
local raw_dispatcher
|
||||
local print = _G.print
|
||||
local skynet_suspend
|
||||
local prompt
|
||||
local newline
|
||||
|
||||
local function change_prompt(s)
|
||||
newline = true
|
||||
prompt = s
|
||||
end
|
||||
|
||||
local function replace_upvalue(func, uvname, value)
|
||||
local i = 1
|
||||
while true do
|
||||
local name, uv = debug.getupvalue(func, i)
|
||||
if name == nil then
|
||||
break
|
||||
end
|
||||
if name == uvname then
|
||||
if value then
|
||||
debug.setupvalue(func, i, value)
|
||||
end
|
||||
return uv
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
local function remove_hook(dispatcher)
|
||||
assert(raw_dispatcher, "Not in debug mode")
|
||||
replace_upvalue(dispatcher, HOOK_FUNC, raw_dispatcher)
|
||||
raw_dispatcher = nil
|
||||
print = _G.print
|
||||
|
||||
skynet.error "Leave debug mode"
|
||||
end
|
||||
|
||||
local function gen_print(fd)
|
||||
-- redirect print to socket fd
|
||||
return function(...)
|
||||
local tmp = table.pack(...)
|
||||
for i=1,tmp.n do
|
||||
tmp[i] = tostring(tmp[i])
|
||||
end
|
||||
table.insert(tmp, "\n")
|
||||
socket.write(fd, table.concat(tmp, "\t"))
|
||||
end
|
||||
end
|
||||
|
||||
local function run_exp(ok, ...)
|
||||
if ok then
|
||||
print(...)
|
||||
end
|
||||
return ok
|
||||
end
|
||||
|
||||
local function run_cmd(cmd, env, co, level)
|
||||
if not run_exp(injectrun("return "..cmd, co, level, env)) then
|
||||
print(select(2, injectrun(cmd,co, level,env)))
|
||||
end
|
||||
end
|
||||
|
||||
local ctx_skynet = debug.getinfo(skynet.start,"S").short_src -- skip when enter this source file
|
||||
local ctx_term = debug.getinfo(run_cmd, "S").short_src -- term when get here
|
||||
local ctx_active = {}
|
||||
|
||||
local linehook
|
||||
local function skip_hook(mode)
|
||||
local co = coroutine.running()
|
||||
local ctx = ctx_active[co]
|
||||
if mode == "return" then
|
||||
ctx.level = ctx.level - 1
|
||||
if ctx.level == 0 then
|
||||
ctx.needupdate = true
|
||||
sethook(linehook, "crl")
|
||||
end
|
||||
else
|
||||
ctx.level = ctx.level + 1
|
||||
end
|
||||
end
|
||||
|
||||
function linehook(mode, line)
|
||||
local co = coroutine.running()
|
||||
local ctx = ctx_active[co]
|
||||
if mode ~= "line" then
|
||||
ctx.needupdate = true
|
||||
if mode ~= "return" then
|
||||
if ctx.next_mode or debug.getinfo(2,"S").short_src == ctx_skynet then
|
||||
ctx.level = 1
|
||||
sethook(skip_hook, "cr")
|
||||
end
|
||||
end
|
||||
else
|
||||
if ctx.needupdate then
|
||||
ctx.needupdate = false
|
||||
ctx.filename = debug.getinfo(2, "S").short_src
|
||||
if ctx.filename == ctx_term then
|
||||
ctx_active[co] = nil
|
||||
sethook()
|
||||
change_prompt(string.format(":%08x>", skynet.self()))
|
||||
return
|
||||
end
|
||||
end
|
||||
change_prompt(string.format("%s(%d)>",ctx.filename, line))
|
||||
return true -- yield
|
||||
end
|
||||
end
|
||||
|
||||
local function add_watch_hook()
|
||||
local co = coroutine.running()
|
||||
local ctx = {}
|
||||
ctx_active[co] = ctx
|
||||
local level = 1
|
||||
sethook(function(mode)
|
||||
if mode == "return" then
|
||||
level = level - 1
|
||||
else
|
||||
level = level + 1
|
||||
if level == 0 then
|
||||
ctx.needupdate = true
|
||||
sethook(linehook, "crl")
|
||||
end
|
||||
end
|
||||
end, "cr")
|
||||
end
|
||||
|
||||
local function watch_proto(protoname, cond)
|
||||
local proto = assert(replace_upvalue(skynet.register_protocol, "proto"), "Can't find proto table")
|
||||
local p = proto[protoname]
|
||||
local dispatch = p.dispatch_origin or p.dispatch
|
||||
if p == nil or dispatch == nil then
|
||||
return "No " .. protoname
|
||||
end
|
||||
p.dispatch_origin = dispatch
|
||||
p.dispatch = function(...)
|
||||
if not cond or cond(...) then
|
||||
p.dispatch = dispatch -- restore origin dispatch function
|
||||
add_watch_hook()
|
||||
end
|
||||
dispatch(...)
|
||||
end
|
||||
end
|
||||
|
||||
local function remove_watch()
|
||||
for co in pairs(ctx_active) do
|
||||
sethook(co)
|
||||
end
|
||||
ctx_active = {}
|
||||
end
|
||||
|
||||
local dbgcmd = {}
|
||||
|
||||
function dbgcmd.s(co)
|
||||
local ctx = ctx_active[co]
|
||||
ctx.next_mode = false
|
||||
skynet_suspend(co, coroutine.resume(co))
|
||||
end
|
||||
|
||||
function dbgcmd.n(co)
|
||||
local ctx = ctx_active[co]
|
||||
ctx.next_mode = true
|
||||
skynet_suspend(co, coroutine.resume(co))
|
||||
end
|
||||
|
||||
function dbgcmd.c(co)
|
||||
sethook(co)
|
||||
ctx_active[co] = nil
|
||||
change_prompt(string.format(":%08x>", skynet.self()))
|
||||
skynet_suspend(co, coroutine.resume(co))
|
||||
end
|
||||
|
||||
local function hook_dispatch(dispatcher, resp, fd, channel)
|
||||
change_prompt(string.format(":%08x>", skynet.self()))
|
||||
|
||||
print = gen_print(fd)
|
||||
local env = {
|
||||
print = print,
|
||||
watch = watch_proto
|
||||
}
|
||||
|
||||
local watch_env = {
|
||||
print = print
|
||||
}
|
||||
|
||||
local function watch_cmd(cmd)
|
||||
local co = next(ctx_active)
|
||||
watch_env._CO = co
|
||||
if dbgcmd[cmd] then
|
||||
dbgcmd[cmd](co)
|
||||
else
|
||||
run_cmd(cmd, watch_env, co, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function debug_hook()
|
||||
while true do
|
||||
if newline then
|
||||
socket.write(fd, prompt)
|
||||
newline = false
|
||||
end
|
||||
local cmd = channel:read()
|
||||
if cmd then
|
||||
if cmd == "cont" then
|
||||
-- leave debug mode
|
||||
break
|
||||
end
|
||||
if cmd ~= "" then
|
||||
if next(ctx_active) then
|
||||
watch_cmd(cmd)
|
||||
else
|
||||
run_cmd(cmd, env, coroutine.running(),2)
|
||||
end
|
||||
end
|
||||
newline = true
|
||||
else
|
||||
-- no input
|
||||
return
|
||||
end
|
||||
end
|
||||
-- exit debug mode
|
||||
remove_watch()
|
||||
remove_hook(dispatcher)
|
||||
resp(true)
|
||||
end
|
||||
|
||||
local func
|
||||
local function hook(...)
|
||||
debug_hook()
|
||||
return func(...)
|
||||
end
|
||||
func = replace_upvalue(dispatcher, HOOK_FUNC, hook)
|
||||
if func then
|
||||
local function idle()
|
||||
skynet.timeout(10,idle) -- idle every 0.1s
|
||||
end
|
||||
skynet.timeout(0, idle)
|
||||
end
|
||||
return func
|
||||
end
|
||||
|
||||
function M.start(import, fd, handle)
|
||||
local dispatcher = import.dispatch
|
||||
skynet_suspend = import.suspend
|
||||
assert(raw_dispatcher == nil, "Already in debug mode")
|
||||
skynet.error "Enter debug mode"
|
||||
local channel = debugchannel.connect(handle)
|
||||
raw_dispatcher = hook_dispatch(dispatcher, skynet.response(), fd, channel)
|
||||
end
|
||||
|
||||
return M
|
||||
@@ -4,7 +4,9 @@ local snax_interface = require "snax.interface"
|
||||
local snax = {}
|
||||
local typeclass = {}
|
||||
|
||||
local G = { require = function() end }
|
||||
local interface_g = skynet.getenv("snax_interface_g")
|
||||
local G = interface_g and require (interface_g) or { require = function() end }
|
||||
interface_g = nil
|
||||
|
||||
skynet.register_protocol {
|
||||
name = "snax",
|
||||
|
||||
@@ -12,8 +12,8 @@ function sproto_mt:__gc()
|
||||
core.deleteproto(self.__cobj)
|
||||
end
|
||||
|
||||
function sproto.new(pbin)
|
||||
local cobj = assert(core.newproto(pbin))
|
||||
function sproto.new(...)
|
||||
local cobj = assert(core.newproto(...))
|
||||
local self = {
|
||||
__cobj = cobj,
|
||||
__tcache = setmetatable( {} , weak_mt ),
|
||||
@@ -53,9 +53,9 @@ function sproto:encode(typename, tbl)
|
||||
return core.encode(st, tbl)
|
||||
end
|
||||
|
||||
function sproto:decode(typename, bin)
|
||||
function sproto:decode(typename, ...)
|
||||
local st = querytype(self, typename)
|
||||
return core.decode(st, bin)
|
||||
return core.decode(st, ...)
|
||||
end
|
||||
|
||||
function sproto:pencode(typename, tbl)
|
||||
|
||||
23
lualib/sprotoloader.lua
Normal file
23
lualib/sprotoloader.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
local parser = require "sprotoparser"
|
||||
local core = require "sproto.core"
|
||||
local sproto = require "sproto"
|
||||
|
||||
local loader = {}
|
||||
|
||||
function loader.register(filename, index)
|
||||
local f = assert(io.open(filename), "Can't open sproto file")
|
||||
local data = f:read "a"
|
||||
f:close()
|
||||
local bin = parser.parse(data)
|
||||
core.saveproto(bin, index)
|
||||
end
|
||||
|
||||
loader.save = core.saveproto
|
||||
|
||||
function loader.load(index)
|
||||
local bin, sz = core.loadproto(index)
|
||||
return sproto.new(bin,sz)
|
||||
end
|
||||
|
||||
return loader
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
local lpeg = require "lpeg"
|
||||
local bit32 = require "bit32"
|
||||
local table = require "table"
|
||||
|
||||
local P = lpeg.P
|
||||
@@ -196,18 +195,14 @@ end
|
||||
]]
|
||||
|
||||
local function packbytes(str)
|
||||
local size = #str
|
||||
return string.char(bit32.extract(size,0,8))..
|
||||
string.char(bit32.extract(size,8,8))..
|
||||
string.char(bit32.extract(size,16,8))..
|
||||
string.char(bit32.extract(size,24,8))..
|
||||
str
|
||||
str = string.pack("<s4",str)
|
||||
return str
|
||||
end
|
||||
|
||||
local function packvalue(id)
|
||||
id = (id + 1) * 2
|
||||
assert(id >=0 and id < 65536)
|
||||
return string.char(bit32.extract(id, 0, 8)) .. string.char(bit32.extract(id, 8, 8))
|
||||
local str = string.pack("<I2", id)
|
||||
return str
|
||||
end
|
||||
|
||||
local function packfield(f)
|
||||
|
||||
Reference in New Issue
Block a user