调试protobuffer接口的神器——luapb
2014-01-16 19:45 mahisaoo 阅读(5500) 评论(2) 编辑 收藏 举报luapb和云风写的lua-pbc(git://github.com/cloudwu/pbc.git)并不是一个东西。它们最主要的区别是:pbc虽然也不需要把.proto文件生成.js文件后使用,但是它却需要生成.pb文件;luapb是完全不需要生成任何中间文件,可以直接对.proto文件操作。
luapb是开源的一个小项目,源码也很小。github的连接为: https://github.com/zhanjunxiong/luapb。
我在工作中经常遇到要和后端的protobuffer对象调试,后端的程序是C封装的protobuffer,前端是用protojs(https://github.com/sirikata/protojs)解析protobuffer对象;在调试的过程中为了能更好的验证接口,luapb可以快速的验证;还是直接看代码吧:
利用luapb动态的填充protobuffer对象的文件simple.lua:
///////////////
require("luapb")
function encodeSimp()
pb.import("simple.proto")
local msg = pb.new("simple.Simple")
msg.name = "jack"
pb.import("simple.proto")
local msg = pb.new("simple.Simple")
msg.name = "jack"
msg.id = 2
msg.email = "jack@request.com"
msg.longid = 18446744073709551615
--[[ for decode
local resProto = pb.new("simple.Simple")
pb.parseFromString(resProto, decStr)
print("res:",resProto.uid)
print("res:",resProto.uid)
]]--
return pb.serializeToString(msg)
end
return pb.serializeToString(msg)
end
proto文件:simple.proto
package simple;
message Simple {
required string name = 1;
required int32 id = 2;
optional string email = 3;
required uint64 longid = 4;
}
message Simple {
required string name = 1;
required int32 id = 2;
optional string email = 3;
required uint64 longid = 4;
}
从上面的例子中可以看到,luapb的用法比较直观;适合需要快速开发的场景。似乎太简单了也不需要多的解释。
和server端通信的文件send.lua, 通信的方式是zmq,假设在本地的8765端口起了一个server程序:
require("zmq")
function writeFile(file,str)
local f = assert(io.open(file, "w"))
f:write(str)
f:close()
end
function readIO()
local method = os.getenv("REQUEST_METHOD")
local cmd = ""
if method == "POST" then
local len = os.getenv("CONTENT_LENGTH")
cmd = io.read(tonumber(len))
elseif method == "GET" then
cmd = os.getenv("QUERY_STRING")
end
local addr = os.getenv("REMOTE_ADDR")
local uci = luci.model.uci.cursor()
uci:tset("luci","sysauth_info",{ipaddr=addr})
uci:save("luci")
uci:commit("luci")
return cmd
end
function send_one(reqstring)
local cmd = reqstring
if cmd ~="" then
local ctx = zmq.init(1,1,0)
local s = ctx:socket(zmq.REQ)
local path = "tcp://127.0.0.1:8765"
s:connect(path)
s:send(cmd)
local result=s:recv()
writefile(result)
io.write(result)
s:close()
ctx:term()
else
io.write("")
end
end
dofile("simple.lua")
local req = encodeSimp()
local resString = send_one(req)
print("Decode Message:"..resString)
function writeFile(file,str)
local f = assert(io.open(file, "w"))
f:write(str)
f:close()
end
function readIO()
local method = os.getenv("REQUEST_METHOD")
local cmd = ""
if method == "POST" then
local len = os.getenv("CONTENT_LENGTH")
cmd = io.read(tonumber(len))
elseif method == "GET" then
cmd = os.getenv("QUERY_STRING")
end
local addr = os.getenv("REMOTE_ADDR")
local uci = luci.model.uci.cursor()
uci:tset("luci","sysauth_info",{ipaddr=addr})
uci:save("luci")
uci:commit("luci")
return cmd
end
function send_one(reqstring)
local cmd = reqstring
if cmd ~="" then
local ctx = zmq.init(1,1,0)
local s = ctx:socket(zmq.REQ)
local path = "tcp://127.0.0.1:8765"
s:connect(path)
s:send(cmd)
local result=s:recv()
writefile(result)
io.write(result)
s:close()
ctx:term()
else
io.write("")
end
end
dofile("simple.lua")
local req = encodeSimp()
local resString = send_one(req)
print("Decode Message:"..resString)
以上的这部分代码实现的是lua-zmq的通讯,即利用lua-zmq将动态填充的proto对象发送到server端;反之我们也通过lua-zmq接受server端返回的proto,并用luapb解析。
luapb提供的API有:
new:新建一个pb的对象; 用法: pb.import("simple.proto"); local msg = pb.new("simple.Simple")
import:导入proto文件; 用法: pb.import("simple.proto")
tostring: 转化成stringpb.serializeToString(msg)
parseFromString:解析成proto对象,用于decode时; 用法:local resProto = pb.new("lm.test"); pb.parseFromString(resProto, decStr); print("res:",resProto.uid)
serializeToString:序列化proto, 用于encode时; 用法:pb.serializeToString(msg)