tcp-server 1.0.7-java → 1.0.10-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: 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