client_for_poslynx 0.9.0 → 1.0.0.pre
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 +8 -8
- data/README.md +172 -147
- data/examples/em_protocol_example.rb +82 -0
- data/examples/em_session_basic_example.rb +85 -0
- data/examples/em_session_interrupt_example.rb +155 -0
- data/lib/client_for_poslynx/data/requests/abstract_request.rb +6 -0
- data/lib/client_for_poslynx/net.rb +2 -1
- data/lib/client_for_poslynx/net/em_connector.rb +344 -0
- data/lib/client_for_poslynx/net/em_connector/callback_map.rb +50 -0
- data/lib/client_for_poslynx/net/em_connector/connection_handler.rb +14 -0
- data/lib/client_for_poslynx/net/em_connector/connector_state.rb +24 -0
- data/lib/client_for_poslynx/net/em_connector/event_dispatcher.rb +66 -0
- data/lib/client_for_poslynx/net/em_connector/handles_connection.rb +57 -0
- data/lib/client_for_poslynx/net/em_connector/request_call.rb +27 -0
- data/lib/client_for_poslynx/net/em_protocol.rb +1 -1
- data/lib/client_for_poslynx/net/em_session.rb +250 -0
- data/lib/client_for_poslynx/version.rb +1 -1
- data/spec/client_for_poslynx/net/em_connector_spec.rb +624 -0
- data/spec/client_for_poslynx/net/em_session_spec.rb +313 -0
- metadata +19 -8
- data/lib/client_for_poslynx/net/structured_client.rb +0 -104
- data/lib/client_for_poslynx/net/structured_client/em_connection.rb +0 -72
- data/spec/client_for_poslynx/net/structured_client_spec.rb +0 -118
@@ -0,0 +1,313 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
module ClientForPoslynx
|
6
|
+
|
7
|
+
describe Net::EM_Session do
|
8
|
+
subject {
|
9
|
+
described_class.new( connector, em_system: em_system )
|
10
|
+
}
|
11
|
+
let( :connector ) { double(
|
12
|
+
:connector,
|
13
|
+
request_pending?: false,
|
14
|
+
latest_request: nil,
|
15
|
+
) }
|
16
|
+
let( :em_system ) { double(:em_system) }
|
17
|
+
|
18
|
+
it "allows making a request and returning the response" do
|
19
|
+
expect( connector ).to receive( :connect ) do |opts|
|
20
|
+
opts[:on_success].call
|
21
|
+
end
|
22
|
+
allow( connector ).to receive( :send_request ) do |data, opts|
|
23
|
+
opts[:on_response].call :the_response
|
24
|
+
end
|
25
|
+
|
26
|
+
response = nil
|
27
|
+
subject.execute do |s|
|
28
|
+
response = s.request( :the_request_data )
|
29
|
+
end
|
30
|
+
|
31
|
+
expect( response ).to eq( :the_response )
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raises an exception when making a request with an initial connection failure" do
|
35
|
+
expect( connector ).to receive( :connect ) do |opts|
|
36
|
+
opts[:on_failure].call
|
37
|
+
end
|
38
|
+
|
39
|
+
exception = nil
|
40
|
+
subject.execute do |s|
|
41
|
+
begin
|
42
|
+
s.request( :the_request_data )
|
43
|
+
rescue => ex
|
44
|
+
exception = ex
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
expect( exception ).to be_kind_of( Net::EM_Session::RequestError )
|
49
|
+
end
|
50
|
+
|
51
|
+
it "raises an exception when making a request that fails" do
|
52
|
+
expect( connector ).to receive( :connect ) do |opts|
|
53
|
+
opts[:on_success].call
|
54
|
+
end
|
55
|
+
allow( connector ).to receive( :send_request ) do |data, opts|
|
56
|
+
opts[:on_failure].call
|
57
|
+
end
|
58
|
+
|
59
|
+
exception = nil
|
60
|
+
subject.execute do |s|
|
61
|
+
begin
|
62
|
+
s.request( :the_request_data )
|
63
|
+
rescue => ex
|
64
|
+
exception = ex
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
expect( exception ).to be_kind_of( Net::EM_Session::RequestError )
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when an existing pin pad reset request is pending" do
|
72
|
+
before do
|
73
|
+
allow( connector ).to receive( :request_pending? ).and_return( true )
|
74
|
+
allow( connector ).to receive( :latest_request ).and_return(
|
75
|
+
Net::EMC.RequestCall(
|
76
|
+
prev_request_data, { on_failure: prev_on_failure}
|
77
|
+
)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
let( :prev_request_data ) {
|
82
|
+
Data::Requests::PinPadReset.new
|
83
|
+
}
|
84
|
+
let( :prev_on_failure ) { double(:prev_on_failure, call: nil) }
|
85
|
+
|
86
|
+
it "usurps the pending request when making a new pin pad reset request" do
|
87
|
+
allow( connector ).to receive( :get_response ) do |opts|
|
88
|
+
opts[:on_response].call :the_response
|
89
|
+
end
|
90
|
+
|
91
|
+
response = nil
|
92
|
+
subject.execute do |s|
|
93
|
+
response = s.request( Data::Requests::PinPadReset.new )
|
94
|
+
end
|
95
|
+
|
96
|
+
expect( prev_on_failure ).to have_received( :call )
|
97
|
+
expect( response ).to eq( :the_response )
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "when a request is pending" do
|
102
|
+
before do
|
103
|
+
allow( connector ).to receive( :connection_status ).and_return( :connected )
|
104
|
+
allow( connector ).to receive( :request_pending? ).and_return( true )
|
105
|
+
allow( connector ).to receive( :latest_request ).and_return(
|
106
|
+
Net::EMC.RequestCall(
|
107
|
+
prev_request_data,
|
108
|
+
{
|
109
|
+
on_response: prev_on_response,
|
110
|
+
on_failure: prev_on_failure,
|
111
|
+
on_detached: prev_on_detached,
|
112
|
+
}
|
113
|
+
)
|
114
|
+
)
|
115
|
+
end
|
116
|
+
let( :prev_request_data ) { Data::Requests::PinPadInitialize.new }
|
117
|
+
let( :prev_on_response ) { double(:prev_on_response, call: nil) }
|
118
|
+
let( :prev_on_failure ) { double(:prev_on_failure, call: nil) }
|
119
|
+
let( :prev_on_detached ) { double(:prev_on_detached, call: nil) }
|
120
|
+
|
121
|
+
context "making a new request of the same type" do
|
122
|
+
it "raises an appropriate exception" do
|
123
|
+
request_data = Data::Requests::PinPadInitialize.new
|
124
|
+
|
125
|
+
exception = nil
|
126
|
+
subject.execute do |s|
|
127
|
+
begin
|
128
|
+
s.request( request_data )
|
129
|
+
rescue => ex
|
130
|
+
exception = ex
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
expect( exception ).to be_kind_of( Net::EM_Session::ConflictingRequestError )
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "making a new request of a different type" do
|
139
|
+
it "supplants the pending request if possible" do
|
140
|
+
request_data = Data::Requests::PinPadDisplayMessage.new
|
141
|
+
response_data = Data::Responses::PinPadDisplayMessage.new
|
142
|
+
allow( connector ).to receive( :connect ) do |opts|
|
143
|
+
opts[:on_success].call
|
144
|
+
end
|
145
|
+
allow( connector ).to receive( :send_request ).with( request_data, anything ) do |data, opts|
|
146
|
+
opts[:on_response].call response_data
|
147
|
+
end
|
148
|
+
|
149
|
+
response = nil
|
150
|
+
subject.execute do |s|
|
151
|
+
response = s.request( request_data )
|
152
|
+
end
|
153
|
+
|
154
|
+
expect( prev_on_failure ).to have_received( :call )
|
155
|
+
expect( response ).to eq( response_data )
|
156
|
+
end
|
157
|
+
|
158
|
+
it "detaches the other event chain if supplanting the pending request is unsuccessful" do
|
159
|
+
# FIXME: This is awfully convoluted, even by comparison
|
160
|
+
# with other examples in this spec file.
|
161
|
+
allow( connector ).to receive( :connect ) do |opts|
|
162
|
+
opts[:on_success].call
|
163
|
+
end
|
164
|
+
|
165
|
+
request_data = Data::Requests::PinPadDisplayMessage.new
|
166
|
+
first_response_data = Data::Responses::PinPadInitialize.new
|
167
|
+
second_response_data = Data::Responses::PinPadDisplayMessage.new
|
168
|
+
|
169
|
+
expect( connector ).to receive( :send_request ).ordered.with( request_data, anything ) do |data, opts|
|
170
|
+
opts[:on_response].call first_response_data
|
171
|
+
end
|
172
|
+
expect( prev_on_detached ).to receive( :call ).ordered
|
173
|
+
expect( prev_on_response ).to receive( :call ).ordered.with( first_response_data )
|
174
|
+
expect( connector ).to receive( :get_response ).ordered do |opts|
|
175
|
+
opts[:on_response].call second_response_data
|
176
|
+
end
|
177
|
+
|
178
|
+
response = nil
|
179
|
+
subject.execute do |s|
|
180
|
+
response = s.request( request_data )
|
181
|
+
end
|
182
|
+
|
183
|
+
expect( prev_on_failure ).not_to have_received( :call )
|
184
|
+
expect( response ).to eq( second_response_data )
|
185
|
+
end
|
186
|
+
|
187
|
+
it "fails both the new and previously pending requests on request failure without response" do
|
188
|
+
request_data = Data::Requests::PinPadDisplayMessage.new
|
189
|
+
response_data = Data::Responses::PinPadInitialize.new
|
190
|
+
allow( connector ).to receive( :connect ) do |opts|
|
191
|
+
opts[:on_success].call
|
192
|
+
end
|
193
|
+
allow( connector ).to receive( :send_request ).with( request_data, anything ) do |data, opts|
|
194
|
+
opts[:on_failure].call
|
195
|
+
end
|
196
|
+
|
197
|
+
exception = nil
|
198
|
+
subject.execute do |s|
|
199
|
+
begin
|
200
|
+
s.request( request_data )
|
201
|
+
rescue => ex
|
202
|
+
exception = ex
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
expect( prev_on_failure ).to have_received( :call )
|
207
|
+
expect( exception ).to be_kind_of( Net::EM_Session::RequestError )
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
context "when its event chain is detached during successful receipt of response" do
|
213
|
+
it "continues to run and receives the returned response" do
|
214
|
+
expect( connector ).to receive( :connect ) do |opts|
|
215
|
+
opts[:on_success].call
|
216
|
+
end
|
217
|
+
allow( connector ).to receive( :send_request ) do |data, opts|
|
218
|
+
opts[:on_detached].call
|
219
|
+
opts[:on_response].call :the_response
|
220
|
+
end
|
221
|
+
|
222
|
+
response = nil
|
223
|
+
subject.execute do |s|
|
224
|
+
response = s.request( :the_request_data )
|
225
|
+
end
|
226
|
+
|
227
|
+
expect( response ).to eq( :the_response )
|
228
|
+
end
|
229
|
+
|
230
|
+
it "is blocked from making additional requests" do
|
231
|
+
expect( connector ).to receive( :connect ) do |opts|
|
232
|
+
opts[:on_success].call
|
233
|
+
end
|
234
|
+
allow( connector ).to receive( :send_request ) do |data, opts|
|
235
|
+
opts[:on_detached].call
|
236
|
+
opts[:on_response].call :the_response
|
237
|
+
end
|
238
|
+
|
239
|
+
exception = nil
|
240
|
+
subject.execute do |s|
|
241
|
+
s.request( :the_request_data )
|
242
|
+
begin
|
243
|
+
s.request( :the_request_data )
|
244
|
+
rescue Net::EM_Session::RequestError => ex
|
245
|
+
exception = ex
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
expect( prev_on_failure ).to have_received( :call )
|
250
|
+
expect( exception ).to be_kind_of( Net::EM_Session::RequestError )
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
context "executing a dissociated code" do
|
256
|
+
before do
|
257
|
+
allow( em_system ).to receive( :defer ) do |block, callback|
|
258
|
+
result = block.call
|
259
|
+
callback.call result
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
it "gets the value returned from the code execution" do
|
264
|
+
exec_result = nil
|
265
|
+
subject.execute do |s|
|
266
|
+
exec_result = subject.exec_dissociated {
|
267
|
+
:the_result
|
268
|
+
}
|
269
|
+
end
|
270
|
+
expect( exec_result ).to eq( :the_result )
|
271
|
+
end
|
272
|
+
|
273
|
+
it "gets the exception raised during the code execution" do
|
274
|
+
exception = nil
|
275
|
+
subject.execute do |s|
|
276
|
+
begin
|
277
|
+
subject.exec_dissociated do
|
278
|
+
raise 'the error'
|
279
|
+
end
|
280
|
+
rescue => e
|
281
|
+
exception = e
|
282
|
+
end
|
283
|
+
end
|
284
|
+
expect( exception ).to be_kind_of( StandardError )
|
285
|
+
expect( exception.message ).to eq( 'the error' )
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
context "sleeping" do
|
290
|
+
before do
|
291
|
+
@run_sequence = []
|
292
|
+
allow( em_system ).to receive( :add_timer ) do |delay_time, callback|
|
293
|
+
@run_sequence << [:add_timer, delay_time]
|
294
|
+
callback.call
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
it "adds an EM timer, and resumes after the timer callback fires" do
|
299
|
+
subject.execute do |s|
|
300
|
+
s.sleep 5.5
|
301
|
+
@run_sequence << :after_timer
|
302
|
+
end
|
303
|
+
|
304
|
+
expect( @run_sequence ).to eq( [
|
305
|
+
[:add_timer, 5.5],
|
306
|
+
:after_timer
|
307
|
+
] )
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: client_for_poslynx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.pre
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steve Jorgensen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -113,6 +113,9 @@ files:
|
|
113
113
|
- TODO.txt
|
114
114
|
- bin/fake_pos_terminal
|
115
115
|
- client_for_poslynx.gemspec
|
116
|
+
- examples/em_protocol_example.rb
|
117
|
+
- examples/em_session_basic_example.rb
|
118
|
+
- examples/em_session_interrupt_example.rb
|
116
119
|
- lib/client_for_poslynx.rb
|
117
120
|
- lib/client_for_poslynx/bit_sequence.rb
|
118
121
|
- lib/client_for_poslynx/data.rb
|
@@ -176,9 +179,15 @@ files:
|
|
176
179
|
- lib/client_for_poslynx/message_handling/xml_extractor.rb
|
177
180
|
- lib/client_for_poslynx/message_handling/xml_lines_buffer.rb
|
178
181
|
- lib/client_for_poslynx/net.rb
|
182
|
+
- lib/client_for_poslynx/net/em_connector.rb
|
183
|
+
- lib/client_for_poslynx/net/em_connector/callback_map.rb
|
184
|
+
- lib/client_for_poslynx/net/em_connector/connection_handler.rb
|
185
|
+
- lib/client_for_poslynx/net/em_connector/connector_state.rb
|
186
|
+
- lib/client_for_poslynx/net/em_connector/event_dispatcher.rb
|
187
|
+
- lib/client_for_poslynx/net/em_connector/handles_connection.rb
|
188
|
+
- lib/client_for_poslynx/net/em_connector/request_call.rb
|
179
189
|
- lib/client_for_poslynx/net/em_protocol.rb
|
180
|
-
- lib/client_for_poslynx/net/
|
181
|
-
- lib/client_for_poslynx/net/structured_client/em_connection.rb
|
190
|
+
- lib/client_for_poslynx/net/em_session.rb
|
182
191
|
- lib/client_for_poslynx/signature_image.rb
|
183
192
|
- lib/client_for_poslynx/signature_image/draw.rb
|
184
193
|
- lib/client_for_poslynx/signature_image/metrics.rb
|
@@ -207,8 +216,9 @@ files:
|
|
207
216
|
- spec/client_for_poslynx/message_handling/data_extractor_spec.rb
|
208
217
|
- spec/client_for_poslynx/message_handling/xml_extractor_spec.rb
|
209
218
|
- spec/client_for_poslynx/message_handling_spec.rb
|
219
|
+
- spec/client_for_poslynx/net/em_connector_spec.rb
|
210
220
|
- spec/client_for_poslynx/net/em_protocol_spec.rb
|
211
|
-
- spec/client_for_poslynx/net/
|
221
|
+
- spec/client_for_poslynx/net/em_session_spec.rb
|
212
222
|
- spec/client_for_poslynx/signature_image/to_svg_converter_spec.rb
|
213
223
|
- spec/client_for_poslynx/signature_image_spec.rb
|
214
224
|
- spec/client_for_poslynx_spec.rb
|
@@ -230,9 +240,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
230
240
|
version: 1.9.3
|
231
241
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
232
242
|
requirements:
|
233
|
-
- - ! '
|
243
|
+
- - ! '>'
|
234
244
|
- !ruby/object:Gem::Version
|
235
|
-
version:
|
245
|
+
version: 1.3.1
|
236
246
|
requirements: []
|
237
247
|
rubyforge_project:
|
238
248
|
rubygems_version: 2.2.2
|
@@ -262,8 +272,9 @@ test_files:
|
|
262
272
|
- spec/client_for_poslynx/message_handling/data_extractor_spec.rb
|
263
273
|
- spec/client_for_poslynx/message_handling/xml_extractor_spec.rb
|
264
274
|
- spec/client_for_poslynx/message_handling_spec.rb
|
275
|
+
- spec/client_for_poslynx/net/em_connector_spec.rb
|
265
276
|
- spec/client_for_poslynx/net/em_protocol_spec.rb
|
266
|
-
- spec/client_for_poslynx/net/
|
277
|
+
- spec/client_for_poslynx/net/em_session_spec.rb
|
267
278
|
- spec/client_for_poslynx/signature_image/to_svg_converter_spec.rb
|
268
279
|
- spec/client_for_poslynx/signature_image_spec.rb
|
269
280
|
- spec/client_for_poslynx_spec.rb
|
@@ -1,104 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
|
3
|
-
require_relative 'structured_client/em_connection'
|
4
|
-
|
5
|
-
module ClientForPoslynx
|
6
|
-
module Net
|
7
|
-
|
8
|
-
# A network client API suitable for use in a Structured (as
|
9
|
-
# oppoesed to Event-Driven) context such as from within an
|
10
|
-
# irb console session.
|
11
|
-
class StructuredClient
|
12
|
-
|
13
|
-
class SessionEndedError < StandardError ; end
|
14
|
-
class SessionEndingError < StandardError ; end
|
15
|
-
|
16
|
-
# Initializes a new instance, given a host name or address
|
17
|
-
# and a host IP port number. If an SSL connection is
|
18
|
-
# required, then supply true for the use_ssl argument.
|
19
|
-
def initialize(host, port, use_ssl = false)
|
20
|
-
@directive_queue = Queue.new
|
21
|
-
@activity_queue = Queue.new
|
22
|
-
@em_thread = Thread.new do
|
23
|
-
EM.run do
|
24
|
-
EM.connect host, port, EM_Connection, use_ssl, directive_queue, activity_queue
|
25
|
-
EM.error_handler do |e|
|
26
|
-
raise e
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# Close the server connection if it is open and end the
|
33
|
-
# session managed by the receiving instance.
|
34
|
-
def end_session
|
35
|
-
return unless em_thread.status
|
36
|
-
directive_queue << :end_session
|
37
|
-
self.session_end_initiated = true
|
38
|
-
em_thread.join
|
39
|
-
nil
|
40
|
-
end
|
41
|
-
|
42
|
-
# Sends a request to the POSLynx system and returns
|
43
|
-
# immediately.
|
44
|
-
# The request object is expected to behave like an
|
45
|
-
# instance of a descendant class of
|
46
|
-
# ClientForPoslynx::Data::Requests::AbstractRequest.
|
47
|
-
def send_request(request_data)
|
48
|
-
if session_ended?
|
49
|
-
raise SessionEndedError, "The session has been closed and cannot be used to send requests"
|
50
|
-
elsif session_ending?
|
51
|
-
raise SessionEndingError, "The session is ending and cannot be used to send requests"
|
52
|
-
end
|
53
|
-
directive_queue << [ :send_request, request_data ]
|
54
|
-
nil
|
55
|
-
end
|
56
|
-
|
57
|
-
# Returns the next available received response, if any.
|
58
|
-
# Returns nil is there are no remaining received responses
|
59
|
-
# to get.
|
60
|
-
# Each response will be an instance of a descendent class
|
61
|
-
# of
|
62
|
-
# ClientForPoslynx::Data::Responses::AbstractResponse.
|
63
|
-
def get_response
|
64
|
-
process_new_activity
|
65
|
-
received_responses.shift
|
66
|
-
end
|
67
|
-
|
68
|
-
# Returns true if the managed session has ended, either
|
69
|
-
# as a result of a call to #end_session or because the
|
70
|
-
# connection was closed by the server or otherwise lost.
|
71
|
-
def session_ended?
|
72
|
-
! em_thread.status
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
|
77
|
-
attr_reader :em_thread, :directive_queue, :activity_queue
|
78
|
-
attr_accessor :session_end_initiated
|
79
|
-
|
80
|
-
def session_ending?
|
81
|
-
session_end_initiated && ! session_ended?
|
82
|
-
end
|
83
|
-
|
84
|
-
def process_new_activity
|
85
|
-
until activity_queue.empty?
|
86
|
-
process_activity_entry *activity_queue.shift
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def process_activity_entry(kind, data=nil)
|
91
|
-
case kind
|
92
|
-
when :received_response
|
93
|
-
received_responses << data
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def received_responses
|
98
|
-
@received_responses ||= []
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
end
|
104
|
-
end
|