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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +55 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +228 -0
  5. data/CHANGELOG.md +67 -0
  6. data/Gemfile +17 -0
  7. data/README.md +240 -13
  8. data/Rakefile +3 -1
  9. data/bin/console +1 -0
  10. data/bin/jrpc +37 -26
  11. data/bin/jrpc-shell +34 -24
  12. data/jrpc.gemspec +6 -8
  13. data/lib/jrpc/errors.rb +65 -0
  14. data/lib/jrpc/id_generator.rb +22 -0
  15. data/lib/jrpc/message.rb +78 -0
  16. data/lib/jrpc/payload_logging.rb +19 -0
  17. data/lib/jrpc/shared_client/outbound_queue.rb +71 -0
  18. data/lib/jrpc/shared_client/registry.rb +46 -0
  19. data/lib/jrpc/shared_client/ticket.rb +84 -0
  20. data/lib/jrpc/shared_client/transport_loop.rb +298 -0
  21. data/lib/jrpc/shared_client.rb +194 -0
  22. data/lib/jrpc/simple_client.rb +98 -0
  23. data/lib/jrpc/transport/base.rb +63 -0
  24. data/lib/jrpc/transport/tcp.rb +292 -0
  25. data/lib/jrpc/transport/test.rb +333 -0
  26. data/lib/jrpc/transport.rb +12 -0
  27. data/lib/jrpc/version.rb +3 -1
  28. data/lib/jrpc.rb +14 -16
  29. metadata +25 -71
  30. data/.travis.yml +0 -4
  31. data/lib/jrpc/base_client.rb +0 -123
  32. data/lib/jrpc/error/client_error.rb +0 -5
  33. data/lib/jrpc/error/connection_error.rb +0 -11
  34. data/lib/jrpc/error/error.rb +0 -5
  35. data/lib/jrpc/error/internal_error.rb +0 -9
  36. data/lib/jrpc/error/internal_server_error.rb +0 -5
  37. data/lib/jrpc/error/invalid_params.rb +0 -9
  38. data/lib/jrpc/error/invalid_request.rb +0 -9
  39. data/lib/jrpc/error/method_not_found.rb +0 -9
  40. data/lib/jrpc/error/parse_error.rb +0 -9
  41. data/lib/jrpc/error/server_error.rb +0 -11
  42. data/lib/jrpc/error/unknown_error.rb +0 -5
  43. data/lib/jrpc/tcp_client.rb +0 -112
  44. data/lib/jrpc/transport/socket_base.rb +0 -88
  45. data/lib/jrpc/transport/socket_tcp.rb +0 -132
  46. data/lib/jrpc/utils.rb +0 -9
metadata CHANGED
@@ -1,85 +1,42 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jrpc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Talakevich
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2020-10-21 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: netstring
13
+ name: concurrent-ruby
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- - !ruby/object:Gem::Dependency
28
- name: oj
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '3.0'
18
+ version: '1.2'
34
19
  type: :runtime
35
20
  prerelease: false
36
21
  version_requirements: !ruby/object:Gem::Requirement
37
22
  requirements:
38
23
  - - "~>"
39
24
  - !ruby/object:Gem::Version
40
- version: '3.0'
25
+ version: '1.2'
41
26
  - !ruby/object:Gem::Dependency
42
- name: bundler
27
+ name: logger
43
28
  requirement: !ruby/object:Gem::Requirement
44
29
  requirements:
45
30
  - - ">="
46
31
  - !ruby/object:Gem::Version
47
32
  version: '0'
48
- type: :development
33
+ type: :runtime
49
34
  prerelease: false
50
35
  version_requirements: !ruby/object:Gem::Requirement
51
36
  requirements:
52
37
  - - ">="
53
38
  - !ruby/object:Gem::Version
54
39
  version: '0'
55
- - !ruby/object:Gem::Dependency
56
- name: rake
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '13.0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '13.0'
69
- - !ruby/object:Gem::Dependency
70
- name: rspec
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '3.0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '3.0'
83
40
  description: JSON RPC client over TCP
84
41
  email:
85
42
  - senid231@gmail.com
@@ -89,9 +46,10 @@ executables:
89
46
  extensions: []
90
47
  extra_rdoc_files: []
91
48
  files:
49
+ - ".github/workflows/ci.yml"
92
50
  - ".gitignore"
93
51
  - ".rspec"
94
- - ".travis.yml"
52
+ - ".rubocop.yml"
95
53
  - CHANGELOG.md
96
54
  - Gemfile
97
55
  - LICENSE.txt
@@ -103,28 +61,25 @@ files:
103
61
  - bin/setup
104
62
  - jrpc.gemspec
105
63
  - lib/jrpc.rb
106
- - lib/jrpc/base_client.rb
107
- - lib/jrpc/error/client_error.rb
108
- - lib/jrpc/error/connection_error.rb
109
- - lib/jrpc/error/error.rb
110
- - lib/jrpc/error/internal_error.rb
111
- - lib/jrpc/error/internal_server_error.rb
112
- - lib/jrpc/error/invalid_params.rb
113
- - lib/jrpc/error/invalid_request.rb
114
- - lib/jrpc/error/method_not_found.rb
115
- - lib/jrpc/error/parse_error.rb
116
- - lib/jrpc/error/server_error.rb
117
- - lib/jrpc/error/unknown_error.rb
118
- - lib/jrpc/tcp_client.rb
119
- - lib/jrpc/transport/socket_base.rb
120
- - lib/jrpc/transport/socket_tcp.rb
121
- - lib/jrpc/utils.rb
64
+ - lib/jrpc/errors.rb
65
+ - lib/jrpc/id_generator.rb
66
+ - lib/jrpc/message.rb
67
+ - lib/jrpc/payload_logging.rb
68
+ - lib/jrpc/shared_client.rb
69
+ - lib/jrpc/shared_client/outbound_queue.rb
70
+ - lib/jrpc/shared_client/registry.rb
71
+ - lib/jrpc/shared_client/ticket.rb
72
+ - lib/jrpc/shared_client/transport_loop.rb
73
+ - lib/jrpc/simple_client.rb
74
+ - lib/jrpc/transport.rb
75
+ - lib/jrpc/transport/base.rb
76
+ - lib/jrpc/transport/tcp.rb
77
+ - lib/jrpc/transport/test.rb
122
78
  - lib/jrpc/version.rb
123
79
  homepage: https://github.com/didww/jrpc
124
80
  licenses:
125
81
  - MIT
126
82
  metadata: {}
127
- post_install_message:
128
83
  rdoc_options: []
129
84
  require_paths:
130
85
  - lib
@@ -132,15 +87,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
87
  requirements:
133
88
  - - ">="
134
89
  - !ruby/object:Gem::Version
135
- version: '0'
90
+ version: '3.3'
136
91
  required_rubygems_version: !ruby/object:Gem::Requirement
137
92
  requirements:
138
93
  - - ">="
139
94
  - !ruby/object:Gem::Version
140
95
  version: '0'
141
96
  requirements: []
142
- rubygems_version: 3.0.8
143
- signing_key:
97
+ rubygems_version: 3.6.9
144
98
  specification_version: 4
145
99
  summary: JSON RPC client
146
100
  test_files: []
data/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.2.2
4
- before_install: gem install bundler -v 1.10.6
@@ -1,123 +0,0 @@
1
- require 'oj'
2
- require 'forwardable'
3
- module JRPC
4
- class BaseClient
5
- extend Forwardable
6
-
7
- attr_reader :uri, :options
8
-
9
- ID_CHARACTERS = (('a'..'z').to_a + ('0'..'9').to_a + ('A'..'Z').to_a).freeze
10
- REQUEST_TYPES = [:request, :notification].freeze
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
-
19
- def initialize(uri, options)
20
- @uri = uri
21
- @options = options
22
- end
23
-
24
- def method_missing(method, *params)
25
- invoke_request(method, *params)
26
- end
27
-
28
- def perform_request(method, params: nil, type: :request, read_timeout: nil, write_timeout: nil)
29
- validate_request(params, type)
30
- request = create_message(method.to_s, params)
31
- if type == :request
32
- id = generate_id
33
- request['id'] = id
34
- response = send_command serialize_request(request), read_timeout: read_timeout, write_timeout: write_timeout
35
- response = deserialize_response(response)
36
-
37
- validate_response(response, id)
38
- parse_error(response['error']) if response.has_key?('error')
39
-
40
- response['result']
41
- else
42
- send_notification serialize_request(request), write_timeout: write_timeout
43
- nil
44
- end
45
- end
46
-
47
- def invoke_request(method, *params)
48
- warn '[DEPRECATION] `invoke_request` is deprecated. Please use `perform_request` instead.'
49
- params = nil if params.empty?
50
- perform_request(method, params: params)
51
- end
52
-
53
- def invoke_notification(method, *params)
54
- warn '[DEPRECATION] `invoke_request` is deprecated. Please use `perform_request` instead.'
55
- params = nil if params.empty?
56
- perform_request(method, params: params, type: :notification)
57
- end
58
-
59
- private
60
-
61
- def serialize_request(request)
62
- Oj.dump(request, mode: :compat)
63
- end
64
-
65
- def deserialize_response(response)
66
- Oj.load(response)
67
- end
68
-
69
- def validate_response(response, id)
70
- raise ClientError, 'Wrong response structure' unless response.is_a?(Hash)
71
- raise ClientError, 'Wrong version' if response['jsonrpc'] != JRPC::JSON_RPC_VERSION
72
- if id != response['id']
73
- raise ClientError, "ID response mismatch. expected #{id.inspect} got #{response['id'].inspect}"
74
- end
75
- end
76
-
77
- def validate_request(params, type)
78
- raise ClientError, 'invalid type' unless REQUEST_TYPES.include?(type)
79
- raise ClientError, 'invalid params' if !params.nil? && !params.is_a?(Array) && !params.is_a?(Hash)
80
- end
81
-
82
- def parse_error(error)
83
- case error['code']
84
- when -32700
85
- raise ParseError.new(error['message'])
86
- when -32600
87
- raise InvalidRequest.new(error['message'])
88
- when -32601
89
- raise MethodNotFound.new(error['message'])
90
- when -32602
91
- raise InvalidParams.new(error['message'])
92
- when -32603
93
- raise InternalError.new(error['message'])
94
- when -32099..-32000
95
- raise InternalServerError.new(error['message'], error['code'])
96
- else
97
- raise UnknownError.new(error['message'], error['code'])
98
- end
99
- end
100
-
101
- def send_command(json, options={})
102
- raise NotImplementedError
103
- end
104
-
105
- def send_notification(json, options={})
106
- raise NotImplementedError
107
- end
108
-
109
- def generate_id
110
- size = ID_CHARACTERS.size
111
- (0...32).map { ID_CHARACTERS.to_a[rand(size)] }.join
112
- end
113
-
114
- def create_message(method, params)
115
- message = {
116
- 'jsonrpc' => JSON_RPC_VERSION,
117
- 'method' => method
118
- }
119
- message['params'] = params unless params.nil?
120
- message
121
- end
122
- end
123
- end
@@ -1,5 +0,0 @@
1
- module JRPC
2
- class ClientError < Error
3
-
4
- end
5
- end
@@ -1,11 +0,0 @@
1
- module JRPC
2
- class ConnectionError < Error
3
- attr_reader :original
4
-
5
- def initialize(msg, original=$!)
6
- super(msg)
7
- @original = original
8
- end
9
-
10
- end
11
- end
@@ -1,5 +0,0 @@
1
- module JRPC
2
- class Error < RuntimeError
3
-
4
- end
5
- end
@@ -1,9 +0,0 @@
1
- module JRPC
2
- class InternalError < ServerError
3
-
4
- def initialize(message)
5
- super(message, -32603)
6
- end
7
-
8
- end
9
- end
@@ -1,5 +0,0 @@
1
- module JRPC
2
- class InternalServerError < ServerError
3
-
4
- end
5
- end
@@ -1,9 +0,0 @@
1
- module JRPC
2
- class InvalidParams < ServerError
3
-
4
- def initialize(message)
5
- super(message, -32602)
6
- end
7
-
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module JRPC
2
- class InvalidRequest < ServerError
3
-
4
- def initialize(message)
5
- super(message, -32600)
6
- end
7
-
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module JRPC
2
- class MethodNotFound < ServerError
3
-
4
- def initialize(message)
5
- super(message, -32601)
6
- end
7
-
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- module JRPC
2
- class ParseError < ServerError
3
-
4
- def initialize(message)
5
- super(message, -32700)
6
- end
7
-
8
- end
9
- end
@@ -1,11 +0,0 @@
1
- module JRPC
2
- class ServerError < Error
3
- attr_reader :code
4
-
5
- def initialize(message, code)
6
- @code = code
7
- super(message)
8
- end
9
-
10
- end
11
- end
@@ -1,5 +0,0 @@
1
- module JRPC
2
- class UnknownError < ServerError
3
-
4
- end
5
- end
@@ -1,112 +0,0 @@
1
- require 'netstring'
2
- require 'logger'
3
- require 'benchmark'
4
- module JRPC
5
- class TcpClient < BaseClient
6
- attr_reader :namespace, :transport
7
- attr_accessor :logger
8
- def_delegators :@transport, :close, :closed?, :connect
9
-
10
- MAX_LOGGED_MESSAGE_LENGTH = 255
11
-
12
- def initialize(uri, options = {})
13
- super
14
- @logger = @options.delete(:logger) || Logger.new($null)
15
- @namespace = @options.delete(:namespace).to_s
16
-
17
- timeout = @options.fetch(:timeout, 5)
18
- connect_timeout = @options.fetch(:connect_timeout, timeout)
19
- read_timeout = @options.fetch(:read_timeout, timeout)
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
-
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::Transport::SocketTcp::Error
32
- raise ConnectionError, "Can't connect to #{@uri}"
33
- end
34
- end
35
-
36
- private
37
-
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
48
- read_timeout = options.fetch(:read_timeout)
49
- write_timeout = options.fetch(:write_timeout)
50
- response = nil
51
- t = Benchmark.realtime do
52
- logger.debug { "Request address: #{uri}" }
53
- logger.debug { "Request message: #{Utils.truncate(request, MAX_LOGGED_MESSAGE_LENGTH)}" }
54
- logger.debug { "Request read_timeout: #{read_timeout}" }
55
- logger.debug { "Request write_timeout: #{write_timeout}" }
56
- send_request(request, write_timeout)
57
- response = receive_response(read_timeout)
58
- end
59
- logger.debug do
60
- "(#{'%.2f' % (t * 1000)}ms) Response message: #{Utils.truncate(response, MAX_LOGGED_MESSAGE_LENGTH)}"
61
- end
62
- response
63
- ensure
64
- @transport.close if @close_after_sent
65
- end
66
-
67
- def send_notification(request, options = {})
68
- ensure_connected
69
- write_timeout = options.fetch(:write_timeout)
70
- logger.debug { "Request address: #{uri}" }
71
- logger.debug { "Request message: #{Utils.truncate(request, MAX_LOGGED_MESSAGE_LENGTH)}" }
72
- logger.debug { "Request write_timeout: #{write_timeout}" }
73
- send_request(request, write_timeout)
74
- logger.debug { 'No response required' }
75
- ensure
76
- @transport.close if @close_after_sent
77
- end
78
-
79
- def create_message(method, params)
80
- super("#{namespace}#{method}", params)
81
- end
82
-
83
- def send_request(request, timeout)
84
- timeout ||= @transport.write_timeout
85
- @transport.write Netstring.dump(request.to_s), timeout
86
- rescue ::SocketError
87
- raise ConnectionError, "Can't send request to #{uri}"
88
- end
89
-
90
- def receive_response(timeout)
91
- timeout ||= @transport.read_timeout
92
- length = get_msg_length(timeout)
93
- response = @transport.read(length + 1, timeout)
94
- raise ClientError.new('invalid response. missed comma as terminator') if response[-1] != ','
95
- response.chomp(',')
96
- rescue ::SocketError
97
- raise ConnectionError, "Can't receive response from #{uri}"
98
- end
99
-
100
- def get_msg_length(timeout)
101
- length = ''
102
- while true do
103
- character = @transport.read(1, timeout)
104
- break if character == ':'
105
- length += character
106
- end
107
-
108
- Integer(length)
109
- end
110
-
111
- end
112
- end
@@ -1,88 +0,0 @@
1
- module JRPC
2
- module Transport
3
- class SocketBase
4
-
5
- class Error < ::JRPC::Error
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
- class WriteFailedError < Error
27
- end
28
-
29
- class ReadFailedError < Error
30
- end
31
-
32
- attr_reader :options, :read_timeout, :write_timeout
33
-
34
- def self.connect(options)
35
- connection = new(options)
36
- yield(connection)
37
- ensure
38
- connection.close if connection
39
- end
40
-
41
- def initialize(options)
42
- @server = options.fetch(:server)
43
- @read_timeout = options.fetch(:read_timeout, nil)
44
- @write_timeout = options.fetch(:write_timeout, nil)
45
- @connect_timeout = options.fetch(:connect_timeout, nil)
46
- @connect_retry_count = options.fetch(:connect_retry_count, 0)
47
- @options = options
48
- end
49
-
50
- def connect
51
- retries = @connect_retry_count
52
-
53
- while retries >= 0
54
- begin
55
- connect_socket
56
- break
57
- rescue Error => e
58
- retries -= 1
59
- raise e if retries < 0
60
- end
61
- end
62
- end
63
-
64
- def read(_length, _timeout = @read_timeout)
65
- raise NotImplementedError
66
- end
67
-
68
- def write(_data, _timeout = @write_timeout)
69
- raise NotImplementedError
70
- end
71
-
72
- def close
73
- raise NotImplementedError
74
- end
75
-
76
- def closed?
77
- raise NotImplementedError
78
- end
79
-
80
- private
81
-
82
- def connect_socket
83
- raise NotImplementedError
84
- end
85
-
86
- end
87
- end
88
- end