jrpc 1.0.1 → 1.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/jrpc.gemspec +0 -1
- data/lib/jrpc.rb +2 -0
- data/lib/jrpc/base_client.rb +7 -0
- data/lib/jrpc/tcp_client.rb +31 -16
- data/lib/jrpc/transport/socket_base.rb +82 -0
- data/lib/jrpc/transport/socket_tcp.rb +78 -0
- data/lib/jrpc/version.rb +1 -1
- metadata +4 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa57d4ebd661941d43cc81ab71df478fc7e2cd90
|
4
|
+
data.tar.gz: 6675b878174f71c7fc96a7d4a7d5c485cdb99670
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d95b4e15d5611b9b0b032f599c5d0b675887a2cf834bc6796808dcce43c599cbcbd80380b6f9be6783a55f65b8190d7aaa0cb32f31889384d24c41307c2cf7e5
|
7
|
+
data.tar.gz: 9ecb04ea701ef5bd048d777e61c440cd519387247c42e02f39a05092ebbbc40520c918b4c36afb576e277f8dd013c65a34274747b8eef484002f146ef25efa6a
|
data/jrpc.gemspec
CHANGED
data/lib/jrpc.rb
CHANGED
data/lib/jrpc/base_client.rb
CHANGED
@@ -9,6 +9,13 @@ module JRPC
|
|
9
9
|
ID_CHARACTERS = (('a'..'z').to_a + ('0'..'9').to_a + ('A'..'Z').to_a).freeze
|
10
10
|
REQUEST_TYPES = [:request, :notification].freeze
|
11
11
|
|
12
|
+
def self.connect(uri, options)
|
13
|
+
client = new(uri, options)
|
14
|
+
yield(client)
|
15
|
+
ensure
|
16
|
+
client.close if client
|
17
|
+
end
|
18
|
+
|
12
19
|
def initialize(uri, options)
|
13
20
|
@uri = uri
|
14
21
|
@options = options
|
data/lib/jrpc/tcp_client.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'net/tcp_client'
|
2
1
|
require 'netstring'
|
3
2
|
require 'logger'
|
4
3
|
require 'benchmark'
|
@@ -18,22 +17,34 @@ module JRPC
|
|
18
17
|
timeout = @options.fetch(:timeout, 5)
|
19
18
|
connect_timeout = @options.fetch(:connect_timeout, timeout)
|
20
19
|
read_timeout = @options.fetch(:read_timeout, timeout)
|
21
|
-
write_timeout = @options.fetch(:write_timeout,
|
22
|
-
connect_retry_count = @options.fetch(:connect_retry_count,
|
20
|
+
write_timeout = @options.fetch(:write_timeout, 60) # default 60
|
21
|
+
connect_retry_count = @options.fetch(:connect_retry_count, 10) # default 10
|
22
|
+
@close_after_sent = @options.fetch(:close_after_sent, false)
|
23
23
|
|
24
|
-
@transport =
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
@transport = JRPC::Transport::SocketTcp.new server: @uri,
|
25
|
+
connect_retry_count: connect_retry_count,
|
26
|
+
connect_timeout: connect_timeout,
|
27
|
+
read_timeout: read_timeout,
|
28
|
+
write_timeout: write_timeout
|
29
|
+
begin
|
30
|
+
@transport.connect
|
31
|
+
rescue JRPC::SocketTcp::Error
|
32
|
+
raise ConnectionError, "Can't connect to #{@uri}"
|
33
|
+
end
|
32
34
|
end
|
33
35
|
|
34
36
|
private
|
35
37
|
|
36
|
-
def
|
38
|
+
def ensure_connected
|
39
|
+
if @transport.closed?
|
40
|
+
logger.debug { 'Connecting transport...' }
|
41
|
+
@transport.connect
|
42
|
+
logger.debug { 'Connected.' }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def send_command(request, options = {})
|
47
|
+
ensure_connected
|
37
48
|
read_timeout = options.fetch(:read_timeout)
|
38
49
|
write_timeout = options.fetch(:write_timeout)
|
39
50
|
response = nil
|
@@ -49,15 +60,20 @@ module JRPC
|
|
49
60
|
"(#{'%.2f' % (t * 1000)}ms) Response message: #{Utils.truncate(response, MAX_LOGGED_MESSAGE_LENGTH)}"
|
50
61
|
end
|
51
62
|
response
|
63
|
+
ensure
|
64
|
+
@transport.close if @close_after_sent
|
52
65
|
end
|
53
66
|
|
54
|
-
def send_notification(request, options={})
|
67
|
+
def send_notification(request, options = {})
|
68
|
+
ensure_connected
|
55
69
|
write_timeout = options.fetch(:write_timeout)
|
56
70
|
logger.debug { "Request address: #{uri}" }
|
57
71
|
logger.debug { "Request message: #{Utils.truncate(request, MAX_LOGGED_MESSAGE_LENGTH)}" }
|
58
72
|
logger.debug { "Request write_timeout: #{write_timeout}" }
|
59
73
|
send_request(request, write_timeout)
|
60
74
|
logger.debug { 'No response required' }
|
75
|
+
ensure
|
76
|
+
@transport.close if @close_after_sent
|
61
77
|
end
|
62
78
|
|
63
79
|
def create_message(method, params)
|
@@ -74,8 +90,7 @@ module JRPC
|
|
74
90
|
def receive_response(timeout)
|
75
91
|
timeout ||= @transport.read_timeout
|
76
92
|
length = get_msg_length(timeout)
|
77
|
-
response =
|
78
|
-
@transport.read(length+1, response, timeout)
|
93
|
+
response = @transport.read(length + 1, timeout)
|
79
94
|
raise ClientError.new('invalid response. missed comma as terminator') if response[-1] != ','
|
80
95
|
response.chomp(',')
|
81
96
|
rescue ::SocketError
|
@@ -85,7 +100,7 @@ module JRPC
|
|
85
100
|
def get_msg_length(timeout)
|
86
101
|
length = ''
|
87
102
|
while true do
|
88
|
-
character = @transport.read(1,
|
103
|
+
character = @transport.read(1, timeout)
|
89
104
|
break if character == ':'
|
90
105
|
length += character
|
91
106
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module JRPC
|
2
|
+
module Transport
|
3
|
+
class SocketBase
|
4
|
+
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class TimeoutError < Error
|
9
|
+
def initialize
|
10
|
+
super(self.class.to_s.split('::').last)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ReadTimeoutError < TimeoutError
|
15
|
+
end
|
16
|
+
|
17
|
+
class WriteTimeoutError < TimeoutError
|
18
|
+
end
|
19
|
+
|
20
|
+
class ConnectionTimeoutError < TimeoutError
|
21
|
+
end
|
22
|
+
|
23
|
+
class ConnectionFailedError < Error
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :options, :read_timeout, :write_timeout
|
27
|
+
|
28
|
+
def self.connect(options)
|
29
|
+
connection = new(options)
|
30
|
+
yield(connection)
|
31
|
+
ensure
|
32
|
+
connection.close if connection
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(options)
|
36
|
+
@server = options.fetch(:server)
|
37
|
+
@read_timeout = options.fetch(:read_timeout, nil)
|
38
|
+
@write_timeout = options.fetch(:write_timeout, nil)
|
39
|
+
@connect_timeout = options.fetch(:connect_timeout, nil)
|
40
|
+
@connect_retry_count = options.fetch(:connect_retry_count, 0)
|
41
|
+
@options = options
|
42
|
+
end
|
43
|
+
|
44
|
+
def connect
|
45
|
+
retries = @connect_retry_count
|
46
|
+
|
47
|
+
while retries >= 0
|
48
|
+
begin
|
49
|
+
connect_socket
|
50
|
+
break
|
51
|
+
rescue Error => e
|
52
|
+
retries -= 1
|
53
|
+
raise e if retries < 0
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def read(_length, _timeout = @read_timeout)
|
59
|
+
raise NotImplementedError
|
60
|
+
end
|
61
|
+
|
62
|
+
def write(_data, _timeout = @write_timeout)
|
63
|
+
raise NotImplementedError
|
64
|
+
end
|
65
|
+
|
66
|
+
def close
|
67
|
+
raise NotImplementedError
|
68
|
+
end
|
69
|
+
|
70
|
+
def closed?
|
71
|
+
raise NotImplementedError
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def connect_socket
|
77
|
+
raise NotImplementedError
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module JRPC
|
2
|
+
module Transport
|
3
|
+
class SocketTcp < SocketBase
|
4
|
+
|
5
|
+
attr_reader :socket
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
super
|
9
|
+
@socket = build_socket
|
10
|
+
end
|
11
|
+
|
12
|
+
def read(length, timeout = @read_timeout)
|
13
|
+
received = ''
|
14
|
+
length_to_read = length
|
15
|
+
while length_to_read > 0
|
16
|
+
io_read, = IO.select([@socket], [], [], timeout)
|
17
|
+
raise ReadTimeoutError unless io_read
|
18
|
+
chunk = io_read[0].read_nonblock(length_to_read)
|
19
|
+
received += chunk
|
20
|
+
length_to_read -= chunk.bytesize
|
21
|
+
end
|
22
|
+
received
|
23
|
+
end
|
24
|
+
|
25
|
+
def write(data, timeout = @write_timeout)
|
26
|
+
length_written = 0
|
27
|
+
data_to_write = data
|
28
|
+
while data_to_write.bytesize > 0
|
29
|
+
_, io_write, = IO.select([], [@socket], [], timeout)
|
30
|
+
raise WriteTimeoutError unless io_write
|
31
|
+
chunk_length = io_write[0].write_nonblock(data_to_write)
|
32
|
+
length_written += chunk_length
|
33
|
+
data_to_write = data.byteslice(length_written, data.length)
|
34
|
+
end
|
35
|
+
length_written
|
36
|
+
end
|
37
|
+
|
38
|
+
def close
|
39
|
+
@socket.close
|
40
|
+
end
|
41
|
+
|
42
|
+
def closed?
|
43
|
+
@socket.closed?
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def set_timeout_to(socket, type, value)
|
49
|
+
secs = Integer(value)
|
50
|
+
u_secs = Integer((value - secs) * 1_000_000)
|
51
|
+
opt_val = [secs, u_secs].pack('l_2')
|
52
|
+
socket.setsockopt Socket::SOL_SOCKET, type, opt_val
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_socket
|
56
|
+
host = @server.split(':').first
|
57
|
+
addr = Socket.getaddrinfo(host, nil)
|
58
|
+
sock = Socket.new(Socket.const_get(addr[0][0]), Socket::SOCK_STREAM, 0)
|
59
|
+
set_timeout_to(sock, Socket::SO_RCVTIMEO, @connect_timeout) if @connect_timeout
|
60
|
+
sock
|
61
|
+
end
|
62
|
+
|
63
|
+
def connect_socket
|
64
|
+
host, port = @server.split(':')
|
65
|
+
addr = Socket.getaddrinfo(host, nil)
|
66
|
+
full_addr = Socket.pack_sockaddr_in(port, addr[0][3])
|
67
|
+
@socket.connect(full_addr)
|
68
|
+
rescue Errno::EISCONN => _
|
69
|
+
# already connected
|
70
|
+
rescue Errno::ETIMEDOUT => _
|
71
|
+
raise ConnectionTimeoutError
|
72
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ETIMEDOUT => e
|
73
|
+
raise ConnectionFailedError, "#{e.class} #{e.message}"
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/jrpc/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jrpc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Talakevich
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: netstring
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: net_tcp_client
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '2.0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '2.0'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: oj
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -123,6 +109,8 @@ files:
|
|
123
109
|
- lib/jrpc/error/server_error.rb
|
124
110
|
- lib/jrpc/error/unknown_error.rb
|
125
111
|
- lib/jrpc/tcp_client.rb
|
112
|
+
- lib/jrpc/transport/socket_base.rb
|
113
|
+
- lib/jrpc/transport/socket_tcp.rb
|
126
114
|
- lib/jrpc/utils.rb
|
127
115
|
- lib/jrpc/version.rb
|
128
116
|
homepage: https://github.com/senid231/jrpc
|