tcp-server 1.0.7-java → 1.0.8-java

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
  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