client_for_poslynx 0.9.0 → 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
N2JjMGU1MmVkOGYwMWJhMzE2NmVmMzRlYjhjNWM4YTE4OTJiN2ZkMA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YTJhNWNkYzRhYjM5NTJiZGZjYzFmODI1YmU2ODQxNmRmYTI2NTdlMA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MDNlOWZjMzQ2ZmUzZDhjM2EwMGM4ZDUxN2JjYjNiZTljOGZiYzRhZGVjMGI1
|
10
|
+
YzgyOTY0NjJhZjYzMTJjYjdmNzY3OTlmMDU0MGI3NTE4ODRmOTQ1NDgxZTcw
|
11
|
+
ZDk0MDhhODlhM2NiYmY4MGMyNWM3MThjM2YzMTYwODc5NGZhYzY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NDkxMGJiYzk1ZTBjYzliZGE1YWJjMjFlODUwOWUzMmViNWUyMWM0NTZhZjMz
|
14
|
+
ZDM2OWEzMzFkM2Y5MGJhMjc1ZjAyZjk4ZGE3MjE0YWM2M2RlYzUyOWJkMmRl
|
15
|
+
OGY5ZjQyNzU0NDk2Y2Q2ODk1Y2I1NDAyZDczZjRhZTY4MjMzMDU=
|
data/README.md
CHANGED
@@ -9,157 +9,181 @@ Technologies.
|
|
9
9
|
Features:
|
10
10
|
|
11
11
|
* Data models for requests and responses.
|
12
|
-
*
|
13
|
-
*
|
14
|
-
adapter.
|
12
|
+
* Signature image translation to SVG.
|
13
|
+
* Network interaction using via EventMachine.
|
15
14
|
* A fake POSLynx appliance + PIN Pad script.
|
16
15
|
|
17
16
|
## Overview
|
18
17
|
|
19
|
-
The `client_for_poslynx` gem provides network adapters
|
20
|
-
be used to send requests to
|
21
|
-
responses to those requests. The
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
18
|
+
The `client_for_poslynx` gem provides layers of network adapters
|
19
|
+
(operating via EventMachine) that can be used to send requests to
|
20
|
+
a POSLynx unit and receive the responses to those requests. The
|
21
|
+
gem also includes data models with XML
|
22
|
+
serialization/deserialization that are used by those network
|
23
|
+
adapters or may be used as part of another network adapter if you
|
24
|
+
prefer to write one of your own.
|
25
|
+
|
26
|
+
### Asynchronous Messaging
|
27
|
+
|
28
|
+
Message interaction with POSLynx is primarily synchronous, in
|
29
|
+
that the client application makes a request, and then waits for
|
30
|
+
for a response. In any realistic integrated POS solution,
|
31
|
+
however, there are cases in which it is necessary to devaite from
|
32
|
+
the typical synchronous flow.
|
33
|
+
|
34
|
+
Let's say that a customer starts an interaction with the
|
35
|
+
terminal, gets an emergency call, and runs off without completing
|
36
|
+
the interaction. The client application cannot do anything to
|
37
|
+
cancel the interaction because it's still blocked waiting for a
|
38
|
+
response.
|
39
|
+
|
40
|
+
### EventMachine
|
41
|
+
|
42
|
+
[EventMachine](http://rubyeventmachine.com/) is a Ruby library
|
43
|
+
that supports asynchronous network I/O using event callbacks.
|
44
|
+
`client_for_poslynx` provides an EventMachine protocol to allow
|
45
|
+
sending requests and receiving responses over an EventMachine
|
46
|
+
connection as well as adapter layers to simplify event-based
|
47
|
+
interaction via the EventMachine protocol.
|
48
|
+
|
49
|
+
One caveat to basing the library around EventMachine is that it
|
50
|
+
forces developers to deal with the EventMachine workflow in their
|
51
|
+
applications.
|
52
|
+
|
53
|
+
### Data Models
|
54
|
+
|
55
|
+
The `client_for_poslynx` gem includes data model classes for
|
56
|
+
kinds of requests that can be made to the POSLynx as well as for
|
57
|
+
responses that can be received from the POSLynx in response to
|
58
|
+
requests.
|
59
|
+
|
60
|
+
Models can be converted to/from XML-format messages to be sent or
|
61
|
+
receive over a network connection to the POSLynx.
|
62
|
+
|
63
|
+
These models can be used with the EventManager-based
|
64
|
+
communication adapters that exist within the gem, or you can use
|
65
|
+
them independently (e.g. if you perfer to communicate with the
|
66
|
+
POSLynx using Ruby's standard TCP/IP networking facilities.
|
67
|
+
|
68
|
+
Additionally, a `SignatureImage` model is provided that can be
|
69
|
+
used to parse or build POSLynx-compatible signature data strings,
|
70
|
+
along with a facility for converting signature images to SVG for
|
71
|
+
printing or display.
|
72
|
+
|
73
|
+
### Fake POS Terminal
|
74
|
+
|
75
|
+
The `client_for_poslynx` gem includes a script that acts as a
|
76
|
+
fake POSLynx + PIN Pad. This is useful when you are working
|
77
|
+
without access to an actual POSLynx and PIN Pad, and want to test
|
78
|
+
your client code and try out workflows.
|
45
79
|
|
46
80
|
## Usage
|
47
81
|
|
48
|
-
### Using the
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
the
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
# SSL session has been successfully started
|
154
|
-
# Sending the PIN Pad Display Message request
|
155
|
-
# Received response from POSLynx
|
156
|
-
# Result text: Success
|
157
|
-
# Selected button: Tails
|
158
|
-
# Closing the connection
|
159
|
-
# The connection has been closed
|
160
|
-
# Terminating the event loop
|
161
|
-
# The event loop has ended
|
162
|
-
# Bye
|
82
|
+
### Using the "Request" and "Response" Data Models
|
83
|
+
See
|
84
|
+
* [`abstract_data.rb`](lib/client_for_poslynx/data/abstract_data.rb)
|
85
|
+
* [`requests`](lib/client_for_poslynx/data/requests/)
|
86
|
+
* [`responses`](lib/client_for_poslynx/data/responses/)
|
87
|
+
|
88
|
+
### Using the `EM_Session` Adapter
|
89
|
+
|
90
|
+
[`EM_Session`](lib/client_for_poslynx/net/em_session.rb) is the
|
91
|
+
highest level adapter, and the one that you will most likely want
|
92
|
+
to use. It hides the significant complexity of the lower-level
|
93
|
+
event-driven interaction behind a synchronous API. Interruptions
|
94
|
+
to the flow are accommodated by allowing multiple sessions to be
|
95
|
+
active at the same time and for one to interrupt the other. This
|
96
|
+
"magic" is accomplished through the use of Ruby fibers.
|
97
|
+
|
98
|
+
Code examples:
|
99
|
+
* [`em_session_basic_example.rb`](examples/em_session_basic_example.rb)
|
100
|
+
* [`em_session_interrupt_example.rb`](examples/em_session_interrupt_example.rb)
|
101
|
+
|
102
|
+
It is important to note that a session's code block runs on
|
103
|
+
EventMachine's event handling thread, and one of the core
|
104
|
+
principles of EventMachine is to **never block that thread**. If
|
105
|
+
you need to perform any time-consuming or potentially blocking
|
106
|
+
operations in a session, you should run it in a
|
107
|
+
`Session#exec_dissociated` block (runs via `EventMachine.defer`).
|
108
|
+
If you need to pause for a specific amount of time, then you can
|
109
|
+
call the non-blocking `Session#sleep` (runs via
|
110
|
+
`EventMachine.add_timer`).
|
111
|
+
|
112
|
+
When one session is in progress, and a new session makes a
|
113
|
+
request, the new request will attempt to override any pending
|
114
|
+
request of the first session, and to "detach" the other session
|
115
|
+
so that any of its subsequent request attemtps will be rejected
|
116
|
+
and fail with an exception.
|
117
|
+
|
118
|
+
In order to avoid race conditions and to ensure that every
|
119
|
+
response that is received is returned to the session that made
|
120
|
+
the corresponding request, the following rules apply.
|
121
|
+
|
122
|
+
1. If one session has a pending request, a new session makes a
|
123
|
+
different kind of request, and then a response to the
|
124
|
+
**second** request is received, then the first session
|
125
|
+
receives an exception, and the second session will have the
|
126
|
+
response reurned.
|
127
|
+
2. If one session has a pending request, a new session makes a
|
128
|
+
different kind of request, and then a response to the
|
129
|
+
**first** request is received, then the first session will
|
130
|
+
have that response returned and will be detached. The second
|
131
|
+
session continues waiting for the subsequent response (to its
|
132
|
+
request).
|
133
|
+
2. If one session has a pending `PinPadReset` (`PPRESET`)
|
134
|
+
request, and a new session makes a `PinPadReset` request, then
|
135
|
+
the first session receives an exception, and the response is
|
136
|
+
returned to the second session.
|
137
|
+
4. If one session makes a request other than a `PinPadReset`,
|
138
|
+
and a new session makes a request of the same type, then the
|
139
|
+
new session's request fails immediately with an exception.
|
140
|
+
|
141
|
+
An important consequence of the rules above is that if the first
|
142
|
+
request made by a new session is a `PinPadReset`, then it will
|
143
|
+
always be able to successfully interrupt any existing session.
|
144
|
+
If it starts with any other kind of request, however, then it has
|
145
|
+
the potential to fail as described in rule #4.
|
146
|
+
|
147
|
+
For that reason, you should generally start any session with a
|
148
|
+
Pin Pad Reset request, and only do otherwise if you have
|
149
|
+
considered the consequences with respect to the rules above.
|
150
|
+
|
151
|
+
### Using the `EM_Connector` adapter
|
152
|
+
|
153
|
+
[`EM_Connector`](lib/client_for_poslynx/net/em_connector.rb) is
|
154
|
+
a low-level abstraction around an `EventMachine` connection with
|
155
|
+
the [`POSLynx`](lib/client_for_poslynx/net/em_protocol.rb)
|
156
|
+
protocol module included.
|
157
|
+
|
158
|
+
The jobs of `EM_Connector` are...
|
159
|
+
|
160
|
+
1. Simplify the task of making sure that a connection is open and
|
161
|
+
making a request via that connection.
|
162
|
+
2. Assist in keeping track of the state of pending requests.
|
163
|
+
3. Provide a simple API for specifying callbacks to specific
|
164
|
+
attempts to connection or send a request.
|
165
|
+
|
166
|
+
### The `POSLynx` protocol for EventManager
|
167
|
+
|
168
|
+
[`POSLynx`](lib/client_for_poslynx/net/em_protocol.rb) is an
|
169
|
+
`EventMachine` protocol for sending and receiving POSLynx
|
170
|
+
requests and responses.
|
171
|
+
|
172
|
+
This protocol is utilized in the same manner as other typical
|
173
|
+
`EventManager` protocols, by defining a connection handler class
|
174
|
+
that inherits from `EM::Connection` and includes the
|
175
|
+
`EM::Protocols::POSLynx` module, and then passing that class as
|
176
|
+
the handler argument to `EventMachine.connect`.
|
177
|
+
|
178
|
+
Code in the handler can call `#send_request` to send a request
|
179
|
+
(an instance of a subclass of
|
180
|
+
`ClientForPoslynx::Data::Requests::AbstractRequest`) and can
|
181
|
+
override the `#receive_response` method to receive responses
|
182
|
+
(instances of subclasses of
|
183
|
+
`ClientForPoslynx::Data::Response::AbstractResponse`)
|
184
|
+
|
185
|
+
Code example:
|
186
|
+
* [`em_protocol_example.rb`](examples/em_protocol_example.rb)
|
163
187
|
|
164
188
|
### Using the `fake_pos_terminal` script
|
165
189
|
|
@@ -180,8 +204,9 @@ To stop the script, send an interrupt signal by pressing Ctrl+C.
|
|
180
204
|
|
181
205
|
## Known Limitations
|
182
206
|
|
183
|
-
* Only a subset of the possible messages and elements is
|
184
|
-
__More
|
207
|
+
* Only a subset of the possible messages and elements is
|
208
|
+
supported. __More might be added. Contributions are welcome
|
209
|
+
and encouraged. :)__
|
185
210
|
|
186
211
|
## Installation
|
187
212
|
|
@@ -199,7 +224,7 @@ Or install it yourself as:
|
|
199
224
|
|
200
225
|
## Contributing
|
201
226
|
|
202
|
-
1. Fork it ( https://github.com/[my-github-username]/client_for_poslynx/fork )
|
227
|
+
1. Fork it ( `https://github.com/[my-github-username]/client_for_poslynx/fork` )
|
203
228
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
204
229
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
205
230
|
4. Push to the branch (`git push origin my-new-feature`)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'client_for_poslynx'
|
2
|
+
|
3
|
+
SERVER_IP = '192.168.1.25'
|
4
|
+
SERVER_PORT = 12345
|
5
|
+
CLIENT_MAC = '000000000000'
|
6
|
+
USE_SSL = true
|
7
|
+
|
8
|
+
class ButtonSelectionDemo < EM::Connection
|
9
|
+
include EM::Protocols::POSLynx
|
10
|
+
|
11
|
+
def connection_completed
|
12
|
+
puts "IP connection has been opened"
|
13
|
+
if USE_SSL
|
14
|
+
puts "Starting SSL"
|
15
|
+
start_tls verify_peer: false
|
16
|
+
else
|
17
|
+
puts "Using raw connection. No SSL"
|
18
|
+
display_the_message
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def ssl_handshake_completed
|
23
|
+
puts "SSL session has been successfully started"
|
24
|
+
display_the_message
|
25
|
+
end
|
26
|
+
|
27
|
+
def display_the_message
|
28
|
+
puts "Sending the PIN Pad Display Message request"
|
29
|
+
|
30
|
+
req = ClientForPoslynx::Data::Requests::PinPadDisplayMessage.new
|
31
|
+
req.client_mac = CLIENT_MAC
|
32
|
+
req.line_count = 2
|
33
|
+
req.text_lines = [
|
34
|
+
"Heads, we clean the basement",
|
35
|
+
"Tails, we go to the movies"
|
36
|
+
]
|
37
|
+
req.button_labels = %w[ Heads Tails ]
|
38
|
+
|
39
|
+
send_request req
|
40
|
+
end
|
41
|
+
|
42
|
+
def receive_response(response)
|
43
|
+
puts "Received response from POSLynx"
|
44
|
+
puts "Result text: #{response.result_text}"
|
45
|
+
puts "Selected button: #{response.button_response}"
|
46
|
+
|
47
|
+
puts "Closing the connection"
|
48
|
+
close_connection
|
49
|
+
end
|
50
|
+
|
51
|
+
def unbind
|
52
|
+
puts "The connection has been closed"
|
53
|
+
puts "Terminating the event loop"
|
54
|
+
EM.stop_event_loop
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
# This code will block until the event loop exits.
|
60
|
+
EM.run do
|
61
|
+
EM.connect SERVER_IP, SERVER_PORT, ButtonSelectionDemo
|
62
|
+
EM.error_handler do |e|
|
63
|
+
raise e
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
puts "The event loop has ended"
|
68
|
+
puts "Bye"
|
69
|
+
|
70
|
+
# == Sample output ==
|
71
|
+
# IP connection has been opened
|
72
|
+
# Starting SSL
|
73
|
+
# SSL session has been successfully started
|
74
|
+
# Sending the PIN Pad Display Message request
|
75
|
+
# Received response from POSLynx
|
76
|
+
# Result text: Success
|
77
|
+
# Selected button: Tails
|
78
|
+
# Closing the connection
|
79
|
+
# The connection has been closed
|
80
|
+
# Terminating the event loop
|
81
|
+
# The event loop has ended
|
82
|
+
# Bye
|