tcp-server 1.0.4-java → 1.0.7-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: 3e13c7b958e72b6551472ad5a12389bc88687984b2d17f915f31a34dc2a420e8
4
- data.tar.gz: 8682f4628c10fda39dcf7953ce0a31af1947af8507b5fc9ea41593ed8e4e3cba
3
+ metadata.gz: 119b17b7637a9d30ba40c82660e9b2c9eebbabbe59264cbb49e88b82cef6805c
4
+ data.tar.gz: 5fa1261d06c758e2934944f79fc9f747d73f387dd4e2ed04cb119fe496a34010
5
5
  SHA512:
6
- metadata.gz: 0535ec8e3b2a0c4d03f3150a1c8f551b2a32a4cf0c387d00b82b1d16f2b75e5fda2111fa8686febd3a36be2acaed68f165d08c99a6fa36a1515dbd4e129e9406
7
- data.tar.gz: c2546356d7833043fbc7664afacba069ed21d9b8d5f460a58688f8714bd51dacaca95a60ce6319e3d19c6f54ad05faa57717af087c9e2085c5755b1d50efefe3
6
+ metadata.gz: 3d911168c44588f3c89b557b800bde9cbaf5603185c4c850bf6362c8e24458110ed2b1c33ea8736032d7003d01068a4e7b7bf58151e334adab2b1fef2adba251
7
+ data.tar.gz: f2863e4c56547ae3f8af9f1b37085863ffefd3f5ffd07eb46a1e288c72694189ff52e44c7fdb1e1b20ee68c8b841a93699e9d32a2ad4defff093e8ac265b567a
data/README.md CHANGED
@@ -18,7 +18,9 @@ You may run the websocket server in a container. The [`colima`](https://github.c
18
18
 
19
19
  ```sh
20
20
  colima start
21
- docker-compose up
21
+ docker-compose up --detach
22
+ nc localhost 4000
23
+ docker-compose down
22
24
  ```
23
25
 
24
26
  Building the image or running the container:
@@ -57,8 +59,7 @@ Download and install the latest version of [JRuby].
57
59
 
58
60
  ```sh
59
61
  asdf plugin add ruby
60
- pushd "${HOME}/.asdf/plugins/ruby/ruby-build"; git fetch origin; git pull origin master; popd
61
- # ~/.asdf/plugins/ruby/bin/list-all
62
+ asdf plugin update --all
62
63
  asdf list all ruby
63
64
  asdf install ruby jruby-9.3.4.0
64
65
  ```
@@ -123,7 +124,7 @@ Here is a bird's-eye view of the project layout.
123
124
 
124
125
  ```sh
125
126
  # date && tree -I "logs|vendor|tmp"
126
- Thu Jun 16 00:03:23 CDT 2022
127
+ Tue Jun 28 20:25:51 CDT 2022
127
128
  .
128
129
  ├── Dockerfile
129
130
  ├── Gemfile
@@ -157,7 +158,7 @@ Thu Jun 16 00:03:23 CDT 2022
157
158
  │ ├── test_spec.rb
158
159
  │ └── verify
159
160
  │ └── verify_spec.rb
160
- ├── tcp-server-1.0.2-java.gem
161
+ ├── tcp-server-1.0.6-java.gem
161
162
  ├── tcp-server-jruby.gemspec
162
163
  ├── tcp_server.png
163
164
  └── tcp_server.rb
@@ -165,6 +166,7 @@ Thu Jun 16 00:03:23 CDT 2022
165
166
  5 directories, 31 files
166
167
  ```
167
168
 
169
+
168
170
  ## CI linting
169
171
 
170
172
  Use the GitLab CI Linting API to validate the syntax of a CI definition file.
@@ -173,12 +175,13 @@ Use the GitLab CI Linting API to validate the syntax of a CI definition file.
173
175
  jq --null-input --arg yaml "$(<.gitlab/ci/gem.gitlab-ci.yml)" '.content=$yaml' | curl --silent --location https://gitlab.com/api/v4/ci/lint --header "PRIVATE-TOKEN: ${GITLAB_COM_API_PRIVATE_TOKEN}" --header "Content-Type: application/json" --data @- | jq --raw-output '.errors[0]'
174
176
  ```
175
177
 
178
+
176
179
  ## CI configuration
177
180
 
178
181
  Generate a deploy key.
179
182
 
180
183
  ```sh
181
- ssh-keygen -t ed25519 -C deploy_key
184
+ ssh-keygen -t ed25519 -P '' -C deploy_key -f deploy_key_ed25519
182
185
  ```
183
186
 
184
187
  Use the GitLab Project-level Variables API to add the deploy key as a ssh private key variable.
@@ -186,18 +189,21 @@ Use the GitLab Project-level Variables API to add the deploy key as a ssh privat
186
189
  ```sh
187
190
  project_path="nelsnelson/$(basename $(pwd))"
188
191
 
192
+ # Test auth token validity
193
+ curl --silent --show-error --location "https://gitlab.com/api/v4/projects" --header "PRIVATE-TOKEN: ${GITLAB_COM_API_PRIVATE_TOKEN}" | jq '.[0]["id"]'
194
+
189
195
  project=$(curl --silent --show-error --location "https://gitlab.com/api/v4/search?scope=projects&search=${project_path}" --header "PRIVATE-TOKEN: ${GITLAB_COM_API_PRIVATE_TOKEN}" | jq --arg project_path "${project_path}" '.[] | select(.path_with_namespace == $project_path)')
190
196
 
191
197
  project_id=$(curl --silent --show-error --location "https://gitlab.com/api/v4/search?scope=projects&search=${project_path}" --header "PRIVATE-TOKEN: ${GITLAB_COM_API_PRIVATE_TOKEN}" | jq --arg project_path "${project_path}" '.[] | select(.path_with_namespace == $project_path) | .id')
192
198
 
193
199
  # Add the deploy_token as a CI variable:
194
- curl --silent --show-error --location --request POST "https://gitlab.com/api/v4/projects/${project_id}/variables" --header "PRIVATE-TOKEN: ${GITLAB_COM_API_PRIVATE_TOKEN}" --form "key=SSH_PRIVATE_KEY" --form "value=$(cat ./deploy_token)" --form "protected=true" | jq
200
+ curl --silent --show-error --location --request POST "https://gitlab.com/api/v4/projects/${project_id}/variables" --header "PRIVATE-TOKEN: ${GITLAB_COM_API_PRIVATE_TOKEN}" --form "key=SSH_PRIVATE_KEY" --form "value=$(cat ./deploy_key_ed25519)" --form "protected=true" | jq
195
201
  ```
196
202
 
197
203
  Use the Deploy keys API to add a the public deploy key as a deploy key for the project.
198
204
 
199
205
  ```sh
200
- curl --silent --show-error --location --request POST "https://gitlab.com/api/v4/projects/${project_id}/deploy_keys" --header "PRIVATE-TOKEN: ${GITLAB_COM_API_PRIVATE_TOKEN}" --data '{"title": "deploy_key", "key": "$(cat ./deploy_token.pub)", "can_push": "true"}' | jq
206
+ curl --silent --show-error --location --request POST "https://gitlab.com/api/v4/projects/${project_id}/deploy_keys" --header "PRIVATE-TOKEN: ${GITLAB_COM_API_PRIVATE_TOKEN}" --form "title=deploy_key" --form "key=$(cat ./deploy_key_ed25519.pub)" --form "can_push=true" | jq
201
207
  ```
202
208
 
203
209
  [license]: https://gitlab.com/nelsnelson/tcp-server-jruby/blob/master/LICENSE
data/lib/client.rb CHANGED
@@ -12,11 +12,12 @@
12
12
  #
13
13
  # =end
14
14
 
15
- require 'optparse'
16
-
17
15
  require 'java'
18
16
  require 'netty'
19
17
 
18
+ require 'logger'
19
+ require 'optparse'
20
+
20
21
  require 'log'
21
22
 
22
23
  # The Client module
@@ -26,16 +27,23 @@ end
26
27
 
27
28
  # The Client module
28
29
  module Client
29
- # The Config module
30
- module Config
31
- DEFAULTS = {
30
+ # rubocop: disable Metrics/MethodLength
31
+ def client_config
32
+ @client_config ||= {
33
+ host: '0.0.0.0',
32
34
  port: 8080,
33
- host: 'localhost',
34
35
  ssl: false,
35
- quit_commands: %i[bye quit],
36
- log_level: Logger::INFO
36
+ idle_reading: 5 * 60, # seconds
37
+ idle_writing: 30, # seconds
38
+ log_requests: false,
39
+ log_level: Logger::INFO,
40
+ quit_commands: %i[bye cease desist exit leave quit stop terminate],
41
+ max_frame_length: 8192,
42
+ delimiter: Java::io.netty.handler.codec.Delimiters.lineDelimiter
37
43
  }.freeze
38
44
  end
45
+ # rubocop: enable Metrics/MethodLength
46
+ module_function :client_config
39
47
  end
40
48
 
41
49
  # The Client module
@@ -77,8 +85,8 @@ module Client
77
85
  end
78
86
 
79
87
  def configure_handlers(*handlers, &block)
80
- ::Client::ChannelInitializer::DefaultHandler.add_listener(self)
81
- listeners.addAll(handlers)
88
+ channel_initializer.default_handler.add_listener(self)
89
+ channel_initializer.default_handler.listeners.addAll(handlers)
82
90
  @user_app = block
83
91
  @application_handler = lambda do |ctx, msg|
84
92
  if @user_app.nil? || @user_app.arity == 1
@@ -342,12 +350,11 @@ module Client
342
350
 
343
351
  # The ChannelInitializer class
344
352
  class ChannelInitializer < Java::io.netty.channel.ChannelInitializer
345
- DefaultHandler = ::Client::ModularHandler.new
346
- FrameDecoderBufferSize = 8192 # bytes
347
353
  # The encoder and decoder are sharable. If they were not, then
348
354
  # constant definitions could not be used.
349
- Decoder = StringDecoder.new
350
- Encoder = StringEncoder.new
355
+ DECODER = StringDecoder.new
356
+ ENCODER = StringEncoder.new
357
+ MAX_FRAME_LENGTH = 8192
351
358
  attr_accessor :handlers
352
359
 
353
360
  def initialize(options = {})
@@ -366,12 +373,16 @@ module Client
366
373
  pipeline = channel.pipeline
367
374
  pipeline.addLast(ssl_handler(channel)) if @options[:ssl]
368
375
  pipeline.addLast(
369
- DelimiterBasedFrameDecoder.new(FrameDecoderBufferSize, Delimiters.lineDelimiter()),
370
- Decoder,
371
- Encoder
376
+ DelimiterBasedFrameDecoder.new(MAX_FRAME_LENGTH, Delimiters.lineDelimiter()),
377
+ DECODER,
378
+ ENCODER
372
379
  )
373
380
  add_user_handlers(pipeline)
374
- pipeline.addLast(DefaultHandler)
381
+ pipeline.addLast(default_handler)
382
+ end
383
+
384
+ def default_handler
385
+ @default_handler ||= ::Client::ModularHandler.new
375
386
  end
376
387
 
377
388
  protected
@@ -424,7 +435,7 @@ module TCP
424
435
  include ::Client::Listenable
425
436
 
426
437
  def initialize(options = {}, *handlers, &block)
427
- init(::Client::Config::DEFAULTS.merge(options))
438
+ init(::Client.client_config.merge(options))
428
439
  configure_handlers(*handlers, &block)
429
440
  connect
430
441
  session
@@ -447,7 +458,7 @@ module Client
447
458
  Flags = %i[banner port ssl log_level help version].freeze
448
459
  attr_reader :parser, :options
449
460
 
450
- def initialize(parser = OptionParser.new, options = ::Client::Config::DEFAULTS.dup)
461
+ def initialize(parser = OptionParser.new, options = ::Client.client_config.dup)
451
462
  @parser = parser
452
463
  @options = options
453
464
  Flags.each { |method_name| method(method_name).call }
data/lib/log.rb CHANGED
@@ -12,56 +12,98 @@ require 'logger'
12
12
 
13
13
  require 'log4j-2'
14
14
 
15
+ require 'fileutils'
16
+
17
+ # The Logging module
18
+ module Logging
19
+ # rubocop: disable Metrics/MethodLength
20
+ def config
21
+ @config ||= begin
22
+ lib_dir_path = File.expand_path(__dir__)
23
+ project_dir_path = File.expand_path(File.dirname(lib_dir_path))
24
+ logs_dir_path = File.expand_path(File.join(project_dir_path, 'logs'))
25
+ server_log_file = File.expand_path(File.join(logs_dir_path, 'server.log'))
26
+ {
27
+ level: :info,
28
+ name: 'tcp-server',
29
+ lib_dir_path: lib_dir_path,
30
+ project_dir_path: project_dir_path,
31
+ logs_dir_path: logs_dir_path,
32
+ server_log_file: server_log_file,
33
+ rolling_log_file_name_template: 'server-%d{yyyy-MM-dd}.log.gz',
34
+ logger_pattern_template: '%d{ABSOLUTE} %-5p [%c{1}] %m%n',
35
+ schedule: '0 0 0 * * ?',
36
+ size: '100M'
37
+ }
38
+ end
39
+ end
40
+ module_function :config
41
+ # rubocop: enable Metrics/MethodLength
42
+ end
43
+
15
44
  # The LogInitialization module
16
45
  module LogInitialization
17
- LibDirPath = File.expand_path(__dir__) unless defined?(LibDirPath)
18
- ProjectDirPath = File.expand_path(File.dirname(LibDirPath)) unless defined?(ProjectDirPath)
19
- LogsDirPath = File.expand_path(File.join(ProjectDirPath, 'logs'))
20
- Dir.mkdir(LogsDirPath) unless File.exist?(LogsDirPath)
21
- ServerLogFile = File.join(LogsDirPath, 'server.log')
22
- RollLogFileNameTemplate = 'server-%d{yyyy-MM-dd}.log.gz'.freeze
23
- RollingLogFilePath = File.join(LogsDirPath, RollLogFileNameTemplate)
24
- File.write(ServerLogFile, '') unless File.file? ServerLogFile
25
- LoggerPatternTemplate = '%d{ABSOLUTE} %-5p [%c{1}] %m%n'.freeze
46
+ def init
47
+ init_log_file
48
+ init_log4j if defined? Java
49
+ end
50
+ module_function :init
51
+
52
+ def init_log_file
53
+ FileUtils.mkdir_p(Logging.config[:logs_dir_path])
54
+ return if File.file?(Logging.config[:server_log_file])
55
+
56
+ File.write(Logging.config[:server_log_file], '')
57
+ end
58
+ module_function :init_log_file
26
59
 
27
60
  # rubocop: disable Metrics/AbcSize
28
61
  # rubocop: disable Metrics/MethodLength
29
- def self.init_log4j(log_level = org.apache.logging.log4j.Level::INFO)
62
+ def init_log4j(log_level = org.apache.logging.log4j.Level::INFO)
63
+ server_log_file = Logging.config[:server_log_file]
64
+ logs_dir_path = Logging.config[:logs_dir_path]
65
+ rolling_log_file_name_template = Logging.config[:rolling_log_file_name_template]
66
+ rolling_log_file_path = File.join(logs_dir_path, rolling_log_file_name_template)
67
+
30
68
  java.lang::System.setProperty('log4j.shutdownHookEnabled', java.lang::Boolean.toString(false))
31
69
  factory = org.apache.logging.log4j.core.config.builder.api::ConfigurationBuilderFactory
32
70
  config = factory.newConfigurationBuilder()
33
71
 
34
- log_level = org.apache.logging.log4j.Level.to_level(log_level.to_s.upcase) if log_level.is_a?(Symbol)
72
+ if log_level.is_a?(Symbol)
73
+ log_level = org.apache.logging.log4j.Level.to_level(
74
+ log_level.to_s.upcase
75
+ )
76
+ end
35
77
  config.setStatusLevel(log_level)
36
- config.setConfigurationName('websocket')
78
+ config.setConfigurationName(Logging.config['name'])
37
79
 
38
- # create a console appender
80
+ # Create a console appender
39
81
  target = org.apache.logging.log4j.core.appender::ConsoleAppender::Target::SYSTEM_OUT
40
82
  layout = config.newLayout('PatternLayout')
41
- layout = layout.addAttribute('pattern', LoggerPatternTemplate)
83
+ layout = layout.addAttribute('pattern', Logging.config[:logger_pattern_template])
42
84
  appender = config.newAppender('stdout', 'CONSOLE')
43
85
  appender = appender.addAttribute('target', target)
44
86
  appender = appender.add(layout)
45
87
  config.add(appender)
46
88
 
47
- # create a root logger
89
+ # Create a root logger
48
90
  root_logger = config.newRootLogger(log_level)
49
91
  root_logger = root_logger.add(config.newAppenderRef('stdout'))
50
92
 
51
- # create a rolling file appender
93
+ # Create a rolling file appender
52
94
  cron = config.newComponent('CronTriggeringPolicy')
53
- cron = cron.addAttribute('schedule', '0 0 0 * * ?')
95
+ cron = cron.addAttribute('schedule', Logging.config[:schedule])
54
96
 
55
97
  size = config.newComponent('SizeBasedTriggeringPolicy')
56
- size = size.addAttribute('size', '100M')
98
+ size = size.addAttribute('size', Logging.config[:size])
57
99
 
58
100
  policies = config.newComponent('Policies')
59
101
  policies = policies.addComponent(cron)
60
102
  policies = policies.addComponent(size)
61
103
 
62
104
  appender = config.newAppender('rolling_file', 'RollingFile')
63
- appender = appender.addAttribute('fileName', ServerLogFile)
64
- appender = appender.addAttribute('filePattern', RollingLogFilePath)
105
+ appender = appender.addAttribute('fileName', server_log_file)
106
+ appender = appender.addAttribute('filePattern', rolling_log_file_path)
65
107
  appender = appender.add(layout)
66
108
  appender = appender.addComponent(policies)
67
109
  config.add(appender)
@@ -77,10 +119,11 @@ module LogInitialization
77
119
  # rubocop: enable Metrics/AbcSize
78
120
  # rubocop: enable Metrics/MethodLength
79
121
  # def init_log4j
122
+ module_function :init_log4j
80
123
  end
81
124
  # module LogInitialization
82
125
 
83
- ::LogInitialization.init_log4j if defined? Java
126
+ ::LogInitialization.init
84
127
 
85
128
  # The Apache log4j Logger class
86
129
  # rubocop: disable Style/ClassAndModuleChildren
@@ -113,35 +156,14 @@ end
113
156
 
114
157
  # The Logging module
115
158
  module Logging
116
- # rubocop: disable Style/MutableConstant
117
- Configuration = {
118
- level: Logger::INFO
119
- }
120
- # rubocop: enable Style/MutableConstant
121
-
122
- def self.log_level=(log_level)
123
- Logging::Configuration[:level] = log_level
124
- end
125
-
126
- def self.log_level
127
- Logging::Configuration[:level]
128
- end
129
-
130
- def log(level = Logging.log_level, log_name = nil)
131
- @log ||= init_logger(level, log_name)
132
- end
133
- alias logger log
134
-
135
- protected
136
-
137
- def init_logger(level = Logging.log_level, logger_name = nil)
159
+ def init_logger(level = :all, logger_name = nil)
138
160
  return init_java_logger(level, logger_name, caller[2]) if defined?(Java)
139
- Logging.init_ruby_logger(level, logger_name)
161
+ init_ruby_logger(level)
140
162
  end
141
163
 
142
- def init_ruby_logger(level, logger_name = nil)
143
- logger_instance = Logger.new(logger_name)
144
- logger_instance.level = level
164
+ def init_ruby_logger(level)
165
+ logger_instance = Logger.new
166
+ logger_instance.level = Logging::Level.to_level(level.to_s.upcase)
145
167
  logger_instance
146
168
  end
147
169
 
@@ -149,9 +171,8 @@ module Logging
149
171
  def init_java_logger(level, logger_name = nil, source_location = nil)
150
172
  logger_name = get_formatted_logger_name(logger_name)
151
173
  logger_name = source_location.split(/\//).last if logger_name.empty?
152
- level_name = symbolize_numeric_log_level(level).to_s.upcase
153
174
  logger_instance = org.apache.logging.log4j.LogManager.getLogger(logger_name)
154
- logger_instance.level = org.apache.logging.log4j.Level.to_level(level_name)
175
+ logger_instance.level = org.apache.logging.log4j.Level.to_level(level.to_s.upcase)
155
176
  logger_instance
156
177
  end
157
178
  # rubocop: enable Metrics/AbcSize
@@ -185,6 +206,22 @@ module Logging
185
206
  end
186
207
  end
187
208
  # rubocop: enable Metrics/CyclomaticComplexity
209
+ module_function :symbolize_numeric_log_level
210
+
211
+ def log_level=(log_level)
212
+ Logging.config[:level] = symbolize_numeric_log_level(log_level)
213
+ end
214
+ module_function :log_level=
215
+
216
+ def log_level
217
+ Logging.config[:level]
218
+ end
219
+ module_function :log_level
220
+
221
+ def log(level = Logging.log_level, log_name = nil)
222
+ @log ||= init_logger(level, log_name)
223
+ end
224
+ alias logger log
188
225
  end
189
226
  # module Logging
190
227
 
@@ -26,7 +26,7 @@ module Server
26
26
 
27
27
  def initialize(option_parser = OptionParser.new)
28
28
  @parser = option_parser
29
- @options = ::Server::Config::DEFAULTS.dup
29
+ @options = ::Server.server_config.dup
30
30
  Flags.each { |method_name| method(method_name).call }
31
31
  end
32
32
 
@@ -76,7 +76,8 @@ module Server
76
76
 
77
77
  def log_level
78
78
  @parser.on_tail('-v', '--verbose', 'Increase verbosity') do
79
- @options[:log_level] -= 1
79
+ current_level = @options.fetch(:log_level, 0)
80
+ @options[:log_level] = current_level - 1
80
81
  end
81
82
  end
82
83
 
@@ -30,19 +30,18 @@ module Server
30
30
 
31
31
  # The ChannelInitializer class
32
32
  class ChannelInitializer < Java::io.netty.channel.ChannelInitializer
33
- DefaultHandler = ModularHandler.new
34
- FrameDecoderBufferBytesSize = 8192
35
33
  # The encoder and decoder are sharable. If they were not, then
36
34
  # constant definitions could not be used.
37
- Decoder = StringDecoder.new
38
- Encoder = StringEncoder.new
35
+ DECODER = StringDecoder.new
36
+ ENCODER = StringEncoder.new
39
37
  attr_accessor :user_handlers
40
38
  attr_reader :options
41
39
 
42
- def initialize(options = {})
40
+ def initialize(channel_group, options = {})
43
41
  super()
42
+ @channel_group = channel_group
44
43
  @options = options
45
- @user_handlers = []
44
+ @user_handlers = @options.fetch(:handlers, [])
46
45
  end
47
46
 
48
47
  def <<(handler)
@@ -53,12 +52,20 @@ module Server
53
52
  pipeline = channel.pipeline
54
53
  pipeline.addLast(ssl_handler(channel)) if @options[:ssl]
55
54
  pipeline.addLast(
56
- DelimiterBasedFrameDecoder.new(FrameDecoderBufferBytesSize, Delimiters.lineDelimiter),
57
- Decoder,
58
- Encoder
55
+ DelimiterBasedFrameDecoder.new(@options[:max_frame_length], @options[:delimiter]),
56
+ DECODER,
57
+ ENCODER
59
58
  )
60
59
  add_user_handlers(pipeline)
61
- pipeline.addLast(DefaultHandler)
60
+ pipeline.addLast(default_handler)
61
+ end
62
+
63
+ def default_handler
64
+ @default_handler ||= ::Server::ModularHandler.new(@channel_group)
65
+ end
66
+
67
+ def add_listener(listener)
68
+ default_handler.add_listener(listener)
62
69
  end
63
70
 
64
71
  protected
@@ -67,7 +74,7 @@ module Server
67
74
  @user_handlers.each do |handler|
68
75
  case handler
69
76
  when Class then pipeline.addLast(handler.new)
70
- when Proc then pipeline.addLast(Server::MessageHandler.new(&handler))
77
+ when Proc then pipeline.addLast(::Server::MessageHandler.new(&handler))
71
78
  else pipeline.addLast(handler)
72
79
  end
73
80
  end
data/lib/server/config.rb CHANGED
@@ -10,13 +10,15 @@
10
10
  #
11
11
  # =end
12
12
 
13
+ require 'netty'
14
+
13
15
  require 'logger'
14
16
 
15
17
  # The Server module
16
18
  module Server
17
- # The Config module
18
- module Config
19
- DEFAULTS = {
19
+ # rubocop: disable Metrics/MethodLength
20
+ def server_config
21
+ @server_config ||= {
20
22
  host: '0.0.0.0',
21
23
  port: 8080,
22
24
  ssl: false,
@@ -24,7 +26,11 @@ module Server
24
26
  idle_writing: 30, # seconds
25
27
  log_requests: false,
26
28
  log_level: Logger::INFO,
27
- quit_commands: %i[bye quit]
29
+ quit_commands: %i[bye cease desist exit leave quit stop terminate],
30
+ max_frame_length: 8192,
31
+ delimiter: Java::io.netty.handler.codec.Delimiters.lineDelimiter
28
32
  }.freeze
29
33
  end
34
+ module_function :server_config
35
+ # rubocop: enable Metrics/MethodLength
30
36
  end
@@ -20,9 +20,11 @@ require_relative 'shutdown_hook'
20
20
  module Server
21
21
  java_import Java::io.netty.bootstrap.ServerBootstrap
22
22
  java_import Java::io.netty.channel.ChannelOption
23
+ java_import Java::io.netty.channel.group.DefaultChannelGroup
23
24
  java_import Java::io.netty.channel.nio.NioEventLoopGroup
24
25
  java_import Java::io.netty.handler.logging.LogLevel
25
26
  java_import Java::io.netty.handler.logging.LoggingHandler
27
+ java_import Java::io.netty.util.concurrent.GlobalEventExecutor
26
28
 
27
29
  # The InstanceMethods module
28
30
  module InstanceMethods
@@ -41,7 +43,7 @@ module Server
41
43
  end
42
44
 
43
45
  def channel_initializer
44
- @channel_initializer ||= ::Server::ChannelInitializer.new(@options)
46
+ @channel_initializer ||= ::Server::ChannelInitializer.new(channel_group, @options)
45
47
  end
46
48
 
47
49
  def boss_group
@@ -52,6 +54,10 @@ module Server
52
54
  @worker_group ||= NioEventLoopGroup.new
53
55
  end
54
56
 
57
+ def channel_group
58
+ @channel_group ||= DefaultChannelGroup.new('server_channels', GlobalEventExecutor::INSTANCE)
59
+ end
60
+
55
61
  def logging_handler
56
62
  @logging_handler ||= LoggingHandler.new(LogLevel::INFO)
57
63
  end
@@ -60,7 +66,7 @@ module Server
60
66
  # rubocop: disable Metrics/MethodLength
61
67
  def run(port = @options[:port])
62
68
  channel = bootstrap.bind(port).sync().channel()
63
- ::Server::Channels.add(channel)
69
+ channel_group.add(channel)
64
70
  ::Server::ShutdownHook.new(self)
65
71
  log.info "Listening on #{channel.local_address}"
66
72
  channel.closeFuture().sync()
@@ -77,8 +83,8 @@ module Server
77
83
  # rubocop: enable Metrics/MethodLength
78
84
 
79
85
  def shutdown
80
- ::Server::Channels.disconnect().awaitUninterruptibly()
81
- ::Server::Channels.close().awaitUninterruptibly()
86
+ channel_group.disconnect().awaitUninterruptibly()
87
+ channel_group.close().awaitUninterruptibly()
82
88
  end
83
89
 
84
90
  def stop
@@ -91,7 +97,7 @@ module Server
91
97
  end
92
98
 
93
99
  def add_listener(listener)
94
- ::Server::ChannelInitializer::DefaultHandler.add_listener(listener)
100
+ channel_initializer.add_listener(listener)
95
101
  end
96
102
  end
97
103
  # module ServerInstanceMethods
@@ -39,7 +39,7 @@ module Server
39
39
  end
40
40
 
41
41
  def messageReceived(ctx, msg)
42
- log.trace "##{__method} channel: #{ctx.channel}, message: #{msg.inspect}"
42
+ log.trace "##{__method__} channel: #{ctx.channel}, message: #{msg.inspect}"
43
43
  msg&.chomp!
44
44
  log.info "Received message: #{msg}"
45
45
  return super(ctx, msg) unless respond_to?(:handle_message) && @handler.arity == 2
@@ -49,7 +49,7 @@ module Server
49
49
  def handle_message(ctx, message)
50
50
  request = message.to_s.strip
51
51
  response = @handler.call(ctx.channel, request).to_s.chomp
52
- log.debug "response: #{response}"
52
+ log.debug "##{__method__} response: #{response}"
53
53
  ctx.channel.writeAndFlush("#{response}\n")
54
54
  end
55
55
  end
@@ -18,19 +18,16 @@ require_relative 'listenable'
18
18
  # The Server module
19
19
  module Server
20
20
  java_import Java::io.netty.channel.SimpleChannelInboundHandler
21
- java_import Java::io.netty.channel.group.DefaultChannelGroup
22
- java_import Java::io.netty.util.concurrent.GlobalEventExecutor
23
-
24
- # rubocop: disable Style/IfUnlessModifier
25
- unless defined?(::Server::Channels)
26
- Channels = DefaultChannelGroup.new('channels', GlobalEventExecutor::INSTANCE)
27
- end
28
- # rubocop: enable Style/IfUnlessModifier
29
21
 
30
22
  # The ModularHandler class notifies listeners about events.
31
23
  class ModularHandler < SimpleChannelInboundHandler
32
24
  include ::Server::Listenable
33
25
 
26
+ def initialize(channel_group)
27
+ super()
28
+ @channel_group = channel_group
29
+ end
30
+
34
31
  def isSharable
35
32
  true
36
33
  end
@@ -48,8 +45,8 @@ module Server
48
45
  end
49
46
 
50
47
  def channelActive(ctx)
51
- log.trace "##{__method__} channel: #{ctx.channel}"
52
- ::Server::Channels.add(ctx.channel)
48
+ log.info "##{__method__} channel: #{ctx.channel}"
49
+ @channel_group.add(ctx.channel)
53
50
  notify :channel_active, ctx
54
51
  super(ctx)
55
52
  end
@@ -107,10 +104,10 @@ module Server
107
104
  super(ctx, cause) if listeners.nil? || listeners.empty?
108
105
  end
109
106
 
110
- IdentiferTemplate = '#<%<class>s:0x%<id>s>'.freeze
107
+ IdentifierTemplate = '#<%<class>s:0x%<id>s>'.freeze
111
108
 
112
109
  def to_s
113
- format(IdentiferTemplate, class: self.class.name, id: object_id.to_s(16))
110
+ format(IdentifierTemplate, class: self.class.name, id: object_id.to_s(16))
114
111
  end
115
112
  alias inspect to_s
116
113
  end
data/lib/server/server.rb CHANGED
@@ -25,7 +25,7 @@ module Server
25
25
  attr_reader :options
26
26
 
27
27
  def initialize(params = {}, &block)
28
- @options = ::Server::Config::DEFAULTS.merge(params.fetch(:options, {}))
28
+ @options = ::Server.server_config.merge(params.fetch(:options, {}))
29
29
  configure_handlers(&block)
30
30
  end
31
31
 
@@ -12,5 +12,5 @@
12
12
 
13
13
  # The Server module
14
14
  module Server
15
- VERSION = '1.0.4'.freeze
15
+ VERSION = '1.0.7'.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.4
4
+ version: 1.0.7
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-17 00:00:00.000000000 Z
11
+ date: 2022-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement