tcp-server 1.0.7-java → 1.0.8-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 +52 -42
- data/lib/server/argument_parser.rb +5 -8
- data/lib/server/channel_initializer.rb +8 -10
- data/lib/server/listenable.rb +6 -4
- 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: 3c55987f7d6c92030cd96937448d5dea7b62c5dd43292e2d47a5b1901cdcbfa8
|
4
|
+
data.tar.gz: 6396aaaa64e18e454801debd881e618558ab65bec55de917fd328f0f4cdc041e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
|
@@ -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(
|
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
|
-
|
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
|
-
|
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
|
-
|
377
|
-
|
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
|
-
|
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)} [
|
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', '--
|
476
|
+
@parser.on('-h', '--hostname=<hostname>', description) do |v|
|
476
477
|
@options[:host] = v
|
477
478
|
end
|
478
479
|
end
|
479
480
|
|
480
|
-
|
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.
|
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::
|
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
|
553
|
-
class
|
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
|
-
|
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
|
-
|
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
|
-
|
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,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
|
data/lib/server/listenable.rb
CHANGED
@@ -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(
|
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
|
-
|
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
|
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.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-
|
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
|