upfluence-thrift 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +43 -0
  3. data/benchmark/Benchmark.thrift +24 -0
  4. data/benchmark/benchmark.rb +271 -0
  5. data/benchmark/client.rb +74 -0
  6. data/benchmark/gen-rb/benchmark_constants.rb +11 -0
  7. data/benchmark/gen-rb/benchmark_service.rb +80 -0
  8. data/benchmark/gen-rb/benchmark_types.rb +10 -0
  9. data/benchmark/server.rb +82 -0
  10. data/benchmark/thin_server.rb +44 -0
  11. data/ext/binary_protocol_accelerated.c +460 -0
  12. data/ext/binary_protocol_accelerated.h +20 -0
  13. data/ext/bytes.c +36 -0
  14. data/ext/bytes.h +31 -0
  15. data/ext/compact_protocol.c +637 -0
  16. data/ext/compact_protocol.h +20 -0
  17. data/ext/constants.h +99 -0
  18. data/ext/extconf.rb +34 -0
  19. data/ext/macros.h +41 -0
  20. data/ext/memory_buffer.c +134 -0
  21. data/ext/memory_buffer.h +20 -0
  22. data/ext/protocol.c +0 -0
  23. data/ext/protocol.h +0 -0
  24. data/ext/strlcpy.c +41 -0
  25. data/ext/strlcpy.h +34 -0
  26. data/ext/struct.c +707 -0
  27. data/ext/struct.h +25 -0
  28. data/ext/thrift_native.c +201 -0
  29. data/lib/thrift.rb +68 -0
  30. data/lib/thrift/bytes.rb +131 -0
  31. data/lib/thrift/client.rb +71 -0
  32. data/lib/thrift/core_ext.rb +23 -0
  33. data/lib/thrift/core_ext/fixnum.rb +29 -0
  34. data/lib/thrift/exceptions.rb +87 -0
  35. data/lib/thrift/multiplexed_processor.rb +76 -0
  36. data/lib/thrift/processor.rb +57 -0
  37. data/lib/thrift/protocol/base_protocol.rb +379 -0
  38. data/lib/thrift/protocol/binary_protocol.rb +237 -0
  39. data/lib/thrift/protocol/binary_protocol_accelerated.rb +39 -0
  40. data/lib/thrift/protocol/compact_protocol.rb +435 -0
  41. data/lib/thrift/protocol/json_protocol.rb +769 -0
  42. data/lib/thrift/protocol/multiplexed_protocol.rb +40 -0
  43. data/lib/thrift/protocol/protocol_decorator.rb +194 -0
  44. data/lib/thrift/serializer/deserializer.rb +33 -0
  45. data/lib/thrift/serializer/serializer.rb +34 -0
  46. data/lib/thrift/server/base_server.rb +31 -0
  47. data/lib/thrift/server/mongrel_http_server.rb +60 -0
  48. data/lib/thrift/server/nonblocking_server.rb +305 -0
  49. data/lib/thrift/server/rack_application.rb +61 -0
  50. data/lib/thrift/server/simple_server.rb +43 -0
  51. data/lib/thrift/server/thin_http_server.rb +51 -0
  52. data/lib/thrift/server/thread_pool_server.rb +75 -0
  53. data/lib/thrift/server/threaded_server.rb +47 -0
  54. data/lib/thrift/struct.rb +237 -0
  55. data/lib/thrift/struct_union.rb +192 -0
  56. data/lib/thrift/thrift_native.rb +24 -0
  57. data/lib/thrift/transport/base_server_transport.rb +37 -0
  58. data/lib/thrift/transport/base_transport.rb +109 -0
  59. data/lib/thrift/transport/buffered_transport.rb +114 -0
  60. data/lib/thrift/transport/framed_transport.rb +117 -0
  61. data/lib/thrift/transport/http_client_transport.rb +56 -0
  62. data/lib/thrift/transport/io_stream_transport.rb +39 -0
  63. data/lib/thrift/transport/memory_buffer_transport.rb +125 -0
  64. data/lib/thrift/transport/server_socket.rb +63 -0
  65. data/lib/thrift/transport/socket.rb +139 -0
  66. data/lib/thrift/transport/unix_server_socket.rb +60 -0
  67. data/lib/thrift/transport/unix_socket.rb +40 -0
  68. data/lib/thrift/types.rb +101 -0
  69. data/lib/thrift/union.rb +179 -0
  70. data/spec/BaseService.thrift +27 -0
  71. data/spec/ExtendedService.thrift +25 -0
  72. data/spec/Referenced.thrift +44 -0
  73. data/spec/ThriftNamespacedSpec.thrift +53 -0
  74. data/spec/ThriftSpec.thrift +183 -0
  75. data/spec/base_protocol_spec.rb +217 -0
  76. data/spec/base_transport_spec.rb +350 -0
  77. data/spec/binary_protocol_accelerated_spec.rb +42 -0
  78. data/spec/binary_protocol_spec.rb +66 -0
  79. data/spec/binary_protocol_spec_shared.rb +455 -0
  80. data/spec/bytes_spec.rb +160 -0
  81. data/spec/client_spec.rb +99 -0
  82. data/spec/compact_protocol_spec.rb +143 -0
  83. data/spec/exception_spec.rb +141 -0
  84. data/spec/flat_spec.rb +62 -0
  85. data/spec/gen-rb/base/base_service.rb +80 -0
  86. data/spec/gen-rb/base/base_service_constants.rb +11 -0
  87. data/spec/gen-rb/base/base_service_types.rb +26 -0
  88. data/spec/gen-rb/extended/extended_service.rb +78 -0
  89. data/spec/gen-rb/extended/extended_service_constants.rb +11 -0
  90. data/spec/gen-rb/extended/extended_service_types.rb +12 -0
  91. data/spec/gen-rb/flat/namespaced_nonblocking_service.rb +272 -0
  92. data/spec/gen-rb/flat/referenced_constants.rb +11 -0
  93. data/spec/gen-rb/flat/referenced_types.rb +17 -0
  94. data/spec/gen-rb/flat/thrift_namespaced_spec_constants.rb +11 -0
  95. data/spec/gen-rb/flat/thrift_namespaced_spec_types.rb +28 -0
  96. data/spec/gen-rb/namespaced_spec_namespace/namespaced_nonblocking_service.rb +272 -0
  97. data/spec/gen-rb/namespaced_spec_namespace/thrift_namespaced_spec_constants.rb +11 -0
  98. data/spec/gen-rb/namespaced_spec_namespace/thrift_namespaced_spec_types.rb +28 -0
  99. data/spec/gen-rb/nonblocking_service.rb +272 -0
  100. data/spec/gen-rb/other_namespace/referenced_constants.rb +11 -0
  101. data/spec/gen-rb/other_namespace/referenced_types.rb +17 -0
  102. data/spec/gen-rb/thrift_spec_constants.rb +11 -0
  103. data/spec/gen-rb/thrift_spec_types.rb +538 -0
  104. data/spec/http_client_spec.rb +120 -0
  105. data/spec/json_protocol_spec.rb +513 -0
  106. data/spec/namespaced_spec.rb +67 -0
  107. data/spec/nonblocking_server_spec.rb +263 -0
  108. data/spec/processor_spec.rb +80 -0
  109. data/spec/serializer_spec.rb +67 -0
  110. data/spec/server_socket_spec.rb +79 -0
  111. data/spec/server_spec.rb +147 -0
  112. data/spec/socket_spec.rb +61 -0
  113. data/spec/socket_spec_shared.rb +104 -0
  114. data/spec/spec_helper.rb +64 -0
  115. data/spec/struct_nested_containers_spec.rb +191 -0
  116. data/spec/struct_spec.rb +293 -0
  117. data/spec/thin_http_server_spec.rb +141 -0
  118. data/spec/types_spec.rb +115 -0
  119. data/spec/union_spec.rb +203 -0
  120. data/spec/unix_socket_spec.rb +107 -0
  121. data/test/debug_proto/gen-rb/debug_proto_test_constants.rb +274 -0
  122. data/test/debug_proto/gen-rb/debug_proto_test_types.rb +761 -0
  123. data/test/debug_proto/gen-rb/empty_service.rb +24 -0
  124. data/test/debug_proto/gen-rb/inherited.rb +79 -0
  125. data/test/debug_proto/gen-rb/reverse_order_service.rb +82 -0
  126. data/test/debug_proto/gen-rb/service_for_exception_with_a_map.rb +81 -0
  127. data/test/debug_proto/gen-rb/srv.rb +330 -0
  128. metadata +388 -0
@@ -0,0 +1,117 @@
1
+ # encoding: ascii-8bit
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ module Thrift
22
+ class FramedTransport < BaseTransport
23
+ def initialize(transport, read=true, write=true)
24
+ @transport = transport
25
+ @rbuf = Bytes.empty_byte_buffer
26
+ @wbuf = Bytes.empty_byte_buffer
27
+ @read = read
28
+ @write = write
29
+ @index = 0
30
+ end
31
+
32
+ def open?
33
+ @transport.open?
34
+ end
35
+
36
+ def open
37
+ @transport.open
38
+ end
39
+
40
+ def close
41
+ @transport.close
42
+ end
43
+
44
+ def read(sz)
45
+ return @transport.read(sz) unless @read
46
+
47
+ return Bytes.empty_byte_buffer if sz <= 0
48
+
49
+ read_frame if @index >= @rbuf.length
50
+
51
+ @index += sz
52
+ @rbuf.slice(@index - sz, sz) || Bytes.empty_byte_buffer
53
+ end
54
+
55
+ def read_byte
56
+ return @transport.read_byte() unless @read
57
+
58
+ read_frame if @index >= @rbuf.length
59
+
60
+ # The read buffer has some data now, read a single byte. Using get_string_byte() avoids
61
+ # allocating a temp string of size 1 unnecessarily.
62
+ @index += 1
63
+ return Bytes.get_string_byte(@rbuf, @index - 1)
64
+ end
65
+
66
+ def read_into_buffer(buffer, size)
67
+ i = 0
68
+ while i < size
69
+ read_frame if @index >= @rbuf.length
70
+
71
+ # The read buffer has some data now, so copy bytes over to the output buffer.
72
+ byte = Bytes.get_string_byte(@rbuf, @index)
73
+ Bytes.set_string_byte(buffer, i, byte)
74
+ @index += 1
75
+ i += 1
76
+ end
77
+ i
78
+ end
79
+
80
+ def write(buf, sz=nil)
81
+ return @transport.write(buf) unless @write
82
+
83
+ buf = Bytes.force_binary_encoding(buf)
84
+ @wbuf << (sz ? buf[0...sz] : buf)
85
+ end
86
+
87
+ #
88
+ # Writes the output buffer to the stream in the format of a 4-byte length
89
+ # followed by the actual data.
90
+ #
91
+ def flush
92
+ return @transport.flush unless @write
93
+
94
+ out = [@wbuf.length].pack('N')
95
+ # Array#pack should return a BINARY encoded String, so it shouldn't be necessary to force encoding
96
+ out << @wbuf
97
+ @transport.write(out)
98
+ @transport.flush
99
+ @wbuf = Bytes.empty_byte_buffer
100
+ end
101
+
102
+ private
103
+
104
+ def read_frame
105
+ sz = @transport.read_all(4).unpack('N').first
106
+
107
+ @index = 0
108
+ @rbuf = @transport.read_all(sz)
109
+ end
110
+ end
111
+
112
+ class FramedTransportFactory < BaseTransportFactory
113
+ def get_transport(transport)
114
+ return FramedTransport.new(transport)
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: ascii-8bit
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ require 'net/http'
22
+ require 'net/https'
23
+ require 'openssl'
24
+ require 'uri'
25
+ require 'stringio'
26
+
27
+ module Thrift
28
+ class HTTPClientTransport < BaseTransport
29
+
30
+ def initialize(url, opts = {})
31
+ @url = URI url
32
+ @headers = {'Content-Type' => 'application/x-thrift'}
33
+ @outbuf = Bytes.empty_byte_buffer
34
+ @ssl_verify_mode = opts.fetch(:ssl_verify_mode, OpenSSL::SSL::VERIFY_PEER)
35
+ end
36
+
37
+ def open?; true end
38
+ def read(sz); @inbuf.read sz end
39
+ def write(buf); @outbuf << Bytes.force_binary_encoding(buf) end
40
+
41
+ def add_headers(headers)
42
+ @headers = @headers.merge(headers)
43
+ end
44
+
45
+ def flush
46
+ http = Net::HTTP.new @url.host, @url.port
47
+ http.use_ssl = @url.scheme == 'https'
48
+ http.verify_mode = @ssl_verify_mode if @url.scheme == 'https'
49
+ resp = http.post(@url.request_uri, @outbuf, @headers)
50
+ data = resp.body
51
+ data = Bytes.force_binary_encoding(data)
52
+ @inbuf = StringIO.new data
53
+ @outbuf = Bytes.empty_byte_buffer
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: ascii-8bit
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ # Very very simple implementation of wrapping two objects, one with a #read
22
+ # method and one with a #write method, into a transport for thrift.
23
+ #
24
+ # Assumes both objects are open, remain open, don't require flushing, etc.
25
+ #
26
+ module Thrift
27
+ class IOStreamTransport < BaseTransport
28
+ def initialize(input, output)
29
+ @input = input
30
+ @output = output
31
+ end
32
+
33
+ def open?; not @input.closed? or not @output.closed? end
34
+ def read(sz); @input.read(sz) end
35
+ def write(buf); @output.write(Bytes.force_binary_encoding(buf)) end
36
+ def close; @input.close; @output.close end
37
+ def to_io; @input end # we're assuming this is used in a IO.select for reading
38
+ end
39
+ end
@@ -0,0 +1,125 @@
1
+ # encoding: ascii-8bit
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ module Thrift
22
+ class MemoryBufferTransport < BaseTransport
23
+ GARBAGE_BUFFER_SIZE = 4*(2**10) # 4kB
24
+
25
+ # If you pass a string to this, you should #dup that string
26
+ # unless you want it to be modified by #read and #write
27
+ #--
28
+ # this behavior is no longer required. If you wish to change it
29
+ # go ahead, just make sure the specs pass
30
+ def initialize(buffer = nil)
31
+ @buf = buffer ? Bytes.force_binary_encoding(buffer) : Bytes.empty_byte_buffer
32
+ @index = 0
33
+ end
34
+
35
+ def open?
36
+ return true
37
+ end
38
+
39
+ def open
40
+ end
41
+
42
+ def close
43
+ end
44
+
45
+ def peek
46
+ @index < @buf.size
47
+ end
48
+
49
+ # this method does not use the passed object directly but copies it
50
+ def reset_buffer(new_buf = '')
51
+ @buf.replace Bytes.force_binary_encoding(new_buf)
52
+ @index = 0
53
+ end
54
+
55
+ def available
56
+ @buf.length - @index
57
+ end
58
+
59
+ def read(len)
60
+ data = @buf.slice(@index, len)
61
+ @index += len
62
+ @index = @buf.size if @index > @buf.size
63
+ if @index >= GARBAGE_BUFFER_SIZE
64
+ @buf = @buf.slice(@index..-1)
65
+ @index = 0
66
+ end
67
+ if data.size < len
68
+ raise EOFError, "Not enough bytes remain in buffer"
69
+ end
70
+ data
71
+ end
72
+
73
+ def read_byte
74
+ raise EOFError.new("Not enough bytes remain in buffer") if @index >= @buf.size
75
+ val = Bytes.get_string_byte(@buf, @index)
76
+ @index += 1
77
+ if @index >= GARBAGE_BUFFER_SIZE
78
+ @buf = @buf.slice(@index..-1)
79
+ @index = 0
80
+ end
81
+ val
82
+ end
83
+
84
+ def read_into_buffer(buffer, size)
85
+ i = 0
86
+ while i < size
87
+ raise EOFError.new("Not enough bytes remain in buffer") if @index >= @buf.size
88
+
89
+ # The read buffer has some data now, so copy bytes over to the output buffer.
90
+ byte = Bytes.get_string_byte(@buf, @index)
91
+ Bytes.set_string_byte(buffer, i, byte)
92
+ @index += 1
93
+ i += 1
94
+ end
95
+ if @index >= GARBAGE_BUFFER_SIZE
96
+ @buf = @buf.slice(@index..-1)
97
+ @index = 0
98
+ end
99
+ i
100
+ end
101
+
102
+ def write(wbuf)
103
+ @buf << Bytes.force_binary_encoding(wbuf)
104
+ end
105
+
106
+ def flush
107
+ end
108
+
109
+ def inspect_buffer
110
+ out = []
111
+ for idx in 0...(@buf.size)
112
+ # if idx != 0
113
+ # out << " "
114
+ # end
115
+
116
+ if idx == @index
117
+ out << ">"
118
+ end
119
+
120
+ out << @buf[idx].ord.to_s(16)
121
+ end
122
+ out.join(" ")
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,63 @@
1
+ # encoding: ascii-8bit
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ require 'socket'
22
+
23
+ module Thrift
24
+ class ServerSocket < BaseServerTransport
25
+ # call-seq: initialize(host = nil, port)
26
+ def initialize(host_or_port, port = nil)
27
+ if port
28
+ @host = host_or_port
29
+ @port = port
30
+ else
31
+ @host = nil
32
+ @port = host_or_port
33
+ end
34
+ @handle = nil
35
+ end
36
+
37
+ attr_reader :handle
38
+
39
+ def listen
40
+ @handle = TCPServer.new(@host, @port)
41
+ end
42
+
43
+ def accept
44
+ unless @handle.nil?
45
+ sock = @handle.accept
46
+ trans = Socket.new
47
+ trans.handle = sock
48
+ trans
49
+ end
50
+ end
51
+
52
+ def close
53
+ @handle.close unless @handle.nil? or @handle.closed?
54
+ @handle = nil
55
+ end
56
+
57
+ def closed?
58
+ @handle.nil? or @handle.closed?
59
+ end
60
+
61
+ alias to_io handle
62
+ end
63
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: ascii-8bit
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one
4
+ # or more contributor license agreements. See the NOTICE file
5
+ # distributed with this work for additional information
6
+ # regarding copyright ownership. The ASF licenses this file
7
+ # to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance
9
+ # with the License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing,
14
+ # software distributed under the License is distributed on an
15
+ # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16
+ # KIND, either express or implied. See the License for the
17
+ # specific language governing permissions and limitations
18
+ # under the License.
19
+ #
20
+
21
+ require 'socket'
22
+
23
+ module Thrift
24
+ class Socket < BaseTransport
25
+ def initialize(host='localhost', port=9090, timeout=nil)
26
+ @host = host
27
+ @port = port
28
+ @timeout = timeout
29
+ @desc = "#{host}:#{port}"
30
+ @handle = nil
31
+ end
32
+
33
+ attr_accessor :handle, :timeout
34
+
35
+ def open
36
+ begin
37
+ addrinfo = ::Socket::getaddrinfo(@host, @port, nil, ::Socket::SOCK_STREAM).first
38
+ @handle = ::Socket.new(addrinfo[4], ::Socket::SOCK_STREAM, 0)
39
+ @handle.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
40
+ sockaddr = ::Socket.sockaddr_in(addrinfo[1], addrinfo[3])
41
+ begin
42
+ @handle.connect_nonblock(sockaddr)
43
+ rescue Errno::EINPROGRESS
44
+ unless IO.select(nil, [ @handle ], nil, @timeout)
45
+ raise TransportException.new(TransportException::NOT_OPEN, "Connection timeout to #{@desc}")
46
+ end
47
+ begin
48
+ @handle.connect_nonblock(sockaddr)
49
+ rescue Errno::EISCONN
50
+ end
51
+ end
52
+ @handle
53
+ rescue StandardError => e
54
+ raise TransportException.new(TransportException::NOT_OPEN, "Could not connect to #{@desc}: #{e}")
55
+ end
56
+ end
57
+
58
+ def open?
59
+ !@handle.nil? and !@handle.closed?
60
+ end
61
+
62
+ def write(str)
63
+ raise IOError, "closed stream" unless open?
64
+ str = Bytes.force_binary_encoding(str)
65
+ begin
66
+ if @timeout.nil? or @timeout == 0
67
+ @handle.write(str)
68
+ else
69
+ len = 0
70
+ start = Time.now
71
+ while Time.now - start < @timeout
72
+ rd, wr, = IO.select(nil, [@handle], nil, @timeout)
73
+ if wr and not wr.empty?
74
+ len += @handle.write_nonblock(str[len..-1])
75
+ break if len >= str.length
76
+ end
77
+ end
78
+ if len < str.length
79
+ raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out writing #{str.length} bytes to #{@desc}")
80
+ else
81
+ len
82
+ end
83
+ end
84
+ rescue TransportException => e
85
+ # pass this on
86
+ raise e
87
+ rescue StandardError => e
88
+ @handle.close
89
+ @handle = nil
90
+ raise TransportException.new(TransportException::NOT_OPEN, e.message)
91
+ end
92
+ end
93
+
94
+ def read(sz)
95
+ raise IOError, "closed stream" unless open?
96
+
97
+ begin
98
+ if @timeout.nil? or @timeout == 0
99
+ data = @handle.readpartial(sz)
100
+ else
101
+ # it's possible to interrupt select for something other than the timeout
102
+ # so we need to ensure we've waited long enough, but not too long
103
+ start = Time.now
104
+ timespent = 0
105
+ rd = loop do
106
+ rd, = IO.select([@handle], nil, nil, @timeout - timespent)
107
+ timespent = Time.now - start
108
+ break rd if (rd and not rd.empty?) or timespent >= @timeout
109
+ end
110
+ if rd.nil? or rd.empty?
111
+ raise TransportException.new(TransportException::TIMED_OUT, "Socket: Timed out reading #{sz} bytes from #{@desc}")
112
+ else
113
+ data = @handle.readpartial(sz)
114
+ end
115
+ end
116
+ rescue TransportException => e
117
+ # don't let this get caught by the StandardError handler
118
+ raise e
119
+ rescue StandardError => e
120
+ @handle.close unless @handle.closed?
121
+ @handle = nil
122
+ raise TransportException.new(TransportException::NOT_OPEN, e.message)
123
+ end
124
+ if (data.nil? or data.length == 0)
125
+ raise TransportException.new(TransportException::UNKNOWN, "Socket: Could not read #{sz} bytes from #{@desc}")
126
+ end
127
+ data
128
+ end
129
+
130
+ def close
131
+ @handle.close unless @handle.nil? or @handle.closed?
132
+ @handle = nil
133
+ end
134
+
135
+ def to_io
136
+ @handle
137
+ end
138
+ end
139
+ end