jrpc 1.1.7 → 1.1.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67534bff4d06dfed8a49ddf71bb56356d65f9c119731b220e6490394a187f720
4
- data.tar.gz: fd53da1804ddc60f54d549811b7d866541601dc4b3f58dc15de2a112c10039cf
3
+ metadata.gz: e116c8eef34ce5bd8a4ced0e2e693ad37df69895e67c3d28d68537c60711d012
4
+ data.tar.gz: 8a60df19ba2676a28c03925d0be33b8cda720f9da147e4854a87cba9f25dd251
5
5
  SHA512:
6
- metadata.gz: c99a86b3b5a59ff431d5356604d4cfcd1803212a8e3be22819de4bbab9d826d985a47bec9fed72cc82f8adfa80f208b1823ab85566325fe3f7965db52d631911
7
- data.tar.gz: d565e6cf0cd0afa20b935d1ca6e554d2aa6142dd46bfbefd1468f4910175f326656a6015fae7a160ef5ad8da41574e0c8c9d000ea8d624e5e989e5f8683ca262
6
+ metadata.gz: 10a940570df20f1246c61c6df6d2c950e9acf5e16e397727c6693822f121bfeff14409529b732e385f2f8806ed9c26d32ddcd9c545406ab54c3b26b5e9ee6db2
7
+ data.tar.gz: e79fc4f45058b4aa8570928866d97fb9e473b805fbc2c730879d0d6478824e91c9a37728900fde9e827a58753978b3b9468dd03d145d6c2cd09310bafceb49e8
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+ .rake_tasks~
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ ### Unreleased
4
+
5
+ ### 1.1.8
6
+ * handling FIN signal for TCP socket [didww/jrpc#19](https://github.com/didww/jrpc/pull/19)
7
+ * add gem executables [didww/jrpc#19](https://github.com/didww/jrpc/pull/19)
8
+
9
+ ### 1.1.7
10
+ * connect ot socket in nonblock mode
11
+
12
+ ### 1.1.6
13
+ * update oj version to ~> 3.0
14
+
15
+ ### 1.1.5
16
+ * update oj version to ~> 2.0
17
+
18
+ ### 1.1.4
19
+ * handle EOF on read
20
+ * fix jrpc error require
21
+ * use JRPC::Error as base class for JRPC::Transport::SocketBase::Error
22
+
23
+ ### 1.1.3
24
+ * close socket when clearing socket if it's not closed
25
+
26
+ ### 1.1.2
27
+ * reset socket when broken pipe error appears
28
+
29
+ ### 1.1.1
30
+ * fix rescuing error in TcpClient initializer
31
+
32
+ ### 1.1.0
33
+ * use own socket wrapper
34
+
35
+ ### 1.0.1
36
+ * Net::TCPClient#read method process data with buffer variable
37
+
38
+ ### 1.0.0
39
+ * stable release
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'jrpc'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start(__FILE__)
@@ -0,0 +1,100 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'optparse'
5
+ require 'jrpc'
6
+
7
+ Options = Struct.new(
8
+ :host,
9
+ :port,
10
+ :type,
11
+ :method,
12
+ :params,
13
+ :id,
14
+ :debug,
15
+ :namespace,
16
+ :timeout
17
+ )
18
+
19
+ class Parser
20
+ def self.parse(argv)
21
+ args = Options.new
22
+ args.host = '127.0.0.1'
23
+ args.port = 7080
24
+ args.type = 'request'
25
+ args.timeout = 5
26
+
27
+ opt_parser = OptionParser.new do |opts|
28
+ opts.banner = 'Usage: jrpc [options] method [params, ...]'
29
+
30
+ opts.on('--host=HOST', 'host (default 127.0.0.1)') do |host|
31
+ args.host = host
32
+ end
33
+
34
+ opts.on('-p=PORT', '--port=PORT', 'port (default 7080)') do |port|
35
+ args.port = port
36
+ end
37
+
38
+ opts.on('-r', '--request', 'Sets type to request (default true)') do
39
+ args.type = 'request'
40
+ end
41
+
42
+ opts.on('-n', '--notification', 'Sets type to is notification (default false)') do
43
+ args.type = 'notification'
44
+ end
45
+
46
+ opts.on('--namespace=NAMESPACE', 'Sets method namespace') do |namespace|
47
+ args.namespace = namespace
48
+ end
49
+
50
+ opts.on('--id=ID', 'Request ID (will be generated randomly by default)') do |id|
51
+ args.id = id
52
+ end
53
+
54
+ opts.on('--timeout=TIMEOUT', 'timeout for socket') do |timeout|
55
+ args.timeout = timeout
56
+ end
57
+
58
+ opts.on('-d', '--debug', 'Debug output') do
59
+ args.debug = true
60
+ end
61
+
62
+ opts.on('-h', '--help', 'Prints this help and exit') do
63
+ puts opts
64
+ exit
65
+ end
66
+
67
+ opts.on('-v', '--version', 'Prints version and exit') do
68
+ puts "JRPC version: #{JRPC::VERSION}"
69
+ exit
70
+ end
71
+ end
72
+
73
+ opt_parser.parse!(argv)
74
+ args.method = argv.first
75
+ args.params = argv[1..-1]
76
+ # puts "PARSED:\n#{args.inspect}\n#{argv.inspect}"
77
+ return args
78
+ end
79
+ end
80
+
81
+ options = Parser.parse(ARGV.dup)
82
+
83
+ logger = Logger.new($stdout)
84
+ logger.level = options.debug ? Logger::DEBUG : Logger::INFO
85
+ addr = "#{options.host}:#{options.port}"
86
+ logger.debug { "Connecting to #{addr} ..." }
87
+ client = JRPC::TcpClient.new(addr, namespace: options.namespace, timeout: options.timeout, logger: logger)
88
+
89
+ logger.debug { "Sending #{options.type} #{options.method} #{options.params} ..." }
90
+ response = client.perform_request(options.method, params: options.params, type: options.type.to_sym)
91
+
92
+ if options.type == 'request'
93
+ logger.debug { "Request was sent. Response: #{response.inspect}" }
94
+ puts JSON.pretty_generate(response)
95
+ else
96
+ logger.debug 'Notification was sent.'
97
+ end
98
+
99
+ client.close
100
+ logger.debug 'Exited'
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'readline'
5
+ require 'singleton'
6
+ require 'jrpc'
7
+
8
+ class Command
9
+ include Singleton
10
+
11
+ def self.call(command, args)
12
+ meth = "cmd_#{command}"
13
+ if instance.respond_to?(meth)
14
+ instance.public_send(meth, *args)
15
+ else
16
+ "ERROR: invalid command #{command.inspect}\n#{instance.help_usage}"
17
+ end
18
+ rescue ArgumentError => e
19
+ "ERROR: ArgumentError #{e.message}\n#{instance.help_usage}"
20
+ end
21
+
22
+ attr_accessor :logger, :client, :help_usage
23
+ instance.logger = Logger.new(STDOUT)
24
+ instance.logger.level = Logger::INFO
25
+ instance.help_usage = [
26
+ 'Usage:',
27
+ ' connect host port',
28
+ ' disconnect',
29
+ ' request method param1 param2',
30
+ ' request method {"param1": 1. "param2": 2}',
31
+ ' notification method param1 param2',
32
+ ' notification method {"param1": 1. "param2": 2}',
33
+ ' help',
34
+ ' version'
35
+ ].join("\n")
36
+
37
+ def cmd_help
38
+ help_usage
39
+ end
40
+
41
+ def cmd_version
42
+ "JRPC version: #{JRPC::VERSION}"
43
+ end
44
+
45
+ def cmd_connect(host, port)
46
+ client&.close
47
+ self.client = JRPC::TcpClient.new("#{host}:#{port}", namespace: '', timeout: 5, logger: logger)
48
+ 'Connected.'
49
+ rescue JRPC::Error => e
50
+ "ERROR: JRPC #{e.message}\n#{help_usage}"
51
+ end
52
+
53
+ def cmd_disconnect
54
+ return "ERROR: Not connected\n#{help_usage}" if client.nil?
55
+
56
+ client.close
57
+ self.client = nil
58
+ 'Disconnected'
59
+ end
60
+
61
+ def cmd_request(method, *params)
62
+ return "ERROR: Not connected\n#{help_usage}" if client.nil?
63
+
64
+ params = JSON.parse(params.first) if params.size == 1 && params[0] == '{'
65
+
66
+ response = client.perform_request(method, params: params)
67
+ JSON.pretty_generate(response)
68
+ rescue JRPC::Error => e
69
+ "ERROR: JRPC #{e.message}\n#{help_usage}"
70
+ end
71
+
72
+ def cmd_notification(method, *params)
73
+ return "ERROR: Not connected\n#{help_usage}" if client.nil?
74
+
75
+ params = JSON.parse(params.first) if params.size == 1 && params[0] == '{'
76
+
77
+ response = client.perform_request(method, params: params, type: :notification)
78
+ JSON.pretty_generate(response)
79
+ rescue JRPC::Error => e
80
+ "ERROR: JRPC #{e.message}\n#{help_usage}"
81
+ end
82
+ end
83
+
84
+ puts 'Welcome to JRPC shell'
85
+ while input = Readline.readline('> ', true)
86
+ if %w[exit close quit].include?(input)
87
+ break
88
+ elsif input == 'hist'
89
+ puts Readline::HISTORY.to_a
90
+ elsif input == ''
91
+ # Remove blank lines from history
92
+ Readline::HISTORY.pop
93
+ else
94
+ command, *args = input.split(' ')
95
+ puts Command.call(command, args)
96
+ end
97
+ end
98
+
99
+ puts 'Shell Exited'
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
 
12
12
  spec.summary = 'JSON RPC client'
13
13
  spec.description = 'JSON RPC client over TCP'
14
- spec.homepage = 'https://github.com/senid231/jrpc'
14
+ spec.homepage = 'https://github.com/didww/jrpc'
15
15
  spec.license = 'MIT'
16
16
 
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
@@ -20,7 +20,10 @@ Gem::Specification.new do |spec|
20
20
  spec.add_dependency 'netstring', '~> 0'
21
21
  spec.add_dependency 'oj', '~> 3.0'
22
22
 
23
- spec.add_development_dependency 'bundler', '~> 1.10'
24
- spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.executables << 'jrpc'
24
+ spec.executables << 'jrpc-shell'
25
+
26
+ spec.add_development_dependency 'bundler'
27
+ spec.add_development_dependency 'rake', '~> 13.0'
25
28
  spec.add_development_dependency 'rspec', '~> 3.0'
26
29
  end
@@ -1,3 +1,5 @@
1
+ require 'socket'
2
+ require 'json'
1
3
  require 'jrpc/version'
2
4
  require 'jrpc/error/error'
3
5
  require 'jrpc/utils'
@@ -8,6 +8,7 @@ module JRPC
8
8
  while length_to_read > 0
9
9
  io_read, = IO.select([socket], [], [], timeout)
10
10
  raise ReadTimeoutError unless io_read
11
+ check_fin_signal
11
12
  chunk = io_read[0].read_nonblock(length_to_read)
12
13
  received += chunk
13
14
  length_to_read -= chunk.bytesize
@@ -25,6 +26,7 @@ module JRPC
25
26
  while data_to_write.bytesize > 0
26
27
  _, io_write, = IO.select([], [socket], [], timeout)
27
28
  raise WriteTimeoutError unless io_write
29
+ check_fin_signal
28
30
  chunk_length = io_write[0].write_nonblock(data_to_write)
29
31
  length_written += chunk_length
30
32
  data_to_write = data.byteslice(length_written, data.length)
@@ -41,8 +43,27 @@ module JRPC
41
43
  socket.close
42
44
  end
43
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.
44
50
  def closed?
45
- @socket.nil? || socket.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?
46
67
  end
47
68
 
48
69
  def socket
@@ -51,6 +72,19 @@ module JRPC
51
72
 
52
73
  private
53
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
+
54
88
  def clear_socket!
55
89
  return if @socket.nil?
56
90
  @socket.close unless @socket.closed?
@@ -1,3 +1,3 @@
1
1
  module JRPC
2
- VERSION = '1.1.7'
2
+ VERSION = '1.1.8'
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.1.7
4
+ version: 1.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Talakevich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-04 00:00:00.000000000 Z
11
+ date: 2020-10-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: netstring
@@ -42,30 +42,30 @@ dependencies:
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '1.10'
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '1.10'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '10.0'
61
+ version: '13.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '10.0'
68
+ version: '13.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -83,17 +83,24 @@ dependencies:
83
83
  description: JSON RPC client over TCP
84
84
  email:
85
85
  - senid231@gmail.com
86
- executables: []
86
+ executables:
87
+ - jrpc
88
+ - jrpc-shell
87
89
  extensions: []
88
90
  extra_rdoc_files: []
89
91
  files:
90
92
  - ".gitignore"
91
93
  - ".rspec"
92
94
  - ".travis.yml"
95
+ - CHANGELOG.md
93
96
  - Gemfile
94
97
  - LICENSE.txt
95
98
  - README.md
96
99
  - Rakefile
100
+ - bin/console
101
+ - bin/jrpc
102
+ - bin/jrpc-shell
103
+ - bin/setup
97
104
  - jrpc.gemspec
98
105
  - lib/jrpc.rb
99
106
  - lib/jrpc/base_client.rb
@@ -113,7 +120,7 @@ files:
113
120
  - lib/jrpc/transport/socket_tcp.rb
114
121
  - lib/jrpc/utils.rb
115
122
  - lib/jrpc/version.rb
116
- homepage: https://github.com/senid231/jrpc
123
+ homepage: https://github.com/didww/jrpc
117
124
  licenses:
118
125
  - MIT
119
126
  metadata: {}
@@ -132,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
139
  - !ruby/object:Gem::Version
133
140
  version: '0'
134
141
  requirements: []
135
- rubygems_version: 3.1.2
142
+ rubygems_version: 3.0.8
136
143
  signing_key:
137
144
  specification_version: 4
138
145
  summary: JSON RPC client