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