jrpc 1.1.8 → 2.1.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +55 -0
- data/.rspec +1 -0
- data/.rubocop.yml +228 -0
- data/CHANGELOG.md +67 -0
- data/Gemfile +17 -0
- data/README.md +240 -13
- data/Rakefile +3 -1
- data/bin/console +1 -0
- data/bin/jrpc +37 -26
- data/bin/jrpc-shell +34 -24
- data/jrpc.gemspec +6 -8
- data/lib/jrpc/errors.rb +65 -0
- data/lib/jrpc/id_generator.rb +22 -0
- data/lib/jrpc/message.rb +78 -0
- data/lib/jrpc/payload_logging.rb +19 -0
- data/lib/jrpc/shared_client/outbound_queue.rb +71 -0
- data/lib/jrpc/shared_client/registry.rb +46 -0
- data/lib/jrpc/shared_client/ticket.rb +84 -0
- data/lib/jrpc/shared_client/transport_loop.rb +298 -0
- data/lib/jrpc/shared_client.rb +194 -0
- data/lib/jrpc/simple_client.rb +98 -0
- data/lib/jrpc/transport/base.rb +63 -0
- data/lib/jrpc/transport/tcp.rb +292 -0
- data/lib/jrpc/transport/test.rb +333 -0
- data/lib/jrpc/transport.rb +12 -0
- data/lib/jrpc/version.rb +3 -1
- data/lib/jrpc.rb +14 -16
- metadata +25 -71
- data/.travis.yml +0 -4
- data/lib/jrpc/base_client.rb +0 -123
- data/lib/jrpc/error/client_error.rb +0 -5
- data/lib/jrpc/error/connection_error.rb +0 -11
- data/lib/jrpc/error/error.rb +0 -5
- data/lib/jrpc/error/internal_error.rb +0 -9
- data/lib/jrpc/error/internal_server_error.rb +0 -5
- data/lib/jrpc/error/invalid_params.rb +0 -9
- data/lib/jrpc/error/invalid_request.rb +0 -9
- data/lib/jrpc/error/method_not_found.rb +0 -9
- data/lib/jrpc/error/parse_error.rb +0 -9
- data/lib/jrpc/error/server_error.rb +0 -11
- data/lib/jrpc/error/unknown_error.rb +0 -5
- data/lib/jrpc/tcp_client.rb +0 -112
- data/lib/jrpc/transport/socket_base.rb +0 -88
- data/lib/jrpc/transport/socket_tcp.rb +0 -132
- data/lib/jrpc/utils.rb +0 -9
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
module JRPC
|
|
2
|
-
module Transport
|
|
3
|
-
class SocketTcp < SocketBase
|
|
4
|
-
|
|
5
|
-
def read(length, timeout = @read_timeout)
|
|
6
|
-
received = ''
|
|
7
|
-
length_to_read = length
|
|
8
|
-
while length_to_read > 0
|
|
9
|
-
io_read, = IO.select([socket], [], [], timeout)
|
|
10
|
-
raise ReadTimeoutError unless io_read
|
|
11
|
-
check_fin_signal
|
|
12
|
-
chunk = io_read[0].read_nonblock(length_to_read)
|
|
13
|
-
received += chunk
|
|
14
|
-
length_to_read -= chunk.bytesize
|
|
15
|
-
end
|
|
16
|
-
received
|
|
17
|
-
rescue Errno::EPIPE, EOFError => e
|
|
18
|
-
# EPIPE, in this case, means that the data connection was unexpectedly terminated.
|
|
19
|
-
clear_socket!
|
|
20
|
-
raise ReadFailedError, "#{e.class} #{e.message}"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def write(data, timeout = @write_timeout)
|
|
24
|
-
length_written = 0
|
|
25
|
-
data_to_write = data
|
|
26
|
-
while data_to_write.bytesize > 0
|
|
27
|
-
_, io_write, = IO.select([], [socket], [], timeout)
|
|
28
|
-
raise WriteTimeoutError unless io_write
|
|
29
|
-
check_fin_signal
|
|
30
|
-
chunk_length = io_write[0].write_nonblock(data_to_write)
|
|
31
|
-
length_written += chunk_length
|
|
32
|
-
data_to_write = data.byteslice(length_written, data.length)
|
|
33
|
-
end
|
|
34
|
-
length_written
|
|
35
|
-
rescue Errno::EPIPE => e
|
|
36
|
-
# EPIPE, in this case, means that the data connection was unexpectedly terminated.
|
|
37
|
-
clear_socket!
|
|
38
|
-
raise WriteFailedError, "#{e.class} #{e.message}"
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def close
|
|
42
|
-
return if @socket.nil?
|
|
43
|
-
socket.close
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Socket implementation allows client to send data to server after FIN,
|
|
47
|
-
# but server will never receive this data.
|
|
48
|
-
# So we consider socket closed when it have FIN event
|
|
49
|
-
# and close it correctly from client side.
|
|
50
|
-
def closed?
|
|
51
|
-
return true if @socket.nil? || socket.closed?
|
|
52
|
-
|
|
53
|
-
if fin_signal?
|
|
54
|
-
close
|
|
55
|
-
return true
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
false
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Socket implementation allows client to send data to server after FIN,
|
|
62
|
-
# but server will never receive this data.
|
|
63
|
-
# We correctly close socket from client side when FIN event received.
|
|
64
|
-
# Should be checked before send data to socket or recv data from socket.
|
|
65
|
-
def check_fin_signal
|
|
66
|
-
close if socket && !socket.closed? && fin_signal?
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def socket
|
|
70
|
-
@socket ||= build_socket
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
private
|
|
74
|
-
|
|
75
|
-
# when recv_nonblock(1) responds with empty string means that FIN event was received.
|
|
76
|
-
# in other cases it will return 1 byte string or raise EAGAINWaitReadable.
|
|
77
|
-
# MSG_PEEK means we do not move pointer when reading data.
|
|
78
|
-
# see https://apidock.com/ruby/BasicSocket/recv_nonblock
|
|
79
|
-
def fin_signal?
|
|
80
|
-
begin
|
|
81
|
-
resp = socket.recv_nonblock(1, Socket::MSG_PEEK)
|
|
82
|
-
rescue IO::EAGAINWaitReadable => _
|
|
83
|
-
resp = nil
|
|
84
|
-
end
|
|
85
|
-
resp == ''
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def clear_socket!
|
|
89
|
-
return if @socket.nil?
|
|
90
|
-
@socket.close unless @socket.closed?
|
|
91
|
-
@socket = nil
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
def set_timeout_to(socket, type, value)
|
|
95
|
-
secs = Integer(value)
|
|
96
|
-
u_secs = Integer((value - secs) * 1_000_000)
|
|
97
|
-
opt_val = [secs, u_secs].pack('l_2')
|
|
98
|
-
socket.setsockopt Socket::SOL_SOCKET, type, opt_val
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def build_socket
|
|
102
|
-
host = @server.split(':').first
|
|
103
|
-
addr = Socket.getaddrinfo(host, nil)
|
|
104
|
-
Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def connect_socket
|
|
108
|
-
host, port = @server.split(':')
|
|
109
|
-
addr = Socket.getaddrinfo(host, nil)
|
|
110
|
-
full_addr = Socket.pack_sockaddr_in(port, addr[0][3])
|
|
111
|
-
|
|
112
|
-
begin
|
|
113
|
-
socket.connect_nonblock(full_addr)
|
|
114
|
-
rescue IO::WaitWritable => _
|
|
115
|
-
if IO.select(nil, [socket], nil, @connect_timeout)
|
|
116
|
-
socket.connect_nonblock(full_addr)
|
|
117
|
-
else
|
|
118
|
-
clear_socket!
|
|
119
|
-
raise ConnectionFailedError, "Can't connect during #{@connect_timeout}"
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
rescue Errno::EISCONN => _
|
|
124
|
-
# already connected
|
|
125
|
-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ETIMEDOUT, Errno::EPIPE => e
|
|
126
|
-
clear_socket!
|
|
127
|
-
raise ConnectionFailedError, "#{e.class} #{e.message}"
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|