client_for_poslynx 0.2.6 → 0.3.0

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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YzhiNDI0YzUzYjUzNTZjMTQ0ZDQ0ZmYzOTk1MmY2ZWUyNjY4ZjNlNw==
4
+ MDIyYTM1NTlkMTFhYTllNzI4ZDNlZjBlMGJjY2E3MzcxNjQ1ODJmNA==
5
5
  data.tar.gz: !binary |-
6
- N2Y1MDE0NGU2NDczOWNiYzVjMTU0ODMwMWQ5MDNjNTM3NWE5NDVjNg==
6
+ ZGM2ODlhZmQ2ZDZiMWM5ODkwM2QyNjc4MTdmMzFhMGU4OTVkYmNmZg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OWJmOGE4ZWFiZWJkNDIwMDgzYzhkOTdhNDYyOGI5NjA1ZjRhYjllMzM5OGUx
10
- MzVjNjkyNmEzOGUyNWQxNThjM2Q0MWM0ZjJjMjNlYWZkODMxNmY0YTA4ZDhh
11
- ZDNkOTA1ZTc3NWU1MjA3MWY5OGMwZGFmOWRkYjgxOTExODMxZmI=
9
+ MDE0NDIxOTM5NWI3YTU5OTg5OGM2ZDRhYzMzNDcxNzdkMzQ1NGY2OGQ2MTNl
10
+ ZDk5ZjBiZTVjMzE2Mzc0ZGRkM2JjZmFjZjBkZWEzOGYyOTM0N2RhYWE4ZDM0
11
+ ZGE2YjYzOWU1OGE0MzkyMzQwYTIwYWI4NjQzZmYwMjJiNTMyYmE=
12
12
  data.tar.gz: !binary |-
13
- Mjk2YjA5MWU2Zjg4NTQ3M2YxMDEwOGM5YzJjYjc2MTAwYWNlNDJjMmQwMDM5
14
- NGJkNDEzM2I2YmNlZDRkMDNiMWU0YWQ5MmYwYjBiM2JmMWQ5YjdlODI5NDhm
15
- MmMwMDlkMTAzMzgzOWExM2ZlNWZiMGE0Mjc2Mzk2YmIzNTE5OTk=
13
+ NzA1ZmFiMDc1MDYyNTc4NTQyODZjZGNlZWI5N2U2OWE2NzkzNjM4MjYxZjBm
14
+ MjYzMmM5NDZjMjY3MTBmNGQyYjdlYWU0NDk1NWE3MjZiZTJhMmJlZjQyZmYz
15
+ YjA1NmJlNGUyOTIzNTY1MGMyYTQyNzY4MGZlMDE3YzFhYWQzMTM=
data/CHANGELOG CHANGED
@@ -32,6 +32,14 @@ Version 0.2.5
32
32
 
33
33
  Version 0.2.6
34
34
  - Add enhanced-format signature data handling.
35
- - Fix misconception about signed number representation in
36
- signature image data.
35
+ - Fix misconception about signed number representation in signa-
36
+ ture image data.
37
37
  - Bring signature image handling out of experimental status.
38
+
39
+ Version 0.3.0
40
+ - Allow user to cancel waiting for reply in
41
+ poslynx_client_console.
42
+ - Support SSL connections from poslynx_client_console.
43
+ - Change word separators in poslynx_client_console from under-
44
+ scores to dashes.
45
+ - Fake Poslynx includes signature image data in response.
data/README.md CHANGED
@@ -16,11 +16,11 @@ Features:
16
16
 
17
17
  The best introduction to this gem is probably to play around with
18
18
  with the POSLynx client console. Assuming you have a POSLynx
19
- unit with IP address 192.168.1.123, listening on port 54321, with
20
- a registered client MAC of 000000000000, an example poslynx
21
- client session might look like...
19
+ unit with IP address 192.168.1.123, listening on port 54321 using
20
+ SSL encryption, with a registered client MAC of 000000000000, an
21
+ example poslynx client session might look like...
22
22
 
23
- $ bundle exec poslynx_client_console 173.195.60.144:14270 --client_mac=000000000000
23
+ $ bundle exec poslynx_client_console 173.195.60.144:14270 --use-ssl --client_mac=000000000000
24
24
  1.9.3-p545 :001 > req = poslynx_client.example_pin_pad_display_message_request
25
25
  => #<ClientForPoslynx::Data::Requests::PinPadDisplayMessage:0x007f941b4b1fe8 @client_mac="001C42E644FE", @text_lines=["First example line", "Second example line"], @line_count=2, @button_labels=["1st of optional buttons", "2nd button"]>
26
26
  1.9.3-p545 :002 > resp = poslynx_client.send_request(req)
@@ -29,8 +29,8 @@ client session might look like...
29
29
 
30
30
  This gem also provides a fake POS/terminal application that you
31
31
  can run in a separate console window when you are working without
32
- the necessary access to an actual POSLynx unit and PIN pad. To
33
- start the fake POS/terminal listening on port 3010...
32
+ access to an actual POSLynx unit and PIN pad. To start the fake
33
+ POS/terminal listening on port 3010...
34
34
 
35
35
  bundle exec fake_pos_terminal 3010
36
36
 
@@ -13,10 +13,15 @@ end
13
13
  $*.replace []
14
14
 
15
15
  # Take --client_mac=<hexadecimal-value> if present.
16
- client_mac_opts = option_args.select{ |opt| opt =~ /^--client_mac=[0-9a-fA-F]+$/ }
16
+ client_mac_opts = option_args.select{ |opt| opt =~ /^--client-mac=[0-9a-fA-F]+$/ }
17
17
  option_args -= client_mac_opts
18
18
  client_mac_option = client_mac_opts.last
19
19
 
20
+ # Take --use-ssl or --no-ssl if present.
21
+ ssl_opts = option_args.select{ |opt| opt =~ /^--(use|no)-ssl$/ }
22
+ option_args -= ssl_opts
23
+ ssl_option = ssl_opts.last
24
+
20
25
  # The only remaining option we care about is --help, so we either
21
26
  # show usage for --help or because an unrecognized option was given.
22
27
  show_usage = option_args.length > 0
@@ -46,9 +51,16 @@ assumed.
46
51
 
47
52
  Options:
48
53
 
49
- --client_mac=<hexadecimal> The client MAC value to be assigned
54
+ --client-mac=<hexadecimal> The client MAC value to be assigned
50
55
  to example-request objects.
51
56
 
57
+ --use-ssl Use SSL encryption for the connec-
58
+ tion to the POSLynx.
59
+
60
+ --no-ssl Don't use SSL encryption for the
61
+ connection to the POSLynx. This is
62
+ the default behavior.
63
+
52
64
  --help Prints this usage information.
53
65
 
54
66
  Opens an interactive Ruby shell with a globally acccessible
@@ -82,6 +94,7 @@ else
82
94
  config = poslynx_client.config
83
95
  config.host = host
84
96
  config.port = port
97
+ config.use_ssl = ssl_option == '--use-ssl'
85
98
 
86
99
  if client_mac_option
87
100
  config.client_mac_for_examples = client_mac_option.split('=').last
@@ -28,12 +28,26 @@ module ClientForPoslynx
28
28
  attr_element_mapping attribute: :customer_receipt, element: 'ReceiptCustomer', numbered_lines: 'Receipt%d'
29
29
 
30
30
  def signature=(value)
31
+ # Extract content from CDATA section XML improperly encoded
32
+ # as text node content by some POSLynx versions.
31
33
  if value =~ /^<!\[CDATA\[(.*)\]\]>$/
32
34
  @signature = $1
33
35
  else
34
36
  @signature = value
35
37
  end
36
38
  end
39
+
40
+ def signature_image=(img)
41
+ self.signature = img.nil? ?
42
+ nil :
43
+ img.serialize
44
+ end
45
+
46
+ def signature_image
47
+ return nil if signature.nil?
48
+ SignatureImage.deserialize( signature )
49
+ end
50
+
37
51
  end
38
52
 
39
53
  end
@@ -18,6 +18,7 @@ module ClientForPoslynx
18
18
  response.input_method = 'SWIPED'
19
19
  confirmed = get_confirmation
20
20
  response.card_type = 'Visa'
21
+ response.signature_image = signature_image if request.capture_signature == 'Yes'
21
22
  assemble_supported_source_response confirmed
22
23
  end
23
24
 
@@ -25,6 +26,31 @@ module ClientForPoslynx
25
26
  request.amount
26
27
  end
27
28
 
29
+ def signature_image
30
+ SignatureImage.new.tap { |si|
31
+ si.metrics = SignatureImage::Metrics.new( [2048, 256], [20_000, 2_500] )
32
+
33
+ # Say "Hi"
34
+
35
+ si.move 40, 40
36
+ si.draw -5, 30
37
+ si.draw -5, 30
38
+
39
+ si.move 70, 40
40
+ si.draw -5, 30
41
+ si.draw -5, 30
42
+
43
+ si.move 35, 70
44
+ si.draw 30, 0
45
+
46
+
47
+ si.move 80, 70
48
+ si.draw -5, 30
49
+
50
+ si.move 81, 64
51
+ }
52
+ end
53
+
28
54
  def assemble_request_response_passthrough
29
55
  response.merchant_supplied_id = request.merchant_supplied_id
30
56
  response.client_id = request.client_id
@@ -21,6 +21,10 @@ module ClientForPoslynx
21
21
  raise NotImplementedError
22
22
  end
23
23
 
24
+ def handle_supported_source_request
25
+ raise NotImplementedError, "Including class responsibility"
26
+ end
27
+
24
28
  def handle_unsupported_source_request
25
29
  set_result '0135', 'Transaction Not Supported'
26
30
  response.result_text = "Fake POSLynx doesn't currently support input source other than EXTERNAL"
@@ -0,0 +1,56 @@
1
+ require 'socket'
2
+ require 'openssl'
3
+ require 'forwardable'
4
+
5
+ module ClientForPoslynx
6
+ module HasClientConsoleSupport
7
+
8
+ class Connection
9
+ def self.connect(config)
10
+ new(config).connect
11
+ end
12
+
13
+ attr_accessor :io
14
+ private :io=
15
+
16
+ def initialize(config)
17
+ self.config = config
18
+ end
19
+
20
+ def connect
21
+ self.tcp_connection = TCPSocket.new( config.host, config.port )
22
+ self.io = config.use_ssl ?
23
+ connect_ssl_socket :
24
+ tcp_connection
25
+ self
26
+ rescue StandardError
27
+ close
28
+ raise
29
+ end
30
+
31
+ def close
32
+ tcp_connection.close unless tcp_connection.closed?
33
+ self.io = self.tcp_connection = nil
34
+ end
35
+
36
+ def puts(*args)
37
+ io.puts *args
38
+ end
39
+
40
+ def ===(other)
41
+ self == other || self.io == other
42
+ end
43
+
44
+ private
45
+
46
+ def connect_ssl_socket
47
+ OpenSSL::SSL::SSLSocket.new( tcp_connection ).tap { |ssl_conn|
48
+ ssl_conn.connect
49
+ }
50
+ end
51
+
52
+ attr_accessor :config, :tcp_connection
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,44 @@
1
+ module ClientForPoslynx
2
+ module HasClientConsoleSupport
3
+
4
+ class ResponseReadyMonitor
5
+ def self.ready?(conn)
6
+ new( conn ).ready?
7
+ end
8
+
9
+ def initialize(conn)
10
+ self.conn = conn
11
+ end
12
+
13
+ def ready?
14
+ # Wait up to 1 second for data ready to read or error.
15
+ ready = !! IO.select( [conn.io], [], [conn.io], 1 )
16
+ return true if ready
17
+
18
+ puts "Waiting for response. Press Enter to cancel."
19
+ print "Waiting: "
20
+ while true do
21
+ print '.'
22
+
23
+ # Wait up to 1 second for data or for line of input from user.
24
+ select_state = IO.select( [conn.io, $stdin], [], [conn.io], 1 )
25
+ next unless select_state
26
+
27
+ read_state, _, error_state = select_state
28
+ any_state = read_state + error_state
29
+
30
+ ( ready = true ; break ) if any_state.any? { |io| conn === io }
31
+ ( gets ; break ) if read_state.include?( $stdin )
32
+ end
33
+ puts
34
+
35
+ ready
36
+ end
37
+
38
+ private
39
+
40
+ attr_accessor :conn
41
+ end
42
+
43
+ end
44
+ end
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'client_for_poslynx'
4
- require 'socket'
4
+ require_relative 'has_client_console_support/connection'
5
+ require_relative 'has_client_console_support/response_ready_monitor'
5
6
 
6
7
  module ClientForPoslynx
7
8
 
@@ -17,10 +18,11 @@ module ClientForPoslynx
17
18
  end
18
19
 
19
20
  def send_request(request)
20
- conn = TCPSocket.new( config.host, config.port )
21
+ conn = Connection.connect( config )
21
22
  conn.puts request.xml_serialize
22
- response = get_response_from( conn )
23
- conn.close unless conn.closed?
23
+ ready = ResponseReadyMonitor.ready?( conn )
24
+ response = get_response_from( conn.io ) if ready
25
+ conn.close
24
26
  response
25
27
  end
26
28
 
@@ -52,6 +54,7 @@ module ClientForPoslynx
52
54
  req.merchant_supplied_id = 'INVC-123-MERCH-SUPPL'
53
55
  req.amount = '101.25'
54
56
  req.input_source = 'EXTERNAL'
57
+ req.capture_signature = 'Yes'
55
58
  }
56
59
  end
57
60
 
@@ -99,7 +102,7 @@ module ClientForPoslynx
99
102
  end
100
103
 
101
104
  class Config
102
- attr_accessor :host, :port, :client_mac_for_examples
105
+ attr_accessor :host, :port, :use_ssl, :client_mac_for_examples
103
106
  end
104
107
 
105
108
  end
@@ -1,5 +1,5 @@
1
1
  # coding: utf-8
2
2
 
3
3
  module ClientForPoslynx
4
- VERSION = '0.2.6'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -147,6 +147,39 @@ module ClientForPoslynx
147
147
  end
148
148
 
149
149
 
150
+ context "signature image conveniences" do
151
+ let( :signature_image ) {
152
+ SignatureImage.new.tap { |si|
153
+ si.metrics = SignatureImage::Metrics.new( [3_000, 200], [30_000, 2_000] )
154
+ si.move 20, 15
155
+ si.draw 30, 15
156
+ si.draw 30, 15
157
+ }
158
+ }
159
+ let( :base_64_regex ) { /^[A-Za-z0-9\+\/]+={0,2}$/ }
160
+
161
+ it "sets signature to nil for nil signature image" do
162
+ subject.signature_image = nil
163
+ expect( subject.signature ).to be_nil
164
+ end
165
+
166
+ it "gets nil signature image for nil signature" do
167
+ subject.signature = nil
168
+ expect( subject.signature_image ).to be_nil
169
+ end
170
+
171
+ it "Supports setting/getting signature data as signature image" do
172
+ subject.signature_image = signature_image
173
+ expect( subject.signature ).to match( base_64_regex )
174
+
175
+ subject2 = described_class.new
176
+ subject2.signature = subject.signature
177
+ expect( subject2.signature_image ).to eq( signature_image )
178
+ end
179
+
180
+ end
181
+
182
+
150
183
  end
151
184
 
152
185
  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.2.6
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Jorgensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-10 00:00:00.000000000 Z
11
+ date: 2014-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -128,6 +128,8 @@ files:
128
128
  - lib/client_for_poslynx/fake_pos_terminal/result_assemblers/card_sale_receipt.rb
129
129
  - lib/client_for_poslynx/fake_pos_terminal/server.rb
130
130
  - lib/client_for_poslynx/has_client_console_support.rb
131
+ - lib/client_for_poslynx/has_client_console_support/connection.rb
132
+ - lib/client_for_poslynx/has_client_console_support/response_ready_monitor.rb
131
133
  - lib/client_for_poslynx/message_handling.rb
132
134
  - lib/client_for_poslynx/message_handling/data_extractor.rb
133
135
  - lib/client_for_poslynx/message_handling/stream_data_writer.rb