thrift 0.0.751142

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/CHANGELOG +2 -0
  2. data/COPYING +14 -0
  3. data/LICENSE +14 -0
  4. data/Makefile.am +15 -0
  5. data/Manifest +78 -0
  6. data/README +30 -0
  7. data/Rakefile +102 -0
  8. data/benchmark/Benchmark.thrift +5 -0
  9. data/benchmark/benchmark.rb +254 -0
  10. data/benchmark/client.rb +56 -0
  11. data/benchmark/gen-rb/BenchmarkService.rb +81 -0
  12. data/benchmark/gen-rb/Benchmark_constants.rb +11 -0
  13. data/benchmark/gen-rb/Benchmark_types.rb +10 -0
  14. data/benchmark/server.rb +64 -0
  15. data/benchmark/thin_server.rb +26 -0
  16. data/ext/binary_protocol_accelerated.c +463 -0
  17. data/ext/binary_protocol_accelerated.h +1 -0
  18. data/ext/constants.h +77 -0
  19. data/ext/extconf.rb +7 -0
  20. data/ext/memory_buffer.c +52 -0
  21. data/ext/memory_buffer.h +1 -0
  22. data/ext/protocol.c +166 -0
  23. data/ext/protocol.h +1 -0
  24. data/ext/struct.c +574 -0
  25. data/ext/struct.h +48 -0
  26. data/ext/thrift_native.c +173 -0
  27. data/lib/thrift/client.rb +44 -0
  28. data/lib/thrift/deprecation.rb +155 -0
  29. data/lib/thrift/exceptions.rb +65 -0
  30. data/lib/thrift/processor.rb +39 -0
  31. data/lib/thrift/protocol/binaryprotocol.rb +213 -0
  32. data/lib/thrift/protocol/binaryprotocolaccelerated.rb +19 -0
  33. data/lib/thrift/protocol/tbinaryprotocol.rb +2 -0
  34. data/lib/thrift/protocol/tprotocol.rb +2 -0
  35. data/lib/thrift/protocol.rb +270 -0
  36. data/lib/thrift/serializer.rb +27 -0
  37. data/lib/thrift/server/httpserver.rb +44 -0
  38. data/lib/thrift/server/nonblockingserver.rb +278 -0
  39. data/lib/thrift/server/thttpserver.rb +2 -0
  40. data/lib/thrift/server/tserver.rb +2 -0
  41. data/lib/thrift/server.rb +135 -0
  42. data/lib/thrift/struct.rb +272 -0
  43. data/lib/thrift/thrift.rb +14 -0
  44. data/lib/thrift/transport/httpclient.rb +29 -0
  45. data/lib/thrift/transport/socket.rb +167 -0
  46. data/lib/thrift/transport/thttpclient.rb +2 -0
  47. data/lib/thrift/transport/tsocket.rb +2 -0
  48. data/lib/thrift/transport/ttransport.rb +2 -0
  49. data/lib/thrift/transport/unixsocket.rb +58 -0
  50. data/lib/thrift/transport.rb +319 -0
  51. data/lib/thrift/types.rb +83 -0
  52. data/lib/thrift.rb +28 -0
  53. data/setup.rb +1585 -0
  54. data/spec/ThriftSpec.thrift +46 -0
  55. data/spec/backwards_compatibility_spec.rb +136 -0
  56. data/spec/binaryprotocol_spec.rb +45 -0
  57. data/spec/binaryprotocol_spec_shared.rb +274 -0
  58. data/spec/binaryprotocolaccelerated_spec.rb +101 -0
  59. data/spec/client_spec.rb +81 -0
  60. data/spec/deprecation_spec.rb +443 -0
  61. data/spec/exception_spec.rb +123 -0
  62. data/spec/gen-rb/NonblockingService.rb +268 -0
  63. data/spec/gen-rb/ThriftSpec_constants.rb +11 -0
  64. data/spec/gen-rb/ThriftSpec_types.rb +134 -0
  65. data/spec/httpclient_spec.rb +31 -0
  66. data/spec/httpserver_spec.rb +98 -0
  67. data/spec/nonblockingserver_spec.rb +245 -0
  68. data/spec/processor_spec.rb +64 -0
  69. data/spec/protocol_spec.rb +142 -0
  70. data/spec/serializer_spec.rb +52 -0
  71. data/spec/server_spec.rb +141 -0
  72. data/spec/socket_spec.rb +97 -0
  73. data/spec/socket_spec_shared.rb +85 -0
  74. data/spec/spec_helper.rb +35 -0
  75. data/spec/struct_spec.rb +244 -0
  76. data/spec/transport_spec.rb +359 -0
  77. data/spec/types_spec.rb +98 -0
  78. data/spec/unixsocket_spec.rb +90 -0
  79. data/thrift.gemspec +33 -0
  80. data.tar.gz.sig +0 -0
  81. metadata +200 -0
  82. metadata.gz.sig +0 -0
@@ -0,0 +1,2 @@
1
+ require 'thrift/deprecation'
2
+ require 'thrift/protocol/binaryprotocol'
@@ -0,0 +1,2 @@
1
+ require 'thrift/deprecation'
2
+ require 'thrift/protocol'
@@ -0,0 +1,270 @@
1
+ #
2
+ # Copyright (c) 2006- Facebook
3
+ # Distributed under the Apache Software License
4
+ #
5
+ # See accompanying file LICENSE or visit the Thrift site at:
6
+ # http://developers.facebook.com/thrift/
7
+ #
8
+ # Author: Mark Slee <mcslee@facebook.com>
9
+ #
10
+
11
+ # this require is to make generated struct definitions happy
12
+ require 'set'
13
+
14
+ module Thrift
15
+ class ProtocolException < Exception
16
+
17
+ UNKNOWN = 0
18
+ INVALID_DATA = 1
19
+ NEGATIVE_SIZE = 2
20
+ SIZE_LIMIT = 3
21
+ BAD_VERSION = 4
22
+
23
+ attr_reader :type
24
+
25
+ def initialize(type=UNKNOWN, message=nil)
26
+ super(message)
27
+ @type = type
28
+ end
29
+
30
+ end
31
+ deprecate_class! :TProtocolException => ProtocolException
32
+
33
+ class Protocol
34
+
35
+ attr_reader :trans
36
+
37
+ def initialize(trans)
38
+ @trans = trans
39
+ end
40
+
41
+ def native?
42
+ puts "wrong method is being called!"
43
+ false
44
+ end
45
+
46
+ def write_message_begin(name, type, seqid); nil; end
47
+ deprecate! :writeMessageBegin => :write_message_begin
48
+
49
+ def write_message_end; nil; end
50
+ deprecate! :writeMessageEnd => :write_message_end
51
+
52
+ def write_struct_begin(name); nil; end
53
+ deprecate! :writeStructBegin => :write_struct_begin
54
+
55
+ def write_struct_end; nil; end
56
+ deprecate! :writeStructEnd => :write_struct_end
57
+
58
+ def write_field_begin(name, type, id); nil; end
59
+ deprecate! :writeFieldBegin => :write_field_begin
60
+
61
+ def write_field_end; nil; end
62
+ deprecate! :writeFieldEnd => :write_field_end
63
+
64
+ def write_field_stop; nil; end
65
+ deprecate! :writeFieldStop => :write_field_stop
66
+
67
+ def write_map_begin(ktype, vtype, size); nil; end
68
+ deprecate! :writeMapBegin => :write_map_begin
69
+
70
+ def write_map_end; nil; end
71
+ deprecate! :writeMapEnd => :write_map_end
72
+
73
+ def write_list_begin(etype, size); nil; end
74
+ deprecate! :writeListBegin => :write_list_begin
75
+
76
+ def write_list_end; nil; end
77
+ deprecate! :writeListEnd => :write_list_end
78
+
79
+ def write_set_begin(etype, size); nil; end
80
+ deprecate! :writeSetBegin => :write_set_begin
81
+
82
+ def write_set_end; nil; end
83
+ deprecate! :writeSetEnd => :write_set_end
84
+
85
+ def write_bool(bool); nil; end
86
+ deprecate! :writeBool => :write_bool
87
+
88
+ def write_byte(byte); nil; end
89
+ deprecate! :writeByte => :write_byte
90
+
91
+ def write_i16(i16); nil; end
92
+ deprecate! :writeI16 => :write_i16
93
+
94
+ def write_i32(i32); nil; end
95
+ deprecate! :writeI32 => :write_i32
96
+
97
+ def write_i64(i64); nil; end
98
+ deprecate! :writeI64 => :write_i64
99
+
100
+ def write_double(dub); nil; end
101
+ deprecate! :writeDouble => :write_double
102
+
103
+ def write_string(str); nil; end
104
+ deprecate! :writeString => :write_string
105
+
106
+ def read_message_begin; nil; end
107
+ deprecate! :readMessageBegin => :read_message_begin
108
+
109
+ def read_message_end; nil; end
110
+ deprecate! :readMessageEnd => :read_message_end
111
+
112
+ def read_struct_begin; nil; end
113
+ deprecate! :readStructBegin => :read_struct_begin
114
+
115
+ def read_struct_end; nil; end
116
+ deprecate! :readStructEnd => :read_struct_end
117
+
118
+ def read_field_begin; nil; end
119
+ deprecate! :readFieldBegin => :read_field_begin
120
+
121
+ def read_field_end; nil; end
122
+ deprecate! :readFieldEnd => :read_field_end
123
+
124
+ def read_map_begin; nil; end
125
+ deprecate! :readMapBegin => :read_map_begin
126
+
127
+ def read_map_end; nil; end
128
+ deprecate! :readMapEnd => :read_map_end
129
+
130
+ def read_list_begin; nil; end
131
+ deprecate! :readListBegin => :read_list_begin
132
+
133
+ def read_list_end; nil; end
134
+ deprecate! :readListEnd => :read_list_end
135
+
136
+ def read_set_begin; nil; end
137
+ deprecate! :readSetBegin => :read_set_begin
138
+
139
+ def read_set_end; nil; end
140
+ deprecate! :readSetEnd => :read_set_end
141
+
142
+ def read_bool; nil; end
143
+ deprecate! :readBool => :read_bool
144
+
145
+ def read_byte; nil; end
146
+ deprecate! :readByte => :read_byte
147
+
148
+ def read_i16; nil; end
149
+ deprecate! :readI16 => :read_i16
150
+
151
+ def read_i32; nil; end
152
+ deprecate! :readI32 => :read_i32
153
+
154
+ def read_i64; nil; end
155
+ deprecate! :readI64 => :read_i64
156
+
157
+ def read_double; nil; end
158
+ deprecate! :readDouble => :read_double
159
+
160
+ def read_string; nil; end
161
+ deprecate! :readString => :read_string
162
+
163
+ def write_field(name, type, fid, value)
164
+ write_field_begin(name, type, fid)
165
+ write_type(type, value)
166
+ write_field_end
167
+ end
168
+
169
+ def write_type(type, value)
170
+ case type
171
+ when Types::BOOL
172
+ write_bool(value)
173
+ when Types::BYTE
174
+ write_byte(value)
175
+ when Types::DOUBLE
176
+ write_double(value)
177
+ when Types::I16
178
+ write_i16(value)
179
+ when Types::I32
180
+ write_i32(value)
181
+ when Types::I64
182
+ write_i64(value)
183
+ when Types::STRING
184
+ write_string(value)
185
+ when Types::STRUCT
186
+ value.write(self)
187
+ else
188
+ raise NotImplementedError
189
+ end
190
+ end
191
+
192
+ def read_type(type)
193
+ case type
194
+ when Types::BOOL
195
+ read_bool
196
+ when Types::BYTE
197
+ read_byte
198
+ when Types::DOUBLE
199
+ read_double
200
+ when Types::I16
201
+ read_i16
202
+ when Types::I32
203
+ read_i32
204
+ when Types::I64
205
+ read_i64
206
+ when Types::STRING
207
+ read_string
208
+ else
209
+ raise NotImplementedError
210
+ end
211
+ end
212
+
213
+ def skip(type)
214
+ case type
215
+ when Types::STOP
216
+ nil
217
+ when Types::BOOL
218
+ read_bool
219
+ when Types::BYTE
220
+ read_byte
221
+ when Types::I16
222
+ read_i16
223
+ when Types::I32
224
+ read_i32
225
+ when Types::I64
226
+ read_i64
227
+ when Types::DOUBLE
228
+ read_double
229
+ when Types::STRING
230
+ read_string
231
+ when Types::STRUCT
232
+ read_struct_begin
233
+ while true
234
+ name, type, id = read_field_begin
235
+ break if type == Types::STOP
236
+ skip(type)
237
+ read_field_end
238
+ end
239
+ read_struct_end
240
+ when Types::MAP
241
+ ktype, vtype, size = read_map_begin
242
+ size.times do
243
+ skip(ktype)
244
+ skip(vtype)
245
+ end
246
+ read_map_end
247
+ when Types::SET
248
+ etype, size = read_set_begin
249
+ size.times do
250
+ skip(etype)
251
+ end
252
+ read_set_end
253
+ when Types::LIST
254
+ etype, size = read_list_begin
255
+ size.times do
256
+ skip(etype)
257
+ end
258
+ read_list_end
259
+ end
260
+ end
261
+
262
+ end
263
+ deprecate_class! :TProtocol => Protocol
264
+
265
+ class ProtocolFactory
266
+ def get_protocol(trans); nil; end
267
+ deprecate! :getProtocol => :get_protocol
268
+ end
269
+ deprecate_class! :TProtocolFactory => ProtocolFactory
270
+ end
@@ -0,0 +1,27 @@
1
+ module Thrift
2
+ class Serializer
3
+ def initialize(protocolFactory = BinaryProtocolFactory.new)
4
+ @transport = MemoryBuffer.new
5
+ @protocol = protocolFactory.get_protocol(@transport)
6
+ end
7
+
8
+ def serialize(base)
9
+ @transport.reset_buffer
10
+ base.write(@protocol)
11
+ @transport.read(@transport.available)
12
+ end
13
+ end
14
+
15
+ class Deserializer
16
+ def initialize(protocolFactory = BinaryProtocolFactory.new)
17
+ @transport = MemoryBuffer.new
18
+ @protocol = protocolFactory.get_protocol(@transport)
19
+ end
20
+
21
+ def deserialize(base, buffer)
22
+ @transport.reset_buffer(buffer)
23
+ base.read(@protocol)
24
+ base
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,44 @@
1
+ require 'thrift/protocol'
2
+ require 'thrift/protocol/binaryprotocol'
3
+ require 'thrift/transport'
4
+
5
+ require 'mongrel'
6
+
7
+ ## Sticks a service on a URL, using mongrel to do the HTTP work
8
+ module Thrift
9
+ class SimpleMongrelHTTPServer
10
+ class Handler < Mongrel::HttpHandler
11
+ def initialize(processor, protocol_factory)
12
+ @processor = processor
13
+ @protocol_factory = protocol_factory
14
+ end
15
+
16
+ def process(request, response)
17
+ if request.params["REQUEST_METHOD"] == "POST"
18
+ response.start(200) do |head, out|
19
+ head["Content-Type"] = "application/x-thrift"
20
+ transport = IOStreamTransport.new request.body, out
21
+ protocol = @protocol_factory.get_protocol transport
22
+ @processor.process protocol, protocol
23
+ end
24
+ else
25
+ response.start(404) { }
26
+ end
27
+ end
28
+ end
29
+
30
+ def initialize(processor, opts={})
31
+ port = opts[:port] || 80
32
+ ip = opts[:ip] || "0.0.0.0"
33
+ path = opts[:path] || ""
34
+ protocol_factory = opts[:protocol_factory] || BinaryProtocolFactory.new
35
+ @server = Mongrel::HttpServer.new ip, port
36
+ @server.register "/#{path}", Handler.new(processor, protocol_factory)
37
+ end
38
+
39
+ def serve
40
+ @server.run.join
41
+ end
42
+ end
43
+ deprecate_class! :TSimpleMongrelHTTPServer => SimpleMongrelHTTPServer
44
+ end
@@ -0,0 +1,278 @@
1
+ require 'thrift/server'
2
+ require 'logger'
3
+ require 'thread'
4
+
5
+ module Thrift
6
+ # this class expects to always use a FramedTransport for reading messages
7
+ class NonblockingServer < Server
8
+ def initialize(processor, serverTransport, transportFactory=nil, protocolFactory=nil, num=20, logger = nil)
9
+ super(processor, serverTransport, transportFactory, protocolFactory)
10
+ @num_threads = num
11
+ if logger.nil?
12
+ @logger = Logger.new(STDERR)
13
+ @logger.level = Logger::WARN
14
+ else
15
+ @logger = logger
16
+ end
17
+ @shutdown_semaphore = Mutex.new
18
+ @transport_semaphore = Mutex.new
19
+ end
20
+
21
+ def serve
22
+ @logger.info "Starting #{self}"
23
+ @serverTransport.listen
24
+ @io_manager = start_io_manager
25
+
26
+ begin
27
+ loop do
28
+ break if @serverTransport.closed?
29
+ rd, = select([@serverTransport], nil, nil, 0.1)
30
+ next if rd.nil?
31
+ socket = @serverTransport.accept
32
+ @logger.debug "Accepted socket: #{socket.inspect}"
33
+ @io_manager.add_connection socket
34
+ end
35
+ rescue IOError => e
36
+ end
37
+ # we must be shutting down
38
+ @logger.info "#{self} is shutting down, goodbye"
39
+ ensure
40
+ @transport_semaphore.synchronize do
41
+ @serverTransport.close
42
+ end
43
+ @io_manager.ensure_closed unless @io_manager.nil?
44
+ end
45
+
46
+ def shutdown(timeout = 0, block = true)
47
+ @shutdown_semaphore.synchronize do
48
+ return if @is_shutdown
49
+ @is_shutdown = true
50
+ end
51
+ # nonblocking is intended for calling from within a Handler
52
+ # but we can't change the order of operations here, so lets thread
53
+ shutdown_proc = lambda do
54
+ @io_manager.shutdown(timeout)
55
+ @transport_semaphore.synchronize do
56
+ @serverTransport.close # this will break the accept loop
57
+ end
58
+ end
59
+ if block
60
+ shutdown_proc.call
61
+ else
62
+ Thread.new &shutdown_proc
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def start_io_manager
69
+ iom = IOManager.new(@processor, @serverTransport, @transportFactory, @protocolFactory, @num_threads, @logger)
70
+ iom.spawn
71
+ iom
72
+ end
73
+
74
+ class IOManager # :nodoc:
75
+ DEFAULT_BUFFER = 2**20
76
+
77
+ def initialize(processor, serverTransport, transportFactory, protocolFactory, num, logger)
78
+ @processor = processor
79
+ @serverTransport = serverTransport
80
+ @transportFactory = transportFactory
81
+ @protocolFactory = protocolFactory
82
+ @num_threads = num
83
+ @logger = logger
84
+ @connections = []
85
+ @buffers = Hash.new { |h,k| h[k] = '' }
86
+ @signal_queue = Queue.new
87
+ @signal_pipes = IO.pipe
88
+ @signal_pipes[1].sync = true
89
+ @worker_queue = Queue.new
90
+ @shutdown_queue = Queue.new
91
+ end
92
+
93
+ def add_connection(socket)
94
+ signal [:connection, socket]
95
+ end
96
+
97
+ def spawn
98
+ @iom_thread = Thread.new do
99
+ @logger.debug "Starting #{self}"
100
+ run
101
+ end
102
+ end
103
+
104
+ def shutdown(timeout = 0)
105
+ @logger.debug "#{self} is shutting down workers"
106
+ @worker_queue.clear
107
+ @num_threads.times { @worker_queue.push [:shutdown] }
108
+ signal [:shutdown, timeout]
109
+ @shutdown_queue.pop
110
+ @signal_pipes[0].close
111
+ @signal_pipes[1].close
112
+ @logger.debug "#{self} is shutting down, goodbye"
113
+ end
114
+
115
+ def ensure_closed
116
+ kill_worker_threads if @worker_threads
117
+ @iom_thread.kill
118
+ end
119
+
120
+ private
121
+
122
+ def run
123
+ spin_worker_threads
124
+
125
+ loop do
126
+ rd, = select([@signal_pipes[0], *@connections])
127
+ if rd.delete @signal_pipes[0]
128
+ break if read_signals == :shutdown
129
+ end
130
+ rd.each do |fd|
131
+ if fd.handle.eof?
132
+ remove_connection fd
133
+ else
134
+ read_connection fd
135
+ end
136
+ end
137
+ end
138
+ join_worker_threads(@shutdown_timeout)
139
+ ensure
140
+ @shutdown_queue.push :shutdown
141
+ end
142
+
143
+ def read_connection(fd)
144
+ @buffers[fd] << fd.read(DEFAULT_BUFFER)
145
+ frame = slice_frame!(@buffers[fd])
146
+ if frame
147
+ @logger.debug "#{self} is processing a frame"
148
+ @worker_queue.push [:frame, fd, frame]
149
+ end
150
+ end
151
+
152
+ def spin_worker_threads
153
+ @logger.debug "#{self} is spinning up worker threads"
154
+ @worker_threads = []
155
+ @num_threads.times do
156
+ @worker_threads << spin_thread
157
+ end
158
+ end
159
+
160
+ def spin_thread
161
+ Worker.new(@processor, @transportFactory, @protocolFactory, @logger, @worker_queue).spawn
162
+ end
163
+
164
+ def signal(msg)
165
+ @signal_queue << msg
166
+ @signal_pipes[1].write " "
167
+ end
168
+
169
+ def read_signals
170
+ # clear the signal pipe
171
+ # note that since read_nonblock is broken in jruby,
172
+ # we can only read up to a set number of signals at once
173
+ sigstr = @signal_pipes[0].readpartial(1024)
174
+ # now read the signals
175
+ begin
176
+ sigstr.length.times do
177
+ signal, obj = @signal_queue.pop(true)
178
+ case signal
179
+ when :connection
180
+ @connections << obj
181
+ when :shutdown
182
+ @shutdown_timeout = obj
183
+ return :shutdown
184
+ end
185
+ end
186
+ rescue ThreadError
187
+ # out of signals
188
+ # note that in a perfect world this would never happen, since we're
189
+ # only reading the number of signals pushed on the pipe, but given the lack
190
+ # of locks, in theory we could clear the pipe/queue while a new signal is being
191
+ # placed on the pipe, at which point our next read_signals would hit this error
192
+ end
193
+ end
194
+
195
+ def remove_connection(fd)
196
+ # don't explicitly close it, a thread may still be writing to it
197
+ @connections.delete fd
198
+ @buffers.delete fd
199
+ end
200
+
201
+ def join_worker_threads(shutdown_timeout)
202
+ start = Time.now
203
+ @worker_threads.each do |t|
204
+ if shutdown_timeout > 0
205
+ timeout = (start + shutdown_timeout) - Time.now
206
+ break if timeout <= 0
207
+ t.join(timeout)
208
+ else
209
+ t.join
210
+ end
211
+ end
212
+ kill_worker_threads
213
+ end
214
+
215
+ def kill_worker_threads
216
+ @worker_threads.each do |t|
217
+ t.kill if t.status
218
+ end
219
+ @worker_threads.clear
220
+ end
221
+
222
+ def slice_frame!(buf)
223
+ if buf.length >= 4
224
+ size = buf.unpack('N').first
225
+ if buf.length >= size + 4
226
+ buf.slice!(0, size + 4)
227
+ else
228
+ nil
229
+ end
230
+ else
231
+ nil
232
+ end
233
+ end
234
+
235
+ class Worker # :nodoc:
236
+ def initialize(processor, transportFactory, protocolFactory, logger, queue)
237
+ @processor = processor
238
+ @transportFactory = transportFactory
239
+ @protocolFactory = protocolFactory
240
+ @logger = logger
241
+ @queue = queue
242
+ end
243
+
244
+ def spawn
245
+ Thread.new do
246
+ @logger.debug "#{self} is spawning"
247
+ run
248
+ end
249
+ end
250
+
251
+ private
252
+
253
+ def run
254
+ loop do
255
+ cmd, *args = @queue.pop
256
+ case cmd
257
+ when :shutdown
258
+ @logger.debug "#{self} is shutting down, goodbye"
259
+ break
260
+ when :frame
261
+ fd, frame = args
262
+ begin
263
+ otrans = @transportFactory.get_transport(fd)
264
+ oprot = @protocolFactory.get_protocol(otrans)
265
+ membuf = MemoryBuffer.new(frame)
266
+ itrans = @transportFactory.get_transport(membuf)
267
+ iprot = @protocolFactory.get_protocol(itrans)
268
+ @processor.process(iprot, oprot)
269
+ rescue => e
270
+ @logger.error "#{Thread.current.inspect} raised error: #{e.inspect}\n#{e.backtrace.join("\n")}"
271
+ end
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
278
+ end
@@ -0,0 +1,2 @@
1
+ require 'thrift/deprecation'
2
+ require 'thrift/server/httpserver'
@@ -0,0 +1,2 @@
1
+ require 'thrift/deprecation'
2
+ require 'thrift/server'