client_for_poslynx 0.2.6 → 0.3.0

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
- 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