blob: a0a2f7e834736e65b4d9c73ab1eeddf705cc85e2 [file] [log] [blame]
#!/usr/bin/env ruby
#
# Copyright (c) 2006- Facebook
# Distributed under the Thrift Software License
#
# See accompanying file LICENSE or visit the Thrift site at:
# http://developers.facebook.com/thrift/
#
# Author: Mark Slee <mcslee@facebook.com>
#
class TType
STOP = 0
VOID = 1
BOOL = 2
BYTE = 3
DOUBLE = 4
I16 = 6
I32 = 8
I64 = 10
STRING = 11
STRUCT = 12
MAP = 13
SET = 14
LIST = 15
end
class TMessageType
CALL = 1
REPLY = 2
EXCEPTION = 3
end
module TProcessor
def initialize(handler)
@handler = handler
end
def process(iprot, oprot)
name, type, seqid = iprot.readMessageBegin()
if respond_to?("process_#{name}")
send("process_#{name}", seqid, iprot, oprot)
return true
else
iprot.skip(TType::STRUCT)
iprot.readMessageEnd()
x = TApplicationException.new(TApplicationException::UNKNOWN_METHOD, 'Unknown function '+name)
oprot.writeMessageBegin(name, TMessageType::EXCEPTION, seqid)
x.write(oprot)
oprot.writeMessageEnd()
oprot.trans.flush()
return
end
end
def read_args(iprot, args_class)
args = args_class.new
args.read(iprot)
iprot.readMessageEnd
args
end
def write_result(result, oprot, name, seqid)
oprot.writeMessageBegin(name, TMessageType::REPLY, seqid)
result.write(oprot)
oprot.writeMessageEnd()
oprot.trans.flush()
end
end
class TException < StandardError
def initialize(message)
super(message)
@message = message
end
attr_reader :message
end
class TApplicationException < TException
UNKNOWN = 0
UNKNOWN_METHOD = 1
INVALID_MESSAGE_TYPE = 2
WRONG_METHOD_NAME = 3
BAD_SEQUENCE_ID = 4
MISSING_RESULT = 5
attr_reader :type
def initialize(type=UNKNOWN, message=nil)
super(message)
@type = type
end
def read(iprot)
iprot.readStructBegin()
while true
fname, ftype, fid = iprot.readFieldBegin()
if (ftype === TType::STOP)
break
end
if (fid == 1)
if (ftype === TType::STRING)
@message = iprot.readString();
else
iprot.skip(ftype)
end
elsif (fid == 2)
if (ftype === TType::I32)
@type = iprot.readI32();
else
iprot.skip(ftype)
end
else
iprot.skip(ftype)
end
iprot.readFieldEnd()
end
iprot.readStructEnd()
end
def write(oprot)
oprot.writeStructBegin('TApplicationException')
if (@message != nil)
oprot.writeFieldBegin('message', TType::STRING, 1)
oprot.writeString(@message)
oprot.writeFieldEnd()
end
if (@type != nil)
oprot.writeFieldBegin('type', TType::I32, 2)
oprot.writeI32(@type)
oprot.writeFieldEnd()
end
oprot.writeFieldStop()
oprot.writeStructEnd()
end
end
module ThriftClient
def initialize(iprot, oprot=nil)
@iprot = iprot
@oprot = oprot || iprot
@seqid = 0
end
def send_message(name, args_class, args = {})
@oprot.writeMessageBegin(name, TMessageType::CALL, @seqid)
data = args_class.new
args.each do |k, v|
data.send("#{k.to_s}=", v)
end
data.write(@oprot)
@oprot.writeMessageEnd()
@oprot.trans.flush()
end
def receive_message(result_klass)
fname, mtype, rseqid = @iprot.readMessageBegin()
handle_exception(mtype)
result = result_klass.new
result.read(@iprot)
@iprot.readMessageEnd()
return result
end
def handle_exception(mtype)
if mtype == TMessageType::EXCEPTION
x = TApplicationException.new()
x.read(@iprot)
@iprot.readMessageEnd()
raise x
end
end
end
module ThriftStruct
def initialize(d={})
each_field do |fid, type, name, default|
instance_variable_set("@#{name}", d[name.to_s] || d[name.intern] || default)
end
end
def struct_fields
self.class.const_get(:FIELDS)
end
def each_field
struct_fields.each do |fid, data|
yield fid, data[:type], data[:name], data[:default]
end
end
def read(iprot)
iprot.readStructBegin()
loop do
fname, ftype, fid = iprot.readFieldBegin()
break if (ftype === TType::STOP)
handle_message(iprot, fid, ftype)
iprot.readFieldEnd()
end
iprot.readStructEnd()
end
def write(oprot)
oprot.writeStructBegin(self.class.name)
each_field do |fid, type, name|
if ((value = instance_variable_get("@#{name}")) != nil)
if is_container? type
oprot.writeFieldBegin(name, type, fid)
write_container(oprot, value, struct_fields[fid])
oprot.writeFieldEnd
else
oprot.write_field(name, type, fid, value)
end
end
end
oprot.writeFieldStop()
oprot.writeStructEnd()
end
protected
def handle_message(iprot, fid, ftype)
field = struct_fields[fid]
if field && field[:type] == ftype
value = read_field(iprot, field)
instance_variable_set("@#{field[:name]}", value)
else
iprot.skip(ftype)
end
end
def read_field(iprot, field = {})
if field[:type] == TType::STRUCT
value = field[:class].new
value.read(iprot)
elsif field[:type] == TType::MAP
key_type, val_type, size = iprot.readMapBegin
value = {}
size.times do
k = read_field(iprot, field_info(field[:key]))
v = read_field(iprot, field_info(field[:value]))
value[k] = v
end
iprot.readMapEnd
elsif field[:type] == TType::LIST
e_type, size = iprot.readListBegin
value = Array.new(size) do |n|
read_field(iprot, field_info(field[:element]))
end
iprot.readListEnd
elsif field[:type] == TType::SET
e_type, size = iprot.readSetBegin
value = {}
size.times do
element = read_field(iprot, field_info(field[:element]))
value[element] = true
end
iprot.readSetEnd
else
value = iprot.read_type(field[:type])
end
value
end
def write_data(oprot, value, field)
if is_container? field[:type]
write_container(oprot, value, field)
else
oprot.write_type(field[:type], value)
end
end
def write_container(oprot, value, field = {})
if field[:type] == TType::MAP
oprot.writeMapBegin(field[:key][:type], field[:value][:type], value.size)
value.each do |k, v|
write_data(oprot, k, field[:key])
write_data(oprot, v, field[:value])
end
oprot.writeMapEnd
elsif field[:type] == TType::LIST
oprot.writeListBegin(field[:element][:type], value.size)
value.each do |elem|
write_data(oprot, elem, field[:element])
end
oprot.writeListEnd
elsif field[:type] == TType::SET
oprot.writeSetBegin(field[:element][:type], value.size)
value.each do |k, v|
write_data(oprot, k, field[:element])
end
oprot.writeSetEnd
else
raise "Not a container type: #{field[:type]}"
end
end
def is_container?(type)
[TType::LIST, TType::MAP, TType::SET].include? type
end
def field_info(field)
{ :type => field[:type],
:class => field[:class],
:key => field[:key],
:value => field[:value],
:element => field[:element] }
end
end