1--
2-- Licensed to the Apache Software Foundation (ASF) under one
3-- or more contributor license agreements. See the NOTICE file
4-- distributed with this work for additional information
5-- regarding copyright ownership. The ASF licenses this file
6-- to you under the Apache License, Version 2.0 (the
7-- "License"); you may not use this file except in compliance
8-- with the License. You may obtain a copy of the License at
9--
10--   http://www.apache.org/licenses/LICENSE-2.0
11--
12-- Unless required by applicable law or agreed to in writing,
13-- software distributed under the License is distributed on an
14-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15-- KIND, either express or implied. See the License for the
16-- specific language governing permissions and limitations
17-- under the License.
18--
19
20---- namespace thrift
21--thrift = {}
22--setmetatable(thrift, {__index = _G}) --> perf hit for accessing global methods
23--setfenv(1, thrift)
24
25package.cpath = package.cpath .. ';bin/?.so' -- TODO FIX
26function ttype(obj)
27  if type(obj) == 'table' and
28    obj.__type and
29    type(obj.__type) == 'string' then
30      return obj.__type
31  end
32  return type(obj)
33end
34
35function terror(e)
36  if e and e.__tostring then
37    error(e:__tostring())
38    return
39  end
40  error(e)
41end
42
43function ttable_size(t)
44  local count = 0
45  for k, v in pairs(t) do
46    count = count + 1
47  end
48  return count
49end
50
51version = '0.18.0'
52
53TType = {
54  STOP   = 0,
55  VOID   = 1,
56  BOOL   = 2,
57  BYTE   = 3,
58  I08    = 3,
59  DOUBLE = 4,
60  I16    = 6,
61  I32    = 8,
62  I64    = 10,
63  STRING = 11,
64  UTF7   = 11,
65  STRUCT = 12,
66  MAP    = 13,
67  SET    = 14,
68  LIST   = 15,
69  UTF8   = 16,
70  UTF16  = 17
71}
72
73TMessageType = {
74  CALL  = 1,
75  REPLY = 2,
76  EXCEPTION = 3,
77  ONEWAY = 4
78}
79
80-- Recursive __index function to achieve inheritance
81function __tobj_index(self, key)
82  local v = rawget(self, key)
83  if v ~= nil then
84    return v
85  end
86
87  local p = rawget(self, '__parent')
88  if p then
89    return __tobj_index(p, key)
90  end
91
92  return nil
93end
94
95-- Basic Thrift-Lua Object
96__TObject = {
97  __type = '__TObject',
98  __mt = {
99    __index = __tobj_index
100  }
101}
102function __TObject:new(init_obj)
103  local obj = {}
104  if ttype(obj) == 'table' then
105    obj = init_obj
106  end
107
108  -- Use the __parent key and the __index function to achieve inheritance
109  obj.__parent = self
110  setmetatable(obj, __TObject.__mt)
111  return obj
112end
113
114-- Return a string representation of any lua variable
115function thrift_print_r(t)
116  local ret = ''
117  local ltype = type(t)
118  if (ltype == 'table') then
119    ret = ret .. '{ '
120    for key,value in pairs(t) do
121      ret = ret .. tostring(key) .. '=' .. thrift_print_r(value) .. ' '
122    end
123    ret = ret .. '}'
124  elseif ltype == 'string' then
125    ret = ret .. "'" .. tostring(t) .. "'"
126  else
127    ret = ret .. tostring(t)
128  end
129  return ret
130end
131
132-- Basic Exception
133TException = __TObject:new{
134  message,
135  errorCode,
136  __type = 'TException'
137}
138function TException:__tostring()
139  if self.message then
140    return string.format('%s: %s', self.__type, self.message)
141  else
142    local message
143    if self.errorCode and self.__errorCodeToString then
144      message = string.format('%d: %s', self.errorCode, self:__errorCodeToString())
145    else
146      message = thrift_print_r(self)
147    end
148    return string.format('%s:%s', self.__type, message)
149  end
150end
151
152TApplicationException = TException:new{
153  UNKNOWN                 = 0,
154  UNKNOWN_METHOD          = 1,
155  INVALID_MESSAGE_TYPE    = 2,
156  WRONG_METHOD_NAME       = 3,
157  BAD_SEQUENCE_ID         = 4,
158  MISSING_RESULT          = 5,
159  INTERNAL_ERROR          = 6,
160  PROTOCOL_ERROR          = 7,
161  INVALID_TRANSFORM       = 8,
162  INVALID_PROTOCOL        = 9,
163  UNSUPPORTED_CLIENT_TYPE = 10,
164  errorCode               = 0,
165  __type = 'TApplicationException'
166}
167
168function TApplicationException:__errorCodeToString()
169  if self.errorCode == self.UNKNOWN_METHOD then
170    return 'Unknown method'
171  elseif self.errorCode == self.INVALID_MESSAGE_TYPE then
172    return 'Invalid message type'
173  elseif self.errorCode == self.WRONG_METHOD_NAME then
174    return 'Wrong method name'
175  elseif self.errorCode == self.BAD_SEQUENCE_ID then
176    return 'Bad sequence ID'
177  elseif self.errorCode == self.MISSING_RESULT then
178    return 'Missing result'
179  elseif self.errorCode == self.INTERNAL_ERROR then
180    return 'Internal error'
181  elseif self.errorCode == self.PROTOCOL_ERROR then
182    return 'Protocol error'
183  elseif self.errorCode == self.INVALID_TRANSFORM then
184    return 'Invalid transform'
185  elseif self.errorCode == self.INVALID_PROTOCOL then
186    return 'Invalid protocol'
187  elseif self.errorCode == self.UNSUPPORTED_CLIENT_TYPE then
188    return 'Unsupported client type'
189  else
190    return 'Default (unknown)'
191  end
192end
193
194function TException:read(iprot)
195  iprot:readStructBegin()
196  while true do
197    local fname, ftype, fid = iprot:readFieldBegin()
198    if ftype == TType.STOP then
199      break
200    elseif fid == 1 then
201      if ftype == TType.STRING then
202        self.message = iprot:readString()
203      else
204        iprot:skip(ftype)
205      end
206    elseif fid == 2 then
207      if ftype == TType.I32 then
208        self.errorCode = iprot:readI32()
209      else
210        iprot:skip(ftype)
211      end
212    else
213      iprot:skip(ftype)
214    end
215    iprot:readFieldEnd()
216  end
217  iprot:readStructEnd()
218end
219
220function TException:write(oprot)
221  oprot:writeStructBegin('TApplicationException')
222  if self.message then
223    oprot:writeFieldBegin('message', TType.STRING, 1)
224    oprot:writeString(self.message)
225    oprot:writeFieldEnd()
226  end
227  if self.errorCode then
228    oprot:writeFieldBegin('type', TType.I32, 2)
229    oprot:writeI32(self.errorCode)
230    oprot:writeFieldEnd()
231  end
232  oprot:writeFieldStop()
233  oprot:writeStructEnd()
234end
235
236-- Basic Client (used in generated lua code)
237__TClient = __TObject:new{
238  __type = '__TClient',
239  _seqid = 0
240}
241function __TClient:new(obj)
242  if ttype(obj) ~= 'table' then
243    error('TClient must be initialized with a table')
244  end
245
246  -- Set iprot & oprot
247  if obj.protocol then
248    obj.iprot = obj.protocol
249    obj.oprot = obj.protocol
250    obj.protocol = nil
251  elseif not obj.iprot then
252    error('You must provide ' .. ttype(self) .. ' with an iprot')
253  end
254  if not obj.oprot then
255    obj.oprot = obj.iprot
256  end
257
258  return __TObject.new(self, obj)
259end
260
261function __TClient:close()
262  self.iprot.trans:close()
263  self.oprot.trans:close()
264end
265
266-- Basic Processor (used in generated lua code)
267__TProcessor = __TObject:new{
268  __type = '__TProcessor'
269}
270function __TProcessor:new(obj)
271  if ttype(obj) ~= 'table' then
272    error('TProcessor must be initialized with a table')
273  end
274
275  -- Ensure a handler is provided
276  if not obj.handler then
277    error('You must provide ' .. ttype(self) .. ' with a handler')
278  end
279
280  return __TObject.new(self, obj)
281end
282