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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OGRhYTY1N2JmMWVkZmVlNzA3MzM3MTBmYjY5YzVhMTE2YTE5YjQ5Mg==
4
+ N2JjMGU1MmVkOGYwMWJhMzE2NmVmMzRlYjhjNWM4YTE4OTJiN2ZkMA==
5
5
  data.tar.gz: !binary |-
6
- N2YxY2IzMTUzODE1NjI2OGEwOWE3ZTFiYzVhMTMzY2IzOGExZTRhNQ==
6
+ YTJhNWNkYzRhYjM5NTJiZGZjYzFmODI1YmU2ODQxNmRmYTI2NTdlMA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MGRlY2MwMTgxMWU3YWExNGIxODE4MDI3NThkZDZjMTkwMmVjM2Y2MDk1MjQ4
10
- MTRmODhhYjcxN2VmY2FkOWMwYTU5MjI4MTZmYTY4YTE1MzI3MzIzZDRkNmNm
11
- MDRmMGE5ZTZjZDM0YTQ0NzFiNmY0N2ZmMTFiZWFiMTY1MmYxOGI=
9
+ MDNlOWZjMzQ2ZmUzZDhjM2EwMGM4ZDUxN2JjYjNiZTljOGZiYzRhZGVjMGI1
10
+ YzgyOTY0NjJhZjYzMTJjYjdmNzY3OTlmMDU0MGI3NTE4ODRmOTQ1NDgxZTcw
11
+ ZDk0MDhhODlhM2NiYmY4MGMyNWM3MThjM2YzMTYwODc5NGZhYzY=
12
12
  data.tar.gz: !binary |-
13
- ZjVkODM0YThiMzZlZDFkM2QwZDhlMDY5MDAwMTk1YTUyYzEzNDIxMzQ1YzIw
14
- YWNhOWNkZWRiZWM0YjY2MGE3NzY2NmNhOWM1MzRjYTc5MTM1ZmFiMGJkZDVl
15
- MTYyMGU1OTliMWM2MDRlMGZhZDEzZjNiYzBhNDQ1NzhiZTU0NjI=
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
- * Network interaction using an EventMachine protocol.
13
- * Simplified network interaction using a structured client
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 that can
20
- be used to send requests to a POSLynx unit and receive the
21
- responses to those requests. The gem also includes data models
22
- with XML serialization/deserialization that are used by those
23
- network adapters or may be used as part of a different network
24
- adapter if you prefer to build your own.
25
-
26
- The first network adapter provided is in the form of a protocol
27
- for EventMachine. EventMachine is a gem for implementing
28
- event-driven communication clients and servers. Essentially,
29
- being event-driven means that requests are sent and responses are
30
- received asynchronously. The application receives a call-back
31
- when the server responds or the connection is lost, etc.
32
-
33
- The second network adapter this gem provides is a "structured"
34
- (as opposed to event-driven) API. This is primarily provided
35
- as a convenience for use in situations where the event-driven
36
- API is inconvenient, such as when experimenting with the gem
37
- from an irb command line session.
38
-
39
- In addition to the network client libraries, this gem includes
40
- a script that acts as a fake POSLynx + PIN Pad. This is useful
41
- when you are working without access to an actual POSLynx and
42
- PIN Pad, and want to test your client code and try out
43
- workflows. This script will probably be extracted into a
44
- separate gem soon.
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 structured client
49
-
50
- A quick and easy way to try out this gem is to use the structured
51
- client and example-request factory from an irb console.
52
-
53
- Assuming you have a POSLynx host running at 192.168.1.99 on port
54
- 1234 with SSL required, and if your lane has a registered client
55
- MAC value of 123456789ABC, then with the client_for_poslynx gem
56
- installed, you should be able to execute a sequence similar to
57
- the following.
58
-
59
- $ irb
60
- 1.9.3-p545 :001 > require 'client_for_poslynx'
61
- => true
62
- 1.9.3-p545 :002 > client = ClientForPoslynx::Net::StructuredClient.new('192.168.1.99', 1234, true)
63
- => #<ClientForPoslynx::Net::StructuredClient:0x007fefa2103aa8 @directive_queue=#<Queue:0x007fefa21039e0 @que=[], @waiting=[], @mutex=#<Mutex:0x007fefa2103968>>, @activity_queue=#<Queue:0x007fefa2103940 @que=[], @waiting=[], @mutex=#<Mutex:0x007fefa2103300>>, @em_thread=#<Thread:0x007fefa2103260 sleep>>
64
- 1.9.3-p545 :003 > reqf = ClientForPoslynx::ExampleRequestFactory.new('1234567890ABC')
65
- => #<ClientForPoslynx::ExampleRequestFactory:0x007fefa2036030 @client_mac="1234567890ABC">
66
- 1.9.3-p545 :004 > req = reqf.pin_pad_initialize_request
67
- => #<ClientForPoslynx::Data::Requests::PinPadInitialize:0x007fefa204f760 @client_mac="1234567890ABC", @idle_prompt="Example idle prompt">
68
- 1.9.3-p545 :005 > client.send_request req
69
- => nil
70
- 1.9.3-p545 :006 > client.get_response
71
- => #<ClientForPoslynx::Data::Responses::PinPadInitialize:0x007fefa21106e0 @result="Success", @result_text="PinPad Initialized", @error_code="1000", @source_data="<?xml version=\"1.0\" standalone=\"yes\" ?><PLResponse><Command>PPINIT</Command><Result>Success</Result><ResultText>PinPad Initialized</ResultText><ErrorCode>1000</ErrorCode></PLResponse>">
72
- 1.9.3-p545 :007 > client.end_session
73
- => nil
74
-
75
- ### Using the EventMachine protocol
76
-
77
- The following example code demonstrates how to write an
78
- event-driven client using EventMachine and the POSLynx protocol
79
- for EventMachine.
80
-
81
- require 'client_for_poslynx'
82
-
83
- HOST = '192.168.1.25'
84
- PORT = 12345
85
- CLIENT_MAC = '000000000000'
86
- USE_SSL = true
87
-
88
- class ButtonSelectionDemo < EM::Connection
89
- include EM::Protocols::POSLynx
90
-
91
- def connection_completed
92
- puts "IP connection has been opened"
93
- if USE_SSL
94
- puts "Starting SSL"
95
- start_tls verify_peer: false
96
- else
97
- puts "Using raw connection. No SSL"
98
- display_the_message
99
- end
100
- end
101
-
102
- def ssl_handshake_completed
103
- puts "SSL session has been successfully started"
104
- display_the_message
105
- end
106
-
107
- def display_the_message
108
- puts "Sending the PIN Pad Display Message request"
109
-
110
- req = ClientForPoslynx::Data::Requests::PinPadDisplayMessage.new
111
- req.client_mac = CLIENT_MAC
112
- req.line_count = 2
113
- req.text_lines = [
114
- "Heads, we clean the basement",
115
- "Tails, we go to the movies"
116
- ]
117
- req.button_labels = %w[ Heads Tails ]
118
-
119
- send_request req
120
- end
121
-
122
- def receive_response(response)
123
- puts "Received response from POSLynx"
124
- puts "Result text: #{response.result_text}"
125
- puts "Selected button: #{response.button_response}"
126
-
127
- puts "Closing the connection"
128
- close_connection
129
- end
130
-
131
- def unbind
132
- puts "The connection has been closed"
133
- puts "Terminating the event loop"
134
- EM.stop_event_loop
135
- end
136
-
137
- end
138
-
139
- # This code will block until the event loop exits.
140
- EM.run do
141
- EM.connect HOST, PORT, ButtonSelectionDemo
142
- EM.error_handler do |e|
143
- raise e
144
- end
145
- end
146
-
147
- puts "The event loop has ended"
148
- puts "Bye"
149
-
150
- # == Sample output ==
151
- # IP connection has been opened
152
- # Starting SSL
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 supported.
184
- __More will be added. Contributions are welcome and encouraged. :)__
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