da_funk 0.4.4
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 +7 -0
- data/.gitignore +11 -0
- data/.yardopts +12 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +21 -0
- data/README.md +108 -0
- data/README_GUIDE.md +52 -0
- data/RELEASE_NOTES.md +23 -0
- data/Rakefile +69 -0
- data/da_funk.gemspec +31 -0
- data/ext/da_funk/Makefile +5 -0
- data/ext/da_funk/extconf.rb +8 -0
- data/guides/sample_input_output.rb +14 -0
- data/guides/sample_message_iso8583.rb +14 -0
- data/guides/sample_network_gprs.rb +26 -0
- data/guides/sample_read_magnect_card.rb +8 -0
- data/guides/sample_socket.rb +29 -0
- data/guides/sample_transaction.rb +23 -0
- data/guides/sample_transaction_download_application.rb +9 -0
- data/guides/sample_transaction_download_file.rb +6 -0
- data/guides/sample_transaction_download_parameter_file.rb +18 -0
- data/guides/sample_transaction_iso8583.rb +222 -0
- data/imgs/daft-punk-da-funk.jpg +0 -0
- data/lib/da_funk/rake_task.rb +129 -0
- data/lib/da_funk/test.rb +87 -0
- data/lib/da_funk.rb +39 -0
- data/lib/device/application.rb +41 -0
- data/lib/device/audio.rb +17 -0
- data/lib/device/crypto.rb +52 -0
- data/lib/device/display.rb +47 -0
- data/lib/device/helper.rb +161 -0
- data/lib/device/io.rb +86 -0
- data/lib/device/magnetic.rb +79 -0
- data/lib/device/network.rb +192 -0
- data/lib/device/notification.rb +116 -0
- data/lib/device/notification_callback.rb +47 -0
- data/lib/device/notification_event.rb +29 -0
- data/lib/device/params_dat.rb +119 -0
- data/lib/device/printer.rb +35 -0
- data/lib/device/runtime.rb +22 -0
- data/lib/device/setting.rb +63 -0
- data/lib/device/support.rb +28 -0
- data/lib/device/system.rb +61 -0
- data/lib/device/transaction/download.rb +268 -0
- data/lib/device/transaction/emv.rb +45 -0
- data/lib/device/transaction/iso.rb +75 -0
- data/lib/device/version.rb +11 -0
- data/lib/device/walk.rb +8 -0
- data/lib/device.rb +28 -0
- data/lib/ext/kernel.rb +9 -0
- data/lib/file_db.rb +47 -0
- data/lib/iso8583/bitmap.rb +114 -0
- data/lib/iso8583/codec.rb +197 -0
- data/lib/iso8583/exception.rb +4 -0
- data/lib/iso8583/field.rb +90 -0
- data/lib/iso8583/fields.rb +171 -0
- data/lib/iso8583/message.rb +455 -0
- data/lib/iso8583/util.rb +91 -0
- data/lib/iso8583/version.rb +6 -0
- data/lib/serfx/commands.rb +191 -0
- data/lib/serfx/connection.rb +160 -0
- data/lib/serfx/exceptions.rb +5 -0
- data/lib/serfx/response.rb +28 -0
- data/lib/serfx.rb +27 -0
- data/lib/version.rb +5 -0
- data/lib/zip.rb +29 -0
- data/test/integration/getc_test.rb +6 -0
- data/test/integration/mrb_eval_test.rb +36 -0
- data/test/integration/notification_test.rb +20 -0
- data/test/integration/params_dat_test.rb +11 -0
- data/test/test_helper.rb +18 -0
- data/test/unit/device/display_test.rb +43 -0
- data/test/unit/device/helper_test.rb +61 -0
- data/test/unit/device/notification_callback_test.rb +6 -0
- data/test/unit/device/notification_event_test.rb +73 -0
- data/test/unit/device/notification_test.rb +21 -0
- data/utils/command_line_platform.rb +67 -0
- data/utils/test_run.rb +3 -0
- metadata +177 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
class Device
|
2
|
+
class ParamsDat
|
3
|
+
FILE_NAME = "./main/params.dat"
|
4
|
+
|
5
|
+
include Device::Helper
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :file, :apps, :status
|
9
|
+
end
|
10
|
+
|
11
|
+
self.apps = Array.new
|
12
|
+
|
13
|
+
# To control if there is any app and parse worked
|
14
|
+
self.status = false
|
15
|
+
|
16
|
+
def self.setup
|
17
|
+
if File.exists?(FILE_NAME)
|
18
|
+
@file = FileDb.new(FILE_NAME)
|
19
|
+
else
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# TODO Scalone: Change after @bmsatierf change the format
|
25
|
+
# For each apps on apps_list We'll have:
|
26
|
+
# Today: <label>,<arquivo>,<pages>,<crc>;
|
27
|
+
# After: <label>,<arquivo>,<type>,<crc>;
|
28
|
+
# Today: "1 - App,pc2_app.posxml,1,E0A0;"
|
29
|
+
# After: "1 - App,pc2_app.posxml,posxml,E0A0;"
|
30
|
+
# After: "1 - App,pc2_app.zip,ruby,E0A0;"
|
31
|
+
def self.parse_apps
|
32
|
+
@apps = []
|
33
|
+
return unless self.setup
|
34
|
+
|
35
|
+
self.file["apps_list"].to_s.gsub("\"", "").split(";").each do |app|
|
36
|
+
@apps << Device::Application.new(*app.split(","))
|
37
|
+
end
|
38
|
+
|
39
|
+
if (@apps.size >= 1)
|
40
|
+
self.status = true
|
41
|
+
else
|
42
|
+
self.status = false
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.download
|
47
|
+
if attach
|
48
|
+
Device::Display.clear
|
49
|
+
puts "Downloading Params"
|
50
|
+
ret = Device::Transaction::Download.request_param_file(FILE_NAME)
|
51
|
+
if value = check_download_error(ret)
|
52
|
+
puts "Downloaded Successfully"
|
53
|
+
Device::Network.close_socket
|
54
|
+
# TODO
|
55
|
+
#Device::Network.walk_socket.close unless Device::Network.walk_socket.closed?
|
56
|
+
parse_apps
|
57
|
+
end
|
58
|
+
value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.update_apps(force = false)
|
63
|
+
if force || ! self.status
|
64
|
+
self.download
|
65
|
+
end
|
66
|
+
if self.status
|
67
|
+
@apps.each do |app|
|
68
|
+
self.update_app(app)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.format!
|
74
|
+
self.apps.each do |app|
|
75
|
+
File.delete(app.zip) if File.exists?(app.zip)
|
76
|
+
Dir.delete(app.file_no_ext) if File.exists?(app.file_no_ext) && File.exists?(app.file_no_ext)
|
77
|
+
end
|
78
|
+
File.delete(FILE_NAME) if File.exists?(FILE_NAME)
|
79
|
+
Device::System.restart
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.update_app(application)
|
83
|
+
if attach && application
|
84
|
+
Device::Display.clear
|
85
|
+
puts "Downloading #{application.file}..."
|
86
|
+
ret = Device::Transaction::Download.request_file(application.file, application.zip)
|
87
|
+
Device::Network.close_socket
|
88
|
+
# TODO
|
89
|
+
#Device::Network.walk_socket.close unless Device::Network.walk_socket.closed?
|
90
|
+
|
91
|
+
unless check_download_error ret
|
92
|
+
sleep 2
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def self.apps
|
98
|
+
self.parse_apps unless self.status
|
99
|
+
@apps
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.executable_app
|
103
|
+
selected = self.executable_apps
|
104
|
+
if selected.size == 1
|
105
|
+
selected[selected.keys.first]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.executable_apps
|
110
|
+
self.apps.select{|app| app.label != "X"}
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.application_menu
|
114
|
+
options = Hash.new
|
115
|
+
executable_apps.each { |app| options[app.label] = app }
|
116
|
+
menu("Application Menu", options, {:number => true})
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
class Device
|
3
|
+
class Printer
|
4
|
+
def self.adapter
|
5
|
+
Device.adapter::Printer
|
6
|
+
end
|
7
|
+
|
8
|
+
# Same as print, but add "\n" at end of print
|
9
|
+
#
|
10
|
+
# @param buf [String] Text to be printed.
|
11
|
+
# @param option [Symbol] :big, :bar_code, :bitmap
|
12
|
+
# @return [String] buffer read from keyboard
|
13
|
+
def self.puts(buf, option=nil)
|
14
|
+
adapter.puts(buf, option)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Print buffer
|
18
|
+
#
|
19
|
+
# @param buf [String] Text to be printed.
|
20
|
+
# @param option [Symbol] :big, :bar_code, :bitmap
|
21
|
+
# @return [String] buffer read from keyboard
|
22
|
+
def self.print(buf, option=nil)
|
23
|
+
adapter.print(buf, option)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.paper?
|
27
|
+
adapter.paper?
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.paperfeed
|
31
|
+
adapter.paperfeed
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Device
|
2
|
+
class Runtime
|
3
|
+
def self.adapter
|
4
|
+
Device.adapter::Runtime
|
5
|
+
end
|
6
|
+
|
7
|
+
# Execute app in new context.
|
8
|
+
# To execute the should exists a zip file cotain the app,
|
9
|
+
# previously downloaded from CloudWalk.
|
10
|
+
#
|
11
|
+
# @param app [String] App name, example "app", should exists file app.zip
|
12
|
+
# @param json [String] Parameters to confifure new aplication.
|
13
|
+
# @return [Object] From the new runtime instance.
|
14
|
+
def self.execute(app, json = nil)
|
15
|
+
zip = "./#{app}.zip"
|
16
|
+
Device::Display.clear
|
17
|
+
raise File::FileError, zip unless File.exists?(zip)
|
18
|
+
raise "Problem to unzip #{zip}" unless Zip.uncompress(zip, app)
|
19
|
+
return mrb_eval "Context.start('#{app}', '#{Device.adapter}', '#{json}')"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
|
2
|
+
class Device
|
3
|
+
class Setting
|
4
|
+
FILE_PATH = "./main/config.dat"
|
5
|
+
HOST_PRODUCTION = "switch.cloudwalk.io"
|
6
|
+
HOST_STAGING = "switch-staging.cloudwalk.io"
|
7
|
+
|
8
|
+
DEFAULT = {
|
9
|
+
"host" => "switch-staging.cloudwalk.io",
|
10
|
+
"host_port" => "31416",
|
11
|
+
"ssl" => "1",
|
12
|
+
"user" => "",
|
13
|
+
"password" => "", #WIFI
|
14
|
+
"apn" => "",
|
15
|
+
"authentication" => "", #WIFI
|
16
|
+
"essid" => "", #WIFI
|
17
|
+
"bssid" => "", #WIFI
|
18
|
+
"cipher" => "", #WIFI
|
19
|
+
"mode" => "", #WIFI
|
20
|
+
"channel" => "", #WIFI
|
21
|
+
"media" => "",
|
22
|
+
"ip" => "",
|
23
|
+
"gateway" => "",
|
24
|
+
"dns1" => "",
|
25
|
+
"dns2" => "",
|
26
|
+
"subnet" => "",
|
27
|
+
"logical_number" => "",
|
28
|
+
"network_configured" => "",
|
29
|
+
"environment" => "",
|
30
|
+
"notification_timeout" => "",
|
31
|
+
"notification_interval" => "",
|
32
|
+
"notification_stream_timeout" => "",
|
33
|
+
"company_name" => ""
|
34
|
+
}
|
35
|
+
|
36
|
+
def self.setup
|
37
|
+
@file = FileDb.new(FILE_PATH, DEFAULT)
|
38
|
+
self.host = HOST_STAGING if self.staging?
|
39
|
+
@file
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.production?
|
43
|
+
self.environment == "production"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.staging?
|
47
|
+
self.environment == "staging"
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.method_missing(method, *args, &block)
|
51
|
+
setup unless @file
|
52
|
+
param = method.to_s
|
53
|
+
if @file[param]
|
54
|
+
@file[param]
|
55
|
+
elsif (param[-1..-1] == "=" && @file[param[0..-2]])
|
56
|
+
@file[param[0..-2]] = args.first
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Device
|
2
|
+
class Support
|
3
|
+
def self.class_to_path(klass)
|
4
|
+
klass.to_s.downcase
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.path_to_class(path)
|
8
|
+
constantize(camelize(remove_extension(path)))
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.camelize(str)
|
12
|
+
str.split('_').map {|w| w.capitalize}.join
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.remove_extension(path)
|
16
|
+
path.to_s.split(".")[-2].split("/").last
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.constantize(name)
|
20
|
+
if ! name.empty? && Object.const_defined?(name)
|
21
|
+
Object.const_get name
|
22
|
+
else
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
class Device
|
3
|
+
class System
|
4
|
+
class << self
|
5
|
+
attr_reader :serial, :backlight
|
6
|
+
attr_accessor :klass
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.adapter
|
10
|
+
Device.adapter::System
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.serial
|
14
|
+
@serial ||= adapter.serial
|
15
|
+
end
|
16
|
+
|
17
|
+
# Set screen backlight (turn on automatically if there has actions like key-pressing, card-swiping or card-inserting).
|
18
|
+
# 0 = Turn off backlight.
|
19
|
+
# 1 = (D200): Keep backlight on for 30 seconds ( auto-shut-down after 30 seconds).
|
20
|
+
# 1 = (Vx510): On.
|
21
|
+
# 2 = (D200): Always on.
|
22
|
+
# n = (Evo/Telium 2): Percentage until 100.
|
23
|
+
def self.backlight=(level)
|
24
|
+
adapter.backlight = level
|
25
|
+
@backlight = level
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.backlight
|
29
|
+
@backlight ||= adapter.backlight
|
30
|
+
end
|
31
|
+
|
32
|
+
# Read the battery level.
|
33
|
+
# 0 Battery voltage low and battery icon blinks. Suggested that do not process transaction, print and wireless communication etc. at this moment. You should recharge the battery immediately to avoid shut down and lost data.
|
34
|
+
# 1 Battery icon displays 1 grid
|
35
|
+
# 2 Battery icon displays 2 grids
|
36
|
+
# 3 Battery icon displays 3 grids
|
37
|
+
# 4 Battery icon displays 4 grids
|
38
|
+
# 5 Powered by external power supply and the battery in charging. Battery icon displays form empty to full cycle. The battery status indicator on the bottom of terminal is displaying red
|
39
|
+
# 6 Powered by external power supply and the battery charging 6 finished. Battery icon displays full grids. The battery status indicator on the bottom of terminal is displaying green.
|
40
|
+
def self.battery
|
41
|
+
adapter.battery
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.beep
|
45
|
+
adapter.beep
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.restart
|
49
|
+
adapter.restart
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.app
|
53
|
+
self.klass.to_s.downcase
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.model
|
57
|
+
adapter.model
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,268 @@
|
|
1
|
+
|
2
|
+
class Device
|
3
|
+
class Transaction
|
4
|
+
class Download
|
5
|
+
ERL_VERSION_MAGIC = 131
|
6
|
+
ERL_NIL_EXT = 'j'
|
7
|
+
ERL_SMALL_TUPLE_EXT = 'h'
|
8
|
+
ERL_ATOM_EXT = 'd'
|
9
|
+
ERL_BINARY_EXT = 'm'
|
10
|
+
ERL_INTEGER_EXT = 'b'
|
11
|
+
ERL_CONTENT_TYPE = "application/x-erlang-binary"
|
12
|
+
MAXATOMLEN = 255
|
13
|
+
PARAMS_FILE = "params.dat"
|
14
|
+
|
15
|
+
SUCCESS = 0
|
16
|
+
FILE_NOT_CHANGE = 1
|
17
|
+
FILE_NOT_FOUND = 2
|
18
|
+
SERIAL_NUMBER_NOT_FOUND = 3
|
19
|
+
COMMUNICATION_ERROR = -1
|
20
|
+
MAPREDUCE_RESPONSE_ERROR = -2
|
21
|
+
IO_ERROR = -3
|
22
|
+
|
23
|
+
def self.request_file(remote_path, local_path)
|
24
|
+
download = Device::Transaction::Download.new(Device::System.serial, "", Device.version)
|
25
|
+
download.perform(Device::Network.walk_socket,
|
26
|
+
Device::Setting.company_name,
|
27
|
+
remote_path, local_path, Device::System.app,
|
28
|
+
Device::Setting.logical_number)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.request_param_file(file = PARAMS_FILE)
|
32
|
+
request_file("#{Device::Setting.logical_number}_#{PARAMS_FILE}", file)
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_accessor :buffer, :request, :first_packet, :socket, :path, :crc
|
36
|
+
|
37
|
+
def initialize(serial, path, version)
|
38
|
+
@serial = serial
|
39
|
+
@path = path
|
40
|
+
@version = version
|
41
|
+
end
|
42
|
+
|
43
|
+
# 0: Success
|
44
|
+
# -1: Commnucation error
|
45
|
+
# -2: Mapreduce response error
|
46
|
+
# -3: IO Error
|
47
|
+
def perform(socket, company_name, remote_path, filepath, current_app, logical_number, file_crc = nil)
|
48
|
+
@socket, @buffer, @request, @first_packet = socket, "", "", ""
|
49
|
+
@crc = file_crc ? file_crc : generate_crc(filepath)
|
50
|
+
key = "#{company_name}_#{remote_path}"
|
51
|
+
|
52
|
+
ei_encode_version # version
|
53
|
+
ei_encode_list_header(3) # mapreduce with 3 tuples
|
54
|
+
ei_encode_tuple_header(2) # tuple 1 inputs
|
55
|
+
ei_encode_atom("inputs") # atom inputs
|
56
|
+
ei_encode_list_header(1) # list inputs
|
57
|
+
ei_encode_tuple_header(2) # tuple contendo 2 elementos binarios, bucket and key
|
58
|
+
ei_encode_binary("assets") # elemento binario bucket
|
59
|
+
ei_encode_binary(key) # elemento binario key
|
60
|
+
ei_encode_list_header(0) # fim da list do inputs
|
61
|
+
|
62
|
+
ei_encode_tuple_header(2) # tuple 2: query
|
63
|
+
ei_encode_atom("query") # atom query
|
64
|
+
ei_encode_list_header(1) # list da query
|
65
|
+
ei_encode_tuple_header(4) # tuple contendo 4 elementos, { map, {modfun,Module,Function}, args, true }
|
66
|
+
ei_encode_atom("map") # primeiro elemento, atom type
|
67
|
+
ei_encode_tuple_header(3) # segundo elemento, nova tuple contendo 3 atoms
|
68
|
+
ei_encode_atom("modfun") # primeiro atom do segundo elemento, modfun
|
69
|
+
ei_encode_atom("walk") # segundo atom do segundo elemento, Module
|
70
|
+
ei_encode_atom("get_asset") # terceiro atom do segundo elemento, Function
|
71
|
+
|
72
|
+
ei_encode_list_header(7) # terceiro elemento, uma list com parametros do walk
|
73
|
+
ei_encode_binary(@serial) # elemento binario serialterminal
|
74
|
+
ei_encode_binary(@version) # elemento binario versao walk
|
75
|
+
ei_encode_binary(remote_path) # elemento binario nomeaplicativo
|
76
|
+
ei_encode_binary(crc) # elemento binario crc aplicativo
|
77
|
+
ei_encode_binary("") # elemento binario buffer do posxml
|
78
|
+
ei_encode_binary(logical_number) # elemento binario numero do terminal
|
79
|
+
ei_encode_binary(current_app) # elemento binario nome do aplicativo que esta sendo executado
|
80
|
+
ei_encode_list_header(0) # fim da list com parametros do walk
|
81
|
+
|
82
|
+
ei_encode_atom("true") # quarto elemento, atom true
|
83
|
+
ei_encode_list_header(0) # fim da list da query
|
84
|
+
|
85
|
+
ei_encode_tuple_header(2) # tuple 3: timeout
|
86
|
+
ei_encode_atom("timeout") # atom timeout
|
87
|
+
ei_encode_long(5000) # integer timeout
|
88
|
+
ei_encode_list_header(0) # fim da list do mapreduce contendo 3 tuples
|
89
|
+
|
90
|
+
mount_request # add request to protocol buffers message
|
91
|
+
|
92
|
+
return COMMUNICATION_ERROR unless @socket
|
93
|
+
|
94
|
+
# Send Request
|
95
|
+
socket.write(@request)
|
96
|
+
|
97
|
+
return COMMUNICATION_ERROR if (response_size = get_response_size(socket.read(4))) <= 0
|
98
|
+
|
99
|
+
return MAPREDUCE_RESPONSE_ERROR unless @first_packet = get_binary_term_beginning(response_size)
|
100
|
+
|
101
|
+
return_code = @first_packet[7].to_s.unpack("C*").first
|
102
|
+
file_size = @first_packet[9..12].to_s.unpack("N*").first
|
103
|
+
|
104
|
+
if return_code != FILE_NOT_CHANGE
|
105
|
+
return IO_ERROR if (partial_download_to_store(filepath, response_size, file_size) < 0)
|
106
|
+
end
|
107
|
+
|
108
|
+
# receive 6A
|
109
|
+
@socket.read(1) if response_size > 1024
|
110
|
+
|
111
|
+
return_code
|
112
|
+
end
|
113
|
+
|
114
|
+
def generate_crc(local_path)
|
115
|
+
if File.exists?(local_path)
|
116
|
+
file = File.open(local_path)
|
117
|
+
Device::Crypto.crc16_hex(file.read)
|
118
|
+
else
|
119
|
+
""
|
120
|
+
end
|
121
|
+
ensure
|
122
|
+
file.close if file
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def get_response_size(bytes)
|
128
|
+
return -1 if bytes.to_s.size <= 0
|
129
|
+
bytes.to_s.unpack("N*").first
|
130
|
+
end
|
131
|
+
|
132
|
+
def get_binary_term_beginning(response_size)
|
133
|
+
if response_size > 1024
|
134
|
+
packet = socket.read(1024)
|
135
|
+
else
|
136
|
+
packet = socket.read(response_size)
|
137
|
+
end
|
138
|
+
|
139
|
+
if packet.include?("\x83\x6c\x00")
|
140
|
+
"\x83\x6c\x00#{packet.split("\x83\x6C\x00")[1]}"
|
141
|
+
else
|
142
|
+
return false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def makelong(a, b)
|
147
|
+
(a & 0xffff) | ((b & 0xffff) << 16)
|
148
|
+
end
|
149
|
+
|
150
|
+
def makeword(a, b)
|
151
|
+
(a & 0xff) | ((b & 0xff) << 8)
|
152
|
+
end
|
153
|
+
|
154
|
+
def partial_download_to_store(filepath, response_size, file_size)
|
155
|
+
tmp = tmp_file(filepath)
|
156
|
+
file = File.open(tmp, "w+")
|
157
|
+
|
158
|
+
if (response_size > 1024)
|
159
|
+
file.write(@first_packet[13..-1])
|
160
|
+
downloaded = 1024
|
161
|
+
while(downloaded < (response_size - 1))
|
162
|
+
|
163
|
+
if (to_download = response_size - downloaded) > 1024
|
164
|
+
to_download = 1024
|
165
|
+
else
|
166
|
+
to_download -= 1 # because of 6A
|
167
|
+
end
|
168
|
+
|
169
|
+
downloaded += file.write(socket.read(to_download))
|
170
|
+
end
|
171
|
+
else
|
172
|
+
# -2 because of 6A
|
173
|
+
downloaded = file.write(@first_packet[13..-2])
|
174
|
+
end
|
175
|
+
|
176
|
+
file.close
|
177
|
+
File.rename(tmp, filepath)
|
178
|
+
downloaded
|
179
|
+
end
|
180
|
+
|
181
|
+
def put(value)
|
182
|
+
@buffer << value
|
183
|
+
end
|
184
|
+
|
185
|
+
def put8(value)
|
186
|
+
@buffer << value
|
187
|
+
end
|
188
|
+
|
189
|
+
def put32be(value)
|
190
|
+
@buffer << [value].pack("N")
|
191
|
+
end
|
192
|
+
|
193
|
+
def put16be(value)
|
194
|
+
@buffer << [value].pack("n")
|
195
|
+
end
|
196
|
+
|
197
|
+
def ei_encode_version
|
198
|
+
put8(ERL_VERSION_MAGIC.chr)
|
199
|
+
end
|
200
|
+
|
201
|
+
def ei_encode_list_header(arity)
|
202
|
+
put8(ERL_NIL_EXT)
|
203
|
+
put32be(arity) if arity > 0
|
204
|
+
end
|
205
|
+
|
206
|
+
def ei_encode_tuple_header(arity)
|
207
|
+
# if (arity <= 0xff) ERL_SMALL_TUPLE_EXT else ERL_LARGE_TUPLE_EXT
|
208
|
+
put8(ERL_SMALL_TUPLE_EXT)
|
209
|
+
put8(arity.chr);
|
210
|
+
end
|
211
|
+
|
212
|
+
# TODO: Check why MAXATOMLEN
|
213
|
+
def ei_encode_atom(value)
|
214
|
+
value.size > MAXATOMLEN ? len = MAXATOMLEN : len = value.size
|
215
|
+
put8(ERL_ATOM_EXT)
|
216
|
+
put16be(len)
|
217
|
+
put(value)
|
218
|
+
end
|
219
|
+
|
220
|
+
def ei_encode_binary(value)
|
221
|
+
put8(ERL_BINARY_EXT)
|
222
|
+
|
223
|
+
# TODO: Check it after to implement on put.
|
224
|
+
if value.is_a? Fixnum
|
225
|
+
put32be(2)
|
226
|
+
@buffer << [value].pack("s")
|
227
|
+
else
|
228
|
+
put32be(value.size)
|
229
|
+
put(value)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def ei_encode_long(value)
|
234
|
+
put8(ERL_INTEGER_EXT)
|
235
|
+
put32be(value)
|
236
|
+
end
|
237
|
+
|
238
|
+
def mount_request
|
239
|
+
request_size = [@buffer.size].pack("s") + "\x01"
|
240
|
+
|
241
|
+
put8("\x12")
|
242
|
+
put8("\x1b")
|
243
|
+
new_request = [@request.size].pack("N")
|
244
|
+
new_request << "\x17"
|
245
|
+
new_request << "\x0A"
|
246
|
+
new_request << "#{request_size}#{@buffer}#{ERL_CONTENT_TYPE}"
|
247
|
+
new_request << @request
|
248
|
+
@request = new_request
|
249
|
+
end
|
250
|
+
|
251
|
+
# MRuby do not support String#ljust
|
252
|
+
# TODO: duplicated from lib/variable.rb
|
253
|
+
def ljust(size, string)
|
254
|
+
if size > string.size
|
255
|
+
string = string + ("\x00" * (size - string.size))
|
256
|
+
end
|
257
|
+
string
|
258
|
+
end
|
259
|
+
|
260
|
+
def tmp_file(path)
|
261
|
+
paths = path.split("/")
|
262
|
+
paths[-1] = "tmp_#{paths.last}"
|
263
|
+
paths.join("/")
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
class Device
|
3
|
+
class Transaction
|
4
|
+
class EMV
|
5
|
+
class << self
|
6
|
+
attr_accessor :status, :mk_slot, :pinpad_type, :pinpad_wk, :show_amout
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :data, :info
|
10
|
+
|
11
|
+
def self.open(mk_slot, pinpad_type, pinpad_wk, show_amout)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.close
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.load_tables(acquirer)
|
18
|
+
end
|
19
|
+
|
20
|
+
def clean
|
21
|
+
@data = {:init => {}, :process => {}, :finish => {}}
|
22
|
+
@info = {:init => {}, :process => {}, :finish => {}}
|
23
|
+
end
|
24
|
+
|
25
|
+
def init
|
26
|
+
end
|
27
|
+
|
28
|
+
def response
|
29
|
+
end
|
30
|
+
|
31
|
+
def parameters
|
32
|
+
end
|
33
|
+
|
34
|
+
def timeout=(seconds)
|
35
|
+
end
|
36
|
+
|
37
|
+
def timeout
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove_card
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|