jrpc 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 89173d093947f7660038fd40edf8df685f0eba58
4
- data.tar.gz: 730eb903478be492a2708c4d104c016b120f17ec
3
+ metadata.gz: fa57d4ebd661941d43cc81ab71df478fc7e2cd90
4
+ data.tar.gz: 6675b878174f71c7fc96a7d4a7d5c485cdb99670
5
5
  SHA512:
6
- metadata.gz: c22cdaf992b9ed4ac0553c8d18fa5ac34de673cb2e7da20a0476734dbf50465e82a7951b7ed4424e7f62330db517c98aba25da2a999a916902c9174d2f5d56d2
7
- data.tar.gz: 39b0a463f4a6353a1daa9f8d81e65e7482907af7a6a8e0a34ee4cc20c8e6b3c1fd1eb7a50e799a5125acf5252701d5892c5d2086f78dfd5dadd00ed6944af87f
6
+ metadata.gz: d95b4e15d5611b9b0b032f599c5d0b675887a2cf834bc6796808dcce43c599cbcbd80380b6f9be6783a55f65b8190d7aaa0cb32f31889384d24c41307c2cf7e5
7
+ data.tar.gz: 9ecb04ea701ef5bd048d777e61c440cd519387247c42e02f39a05092ebbbc40520c918b4c36afb576e277f8dd013c65a34274747b8eef484002f146ef25efa6a
@@ -18,7 +18,6 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ['lib']
19
19
 
20
20
  spec.add_dependency 'netstring', '~> 0'
21
- spec.add_dependency 'net_tcp_client', '~> 2.0'
22
21
  spec.add_dependency 'oj', '~> 2.0'
23
22
 
24
23
  spec.add_development_dependency 'bundler', '~> 1.10'
@@ -1,6 +1,8 @@
1
1
  require 'jrpc/version'
2
2
  require 'jrpc/utils'
3
3
  require 'jrpc/base_client'
4
+ require 'jrpc/transport/socket_base'
5
+ require 'jrpc/transport/socket_tcp'
4
6
  require 'jrpc/tcp_client'
5
7
  require 'jrpc/error/error'
6
8
  require 'jrpc/error/connection_error'
@@ -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
@@ -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, nil) # default 60
22
- connect_retry_count = @options.fetch(:connect_retry_count, nil) # default 10
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 = Net::TCPClient.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
- buffered: false # recommended for RPC
30
- rescue ::SocketError
31
- raise ConnectionError, "Can't connect to #{@uri}"
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 send_command(request, options={})
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, nil, timeout)
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
@@ -1,3 +1,3 @@
1
1
  module JRPC
2
- VERSION = '1.0.1'
2
+ VERSION = '1.1.0'
3
3
  end
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.1
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: 2017-12-11 00:00:00.000000000 Z
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