THRIFT-4386 Add Lua 5.3/5.4 support
Clint: lua
Patch: Thomas Bruggink
This closes #3012
diff --git a/lib/lua/TBinaryProtocol.lua b/lib/lua/TBinaryProtocol.lua
index 4b8e98a..9eacc4a 100644
--- a/lib/lua/TBinaryProtocol.lua
+++ b/lib/lua/TBinaryProtocol.lua
@@ -18,8 +18,8 @@
--
require 'TProtocol'
-require 'libluabpack'
-require 'libluabitwise'
+local libluabpack = require 'libluabpack'
+local libluabitwise = require 'libluabitwise'
TBinaryProtocol = __TObject.new(TProtocolBase, {
__type = 'TBinaryProtocol',
@@ -111,6 +111,11 @@
self.trans:write(buff)
end
+function TBinaryProtocol:writeUI32(i32)
+ local buff = libluabpack.bpack('I', i32)
+ self.trans:write(buff)
+end
+
function TBinaryProtocol:writeI64(i64)
local buff = libluabpack.bpack('l', i64)
self.trans:write(buff)
@@ -127,6 +132,13 @@
self.trans:write(str)
end
+function TBinaryProtocol:writeUuid(uuid)
+ self:writeUI32(uuid.two)
+ self:writeUI32(uuid.three)
+ self:writeUI32(uuid.zero)
+ self:writeUI32(uuid.one)
+end
+
function TBinaryProtocol:readMessageBegin()
local sz, ttype, name, seqid = self:readI32()
if sz < 0 then
@@ -226,6 +238,12 @@
return val
end
+function TBinaryProtocol:readUI32()
+ local buff = self.trans:readAll(4)
+ local val = libluabpack.bunpack('I', buff)
+ return val
+end
+
function TBinaryProtocol:readI64()
local buff = self.trans:readAll(8)
local val = libluabpack.bunpack('l', buff)
@@ -244,6 +262,19 @@
return str
end
+function TBinaryProtocol:readUuid()
+ local a = self:readUI32()
+ local b = self:readUI32()
+ local c = self:readUI32()
+ local d = self:readUI32()
+ return TUUID:new {
+ zero = c,
+ one = d,
+ two = a,
+ three = b
+ }
+end
+
TBinaryProtocolFactory = TProtocolFactory:new{
__type = 'TBinaryProtocolFactory',
strictRead = false
diff --git a/lib/lua/TCompactProtocol.lua b/lib/lua/TCompactProtocol.lua
index 8ec7b3a..f01c56f 100644
--- a/lib/lua/TCompactProtocol.lua
+++ b/lib/lua/TCompactProtocol.lua
@@ -18,9 +18,9 @@
--
require 'TProtocol'
-require 'libluabpack'
-require 'libluabitwise'
-require 'liblualongnumber'
+local libluabpack = require 'libluabpack'
+local libluabitwise = require 'libluabitwise'
+local liblualongnumber = require 'liblualongnumber'
TCompactProtocol = __TObject.new(TProtocolBase, {
__type = 'TCompactProtocol',
@@ -61,7 +61,8 @@
COMPACT_LIST = 0x09,
COMPACT_SET = 0x0A,
COMPACT_MAP = 0x0B,
- COMPACT_STRUCT = 0x0C
+ COMPACT_STRUCT = 0x0C,
+ COMPACT_UUID = 0x0D,
}
TTypeToCompactType = {}
@@ -77,21 +78,23 @@
TTypeToCompactType[TType.SET] = TCompactType.COMPACT_SET
TTypeToCompactType[TType.MAP] = TCompactType.COMPACT_MAP
TTypeToCompactType[TType.STRUCT] = TCompactType.COMPACT_STRUCT
+TTypeToCompactType[TType.UUID] = TCompactType.COMPACT_UUID
CompactTypeToTType = {}
-CompactTypeToTType[TType.STOP] = TType.STOP
-CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_TRUE] = TType.BOOL
+CompactTypeToTType[TType.STOP] = TType.STOP
+CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_TRUE] = TType.BOOL
CompactTypeToTType[TCompactType.COMPACT_BOOLEAN_FALSE] = TType.BOOL
-CompactTypeToTType[TCompactType.COMPACT_BYTE] = TType.BYTE
-CompactTypeToTType[TCompactType.COMPACT_I16] = TType.I16
-CompactTypeToTType[TCompactType.COMPACT_I32] = TType.I32
-CompactTypeToTType[TCompactType.COMPACT_I64] = TType.I64
-CompactTypeToTType[TCompactType.COMPACT_DOUBLE] = TType.DOUBLE
-CompactTypeToTType[TCompactType.COMPACT_BINARY] = TType.STRING
-CompactTypeToTType[TCompactType.COMPACT_LIST] = TType.LIST
-CompactTypeToTType[TCompactType.COMPACT_SET] = TType.SET
-CompactTypeToTType[TCompactType.COMPACT_MAP] = TType.MAP
-CompactTypeToTType[TCompactType.COMPACT_STRUCT] = TType.STRUCT
+CompactTypeToTType[TCompactType.COMPACT_BYTE] = TType.BYTE
+CompactTypeToTType[TCompactType.COMPACT_I16] = TType.I16
+CompactTypeToTType[TCompactType.COMPACT_I32] = TType.I32
+CompactTypeToTType[TCompactType.COMPACT_I64] = TType.I64
+CompactTypeToTType[TCompactType.COMPACT_DOUBLE] = TType.DOUBLE
+CompactTypeToTType[TCompactType.COMPACT_BINARY] = TType.STRING
+CompactTypeToTType[TCompactType.COMPACT_LIST] = TType.LIST
+CompactTypeToTType[TCompactType.COMPACT_SET] = TType.SET
+CompactTypeToTType[TCompactType.COMPACT_MAP] = TType.MAP
+CompactTypeToTType[TCompactType.COMPACT_STRUCT] = TType.STRUCT
+CompactTypeToTType[TCompactType.COMPACT_UUID] = TType.UUID
function TCompactProtocol:resetLastField()
self.lastField = {}
@@ -197,6 +200,11 @@
self:writeVarint32(libluabpack.i32ToZigzag(i32))
end
+function TCompactProtocol:writeUI32(i32)
+ local buff = libluabpack.bpack('I', i32)
+ self.trans:write(buff)
+end
+
function TCompactProtocol:writeI64(i64)
self:writeVarint64(libluabpack.i64ToZigzag(i64))
end
@@ -211,6 +219,13 @@
self:writeBinary(str)
end
+function TCompactProtocol:writeUuid(uuid)
+ self:writeUI32(uuid.two)
+ self:writeUI32(uuid.three)
+ self:writeUI32(uuid.zero)
+ self:writeUI32(uuid.one)
+end
+
function TCompactProtocol:writeBinary(str)
-- Should be utf-8
self:writeVarint32(string.len(str))
@@ -385,6 +400,12 @@
return value
end
+function TCompactProtocol:readUI32()
+ local buff = self.trans:readAll(4)
+ local val = libluabpack.bunpack('I', buff)
+ return val
+end
+
function TCompactProtocol:readI64()
local value = self:readVarint64()
return value
@@ -400,6 +421,19 @@
return self:readBinary()
end
+function TCompactProtocol:readUuid()
+ local a = self:readUI32()
+ local b = self:readUI32()
+ local c = self:readUI32()
+ local d = self:readUI32()
+ return TUUID:new {
+ zero = c,
+ one = d,
+ two = a,
+ three = b
+ }
+end
+
function TCompactProtocol:readBinary()
local size = self:readVarint32()
if size <= 0 then
diff --git a/lib/lua/TFramedTransport.lua b/lib/lua/TFramedTransport.lua
index 768e2d9..4f41e83 100644
--- a/lib/lua/TFramedTransport.lua
+++ b/lib/lua/TFramedTransport.lua
@@ -18,7 +18,7 @@
--
require 'TTransport'
-require 'libluabpack'
+local libluabpack = require 'libluabpack'
TFramedTransport = TTransportBase:new{
__type = 'TFramedTransport',
diff --git a/lib/lua/THttpTransport.lua b/lib/lua/THttpTransport.lua
index 2951db7..e1318c3 100644
--- a/lib/lua/THttpTransport.lua
+++ b/lib/lua/THttpTransport.lua
@@ -160,12 +160,21 @@
end
end
+function THttpTransport:flushOneway()
+ self.wBuf = ''
+ self:writeHttpHeader(0)
+ self.trans:flush()
+end
+
function THttpTransport:flush()
-- If the write fails we still want wBuf to be clear
local tmp = self.wBuf
self.wBuf = ''
- self:writeHttpHeader(string.len(tmp))
- self.trans:write(tmp)
+ local dataLen = string.len(tmp)
+ self:writeHttpHeader(dataLen)
+ if dataLen > 0 then
+ self.trans:write(tmp)
+ end
self.trans:flush()
end
diff --git a/lib/lua/TJsonProtocol.lua b/lib/lua/TJsonProtocol.lua
index db08eec..cec8e26 100644
--- a/lib/lua/TJsonProtocol.lua
+++ b/lib/lua/TJsonProtocol.lua
@@ -18,8 +18,9 @@
--
require 'TProtocol'
-require 'libluabpack'
-require 'libluabitwise'
+local libluabpack = require 'libluabpack'
+local libluabitwise = require 'libluabitwise'
+local liblualongnumber = require 'liblualongnumber'
TJSONProtocol = __TObject.new(TProtocolBase, {
__type = 'TJSONProtocol',
@@ -42,6 +43,7 @@
TTypeToString[TType.LIST] = "lst"
TTypeToString[TType.SET] = "set"
TTypeToString[TType.MAP] = "map"
+TTypeToString[TType.UUID] = "uid"
StringToTType = {
tf = TType.BOOL,
@@ -54,7 +56,8 @@
rec = TType.STRUCT,
map = TType.MAP,
set = TType.SET,
- lst = TType.LIST
+ lst = TType.LIST,
+ uid = TType.UUID,
}
JSONNode = {
@@ -402,13 +405,17 @@
end
function TJSONProtocol:writeDouble(dub)
- self:writeJSONDouble(string.format("%.16f", dub))
+ self:writeJSONDouble(string.format("%.20f", dub))
end
function TJSONProtocol:writeString(str)
self:writeJSONString(str)
end
+function TJSONProtocol:writeUuid(uuid)
+ self:writeJSONString(uuid:getString())
+end
+
function TJSONProtocol:writeBinary(str)
-- Should be utf-8
self:writeJSONBase64(str)
@@ -706,6 +713,10 @@
return self:readJSONString()
end
+function TJSONProtocol:readUuid()
+ return TUUIDfromString(self:readJSONString())
+end
+
function TJSONProtocol:readBinary()
return self:readJSONBase64()
end
diff --git a/lib/lua/TProtocol.lua b/lib/lua/TProtocol.lua
index 1306fb3..f7a993f 100644
--- a/lib/lua/TProtocol.lua
+++ b/lib/lua/TProtocol.lua
@@ -86,6 +86,7 @@
function TProtocolBase:writeI64(i64) end
function TProtocolBase:writeDouble(dub) end
function TProtocolBase:writeString(str) end
+function TProtocolBase:writeUuid(uuid) end
function TProtocolBase:readMessageBegin() end
function TProtocolBase:readMessageEnd() end
function TProtocolBase:readStructBegin() end
@@ -105,6 +106,7 @@
function TProtocolBase:readI64() end
function TProtocolBase:readDouble() end
function TProtocolBase:readString() end
+function TProtocolBase:readUuid() end
function TProtocolBase:skip(ttype)
if ttype == TType.BOOL then
@@ -151,6 +153,8 @@
self:skip(ettype)
end
self:readListEnd()
+ elseif ttype == TType.UUID then
+ self:readUuid()
else
terror(TProtocolException:new{
message = 'Invalid data'
diff --git a/lib/lua/TSocket.lua b/lib/lua/TSocket.lua
index d71fc1f..47ca6f0 100644
--- a/lib/lua/TSocket.lua
+++ b/lib/lua/TSocket.lua
@@ -17,7 +17,7 @@
--
require 'TTransport'
-require 'libluasocket'
+local luasocket = require 'libluasocket'
-- TSocketBase
TSocketBase = TTransportBase:new{
diff --git a/lib/lua/TTransport.lua b/lib/lua/TTransport.lua
index 01c7e59..b7f6b83 100644
--- a/lib/lua/TTransport.lua
+++ b/lib/lua/TTransport.lua
@@ -76,6 +76,8 @@
return buf
end
function TTransportBase:write(buf) end
+-- flushOneway is a NOOP for most transport types.
+function TTransportBase:flushOneway() end
function TTransportBase:flush() end
TServerTransportBase = __TObject:new{
diff --git a/lib/lua/Thrift.lua b/lib/lua/Thrift.lua
index 58daa22..b6e3628 100644
--- a/lib/lua/Thrift.lua
+++ b/lib/lua/Thrift.lua
@@ -23,6 +23,9 @@
--setfenv(1, thrift)
package.cpath = package.cpath .. ';bin/?.so' -- TODO FIX
+
+local libluabitwise = require 'libluabitwise'
+
function ttype(obj)
if type(obj) == 'table' and
obj.__type and
@@ -66,8 +69,7 @@
MAP = 13,
SET = 14,
LIST = 15,
- UTF8 = 16,
- UTF16 = 17
+ UUID = 16
}
TMessageType = {
@@ -233,6 +235,35 @@
oprot:writeStructEnd()
end
+TUUID = {
+ zero,
+ one,
+ two,
+ three
+}
+
+TUUID = __TObject:new{
+ __type = 'TUUID'
+}
+
+function TUUIDfromString(str)
+ local iterator = string.gmatch(str, "[A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9][A-Fa-f0-9]")
+ return TUUID:new {
+ zero = libluabitwise.buor(libluabitwise.ushiftl(tonumber(iterator(), 16), 16), tonumber(iterator(), 16)),
+ one = libluabitwise.buor(libluabitwise.ushiftl(tonumber(iterator(), 16), 16), tonumber(iterator(), 16)),
+ two = libluabitwise.buor(libluabitwise.ushiftl(tonumber(iterator(), 16), 16), tonumber(iterator(), 16)),
+ three = libluabitwise.buor(libluabitwise.ushiftl(tonumber(iterator(), 16), 16), tonumber(iterator(), 16))
+ }
+end
+
+function TUUID:getString()
+ return string.format("%08x-%04x-%04x-%04x-%04x%08x", self.zero, libluabitwise.ushiftr(self.one, 16), libluabitwise.buand(self.one, 0xFFFF), libluabitwise.ushiftr(self.two, 16), libluabitwise.buand(self.two, 0xFFFF), self.three)
+end
+
+function TUUID:__tostring()
+ return "<TUUID: " .. self:getString() .. ">"
+end
+
-- Basic Client (used in generated lua code)
__TClient = __TObject:new{
__type = '__TClient',
diff --git a/lib/lua/src/luabitwise.c b/lib/lua/src/luabitwise.c
index 2e07e17..ea9110a 100644
--- a/lib/lua/src/luabitwise.c
+++ b/lib/lua/src/luabitwise.c
@@ -27,6 +27,13 @@
return 1;
}
+static int l_unot(lua_State *L) {
+ unsigned int a = luaL_checkinteger(L, 1);
+ a = ~a;
+ lua_pushnumber(L, a);
+ return 1;
+}
+
static int l_xor(lua_State *L) {
int a = luaL_checkinteger(L, 1);
int b = luaL_checkinteger(L, 2);
@@ -35,6 +42,15 @@
return 1;
}
+static int l_uxor(lua_State *L) {
+ unsigned int a = luaL_checkinteger(L, 1);
+ unsigned int b = luaL_checkinteger(L, 2);
+ a ^= b;
+ lua_pushnumber(L, a);
+ return 1;
+}
+
+
static int l_and(lua_State *L) {
int a = luaL_checkinteger(L, 1);
int b = luaL_checkinteger(L, 2);
@@ -43,6 +59,14 @@
return 1;
}
+static int l_uand(lua_State *L) {
+ unsigned int a = luaL_checkinteger(L, 1);
+ unsigned int b = luaL_checkinteger(L, 2);
+ a &= b;
+ lua_pushnumber(L, a);
+ return 1;
+}
+
static int l_or(lua_State *L) {
int a = luaL_checkinteger(L, 1);
int b = luaL_checkinteger(L, 2);
@@ -51,6 +75,14 @@
return 1;
}
+static int l_uor(lua_State *L) {
+ unsigned int a = luaL_checkinteger(L, 1);
+ unsigned int b = luaL_checkinteger(L, 2);
+ a |= b;
+ lua_pushnumber(L, a);
+ return 1;
+}
+
static int l_shiftr(lua_State *L) {
int a = luaL_checkinteger(L, 1);
int b = luaL_checkinteger(L, 2);
@@ -59,6 +91,14 @@
return 1;
}
+static int l_ushiftr(lua_State *L) {
+ unsigned int a = luaL_checkinteger(L, 1);
+ unsigned int b = luaL_checkinteger(L, 2);
+ a = a >> b;
+ lua_pushnumber(L, a);
+ return 1;
+}
+
static int l_shiftl(lua_State *L) {
int a = luaL_checkinteger(L, 1);
int b = luaL_checkinteger(L, 2);
@@ -67,17 +107,36 @@
return 1;
}
+static int l_ushiftl(lua_State *L) {
+ unsigned int a = luaL_checkinteger(L, 1);
+ unsigned int b = luaL_checkinteger(L, 2);
+ a = a << b;
+ lua_pushnumber(L, a);
+ return 1;
+}
+
static const struct luaL_Reg funcs[] = {
{"band", l_and},
+ {"buand", l_uand},
{"bor", l_or},
+ {"buor", l_uor},
{"bxor", l_xor},
+ {"buxor", l_uxor},
{"bnot", l_not},
+ {"bunot", l_unot},
{"shiftl", l_shiftl},
+ {"ushiftl", l_ushiftl},
{"shiftr", l_shiftr},
+ {"ushiftr", l_ushiftr},
{NULL, NULL}
};
int luaopen_libluabitwise(lua_State *L) {
+#if LUA_VERSION_NUM >= 502
+ lua_newtable(L);
+ luaL_setfuncs(L, funcs, 0);
+#else
luaL_register(L, "libluabitwise", funcs);
+#endif
return 1;
}
diff --git a/lib/lua/src/luabpack.c b/lib/lua/src/luabpack.c
index 077b6aa..cdfb72a 100644
--- a/lib/lua/src/luabpack.c
+++ b/lib/lua/src/luabpack.c
@@ -45,6 +45,7 @@
* c - Signed Byte
* s - Signed Short
* i - Signed Int
+ * I - Unsigned Int
* l - Signed Long
* d - Double
*/
@@ -72,6 +73,12 @@
luaL_addlstring(&buf, (void*)&data, sizeof(data));
break;
}
+ case 'I': {
+ uint32_t data = luaL_checkinteger(L, 2);
+ data = (uint32_t)htonl(data);
+ luaL_addlstring(&buf, (void*)&data, sizeof(data));
+ break;
+ }
case 'l': {
int64_t data = lualongnumber_checklong(L, 2);
data = (int64_t)T_htonll(data);
@@ -97,6 +104,7 @@
* C - Unsigned Byte
* s - Signed Short
* i - Signed Int
+ * I - Unsigned Int
* l - Signed Long
* d - Double
*/
@@ -144,6 +152,17 @@
lua_pushnumber(L, val);
break;
}
+ /**
+ * unpack unsigned Int.
+ */
+ case 'I': {
+ uint32_t val;
+ luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
+ memcpy(&val, data, sizeof(val));
+ val = (uint32_t)ntohl(val);
+ lua_pushnumber(L, val);
+ break;
+ }
case 'l': {
int64_t val;
luaL_argcheck(L, len == sizeof(val), 1, "Invalid input string size.");
@@ -303,6 +322,11 @@
};
int luaopen_libluabpack(lua_State *L) {
+#if LUA_VERSION_NUM >= 502
+ lua_newtable(L);
+ luaL_setfuncs(L, lua_bpack, 0);
+#else
luaL_register(L, "libluabpack", lua_bpack);
+#endif
return 1;
}
diff --git a/lib/lua/src/lualongnumber.c b/lib/lua/src/lualongnumber.c
index 9001e4a..91df70a 100644
--- a/lib/lua/src/lualongnumber.c
+++ b/lib/lua/src/lualongnumber.c
@@ -223,6 +223,11 @@
lua_pop(L, 1);
set_methods(L, LONG_NUM_TYPE, methods);
+#if LUA_VERSION_NUM >= 502
+ lua_newtable(L);
+ luaL_setfuncs(L, funcs, 0);
+#else
luaL_register(L, "liblualongnumber", funcs);
+#endif
return 1;
}
diff --git a/lib/lua/src/luasocket.c b/lib/lua/src/luasocket.c
index 6f63d3d..07524ab 100644
--- a/lib/lua/src/luasocket.c
+++ b/lib/lua/src/luasocket.c
@@ -185,8 +185,12 @@
set_methods(L, SOCKET_GENERIC, methods_generic);
set_methods(L, SOCKET_CLIENT, methods_client);
set_methods(L, SOCKET_SERVER, methods_server);
-
+#if LUA_VERSION_NUM >= 502
+ lua_newtable(L);
+ luaL_setfuncs(L, funcs_luasocket, 0);
+#else
luaL_register(L, "luasocket", funcs_luasocket);
+#endif
return 1;
}
diff --git a/lib/lua/src/usocket.c b/lib/lua/src/usocket.c
index 21c0bac..27103a0 100644
--- a/lib/lua/src/usocket.c
+++ b/lib/lua/src/usocket.c
@@ -205,21 +205,35 @@
return socket_wait(sock, WAIT_MODE_C, timeout);
}
+#define SEND_RETRY_COUNT 5
T_ERRCODE socket_send(
p_socket sock, const char *data, size_t len, int timeout) {
int err, put = 0;
if (*sock < 0) {
return CLOSED;
}
- do {
- put = send(*sock, data, len, 0);
- if (put > 0) {
- return SUCCESS;
- }
- } while ((err = errno) == EINTR);
+ for(int i = 0; i < SEND_RETRY_COUNT; i++) {
+ do {
+ size_t l = len - put;
+ put = send(*sock, data + put, l, 0);
+ if (put > 0) {
+ if(put == l) {
+ return SUCCESS;
+ }
+ // Not all data was delivered, we need to try again.
+ err = EAGAIN;
+ break;
+ }
+ } while ((err = errno) == EINTR);
- if (err == EAGAIN) {
- return socket_wait(sock, WAIT_MODE_W, timeout);
+ if (err == EAGAIN) {
+ err = socket_wait(sock, WAIT_MODE_W, timeout);
+ // Check if the socket is available again and try to resend.
+ if(err == SUCCESS) {
+ continue;
+ }
+ }
+ break;
}
return err;