tcp-server 1.0.7-java → 1.0.10-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: 87653ba8533d5ecaa864acaec4e535737923226709a5099388bacf32f25d2db4
4
+ data.tar.gz: 202db5cfc4382c95684961ec0524127d4befedea04495b0a8a4f1370e1435c8d
5
5
  SHA512:
6
- metadata.gz: 3d911168c44588f3c89b557b800bde9cbaf5603185c4c850bf6362c8e24458110ed2b1c33ea8736032d7003d01068a4e7b7bf58151e334adab2b1fef2adba251
7
- data.tar.gz: f2863e4c56547ae3f8af9f1b37085863ffefd3f5ffd07eb46a1e288c72694189ff52e44c7fdb1e1b20ee68c8b841a93699e9d32a2ad4defff093e8ac265b567a
6
+ metadata.gz: 4522287f1ea1c1ca866c6bcaa1fa806ba61d51837d27bf77a75b94e0d60c308fd862f7b0aab9375c0312a43640a24f3e740f9bae7ce31c175dcdddfbf293b51b
7
+ data.tar.gz: 81da1844fe86bdcbdabc1231ec7b47b3b9c84573056314090fb669e4272a52e9a66b70292f41344484d644b87315c2d963768a8ddf509970521c371199b142da
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
 
@@ -230,23 +230,32 @@ module Client
230
230
  @listeners ||= java.util.concurrent.CopyOnWriteArrayList.new
231
231
  end
232
232
 
233
- def add_listener(listener)
234
- listeners << listener
233
+ def add_listener(*listener)
234
+ listeners.addAll(listener)
235
+ ensure
236
+ log.trace "Listeners: #{listeners}"
237
+ end
238
+
239
+ def remove_listener(*listener)
240
+ listeners.removeAll(listener)
235
241
  end
236
242
 
237
- def remove_listener(listener)
238
- listeners.delete(listener)
243
+ def replace_listeners(*listener)
244
+ listeners.clear
245
+ add_listener(*listener)
239
246
  end
240
247
 
241
- def notify(message, *args)
242
- return if listeners.empty?
243
- log.trace "Notifying listeners (#{listeners}) of message: #{message}"
248
+ def notify(event, *args)
244
249
  listeners.each do |listener|
245
- listener.send(message.to_sym, *args) if listener.respond_to?(message.to_sym)
250
+ next unless listener.respond_to?(event.to_sym)
251
+ log.trace "Notifying listener #{listener} of event: #{event}"
252
+ listener.send(event.to_sym, *args)
246
253
  end
247
254
  end
248
255
  end
256
+ # module Listenable
249
257
  end
258
+ # module Client
250
259
 
251
260
  # The Client module
252
261
  module Client
@@ -350,12 +359,7 @@ module Client
350
359
 
351
360
  # The ChannelInitializer class
352
361
  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
362
+ attr_accessor :decoder, :encoder, :handlers
359
363
 
360
364
  def initialize(options = {})
361
365
  super()
@@ -363,6 +367,8 @@ module Client
363
367
  @host = @options[:host]
364
368
  @port = @options[:port]
365
369
  @handlers = []
370
+ @decoder = StringDecoder.new
371
+ @encoder = StringEncoder.new
366
372
  end
367
373
 
368
374
  def <<(handler)
@@ -372,15 +378,17 @@ module Client
372
378
  def initChannel(channel)
373
379
  pipeline = channel.pipeline
374
380
  pipeline.addLast(ssl_handler(channel)) if @options[:ssl]
375
- pipeline.addLast(
376
- DelimiterBasedFrameDecoder.new(MAX_FRAME_LENGTH, Delimiters.lineDelimiter()),
377
- DECODER,
378
- ENCODER
379
- )
381
+ # pipeline.addLast(frame_decoder)
382
+ pipeline.addLast(decoder)
383
+ pipeline.addLast(encoder)
380
384
  add_user_handlers(pipeline)
381
385
  pipeline.addLast(default_handler)
382
386
  end
383
387
 
388
+ def frame_decoder
389
+ DelimiterBasedFrameDecoder.new(@options[:max_frame_length], @options[:delimiter])
390
+ end
391
+
384
392
  def default_handler
385
393
  @default_handler ||= ::Client::ModularHandler.new
386
394
  end
@@ -455,32 +463,32 @@ end
455
463
  module Client
456
464
  # The ArgumentsParser class
457
465
  class ArgumentsParser
458
- Flags = %i[banner port ssl log_level help version].freeze
459
466
  attr_reader :parser, :options
460
467
 
461
468
  def initialize(parser = OptionParser.new, options = ::Client.client_config.dup)
462
469
  @parser = parser
463
470
  @options = options
464
- Flags.each { |method_name| method(method_name).call }
471
+ @flags = %i[banner port ssl log_level help version]
472
+ @flags.each { |method_name| method(method_name)&.call if respond_to?(method_name) }
465
473
  end
466
474
 
467
475
  def banner
468
- @parser.banner = "Usage: #{File.basename($PROGRAM_NAME)} [host] [port] [options]"
476
+ @parser.banner = "Usage: #{File.basename($PROGRAM_NAME)} [options] <hostname> [port]"
469
477
  @parser.separator ''
470
478
  @parser.separator 'Options:'
471
479
  end
472
480
 
473
481
  def host
474
482
  description = "Connect to server at this host; default: #{@options[:host]}"
475
- @parser.on('-h', '--host=<host>s', description) do |v|
483
+ @parser.on('-h', '--hostname=<hostname>', description) do |v|
476
484
  @options[:host] = v
477
485
  end
478
486
  end
479
487
 
480
- IntegerPattern = /^\d+$/.freeze
488
+ def validated_port(val, integer_pattern = /^\d+$/)
489
+ raise OptionParser::InvalidArgument, "Invalid port: #{val}" unless \
490
+ integer_pattern.match?(val.to_s) && val.positive? && val < 65_536
481
491
 
482
- def validated_port(val)
483
- raise "Invalid port: #{v}" unless IntegerPattern.match?(val.to_s) && val.positive? && val < 65_536
484
492
  val
485
493
  end
486
494
 
@@ -499,6 +507,7 @@ module Client
499
507
 
500
508
  def log_level
501
509
  @parser.on_tail('-v', '--verbose', 'Increase verbosity') do
510
+ @options[:log_level] ||= 0
502
511
  @options[:log_level] -= 1
503
512
  end
504
513
  end
@@ -516,19 +525,28 @@ module Client
516
525
  exit
517
526
  end
518
527
  end
528
+
529
+ def parse_positional_arguments!
530
+ @options[:host] = ARGV.shift or raise OptionParser::MissingArgument, 'hostname'
531
+ return if (given_port = ARGV.shift&.to_i).nil?
532
+
533
+ @options[:port] = validated_port(given_port).to_i
534
+ end
519
535
  end
520
536
  # class ArgumentsParser
521
537
 
522
- # rubocop: disable Metrics/AbcSize
523
538
  def parse_arguments(arguments_parser = ArgumentsParser.new)
524
539
  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?
540
+ arguments_parser.parse_positional_arguments!
527
541
  arguments_parser.options
528
- rescue OptionParser::InvalidOption, OptionParser::AmbiguousOption => e
542
+ rescue OptionParser::InvalidArgument, OptionParser::InvalidOption,
543
+ OptionParser::MissingArgument, OptionParser::NeedlessArgument => e
544
+ puts e.message
545
+ puts parser
546
+ exit
547
+ rescue OptionParser::AmbiguousOption => e
529
548
  abort e.message
530
549
  end
531
- # rubocop: enable Metrics/AbcSize
532
550
  end
533
551
  # module Client
534
552
 
@@ -549,12 +567,12 @@ end
549
567
 
550
568
  # The Client module
551
569
  module Client
552
- # The ConsoleHandler class
553
- class ConsoleHandler
570
+ # The Console class
571
+ class Console
554
572
  def message_received(ctx, message)
555
573
  log.trace "##{__method__} channel: #{ctx.channel}, message: #{message}"
556
574
  log.debug "Received message: #{message}"
557
- puts message.chomp unless message.nil?
575
+ $stdout.print message unless message.nil?
558
576
  end
559
577
  end
560
578
  end
@@ -568,8 +586,7 @@ module Client
568
586
  # rubocop: disable Metrics/MethodLength
569
587
  def main(args = parse_arguments)
570
588
  Logging.log_level = args[:log_level]
571
- handlers = [::Client::Monitor.new, ::Client::ConsoleHandler.new]
572
- ::TCP::Client.new(args, *handlers)
589
+ ::TCP::Client.new(args, ::Client::Console.new, ::Client::Monitor.new)
573
590
  rescue Interrupt => e
574
591
  warn format(InterruptTemplate, class: e.class)
575
592
  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,21 +49,25 @@ 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
66
64
 
67
- def add_listener(listener)
68
- default_handler.add_listener(listener)
65
+ def add_listener(*listeners)
66
+ default_handler.add_listener(*listeners)
67
+ end
68
+
69
+ def replace_listeners(*listeners)
70
+ default_handler.replace_listener(*listeners)
69
71
  end
70
72
 
71
73
  protected
@@ -96,8 +96,12 @@ module Server
96
96
  channel_initializer << handler
97
97
  end
98
98
 
99
- def add_listener(listener)
100
- channel_initializer.add_listener(listener)
99
+ def add_listener(*listener)
100
+ channel_initializer.add_listener(*listener)
101
+ end
102
+
103
+ def replace_listeners(*listener)
104
+ channel_initializer.replace_listeners(*listener)
101
105
  end
102
106
  end
103
107
  # module ServerInstanceMethods
@@ -20,19 +20,26 @@ module Server
20
20
  @listeners ||= java.util.concurrent.CopyOnWriteArrayList.new
21
21
  end
22
22
 
23
- def add_listener(listener)
24
- listeners << listener
23
+ def add_listener(*listener)
24
+ listeners.addAll(listener)
25
+ ensure
26
+ log.trace "Listeners: #{listeners}"
25
27
  end
26
28
 
27
- def remove_listener(listener)
28
- listeners.delete(listener)
29
+ def remove_listener(*listener)
30
+ listeners.removeAll(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 replace_listeners(*listener)
34
+ listeners.clear
35
+ add_listener(*listener)
36
+ end
37
+
38
+ def notify(event, *args)
34
39
  listeners.each do |listener|
35
- listener.send(message.to_sym, *args) if listener.respond_to?(message.to_sym)
40
+ next unless listener.respond_to?(event.to_sym)
41
+ log.trace "Notifying listener #{listener} of event: #{event}"
42
+ listener.send(event.to_sym, *args)
36
43
  end
37
44
  end
38
45
  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.10'.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.10
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-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement