Module: ThriftClient::Simple

Defined in:
lib/thrift_client/simple.rb

Overview

This is a simplified form of thrift, useful for clients only, and not making any attempt to have good performance. It's intended to be used by small command-line tools that don't want to install a dozen ruby files.

Defined Under Namespace

Modules: ComplexType, ThriftStruct Classes: Field, ThriftException, ThriftService

Constant Summary

VERSION_1 =
0x8001
FORMATS =
{
  BYTE => "c",
  DOUBLE => "G",
  I16 => "n",
  I32 => "N",
}
SIZES =
{
  BYTE => 1,
  DOUBLE => 8,
  I16 => 2,
  I32 => 4,
}
ListType =
make_type(LIST, "ListType", :element_type)
MapType =
make_type(MAP, "MapType", :key_type, :value_type)
SetType =
make_type(SET, "SetType", :element_type)
StructType =
make_type(STRUCT, "StructType", :struct_class)

Class Method Summary (collapse)

Class Method Details

+ (Object) make_struct(name, *fields)



220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/thrift_client/simple.rb', line 220

def self.make_struct(name, *fields)
  st_name = "ST_#{name}"
  if Struct.constants.include?(st_name)
    warn "#{caller[0]}: Struct::#{st_name} is already defined; returning original class."
    Struct.const_get(st_name)
  else
    names = fields.map { |f| f.name.to_sym }
    klass = Struct.new(st_name, *names)
    klass.send(:include, ThriftStruct::Include)
    klass.send(:extend, ThriftStruct::Extend)
    klass._fields = fields
    klass
  end
end

+ (Object) make_type(type_id, name, *args)



55
56
57
58
59
60
61
# File 'lib/thrift_client/simple.rb', line 55

def self.make_type(type_id, name, *args)
  klass = Struct.new("STT_#{name}", *args)
  klass.send(:extend, ComplexType::Extends)
  klass.send(:include, ComplexType::Includes)
  klass.type_id = type_id
  klass
end

+ (Object) pack_request(method_name, arg_struct, request_id = 0)



90
91
92
# File 'lib/thrift_client/simple.rb', line 90

def pack_request(method_name, arg_struct, request_id=0)
  [ VERSION_1, CALL, method_name.to_s.size, method_name.to_s, request_id, arg_struct._pack ].pack("nnNa*Na*")
end

+ (Object) pack_value(type, value)



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/thrift_client/simple.rb', line 69

def pack_value(type, value)
  case type
  when BOOL
    [ value ? 1 : 0 ].pack("c")
  when STRING
    [ value.size, value ].pack("Na*")
  when I64
    [ value >> 32, value & 0xffffffff ].pack("NN")
  when ListType
    [ type.element_type.to_i, value.size ].pack("cN") + value.map { |item| pack_value(type.element_type, item) }.join("")
  when MapType
    [ type.key_type.to_i, type.value_type.to_i, value.size ].pack("ccN") + value.map { |k, v| pack_value(type.key_type, k) + pack_value(type.value_type, v) }.join("")
  when SetType
    [ type.element_type.to_i, value.size ].pack("cN") + value.map { |item| pack_value(type.element_type, item) }.join("")
  when StructType
    value._pack
  else
    [ value ].pack(FORMATS[type])
  end
end

+ (Object) read_list(s, element_type = nil)



130
131
132
133
134
135
136
137
138
# File 'lib/thrift_client/simple.rb', line 130

def read_list(s, element_type=nil)
  etype, len = s.read(5).unpack("cN")
  expected_type = (element_type and element_type.to_i == etype.to_i) ? element_type : etype
  rv = []
  len.times do
    rv << read_value(s, expected_type)
  end
  rv
end

+ (Object) read_map(s, key_type = nil, value_type = nil)



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/thrift_client/simple.rb', line 140

def read_map(s, key_type=nil, value_type=nil)
  ktype, vtype, len = s.read(6).unpack("ccN")
  rv = {}
  expected_key_type, expected_value_type = if key_type and value_type and key_type.to_i == ktype and value_type.to_i == vtype
    [ key_type, value_type ]
  else
    [ ktype, vtype ]
  end
  len.times do
    key = read_value(s, expected_key_type)
    value = read_value(s, expected_value_type)
    rv[key] = value
  end
  rv
end

+ (Object) read_response(s, rv_class)



168
169
170
171
172
173
# File 'lib/thrift_client/simple.rb', line 168

def read_response(s, rv_class)
  version, message_type, method_name_len = s.read(8).unpack("nnN")
  method_name = s.read(method_name_len)
  seq_id = s.read(4).unpack("N").first
  [ method_name, seq_id, read_struct(s, rv_class).rv ]
end

+ (Object) read_struct(s, struct_class = nil)



156
157
158
159
160
161
162
163
164
165
166
# File 'lib/thrift_client/simple.rb', line 156

def read_struct(s, struct_class=nil)
  rv = struct_class.new()
  while true
    type = s.read(1).unpack("c").first
    return rv if type == STOP
    fid = s.read(2).unpack("n").first
    field = struct_class ? struct_class._fields.find { |f| (f.fid == fid) and (f.type.to_i == type) } : nil
    value = read_value(s, field ? field.type : type)
    rv[field.name] = value if field
  end
end

+ (Object) read_value(s, type)



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/thrift_client/simple.rb', line 94

def read_value(s, type)
  case type
  when BOOL
    s.read(1).unpack("c").first != 0
  when STRING
    len = s.read(4).unpack("N").first
    s.read(len)
  when I64
    hi, lo = s.read(8).unpack("NN")
    rv = (hi << 32) | lo
    (rv >= (1 << 63)) ? (rv - (1 << 64)) : rv
  when LIST
    read_list(s)
  when MAP
    read_map(s)
  when STRUCT
    read_struct(s)
  when ListType
    read_list(s, type.element_type)
  when MapType
    read_map(s, type.key_type, type.value_type)
  when StructType
    read_struct(s, type.struct_class)
  else
    rv = s.read(SIZES[type]).unpack(FORMATS[type]).first
    case type
    when I16
      (rv >= (1 << 15)) ? (rv - (1 << 16)) : rv
    when I32
      (rv >= (1 << 31)) ? (rv - (1 << 32)) : rv
    else
      rv
    end
  end
end