io_request 2.1.0 → 2.4.1
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/lib/io_request.rb +7 -1
- data/lib/io_request/client.rb +43 -30
- data/lib/io_request/connection/ssl_sockets.rb +37 -16
- data/lib/io_request/message.rb +2 -2
- data/lib/io_request/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: 987e7926f719a3479bf88cc0bdc76701edbc35e3d77d3c25d0f6ff8009be971c
|
4
|
+
data.tar.gz: 7ad37eab2d0718cdd100a9f16c7f272e538e39ae97939aa3e5858dbeb5f05413
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '089626846b0ce20d3cc9ae7c7dfeb9c4b457de3f3500cd75b7456a112e6f1f1304763a6288c4349b220c7b69c24ef5e4b5f34124235359184b5a7e5f34e50b66'
|
7
|
+
data.tar.gz: 71e6692045f5752e5bd5eda60eeea755a8ac542f465ed6a19804569f5816a3599b615986a81793a8a4248a22000696ac4a362160efc246236c701beb2dcc0383
|
data/lib/io_request.rb
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Main module.
|
4
|
-
module IORequest
|
4
|
+
module IORequest
|
5
|
+
# Client received message of zero size.
|
6
|
+
class ZeroSizeMessageError < RuntimeError; end
|
7
|
+
|
8
|
+
# Authorization failed.
|
9
|
+
class AuthorizationFailureError < RuntimeError; end
|
10
|
+
end
|
5
11
|
|
6
12
|
require_relative 'io_request/version'
|
7
13
|
require_relative 'io_request/logging'
|
data/lib/io_request/client.rb
CHANGED
@@ -45,15 +45,17 @@ module IORequest
|
|
45
45
|
# @param r [IO] object to read from.
|
46
46
|
# @param w [IO] object to write to.
|
47
47
|
# @param rw [IO] read-write object (replaces `r` and `w` arguments).
|
48
|
+
# @return [Object] data from {Authorizer}
|
48
49
|
def open(read: nil, write: nil, read_write: nil)
|
49
50
|
@io_r = read_write || read
|
50
51
|
@io_w = read_write || write
|
51
52
|
|
52
53
|
IORequest.logger.debug(prog_name) { 'Starting connection' }
|
53
54
|
|
54
|
-
authorization
|
55
|
+
auth_data = authorization
|
55
56
|
@open = true
|
56
57
|
@data_transition_thread = in_thread(name: 'connection') { data_transition_loop }
|
58
|
+
auth_data
|
57
59
|
end
|
58
60
|
|
59
61
|
def open?
|
@@ -63,15 +65,21 @@ module IORequest
|
|
63
65
|
# Close connection.
|
64
66
|
def close
|
65
67
|
close_internal
|
68
|
+
|
66
69
|
join_threads
|
67
|
-
@open = false
|
68
70
|
end
|
69
71
|
|
70
72
|
# @yieldparam [Hash]
|
71
73
|
# @yieldreturn [Hash]
|
72
|
-
def
|
73
|
-
IORequest.logger.debug(prog_name) { 'Saved
|
74
|
-
@
|
74
|
+
def on_request(&block)
|
75
|
+
IORequest.logger.debug(prog_name) { 'Saved on_request block' }
|
76
|
+
@on_request = block
|
77
|
+
end
|
78
|
+
alias respond on_request
|
79
|
+
|
80
|
+
def on_close(&block)
|
81
|
+
IORequest.logger.debug(prog_name) { 'Saved on_close block' }
|
82
|
+
@on_close = block
|
75
83
|
end
|
76
84
|
|
77
85
|
# If callback block is provided, request will be sent asynchroniously.
|
@@ -96,50 +104,52 @@ module IORequest
|
|
96
104
|
|
97
105
|
def close_internal
|
98
106
|
IORequest.logger.debug(prog_name) { 'Closing connection' }
|
99
|
-
|
100
|
-
send_zero_size_request
|
101
|
-
rescue StandardError
|
102
|
-
IORequest.logger.debug(prog_name) { 'Failed to send zero-sized message. Closing anyway' }
|
103
|
-
end
|
104
|
-
stop_data_transition
|
107
|
+
send_zero_size_request
|
105
108
|
close_io
|
106
|
-
end
|
107
|
-
|
108
|
-
def stop_data_transition
|
109
|
-
return unless defined?(@data_transition_thread) && !@data_transition_thread.nil?
|
110
|
-
|
111
|
-
IORequest.logger.debug(prog_name) { 'Killing data transition thread' }
|
112
|
-
@data_transition_thread.kill
|
113
109
|
@data_transition_thread = nil
|
110
|
+
@open = false
|
111
|
+
@on_close&.call if defined?(@on_close)
|
114
112
|
end
|
115
113
|
|
116
114
|
def close_io
|
117
|
-
|
118
|
-
|
119
|
-
|
115
|
+
begin
|
116
|
+
@io_r&.close
|
117
|
+
rescue StandardError => e
|
118
|
+
IORequest.logger.debug "Failed to close read IO: #{e}"
|
119
|
+
end
|
120
|
+
begin
|
121
|
+
@io_w&.close
|
122
|
+
rescue StandardError => e
|
123
|
+
IORequest.logger.debug "Failed to close write IO: #{e}"
|
124
|
+
end
|
125
|
+
IORequest.logger.debug(prog_name) { 'Closed IO streams' }
|
120
126
|
end
|
121
127
|
|
122
128
|
def authorization
|
123
|
-
auth_successful =
|
129
|
+
auth_successful = false
|
130
|
+
data = nil
|
131
|
+
@mutex_r.synchronize do
|
124
132
|
@mutex_w.synchronize do
|
125
133
|
IORequest.logger.debug(prog_name) { 'Authorizing new client' }
|
126
|
-
@authorizer.authorize(@io_r, @io_w)
|
134
|
+
auth_successful = @authorizer.authorize(@io_r, @io_w)
|
135
|
+
data = @authorizer.data
|
127
136
|
end
|
128
137
|
end
|
129
|
-
unless auth_successful
|
130
|
-
IORequest.logger.debug(prog_name) { 'Authorization failed' }
|
131
|
-
raise 'Authorization failed'
|
132
|
-
end
|
138
|
+
raise AuthorizationFailureError unless auth_successful
|
133
139
|
|
134
|
-
IORequest.logger.debug(prog_name) { "New client authorized with data #{
|
140
|
+
IORequest.logger.debug(prog_name) { "New client authorized with data #{data}" }
|
141
|
+
data
|
135
142
|
end
|
136
143
|
|
137
144
|
def data_transition_loop
|
138
145
|
IORequest.logger.debug(prog_name) { 'Starting data transition loop' }
|
139
146
|
loop do
|
140
147
|
data_transition_iteration
|
148
|
+
rescue ZeroSizeMessageError
|
149
|
+
IORequest.logger.debug(prog_name) { 'Connection was closed from the other side' }
|
150
|
+
break
|
141
151
|
rescue StandardError => e
|
142
|
-
IORequest.logger.debug(prog_name) { "Data transition
|
152
|
+
IORequest.logger.debug(prog_name) { "Data transition unknown error: #{e}" }
|
143
153
|
break
|
144
154
|
end
|
145
155
|
close_internal
|
@@ -156,7 +166,8 @@ module IORequest
|
|
156
166
|
end
|
157
167
|
|
158
168
|
def handle_request(message)
|
159
|
-
data =
|
169
|
+
data = {}
|
170
|
+
data = @on_request&.call(message.data) if defined?(@on_request)
|
160
171
|
response = Message.new(data, type: :response, to: message.id)
|
161
172
|
send_response(response)
|
162
173
|
end
|
@@ -180,6 +191,8 @@ module IORequest
|
|
180
191
|
IORequest.logger.debug(prog_name) { 'Sending zero size message' }
|
181
192
|
@io_w.write([0].pack('S'))
|
182
193
|
end
|
194
|
+
rescue StandardError => e
|
195
|
+
IORequest.logger.debug(prog_name) { "Failed to send zero-sized message(#{e})" }
|
183
196
|
end
|
184
197
|
|
185
198
|
def send_request_and_wait_for_response(request)
|
@@ -32,11 +32,20 @@ module IORequest
|
|
32
32
|
end
|
33
33
|
|
34
34
|
# @return [Array<IORequest::Client>]
|
35
|
-
|
35
|
+
def clients
|
36
|
+
@clients_data.keys
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param client [IORequest::Client]
|
40
|
+
# @return [Hash, nil] you are free to store anything you want in hash.
|
41
|
+
# Only field you will find in it is `auth` with authenticator data.
|
42
|
+
def data(client)
|
43
|
+
@clients_data[client]
|
44
|
+
end
|
36
45
|
|
37
46
|
# Start server.
|
38
47
|
def start
|
39
|
-
@
|
48
|
+
@clients_data = {}
|
40
49
|
|
41
50
|
@server = TCPServer.new(@port)
|
42
51
|
|
@@ -45,8 +54,8 @@ module IORequest
|
|
45
54
|
|
46
55
|
# Fully stop server.
|
47
56
|
def stop
|
48
|
-
|
49
|
-
@
|
57
|
+
clients.each(&:close)
|
58
|
+
@clients_data.clear
|
50
59
|
|
51
60
|
@server.close
|
52
61
|
@server = nil
|
@@ -68,7 +77,7 @@ module IORequest
|
|
68
77
|
while (socket = @server.accept)
|
69
78
|
handle_socket(socket)
|
70
79
|
end
|
71
|
-
rescue
|
80
|
+
rescue StandardError
|
72
81
|
stop
|
73
82
|
end
|
74
83
|
|
@@ -76,17 +85,21 @@ module IORequest
|
|
76
85
|
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, @ctx)
|
77
86
|
ssl_socket.accept
|
78
87
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
88
|
+
handle_client(ssl_socket, IORequest::Client.new(authorizer: @authorizer))
|
89
|
+
rescue StandardError => e
|
90
|
+
IORequest.logger.warn "Unknown error while handling sockets: #{e}"
|
91
|
+
end
|
92
|
+
|
93
|
+
def handle_client(ssl_socket, client)
|
94
|
+
auth_data = client.open read_write: ssl_socket
|
95
|
+
client.on_request { |data| @requests_handler.call(data, client) }
|
96
|
+
@clients_data[client] = { auth: auth_data }
|
97
|
+
client.on_close do
|
98
|
+
@clients_data.select! { |c, _d| c.open? }
|
87
99
|
end
|
88
100
|
rescue StandardError => e
|
89
|
-
IORequest.
|
101
|
+
IORequest.logger.debug "Failed to open client: #{e}"
|
102
|
+
ssl_socket.close
|
90
103
|
end
|
91
104
|
end
|
92
105
|
|
@@ -105,9 +118,15 @@ module IORequest
|
|
105
118
|
@authorizer = authorizer
|
106
119
|
@requests_handler = requests_handler
|
107
120
|
|
121
|
+
@client = nil
|
122
|
+
|
108
123
|
initialize_ssl_context(certificate, key)
|
109
124
|
end
|
110
125
|
|
126
|
+
def connected?
|
127
|
+
!@client.nil?
|
128
|
+
end
|
129
|
+
|
111
130
|
# Connect to server.
|
112
131
|
# @param host [String] host of server.
|
113
132
|
# @param port [Integer] port of server.
|
@@ -121,9 +140,11 @@ module IORequest
|
|
121
140
|
@client = IORequest::Client.new authorizer: @authorizer
|
122
141
|
begin
|
123
142
|
@client.open read_write: ssl_socket
|
124
|
-
@client.
|
143
|
+
@client.on_request(&@requests_handler)
|
144
|
+
@client.on_close do
|
145
|
+
@client = nil
|
146
|
+
end
|
125
147
|
rescue StandardError
|
126
|
-
IORequest.debug "Failed to open client: #{e}"
|
127
148
|
ssl_socket.close
|
128
149
|
@client = nil
|
129
150
|
end
|
data/lib/io_request/message.rb
CHANGED
@@ -81,8 +81,8 @@ module IORequest
|
|
81
81
|
# @param io_r [:read]
|
82
82
|
# @return [Message]
|
83
83
|
def self.read_from(io_r)
|
84
|
-
size = io_r.read(2)
|
85
|
-
raise
|
84
|
+
size = io_r.read(2)&.unpack1('S') || 0
|
85
|
+
raise ZeroSizeMessageError if size.zero?
|
86
86
|
|
87
87
|
json_string = io_r.read(size).unpack1("a#{size}")
|
88
88
|
msg = JSON.parse(json_string, symbolize_names: true)
|
data/lib/io_request/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: io_request
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1
|
4
|
+
version: 2.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Fizvlad
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-07-
|
11
|
+
date: 2020-07-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|