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 +4 -4
- data/README.md +2 -3
- data/lib/client.rb +63 -46
- data/lib/server/argument_parser.rb +5 -8
- data/lib/server/channel_initializer.rb +14 -12
- data/lib/server/instance_methods.rb +6 -2
- data/lib/server/listenable.rb +15 -8
- data/lib/server/message_handler.rb +1 -1
- data/lib/server/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 87653ba8533d5ecaa864acaec4e535737923226709a5099388bacf32f25d2db4
|
4
|
+
data.tar.gz: 202db5cfc4382c95684961ec0524127d4befedea04495b0a8a4f1370e1435c8d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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,
|
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
|
-
|
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
|
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.
|
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
|
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
|
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
|
238
|
-
listeners.
|
243
|
+
def replace_listeners(*listener)
|
244
|
+
listeners.clear
|
245
|
+
add_listener(*listener)
|
239
246
|
end
|
240
247
|
|
241
|
-
def notify(
|
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
|
-
|
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
|
-
|
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
|
-
|
377
|
-
|
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
|
-
|
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)} [
|
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', '--
|
483
|
+
@parser.on('-h', '--hostname=<hostname>', description) do |v|
|
476
484
|
@options[:host] = v
|
477
485
|
end
|
478
486
|
end
|
479
487
|
|
480
|
-
|
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.
|
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::
|
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
|
553
|
-
class
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
68
|
-
default_handler.add_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
|
data/lib/server/listenable.rb
CHANGED
@@ -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
|
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.
|
29
|
+
def remove_listener(*listener)
|
30
|
+
listeners.removeAll(listener)
|
29
31
|
end
|
30
32
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
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
|
-
|
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
|
45
|
+
return super(ctx, msg) unless respond_to?(:handle_message) && @handler&.arity == 2
|
46
46
|
handle_message(ctx, msg)
|
47
47
|
end
|
48
48
|
|
data/lib/server/version.rb
CHANGED
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.
|
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-
|
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
|