tcp-server 1.0.7-java → 1.0.8-java

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: 119b17b7637a9d30ba40c82660e9b2c9eebbabbe59264cbb49e88b82cef6805c
4
- data.tar.gz: 5fa1261d06c758e2934944f79fc9f747d73f387dd4e2ed04cb119fe496a34010
3
+ metadata.gz: 3c55987f7d6c92030cd96937448d5dea7b62c5dd43292e2d47a5b1901cdcbfa8
4
+ data.tar.gz: 6396aaaa64e18e454801debd881e618558ab65bec55de917fd328f0f4cdc041e
5
5
  SHA512:
6
- metadata.gz: 3d911168c44588f3c89b557b800bde9cbaf5603185c4c850bf6362c8e24458110ed2b1c33ea8736032d7003d01068a4e7b7bf58151e334adab2b1fef2adba251
7
- data.tar.gz: f2863e4c56547ae3f8af9f1b37085863ffefd3f5ffd07eb46a1e288c72694189ff52e44c7fdb1e1b20ee68c8b841a93699e9d32a2ad4defff093e8ac265b567a
6
+ metadata.gz: 115f8b7d5bc5f8f48cfdb72eb4b81d6128f4b69af919eeaed79693bfb04aa1d09d893ba8970682f74afd417cb46c4176b73ca2b70ed082d0adec9268e8d53010
7
+ data.tar.gz: e1c144c6b38c6adca2e96c5e99cbd4a31d52aebe2076e7bd7cc82d2700c0e1f9c11a20d93f32943b6995a6a0e8ba4c20300e6d35170130982403736f64815050
data/README.md CHANGED
@@ -124,7 +124,7 @@ Here is a bird's-eye view of the project layout.
124
124
 
125
125
  ```sh
126
126
  # date && tree -I "logs|vendor|tmp"
127
- Tue Jun 28 20:25:51 CDT 2022
127
+ Wed Jul 20 13:18:23 CDT 2022
128
128
  .
129
129
  ├── Dockerfile
130
130
  ├── Gemfile
@@ -158,12 +158,11 @@ Tue Jun 28 20:25:51 CDT 2022
158
158
  │ ├── test_spec.rb
159
159
  │ └── verify
160
160
  │ └── verify_spec.rb
161
- ├── tcp-server-1.0.6-java.gem
162
161
  ├── tcp-server-jruby.gemspec
163
162
  ├── tcp_server.png
164
163
  └── tcp_server.rb
165
164
 
166
- 5 directories, 31 files
165
+ 5 directories, 30 files
167
166
  ```
168
167
 
169
168
 
data/lib/client.rb CHANGED
@@ -27,22 +27,17 @@ end
27
27
 
28
28
  # The Client module
29
29
  module Client
30
- # rubocop: disable Metrics/MethodLength
31
30
  def client_config
32
31
  @client_config ||= {
33
32
  host: '0.0.0.0',
34
33
  port: 8080,
35
34
  ssl: false,
36
- idle_reading: 5 * 60, # seconds
37
- idle_writing: 30, # seconds
38
- log_requests: false,
39
35
  log_level: Logger::INFO,
40
36
  quit_commands: %i[bye cease desist exit leave quit stop terminate],
41
37
  max_frame_length: 8192,
42
38
  delimiter: Java::io.netty.handler.codec.Delimiters.lineDelimiter
43
39
  }.freeze
44
40
  end
45
- # rubocop: enable Metrics/MethodLength
46
41
  module_function :client_config
47
42
  end
48
43
 
@@ -108,7 +103,7 @@ module Client
108
103
  # The InstanceMethods module
109
104
  module InstanceMethods
110
105
  def puts(msg)
111
- sleep 0.1 until @channel.isActive()
106
+ wait_until_channel_is_active
112
107
  msg.chomp!
113
108
  log.trace "#puts msg: #{msg.inspect}"
114
109
  raise 'Message is empty!' if msg.nil? || msg.empty?
@@ -123,6 +118,10 @@ module Client
123
118
  nil
124
119
  end
125
120
 
121
+ def wait_until_channel_is_active(timeout = 5, give_up = Time.now + timeout)
122
+ sleep 0.1 until @channel.active? || Time.now > give_up
123
+ end
124
+
126
125
  def connect(host = @options[:host], port = @options[:port])
127
126
  return unless @channel.nil?
128
127
  # Start the connection attempt.
@@ -151,7 +150,7 @@ module Client
151
150
 
152
151
  def session
153
152
  when_client_has_shut_down(@client_group) do |group|
154
- log.debug "Channel group has shut down: #{group.inspect}"
153
+ log.debug "Channel group has shut down: #{group}"
155
154
  end
156
155
  @user_app.nil? ? read_user_commands : invoke_user_app
157
156
  end
@@ -184,13 +183,13 @@ module Client
184
183
 
185
184
  def channel_unregistered(ctx)
186
185
  log.trace "##{__method__} channel: #{ctx.channel}"
187
- shutdown
186
+ # shutdown
188
187
  end
189
188
 
190
189
  def message_received(ctx, message)
191
190
  notify :message_received, ctx, message
192
191
  if @application_handler.nil?
193
- $stdout.puts message.chomp unless message.nil?
192
+ $stdout.print message.chomp unless message.nil?
194
193
  else
195
194
  @application_handler.call(ctx, message)
196
195
  end
@@ -205,10 +204,11 @@ module Client
205
204
  def read_user_commands
206
205
  log.trace 'Reading user commands'
207
206
  loop do
207
+ log.debug 'Waiting for user input...'
208
208
  input = $stdin.gets
209
209
  raise 'Poll failure from stdin' if input.nil?
210
210
  break unless @channel.active?
211
- break if execute_command(input).is_a?(AbstractChannel::CloseFuture)
211
+ break unless execute_command(input).nil?
212
212
  end
213
213
  end
214
214
 
@@ -232,17 +232,19 @@ module Client
232
232
 
233
233
  def add_listener(listener)
234
234
  listeners << listener
235
+ ensure
236
+ log.trace "Listeners: #{listeners}"
235
237
  end
236
238
 
237
239
  def remove_listener(listener)
238
240
  listeners.delete(listener)
239
241
  end
240
242
 
241
- def notify(message, *args)
242
- return if listeners.empty?
243
- log.trace "Notifying listeners (#{listeners}) of message: #{message}"
243
+ def notify(event, *args)
244
244
  listeners.each do |listener|
245
- listener.send(message.to_sym, *args) if listener.respond_to?(message.to_sym)
245
+ next unless listener.respond_to?(event.to_sym)
246
+ log.trace "Notifying listener #{listener} of event: #{event}"
247
+ listener.send(event.to_sym, *args)
246
248
  end
247
249
  end
248
250
  end
@@ -350,12 +352,7 @@ module Client
350
352
 
351
353
  # The ChannelInitializer class
352
354
  class ChannelInitializer < Java::io.netty.channel.ChannelInitializer
353
- # The encoder and decoder are sharable. If they were not, then
354
- # constant definitions could not be used.
355
- DECODER = StringDecoder.new
356
- ENCODER = StringEncoder.new
357
- MAX_FRAME_LENGTH = 8192
358
- attr_accessor :handlers
355
+ attr_accessor :decoder, :encoder, :handlers
359
356
 
360
357
  def initialize(options = {})
361
358
  super()
@@ -363,6 +360,8 @@ module Client
363
360
  @host = @options[:host]
364
361
  @port = @options[:port]
365
362
  @handlers = []
363
+ @decoder = StringDecoder.new
364
+ @encoder = StringEncoder.new
366
365
  end
367
366
 
368
367
  def <<(handler)
@@ -372,15 +371,17 @@ module Client
372
371
  def initChannel(channel)
373
372
  pipeline = channel.pipeline
374
373
  pipeline.addLast(ssl_handler(channel)) if @options[:ssl]
375
- pipeline.addLast(
376
- DelimiterBasedFrameDecoder.new(MAX_FRAME_LENGTH, Delimiters.lineDelimiter()),
377
- DECODER,
378
- ENCODER
379
- )
374
+ # pipeline.addLast(frame_decoder)
375
+ pipeline.addLast(decoder)
376
+ pipeline.addLast(encoder)
380
377
  add_user_handlers(pipeline)
381
378
  pipeline.addLast(default_handler)
382
379
  end
383
380
 
381
+ def frame_decoder
382
+ DelimiterBasedFrameDecoder.new(@options[:max_frame_length], @options[:delimiter])
383
+ end
384
+
384
385
  def default_handler
385
386
  @default_handler ||= ::Client::ModularHandler.new
386
387
  end
@@ -455,32 +456,32 @@ end
455
456
  module Client
456
457
  # The ArgumentsParser class
457
458
  class ArgumentsParser
458
- Flags = %i[banner port ssl log_level help version].freeze
459
459
  attr_reader :parser, :options
460
460
 
461
461
  def initialize(parser = OptionParser.new, options = ::Client.client_config.dup)
462
462
  @parser = parser
463
463
  @options = options
464
- Flags.each { |method_name| method(method_name).call }
464
+ @flags = %i[banner port ssl log_level help version]
465
+ @flags.each { |method_name| method(method_name)&.call if respond_to?(method_name) }
465
466
  end
466
467
 
467
468
  def banner
468
- @parser.banner = "Usage: #{File.basename($PROGRAM_NAME)} [host] [port] [options]"
469
+ @parser.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] <hostname> [port]"
469
470
  @parser.separator ''
470
471
  @parser.separator 'Options:'
471
472
  end
472
473
 
473
474
  def host
474
475
  description = "Connect to server at this host; default: #{@options[:host]}"
475
- @parser.on('-h', '--host=<host>s', description) do |v|
476
+ @parser.on('-h', '--hostname=<hostname>', description) do |v|
476
477
  @options[:host] = v
477
478
  end
478
479
  end
479
480
 
480
- IntegerPattern = /^\d+$/.freeze
481
+ def validated_port(val, integer_pattern = /^\d+$/)
482
+ raise OptionParser::InvalidArgument, "Invalid port: #{val}" unless \
483
+ integer_pattern.match?(val.to_s) && val.positive? && val < 65_536
481
484
 
482
- def validated_port(val)
483
- raise "Invalid port: #{v}" unless IntegerPattern.match?(val.to_s) && val.positive? && val < 65_536
484
485
  val
485
486
  end
486
487
 
@@ -499,6 +500,7 @@ module Client
499
500
 
500
501
  def log_level
501
502
  @parser.on_tail('-v', '--verbose', 'Increase verbosity') do
503
+ @options[:log_level] ||= 0
502
504
  @options[:log_level] -= 1
503
505
  end
504
506
  end
@@ -516,19 +518,28 @@ module Client
516
518
  exit
517
519
  end
518
520
  end
521
+
522
+ def parse_positional_arguments!
523
+ @options[:host] = ARGV.shift or raise OptionParser::MissingArgument, 'hostname'
524
+ return if (given_port = ARGV.shift&.to_i).nil?
525
+
526
+ @options[:port] = validated_port(given_port).to_i
527
+ end
519
528
  end
520
529
  # class ArgumentsParser
521
530
 
522
- # rubocop: disable Metrics/AbcSize
523
531
  def parse_arguments(arguments_parser = ArgumentsParser.new)
524
532
  arguments_parser.parser.parse!(ARGV)
525
- arguments_parser.options[:host] = v.to_s unless (v = ARGV.shift).nil?
526
- arguments_parser.options[:port] = validated_port(v).to_i unless (v = ARGV.shift).nil?
533
+ arguments_parser.parse_positional_arguments!
527
534
  arguments_parser.options
528
- rescue OptionParser::InvalidOption, OptionParser::AmbiguousOption => e
535
+ rescue OptionParser::InvalidArgument, OptionParser::InvalidOption,
536
+ OptionParser::MissingArgument, OptionParser::NeedlessArgument => e
537
+ puts e.message
538
+ puts parser
539
+ exit
540
+ rescue OptionParser::AmbiguousOption => e
529
541
  abort e.message
530
542
  end
531
- # rubocop: enable Metrics/AbcSize
532
543
  end
533
544
  # module Client
534
545
 
@@ -549,12 +560,12 @@ end
549
560
 
550
561
  # The Client module
551
562
  module Client
552
- # The ConsoleHandler class
553
- class ConsoleHandler
563
+ # The Console class
564
+ class Console
554
565
  def message_received(ctx, message)
555
566
  log.trace "##{__method__} channel: #{ctx.channel}, message: #{message}"
556
567
  log.debug "Received message: #{message}"
557
- puts message.chomp unless message.nil?
568
+ $stdout.print message unless message.nil?
558
569
  end
559
570
  end
560
571
  end
@@ -568,8 +579,7 @@ module Client
568
579
  # rubocop: disable Metrics/MethodLength
569
580
  def main(args = parse_arguments)
570
581
  Logging.log_level = args[:log_level]
571
- handlers = [::Client::Monitor.new, ::Client::ConsoleHandler.new]
572
- ::TCP::Client.new(args, *handlers)
582
+ ::TCP::Client.new(args, ::Client::Console.new, ::Client::Monitor.new)
573
583
  rescue Interrupt => e
574
584
  warn format(InterruptTemplate, class: e.class)
575
585
  exit
@@ -18,16 +18,13 @@ require_relative 'config'
18
18
  module Server
19
19
  # The ArgumentsParser class
20
20
  class ArgumentsParser
21
- Flags = %i[
22
- banner port ssl idle_reading idle_writing log_requests log_level help
23
- version
24
- ].freeze
25
21
  attr_reader :parser, :options
26
22
 
27
23
  def initialize(option_parser = OptionParser.new)
28
24
  @parser = option_parser
29
25
  @options = ::Server.server_config.dup
30
- Flags.each { |method_name| method(method_name).call }
26
+ @flags = %i[banner port ssl idle_reading idle_writing log_requests log_level help version]
27
+ @flags.each { |method_name| method(method_name).call }
31
28
  end
32
29
 
33
30
  def banner
@@ -36,10 +33,10 @@ module Server
36
33
  @parser.separator 'Options:'
37
34
  end
38
35
 
39
- IntegerPattern = /^\d+$/.freeze
36
+ def validated_port(val, integer_pattern = /^\d+$/)
37
+ raise OptionParser::InvalidArgument, "Invalid port: #{v}" unless \
38
+ integer_pattern.match?(val.to_s) && val.positive? && val < 65_536
40
39
 
41
- def validated_port(val)
42
- raise "Invalid port: #{v}" unless IntegerPattern.match?(val.to_s) && val.positive? && val < 65_536
43
40
  val
44
41
  end
45
42
 
@@ -30,11 +30,7 @@ module Server
30
30
 
31
31
  # The ChannelInitializer class
32
32
  class ChannelInitializer < Java::io.netty.channel.ChannelInitializer
33
- # The encoder and decoder are sharable. If they were not, then
34
- # constant definitions could not be used.
35
- DECODER = StringDecoder.new
36
- ENCODER = StringEncoder.new
37
- attr_accessor :user_handlers
33
+ attr_accessor :decoder, :encoder, :user_handlers
38
34
  attr_reader :options
39
35
 
40
36
  def initialize(channel_group, options = {})
@@ -42,6 +38,8 @@ module Server
42
38
  @channel_group = channel_group
43
39
  @options = options
44
40
  @user_handlers = @options.fetch(:handlers, [])
41
+ @decoder = StringDecoder.new
42
+ @encoder = StringEncoder.new
45
43
  end
46
44
 
47
45
  def <<(handler)
@@ -51,15 +49,15 @@ module Server
51
49
  def initChannel(channel)
52
50
  pipeline = channel.pipeline
53
51
  pipeline.addLast(ssl_handler(channel)) if @options[:ssl]
54
- pipeline.addLast(
55
- DelimiterBasedFrameDecoder.new(@options[:max_frame_length], @options[:delimiter]),
56
- DECODER,
57
- ENCODER
58
- )
52
+ pipeline.addLast(frame_decoder, @decoder, @encoder)
59
53
  add_user_handlers(pipeline)
60
54
  pipeline.addLast(default_handler)
61
55
  end
62
56
 
57
+ def frame_decoder
58
+ DelimiterBasedFrameDecoder.new(@options[:max_frame_length], @options[:delimiter])
59
+ end
60
+
63
61
  def default_handler
64
62
  @default_handler ||= ::Server::ModularHandler.new(@channel_group)
65
63
  end
@@ -22,17 +22,19 @@ module Server
22
22
 
23
23
  def add_listener(listener)
24
24
  listeners << listener
25
+ ensure
26
+ log.trace "Listeners: #{listeners}"
25
27
  end
26
28
 
27
29
  def remove_listener(listener)
28
30
  listeners.delete(listener)
29
31
  end
30
32
 
31
- def notify(message, *args)
32
- return if listeners.empty?
33
- log.trace "Notifying listeners (#{listeners}) of message: #{message}"
33
+ def notify(event, *args)
34
34
  listeners.each do |listener|
35
- listener.send(message.to_sym, *args) if listener.respond_to?(message.to_sym)
35
+ next unless listener.respond_to?(event.to_sym)
36
+ log.trace "Notifying listener #{listener} of event: #{event}"
37
+ listener.send(event.to_sym, *args)
36
38
  end
37
39
  end
38
40
  end
@@ -42,7 +42,7 @@ module Server
42
42
  log.trace "##{__method__} channel: #{ctx.channel}, message: #{msg.inspect}"
43
43
  msg&.chomp!
44
44
  log.info "Received message: #{msg}"
45
- return super(ctx, msg) unless respond_to?(:handle_message) && @handler.arity == 2
45
+ return super(ctx, msg) unless respond_to?(:handle_message) && @handler&.arity == 2
46
46
  handle_message(ctx, msg)
47
47
  end
48
48
 
@@ -12,5 +12,5 @@
12
12
 
13
13
  # The Server module
14
14
  module Server
15
- VERSION = '1.0.7'.freeze
15
+ VERSION = '1.0.8'.freeze
16
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tcp-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.8
5
5
  platform: java
6
6
  authors:
7
7
  - Nels Nelson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-06-29 00:00:00.000000000 Z
11
+ date: 2022-07-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement