tcp-server 1.0.7-java → 1.0.8-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 +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
|