====== Protocol ======
* Encoding [[https://developers.google.com/protocol-buffers/docs/encoding]]
* Protocol Buffer Polymorphism [[http://www.indelible.org/ink/protobuf-polymorphism/]]
====== tools ======
[[http://yura415.github.io/js-protobuf-encode-decode/]]
====== Libraries ======
===== sean-lin based =====
[[https://github.com/sean-lin/protoc-gen-lua]]
* Latest commit 12 Jun 2014
[[https://github.com/djungelorm/protobuf-lua]]
* Latest commit **26 Jan 2016**
* Latest fixes [[https://github.com/skwerlman/protobuf-lua/tree/patch-1]]
* Lua rocks: [[https://luarocks.org/modules/djungelorm/protobuf]]
* Prerequisities
* ''sudo apt-get install python-protobuf''
* protoc plugin used: ''/usr/local/bin/protoc-gen-lua'' which is symlinked to ''/usr/local/lib/luarocks/rocks/protobuf/1.1.1-0/protoc-plugin/protoc-gen-lua''
[[https://github.com/urbanairship/protobuf-lua]]
* Latest commit 13 Nov 2015
* fork of above [[https://github.com/djungelorm/protobuf-lua]]
* Lua 5.2 support
* .proto compilation required. Contains protoc plugin for lua
===== others =====
[[https://github.com/indygreg/lua-protobuf]]
* Last commit 27 Mar 2011
[[https://github.com/haberman/upb]]
* Last commit 8 Jul 2015
* Right now the Lua bindings support:
* Building schema objects manually (eg. you can essentially write .proto files natively in Lua).
* creating message objects.
* parsing Protocol Buffers into message objects.
[[https://github.com/starwing/lua-protobuf]]
* Last commit on Aug 24, 2016
This project offers a simple C library for basic protobuf wire format
encode/decode, it splits to several modules:
- pb.decoder: a wire format decode module.
- pb.buffer: a buffer implement that use to encode basic types into
protobuf's wire format. It also can be used to support
streaming decode protobuf data.
- pb.conv: a module to convert between integers in protobuf.
- pb.io: a module to support binary mode read/write to stdin/stdout.
===== Neopalium =====
[[https://github.com/Neopallium/lua-pb]]
* Latest commit 18 Feb 2016
* **Own LUA parser** for .proto files (no need to compile)
======= Library API =======
-- -------------------------------------------
-- @return string with message dump
local function dumpRawProtoc (binMsg)
local p = io.popen ("protoc --decode_raw", "w")
local stdout
if p then
p:write(binMsg)
local stdout = p:read("*a")
p:close()
end
return stdout
end
===== Neopalium =====
local pb = require 'pb'
-- loading 'pb' module will replace 'require' function
-- now .proto files are automatically loaded by require.
local proto = require 'protos.messages' -- load 'protos/messages.proto'
-- Two methods of message creation
-- 1) direct assign
local protoMsg = proto.Message()
protoMsg.deviceId = 0x1234 -- simple type value
protoMsg.deviceType = 'MODEM' -- enum value
protoMsg.repeatedSubMessage = { { id = 'TEMPERATURE',
value = 34
},
{ id = 'WIND',
value = 2
}
}
protoMsg.subMessage.serialNumber = '123456-1234'
protoMsg.subMessage.version = '2'
-- 2) Initialize from structure
local luaData = {
deviceId = 0x1234,
deviceType = 'MODEM',
repeatedSubMessage = { { id = 'TEMPERATURE',
value = 34
},
{ id = 'WIND',
value = 2
}
},
subMessage = { serialNumber = '123456-1234',
version = '2'
}
}
local protoMsg = proto.Message(luaData) -- initialize from luaData
-- 3) Still possible to directly modify, add values into message
protoMsg.deviceId = 0xdeadbeef
local binProtoMsg = protoMsg:Serialize() -- binProtoMsg is string
print (binProtoMsh:len())
local dumpProtoMsg = protoMsg:SerializePartial('text')
local receivedProtoMsg = proto.Message()
if receivedProtoMsh == nil then
error ("Malformed message")
end
receivedProtoMsg:Parse(binProtoMsg)
print (receivedProtoMsg:SerializePartial('text'))
Raw dump of protobuf message (.proto files not needed)
local function dump_fields(unknown)
local o = ""
for i, v in ipairs(unknown) do
o = o..string.format("#%02d Tag=[%2d] Wire=[%2d] %q\n", i, v.tag, v.wire, tostring(v.value))
if type (v.value) == 'table' then
o = o..dump_fields(v.value)
end
end
return o
end
-- -------------------------------------------
-- @return string with message dump
function PD:pbDumpRawPB(binMsg)
local msg, off = pb.decode_raw(binMsg)
return dump_fields(msg.unknown_fields)
end
==== Issue with 64bit number ====
18446744073709551615 is exactly 2^64-1
in LuaJIT 64bit numbers are stored as double, so some precision is lost:
print (0xFFFFFFFFFFFFFFFF == 0xFFFFFFFFFFFFFF00)
true
If library detects LuaJIT with FFI support, it is using FFI cdata to store 64 bit numbers ''int64_t'' or ''uint64_t''
depends on ''signed'' argument passed to ''make_int64_func''.
If no LuaJIT is used, big values are represented as 8 bytes strings.
local pb = require"pb"
local make_int64 = pb.get_make_int64_func()
-- make_int64(b8,b7,b6,b5,b4,b3,b2,b1, signed)
fakeNodeId = make_int64(0,0,0,0, 0,0,0,1 )
-- or initialize from string
local v = \255\255\255\255\255\255\255\255"
fakeNodeId = make_int65(v:byte(1,8))
print (fakeNodeId)
-- prints: '1ULL'
fakeNodeIs = fakeNodeId * 22
print (fakeNodeId)
-- prints: '22ULL'
But library encoder doesn't work:
luaData = {
["deviceId"] = 1.844674407371e+19;
};
binProtoMsg=
0000 08 00 ..
binProtoMsg decoded=deviceId: 0
===== djungelorm =====
No documentation. Poor examples.
Need to dig in sources to familiarize.
First, proto files needs to be compile with ''protoc'' compile with lua output plugin.
For ''messages.proto'' corresponding lua file ''messages_pb.lua'' will be created.
API:
* RCFC (Repeated Composite Field Container) Repeated fields cannot be modified directly by assignment. Use:
* v:add() return newly vreated value object
* v:remove(key)
* RSFC (Repeted Single Field Container)
* v:append(value)
* v:remove(key)
* Message methods:
* _member:ListFields()
* _member:HasField(field_name)
* _member:ClearField(field_name)
* For extendable messages only:
* _member:ClearExtension (extension_handle)
* _member:HasExtenstion (extension_handle)
* _member:Clear()
* :__tostring()
* _member:SetListener(listener)
* _member:ByteSize()
* _member:SerializeToString()
* _member:SerializePartialToString()
* _member:MergeFromString(serialized)
* _member:IsInitialized(errors) - errors - luaTable (numeric indexes)
* _member:MergeFrom(msg)
Other internal methods:
* _member.RegisterExtension (extension_handle)
* _member.FromString(s)
* _member:SerializeToIOString(iostring)
* _member:_InternalSerialize(write_bytes)
* _member:SerializePartialToIOString(iostring)
* _member:ParseFromString(serialized)
* _member:FindInitalizationErrors()
p = require 'messages_pb'
local message = p.Message()
message.deviceId = 0xdeadbeef -- assign int value
message.code = p.Code.OK -- assign enum value (defined in Code enum)
message.repeatedSubMessage:add()
message.repeatedSubMessage[1].ts = 12345 -- assign int value
message.repeatedSubMessage:add()
message.repeatedSubMessage[2].ts = 6789 -- assign int value
print (message:SerializeToString())