tcp-server 1.0.1-java → 1.0.4-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 +89 -5
- data/lib/demo_listener.rb +31 -0
- data/lib/server/channel_initializer.rb +9 -13
- data/lib/server/instance_methods.rb +12 -4
- data/lib/server/modular_handler.rb +1 -1
- data/lib/server/server.rb +2 -7
- data/lib/server/shutdown_hook.rb +1 -1
- data/lib/server/version.rb +1 -1
- data/lib/server.rb +2 -16
- data/lib/tcp-server.rb +13 -0
- data/lib/tcp_server.rb +13 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e13c7b958e72b6551472ad5a12389bc88687984b2d17f915f31a34dc2a420e8
|
4
|
+
data.tar.gz: 8682f4628c10fda39dcf7953ce0a31af1947af8507b5fc9ea41593ed8e4e3cba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0535ec8e3b2a0c4d03f3150a1c8f551b2a32a4cf0c387d00b82b1d16f2b75e5fda2111fa8686febd3a36be2acaed68f165d08c99a6fa36a1515dbd4e129e9406
|
7
|
+
data.tar.gz: c2546356d7833043fbc7664afacba069ed21d9b8d5f460a58688f8714bd51dacaca95a60ce6319e3d19c6f54ad05faa57717af087c9e2085c5755b1d50efefe3
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[][license]
|
4
4
|
|
5
|
-
This is a small tcp server for [JRuby].
|
5
|
+
This is a small tcp server for [JRuby] available as a [ruby gem](https://rubygems.org/gems/tcp-server).
|
6
6
|
|
7
7
|
It is based on the [Netty project]. Netty is written in java, but I wanted to write ruby.
|
8
8
|
|
@@ -14,7 +14,7 @@ Follow these instructions to get a tcp server echo program running.
|
|
14
14
|
|
15
15
|
### Docker
|
16
16
|
|
17
|
-
You may run the websocket server in a container.
|
17
|
+
You may run the websocket server in a container. The [`colima`](https://github.com/abiosoft/colima) for a container runtime is recommended.
|
18
18
|
|
19
19
|
```sh
|
20
20
|
colima start
|
@@ -24,7 +24,7 @@ docker-compose up
|
|
24
24
|
Building the image or running the container:
|
25
25
|
|
26
26
|
```sh
|
27
|
-
docker build --
|
27
|
+
docker build --tag tcp-server-jruby .
|
28
28
|
docker run --detach --publish 4000:4000 --name tcp-server-jruby tcp-server-jruby
|
29
29
|
```
|
30
30
|
|
@@ -76,7 +76,7 @@ bundle install
|
|
76
76
|
The entrypoint for the web application service may now be invoked from a command line interface terminal shell.
|
77
77
|
|
78
78
|
```sh
|
79
|
-
bundle exec ./
|
79
|
+
bundle exec ./tcp_server.rb
|
80
80
|
```
|
81
81
|
|
82
82
|
|
@@ -93,6 +93,15 @@ bundle exec rake
|
|
93
93
|
|
94
94
|
To publish the gem after first verifying that the built gem works, execute:
|
95
95
|
|
96
|
+
```sh
|
97
|
+
version=$(ruby -r lib/server/version -I . -e 'puts ::Server::VERSION')
|
98
|
+
git tag --annotate --message "Release ${version}" "${version}-release"
|
99
|
+
git push origin --tags
|
100
|
+
```
|
101
|
+
|
102
|
+
|
103
|
+
Or manually, if necessary:
|
104
|
+
|
96
105
|
```sh
|
97
106
|
bundle exec rake verify
|
98
107
|
bundle exec rake publish
|
@@ -113,7 +122,82 @@ bundle exec rake clean clobber
|
|
113
122
|
Here is a bird's-eye view of the project layout.
|
114
123
|
|
115
124
|
```sh
|
116
|
-
# date && tree
|
125
|
+
# date && tree -I "logs|vendor|tmp"
|
126
|
+
Thu Jun 16 00:03:23 CDT 2022
|
127
|
+
.
|
128
|
+
├── Dockerfile
|
129
|
+
├── Gemfile
|
130
|
+
├── Gemfile.lock
|
131
|
+
├── LICENSE
|
132
|
+
├── README.md
|
133
|
+
├── Rakefile
|
134
|
+
├── docker-compose.yaml
|
135
|
+
├── exe
|
136
|
+
│ └── tcp_server
|
137
|
+
├── lib
|
138
|
+
│ ├── client.rb
|
139
|
+
│ ├── demo_listener.rb
|
140
|
+
│ ├── log.rb
|
141
|
+
│ ├── server
|
142
|
+
│ │ ├── argument_parser.rb
|
143
|
+
│ │ ├── channel_initializer.rb
|
144
|
+
│ │ ├── config.rb
|
145
|
+
│ │ ├── instance_methods.rb
|
146
|
+
│ │ ├── listenable.rb
|
147
|
+
│ │ ├── message_handler.rb
|
148
|
+
│ │ ├── modular_handler.rb
|
149
|
+
│ │ ├── server.rb
|
150
|
+
│ │ ├── shutdown_hook.rb
|
151
|
+
│ │ └── version.rb
|
152
|
+
│ ├── server.rb
|
153
|
+
│ ├── tcp-server.rb
|
154
|
+
│ └── tcp_server.rb
|
155
|
+
├── spec
|
156
|
+
│ ├── spec_helper.rb
|
157
|
+
│ ├── test_spec.rb
|
158
|
+
│ └── verify
|
159
|
+
│ └── verify_spec.rb
|
160
|
+
├── tcp-server-1.0.2-java.gem
|
161
|
+
├── tcp-server-jruby.gemspec
|
162
|
+
├── tcp_server.png
|
163
|
+
└── tcp_server.rb
|
164
|
+
|
165
|
+
5 directories, 31 files
|
166
|
+
```
|
167
|
+
|
168
|
+
## CI linting
|
169
|
+
|
170
|
+
Use the GitLab CI Linting API to validate the syntax of a CI definition file.
|
171
|
+
|
172
|
+
```sh
|
173
|
+
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
|
+
```
|
175
|
+
|
176
|
+
## CI configuration
|
177
|
+
|
178
|
+
Generate a deploy key.
|
179
|
+
|
180
|
+
```sh
|
181
|
+
ssh-keygen -t ed25519 -C deploy_key
|
182
|
+
```
|
183
|
+
|
184
|
+
Use the GitLab Project-level Variables API to add the deploy key as a ssh private key variable.
|
185
|
+
|
186
|
+
```sh
|
187
|
+
project_path="nelsnelson/$(basename $(pwd))"
|
188
|
+
|
189
|
+
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
|
+
|
191
|
+
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
|
+
|
193
|
+
# 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
|
195
|
+
```
|
196
|
+
|
197
|
+
Use the Deploy keys API to add a the public deploy key as a deploy key for the project.
|
198
|
+
|
199
|
+
```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
|
117
201
|
```
|
118
202
|
|
119
203
|
[license]: https://gitlab.com/nelsnelson/tcp-server-jruby/blob/master/LICENSE
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: false
|
3
|
+
|
4
|
+
# -*- mode: ruby -*-
|
5
|
+
# vi: set ft=ruby :
|
6
|
+
|
7
|
+
# =begin
|
8
|
+
#
|
9
|
+
# Copyright Nels Nelson 2016-2022 but freely usable (see license)
|
10
|
+
#
|
11
|
+
# =end
|
12
|
+
|
13
|
+
# The Server module
|
14
|
+
module Server
|
15
|
+
# The Demo class
|
16
|
+
class Demo
|
17
|
+
def channel_active(ctx)
|
18
|
+
::Server.log.info "Channel active: #{ctx.channel}"
|
19
|
+
response = 'Hello, world!'
|
20
|
+
log.trace "Sending response: #{response.inspect}"
|
21
|
+
ctx.channel.writeAndFlush("#{response}\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def exception_caught(_ctx, cause)
|
25
|
+
::Server.log.error "Exception caught: #{cause}"
|
26
|
+
cause.backtrace.each { |t| ::Server.log.error t }
|
27
|
+
ctx.close()
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
# module Server
|
@@ -36,17 +36,17 @@ module Server
|
|
36
36
|
# constant definitions could not be used.
|
37
37
|
Decoder = StringDecoder.new
|
38
38
|
Encoder = StringEncoder.new
|
39
|
-
attr_accessor :
|
39
|
+
attr_accessor :user_handlers
|
40
40
|
attr_reader :options
|
41
41
|
|
42
42
|
def initialize(options = {})
|
43
43
|
super()
|
44
44
|
@options = options
|
45
|
-
@
|
45
|
+
@user_handlers = []
|
46
46
|
end
|
47
47
|
|
48
48
|
def <<(handler)
|
49
|
-
@
|
49
|
+
@user_handlers << handler
|
50
50
|
end
|
51
51
|
|
52
52
|
def initChannel(channel)
|
@@ -64,7 +64,7 @@ module Server
|
|
64
64
|
protected
|
65
65
|
|
66
66
|
def add_user_handlers(pipeline)
|
67
|
-
@
|
67
|
+
@user_handlers.each do |handler|
|
68
68
|
case handler
|
69
69
|
when Class then pipeline.addLast(handler.new)
|
70
70
|
when Proc then pipeline.addLast(Server::MessageHandler.new(&handler))
|
@@ -93,23 +93,19 @@ module Server
|
|
93
93
|
|
94
94
|
def ssl_handler(channel)
|
95
95
|
handler = ssl_handler_instance(channel)
|
96
|
-
handler.handshake_future.addListener(
|
96
|
+
handler.handshake_future.addListener(ssl_handshake_future_listener)
|
97
97
|
handler
|
98
98
|
end
|
99
99
|
|
100
|
-
|
101
|
-
|
102
|
-
include FutureListener
|
103
|
-
# @Override
|
104
|
-
#
|
105
|
-
# public void operationComplete(Future<Channel> future) throws Exception
|
106
|
-
def operationComplete(future)
|
100
|
+
def ssl_handshake_future_listener(listener = Object.new.extend(FutureListener))
|
101
|
+
listener.define_singleton_method(:operationComplete) do |future|
|
107
102
|
raise future.cause unless future.success?
|
108
103
|
session = future.now.pipeline.get('SslHandler#0')&.engine&.session
|
109
104
|
::Server.log.info "Channel protocol: #{session.protocol}, cipher suite: #{session.cipher_suite}"
|
110
105
|
rescue StandardError => e
|
111
|
-
::Server.log.warn e.message
|
106
|
+
::Server.log.warn "Error handling operation complete event: #{e.message}"
|
112
107
|
end
|
108
|
+
listener
|
113
109
|
end
|
114
110
|
|
115
111
|
def ssl_engine(ssl_ctx)
|
@@ -27,14 +27,14 @@ module Server
|
|
27
27
|
# The InstanceMethods module
|
28
28
|
module InstanceMethods
|
29
29
|
def configure_handlers(&block)
|
30
|
-
|
30
|
+
add_listener(self)
|
31
31
|
channel_initializer << block if block_given?
|
32
32
|
end
|
33
33
|
|
34
34
|
def bootstrap
|
35
35
|
@bootstrap = ServerBootstrap.new
|
36
36
|
@bootstrap.group(boss_group, worker_group)
|
37
|
-
@bootstrap.channel(
|
37
|
+
@bootstrap.channel(Server::CHANNEL_TYPE)
|
38
38
|
@bootstrap.option(ChannelOption::SO_BACKLOG, 100.to_java(java.lang.Integer))
|
39
39
|
@bootstrap.handler(logging_handler) if options[:log_requests]
|
40
40
|
@bootstrap.childHandler(channel_initializer)
|
@@ -71,8 +71,7 @@ module Server
|
|
71
71
|
rescue java.net.SocketException => e
|
72
72
|
raise "Socket error: #{e.message}: #{options[:host]}:#{port}"
|
73
73
|
ensure
|
74
|
-
|
75
|
-
worker_group&.shutdownGracefully()
|
74
|
+
stop
|
76
75
|
end
|
77
76
|
# rubocop: enable Metrics/AbcSize
|
78
77
|
# rubocop: enable Metrics/MethodLength
|
@@ -82,9 +81,18 @@ module Server
|
|
82
81
|
::Server::Channels.close().awaitUninterruptibly()
|
83
82
|
end
|
84
83
|
|
84
|
+
def stop
|
85
|
+
boss_group&.shutdownGracefully()
|
86
|
+
worker_group&.shutdownGracefully()
|
87
|
+
end
|
88
|
+
|
85
89
|
def <<(handler)
|
86
90
|
channel_initializer << handler
|
87
91
|
end
|
92
|
+
|
93
|
+
def add_listener(listener)
|
94
|
+
::Server::ChannelInitializer::DefaultHandler.add_listener(listener)
|
95
|
+
end
|
88
96
|
end
|
89
97
|
# module ServerInstanceMethods
|
90
98
|
end
|
@@ -104,7 +104,7 @@ module Server
|
|
104
104
|
::Server.log.warn "##{__method__} channel: #{ctx.channel}, cause: #{cause.message}"
|
105
105
|
cause.backtrace.each { |t| ::Server.log.error t }
|
106
106
|
listeners = notify :exception_caught, ctx, cause
|
107
|
-
super(ctx, cause) if listeners.empty?
|
107
|
+
super(ctx, cause) if listeners.nil? || listeners.empty?
|
108
108
|
end
|
109
109
|
|
110
110
|
IdentiferTemplate = '#<%<class>s:0x%<id>s>'.freeze
|
data/lib/server/server.rb
CHANGED
@@ -18,15 +18,14 @@ require_relative 'listenable'
|
|
18
18
|
|
19
19
|
# The Server module
|
20
20
|
module Server
|
21
|
-
CHANNEL_TYPE = Java::io.netty.channel.socket.nio.NioServerSocketChannel.java_class
|
22
|
-
|
23
21
|
# The Server class sets up the netty server.
|
24
22
|
class Server
|
23
|
+
CHANNEL_TYPE = Java::io.netty.channel.socket.nio.NioServerSocketChannel.java_class
|
25
24
|
include ::Server::InstanceMethods
|
26
25
|
attr_reader :options
|
27
26
|
|
28
27
|
def initialize(params = {}, &block)
|
29
|
-
@options = params.fetch(:options, {})
|
28
|
+
@options = ::Server::Config::DEFAULTS.merge(params.fetch(:options, {}))
|
30
29
|
configure_handlers(&block)
|
31
30
|
end
|
32
31
|
|
@@ -40,10 +39,6 @@ module Server
|
|
40
39
|
log.debug "Sending response: #{response.inspect}"
|
41
40
|
ctx.writeAndFlush("#{response}\n")
|
42
41
|
end
|
43
|
-
|
44
|
-
def add_listener(listener)
|
45
|
-
::Server::ChannelInitializer::DefaultHandler.add_listener(listener)
|
46
|
-
end
|
47
42
|
# rubocop: enable Metrics/AbcSize
|
48
43
|
end
|
49
44
|
# class Server
|
data/lib/server/shutdown_hook.rb
CHANGED
data/lib/server/version.rb
CHANGED
data/lib/server.rb
CHANGED
@@ -20,22 +20,6 @@ require_relative 'server/server'
|
|
20
20
|
module Server
|
21
21
|
InterruptTemplate = "\r%<class>s".freeze
|
22
22
|
|
23
|
-
# The Demo class
|
24
|
-
class Demo
|
25
|
-
def channel_active(ctx)
|
26
|
-
::Server.log.info "Channel active: #{ctx.channel}"
|
27
|
-
response = 'Hello, world!'
|
28
|
-
log.trace "Sending response: #{response.inspect}"
|
29
|
-
ctx.channel.writeAndFlush("#{response}\n")
|
30
|
-
end
|
31
|
-
|
32
|
-
def exception_caught(_ctx, cause)
|
33
|
-
::Server.log.error "Exception caught: #{cause}"
|
34
|
-
cause.backtrace.each { |t| ::Server.log.error t }
|
35
|
-
ctx.close()
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
23
|
# rubocop: disable Metrics/AbcSize
|
40
24
|
# rubocop: disable Metrics/MethodLength
|
41
25
|
def main(args = parse_arguments)
|
@@ -56,4 +40,6 @@ module Server
|
|
56
40
|
end
|
57
41
|
# module Server
|
58
42
|
|
43
|
+
require_relative 'demo_listener'
|
44
|
+
|
59
45
|
Object.new.extend(::Server).main if $PROGRAM_NAME == __FILE__
|
data/lib/tcp-server.rb
ADDED
data/lib/tcp_server.rb
ADDED
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.4
|
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-06-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -107,6 +107,7 @@ files:
|
|
107
107
|
- Rakefile
|
108
108
|
- exe/tcp_server
|
109
109
|
- lib/client.rb
|
110
|
+
- lib/demo_listener.rb
|
110
111
|
- lib/log.rb
|
111
112
|
- lib/server.rb
|
112
113
|
- lib/server/argument_parser.rb
|
@@ -119,6 +120,8 @@ files:
|
|
119
120
|
- lib/server/server.rb
|
120
121
|
- lib/server/shutdown_hook.rb
|
121
122
|
- lib/server/version.rb
|
123
|
+
- lib/tcp-server.rb
|
124
|
+
- lib/tcp_server.rb
|
122
125
|
homepage: https://rubygems.org/gems/tcp-server-jruby
|
123
126
|
licenses:
|
124
127
|
- MIT
|
@@ -144,5 +147,5 @@ requirements: []
|
|
144
147
|
rubygems_version: 3.2.29
|
145
148
|
signing_key:
|
146
149
|
specification_version: 4
|
147
|
-
summary: Server for JRuby packaged as a gem.
|
150
|
+
summary: TCP Server for JRuby packaged as a gem.
|
148
151
|
test_files: []
|