io_request 2.3.0 → 2.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/io_request.rb +6 -0
- data/lib/io_request/client.rb +31 -17
- data/lib/io_request/connection/ssl_sockets.rb +36 -17
- 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: 351ec9fd506f974e564ef51c452e47c6bb4a113022b0ec04e708245cd70fe12c
|
4
|
+
data.tar.gz: 7244b2989c36d827d86ef16aa84920e8f91bae6bf9009f4d503f2aaf6f58f164
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 549415e26de1d5919b1f97a8cfa289e07b5510ae8d54640079a213d4fa93e395e55a804d019c8342d8a6c97c1ee1d033beea534fb9d33814431a35eb21d72501
|
7
|
+
data.tar.gz: e1f0d467271a09288471cc1c3251fc6719b7d54e2cbe1f50a044cf118616a05bf2c989bc6b6ad5c70d82d71cdb74e8cac452c01be107e9181c3021d06831a2f4
|
data/lib/io_request.rb
CHANGED
@@ -4,6 +4,12 @@
|
|
4
4
|
module IORequest
|
5
5
|
# Client received message of zero size.
|
6
6
|
class ZeroSizeMessageError < RuntimeError; end
|
7
|
+
|
8
|
+
# Authorization failed.
|
9
|
+
class AuthorizationFailureError < RuntimeError; end
|
10
|
+
|
11
|
+
# Request timed out.
|
12
|
+
class RequestTimeoutError < RuntimeError; end
|
7
13
|
end
|
8
14
|
|
9
15
|
require_relative 'io_request/version'
|
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?
|
@@ -75,6 +77,7 @@ module IORequest
|
|
75
77
|
end
|
76
78
|
alias respond on_request
|
77
79
|
|
80
|
+
# Code to execute after connection is closed.
|
78
81
|
def on_close(&block)
|
79
82
|
IORequest.logger.debug(prog_name) { 'Saved on_close block' }
|
80
83
|
@on_close = block
|
@@ -82,17 +85,18 @@ module IORequest
|
|
82
85
|
|
83
86
|
# If callback block is provided, request will be sent asynchroniously.
|
84
87
|
# @param data [Hash]
|
85
|
-
|
88
|
+
# @param timeout [Integer] timeout in seconds.
|
89
|
+
def request(data, timeout: nil, &callback)
|
86
90
|
message = Message.new(data, type: :request)
|
87
91
|
|
88
92
|
if block_given?
|
89
93
|
# Async execution of request
|
90
94
|
in_thread(callback, name: 'requesting') do |cb|
|
91
|
-
cb.call(send_request_and_wait_for_response(message).data)
|
95
|
+
cb.call(send_request_and_wait_for_response(message, timeout).data)
|
92
96
|
end
|
93
97
|
nil
|
94
98
|
else
|
95
|
-
send_request_and_wait_for_response(message).data
|
99
|
+
send_request_and_wait_for_response(message, timeout).data
|
96
100
|
end
|
97
101
|
end
|
98
102
|
|
@@ -124,18 +128,19 @@ module IORequest
|
|
124
128
|
end
|
125
129
|
|
126
130
|
def authorization
|
127
|
-
auth_successful =
|
131
|
+
auth_successful = false
|
132
|
+
data = nil
|
133
|
+
@mutex_r.synchronize do
|
128
134
|
@mutex_w.synchronize do
|
129
135
|
IORequest.logger.debug(prog_name) { 'Authorizing new client' }
|
130
|
-
@authorizer.authorize(@io_r, @io_w)
|
136
|
+
auth_successful = @authorizer.authorize(@io_r, @io_w)
|
137
|
+
data = @authorizer.data
|
131
138
|
end
|
132
139
|
end
|
133
|
-
unless auth_successful
|
134
|
-
IORequest.logger.debug(prog_name) { 'Authorization failed' }
|
135
|
-
raise 'Authorization failed'
|
136
|
-
end
|
140
|
+
raise AuthorizationFailureError unless auth_successful
|
137
141
|
|
138
|
-
IORequest.logger.debug(prog_name) { "New client authorized with data #{
|
142
|
+
IORequest.logger.debug(prog_name) { "New client authorized with data #{data}" }
|
143
|
+
data
|
139
144
|
end
|
140
145
|
|
141
146
|
def data_transition_loop
|
@@ -179,7 +184,11 @@ module IORequest
|
|
179
184
|
def send_response(response)
|
180
185
|
@mutex_w.synchronize do
|
181
186
|
IORequest.logger.debug(prog_name) { "Sending response: #{response}" }
|
182
|
-
|
187
|
+
begin
|
188
|
+
response.write_to(@io_w)
|
189
|
+
rescue IOError => e
|
190
|
+
IORequest.logger.debug(prog_name) { "Failed to write response message: #{e}" }
|
191
|
+
end
|
183
192
|
end
|
184
193
|
end
|
185
194
|
|
@@ -192,21 +201,26 @@ module IORequest
|
|
192
201
|
IORequest.logger.debug(prog_name) { "Failed to send zero-sized message(#{e})" }
|
193
202
|
end
|
194
203
|
|
195
|
-
def send_request_and_wait_for_response(request)
|
204
|
+
def send_request_and_wait_for_response(request, timeout)
|
196
205
|
@mutex_w.synchronize do
|
197
206
|
IORequest.logger.debug(prog_name) { "Sending message: #{request}" }
|
198
207
|
request.write_to(@io_w)
|
199
208
|
end
|
200
|
-
wait_for_response(request)
|
209
|
+
wait_for_response(request, timeout)
|
201
210
|
end
|
202
211
|
|
203
|
-
def wait_for_response(request)
|
212
|
+
def wait_for_response(request, timeout)
|
204
213
|
IORequest.logger.debug(prog_name) { "Waiting for response for #{request}" }
|
214
|
+
waiting_start_time = Time.now
|
205
215
|
@responses_access_mutex.synchronize do
|
206
216
|
response = nil
|
207
217
|
until response
|
208
|
-
@responses_access_cv.wait(@responses_access_mutex)
|
209
|
-
|
218
|
+
@responses_access_cv.wait(@responses_access_mutex, 1)
|
219
|
+
if @responses_access_mutex.owned?
|
220
|
+
# NOTE: Only accessing responses hash if thread owns access mutex
|
221
|
+
response = @responses.delete(request.id.to_s)
|
222
|
+
end
|
223
|
+
raise RequestTimeoutError if timeout && (Time.now - waiting_start_time >= timeout)
|
210
224
|
end
|
211
225
|
IORequest.logger.debug(prog_name) { "Found response: #{response}" }
|
212
226
|
response
|
@@ -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,20 +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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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? }
|
90
99
|
end
|
91
100
|
rescue StandardError => e
|
92
|
-
IORequest.
|
101
|
+
IORequest.logger.debug "Failed to open client: #{e}"
|
102
|
+
ssl_socket.close
|
93
103
|
end
|
94
104
|
end
|
95
105
|
|
@@ -108,9 +118,15 @@ module IORequest
|
|
108
118
|
@authorizer = authorizer
|
109
119
|
@requests_handler = requests_handler
|
110
120
|
|
121
|
+
@client = nil
|
122
|
+
|
111
123
|
initialize_ssl_context(certificate, key)
|
112
124
|
end
|
113
125
|
|
126
|
+
def connected?
|
127
|
+
!@client.nil?
|
128
|
+
end
|
129
|
+
|
114
130
|
# Connect to server.
|
115
131
|
# @param host [String] host of server.
|
116
132
|
# @param port [Integer] port of server.
|
@@ -125,6 +141,9 @@ module IORequest
|
|
125
141
|
begin
|
126
142
|
@client.open read_write: ssl_socket
|
127
143
|
@client.on_request(&@requests_handler)
|
144
|
+
@client.on_close do
|
145
|
+
@client = nil
|
146
|
+
end
|
128
147
|
rescue StandardError
|
129
148
|
ssl_socket.close
|
130
149
|
@client = nil
|
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.
|
4
|
+
version: 2.5.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-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|