a4tools 1.2.7

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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.bundle/install.log +38 -0
  3. data/.gitignore +2 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +38 -0
  6. data/a4tools.gemspec +38 -0
  7. data/bin/deploy_latest_clients +32 -0
  8. data/bin/devsite_config_server +48 -0
  9. data/bin/netshell +23 -0
  10. data/bin/update_server +101 -0
  11. data/bin/usher +54 -0
  12. data/lib/a4tools.rb +61 -0
  13. data/lib/a4tools/version.rb +3 -0
  14. data/lib/acres_client.rb +376 -0
  15. data/lib/clients/caching_client.rb +151 -0
  16. data/lib/clients/deployment_client.rb +53 -0
  17. data/lib/clients/kai_config_client.rb +39 -0
  18. data/lib/clients/usher_client.rb +72 -0
  19. data/lib/clients/usher_mgmt_client.rb +201 -0
  20. data/lib/event_manager.rb +24 -0
  21. data/lib/events.json +1 -0
  22. data/lib/net_shell/builtin_command.rb +312 -0
  23. data/lib/net_shell/builtin_commands/build.rb +251 -0
  24. data/lib/net_shell/builtin_commands/cd.rb +12 -0
  25. data/lib/net_shell/builtin_commands/connect.rb +122 -0
  26. data/lib/net_shell/builtin_commands/deploy.rb +280 -0
  27. data/lib/net_shell/builtin_commands/disconnect.rb +15 -0
  28. data/lib/net_shell/builtin_commands/excerpt.rb +97 -0
  29. data/lib/net_shell/builtin_commands/exit.rb +7 -0
  30. data/lib/net_shell/builtin_commands/get.rb +38 -0
  31. data/lib/net_shell/builtin_commands/help.rb +40 -0
  32. data/lib/net_shell/builtin_commands/host.rb +126 -0
  33. data/lib/net_shell/builtin_commands/inject.rb +42 -0
  34. data/lib/net_shell/builtin_commands/jsoncache.rb +80 -0
  35. data/lib/net_shell/builtin_commands/kai_event.rb +151 -0
  36. data/lib/net_shell/builtin_commands/persist.rb +24 -0
  37. data/lib/net_shell/builtin_commands/pwd.rb +6 -0
  38. data/lib/net_shell/builtin_commands/recap.rb +188 -0
  39. data/lib/net_shell/builtin_commands/references.rb +63 -0
  40. data/lib/net_shell/builtin_commands/select.rb +36 -0
  41. data/lib/net_shell/builtin_commands/send.rb +74 -0
  42. data/lib/net_shell/builtin_commands/set.rb +29 -0
  43. data/lib/net_shell/builtin_commands/show.rb +183 -0
  44. data/lib/net_shell/builtin_commands/site.rb +122 -0
  45. data/lib/net_shell/builtin_commands/ssh.rb +62 -0
  46. data/lib/net_shell/builtin_commands/talk.rb +90 -0
  47. data/lib/net_shell/builtin_commands/translate.rb +45 -0
  48. data/lib/net_shell/builtin_commands/unset.rb +14 -0
  49. data/lib/net_shell/builtin_commands/usher.rb +55 -0
  50. data/lib/net_shell/builtin_commands/usher_device.rb +39 -0
  51. data/lib/net_shell/builtin_commands/usher_site.rb +245 -0
  52. data/lib/net_shell/builtin_commands/usherm_connect.rb +21 -0
  53. data/lib/net_shell/colors.rb +149 -0
  54. data/lib/net_shell/command.rb +97 -0
  55. data/lib/net_shell/io.rb +132 -0
  56. data/lib/net_shell/net_shell.rb +396 -0
  57. data/lib/net_shell/prompt.rb +335 -0
  58. data/lib/object_builder/definitions/app_info_for_script.rb +83 -0
  59. data/lib/object_builder/definitions/connection_request.rb +28 -0
  60. data/lib/object_builder/definitions/device_info_for_system.rb +37 -0
  61. data/lib/object_builder/object_builder.rb +145 -0
  62. data/lib/talk.json +1 -0
  63. data/lib/talk_consumer.rb +235 -0
  64. metadata +279 -0
@@ -0,0 +1,53 @@
1
+ module A4Tools
2
+ class DeploymentClient < CachingClient
3
+ attr_accessor :cache_timeout
4
+
5
+ cache :buildList, :authenticate => true do
6
+ {
7
+ allowedAppIds:nil,
8
+ allowedCommitIds:nil
9
+ }
10
+ end
11
+
12
+ query :buildPublicationList, :authenticate => true do |site_id|
13
+ {
14
+ siteId:site_id
15
+ }
16
+ end
17
+
18
+ def publish_build(build, sites)
19
+ sites = [*sites]
20
+ return false unless authenticate_if_needed
21
+
22
+ request = {
23
+ commitId:build[:commitId],
24
+ appIds:[build[:appId]],
25
+ publicationTime:0,
26
+ siteIds:sites
27
+ }
28
+
29
+ result = send_message(wrapped_message("buildPublish", "com.acres4.common.info.build.BuildPublishRequest", request))
30
+ return false unless result.code.to_i >= 200 and result.code.to_i < 300
31
+
32
+ true
33
+ end
34
+
35
+ def index_list_by_app
36
+ builds = cache(:buildList)
37
+ apps = {}
38
+ builds.each do |build|
39
+ apps[build[:appId]] ||= []
40
+ apps[build[:appId]].push build
41
+ end
42
+
43
+ apps.values.each { |app_builds| app_builds.sort! { |a,b| a[:postDate] <=> b[:postDate] } }
44
+ apps
45
+ end
46
+
47
+ def builds_for_milestone(milestone, builds=nil)
48
+ index = index_list_by_app(builds)
49
+ in_milestone = []
50
+ (index.map { |app, builds| (builds.select { |b| b[:branches].is_a? Array and b[:branches].include? milestone }).last }).compact
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,39 @@
1
+ module A4Tools
2
+ class KaiConfigClient < CachingClient
3
+ attr_accessor :cache_timeout
4
+
5
+ #cache :getConfigWebVersion, :authenticate => true
6
+
7
+ query :configValueRequest, :authenticate => true do |id_config|
8
+ {
9
+ idConfig:id_config
10
+ }
11
+ end
12
+
13
+ def strip_wrapper(result)
14
+ body = result[:configValueWrappers][0][:wrappedConfigValues][0][:body]
15
+ body[:__class] = result[:configValueWrappers][0][:wrappedConfigValues][0][:className]
16
+ body
17
+ end
18
+
19
+ def site_version
20
+ response_body(send_message(empty_query(:getConfigWebVersion)))[:stringValue] rescue nil
21
+ end
22
+
23
+ def section_bank_info
24
+ strip_wrapper(query(:configValueRequest, talk["SECTION_BANK_LOCATION_VALUES"]))
25
+ end
26
+
27
+ def machines
28
+ (section_bank_info[:locations].map { |loc| loc[:location] })
29
+ end
30
+
31
+ def sections
32
+ (section_bank_info[:sections].map { |sect| sect[:sectionName] })
33
+ end
34
+
35
+ def banks
36
+ (section_bank_info[:banks].map { |bank| bank[:bankName] })
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,72 @@
1
+ module A4Tools
2
+ class UsherClient < AcresClient
3
+ class << self
4
+ def mirrors
5
+ [
6
+ "http://s01.ushers.acres4.net:8080/usher2/json?wrap",
7
+ "http://s02.ushers.acres4.net:8080/usher2/json?wrap",
8
+ "http://s03.ushers.acres4.net:8080/usher2/json?wrap"
9
+ ]
10
+ end
11
+
12
+ def random_mirror
13
+ _m = mirrors
14
+ _m[rand(_m.length)]
15
+ end
16
+ end
17
+
18
+ attr_reader :response
19
+
20
+ def initialize(uri=nil)
21
+ super(uri || self.class.random_mirror)
22
+ end
23
+
24
+ def usher_request_for_params(params)
25
+ request = {
26
+ app: app_info,
27
+ device: device_info
28
+ }
29
+
30
+ request[:device][:serialNumber] = params[:serial] if params.has_key?(:serial)
31
+ request[:ipOverride] = params[:ip] if params.has_key?(:ip)
32
+
33
+ request
34
+ end
35
+
36
+ def list_servers_raw(params={})
37
+ response = send_message(wrapped_message(params[:full] ? "usherAlt" : "usher", "com.acres4.common.info.usher.UsherRequest", usher_request_for_params(params)))
38
+ @list = response_body response
39
+ response
40
+ end
41
+
42
+ def list_servers(params={})
43
+ list_servers_raw
44
+ @list
45
+ end
46
+
47
+ def dump_usher_response(response=nil)
48
+ response ||= @list
49
+ s = "Site #{response['siteID']} (#{response['siteName']})\n"
50
+
51
+ response[:hosts].each do |host|
52
+ s += "\t#{host["product"]}, #{host["url"]}#{host["context"]}\n"
53
+ end
54
+ s += "\n"
55
+ end
56
+
57
+ def locate_service(service, response=nil)
58
+ list_servers unless @list
59
+ response ||= @list
60
+
61
+ products = response[:hosts].select do |h|
62
+ h[:product].match("^#{service}(-(Secure|Server))?$")
63
+ end
64
+
65
+ products.sort! do |h,o|
66
+ h[:product] <=> o[:product]
67
+ end
68
+
69
+ products.first
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,201 @@
1
+ require 'pp'
2
+
3
+ module A4Tools
4
+ class UsherMgmtClient < CachingClient
5
+ attr_accessor :cache_timeout
6
+ def initialize(destination, username, password, timeout=300)
7
+ super(destination || "https://usherm.acres4.net:8181/usher2/json", username, password, timeout)
8
+ end
9
+
10
+ cache :usherSystemId
11
+ cache :devSiteInfoSync
12
+ cache :usherInfo, :authenticate => true do
13
+ {
14
+ force:false,
15
+ crc:nil
16
+ }
17
+ end
18
+
19
+ def find_device_in_info(serial, site_info_list=nil, sync=false)
20
+ if site_info_list.nil? then
21
+ site_info_list = cache(:devSiteInfoSync, sync)
22
+ return nil if site_info_list.nil?
23
+ end
24
+
25
+ site_info_list ||= @site_info_list
26
+
27
+ site_info_list[:devSiteInfoArray].each do |info|
28
+ return info if info[:serialNumber] == serial
29
+ end
30
+
31
+ nil
32
+ end
33
+
34
+ def make_device(serial, description, site)
35
+ {
36
+ idDevSiteInfo: 0,
37
+ serialNumber: serial,
38
+ description: description,
39
+ idSite: site,
40
+ __class: "com.acres4.common.info.usher.DevSiteInfo"
41
+ }
42
+ end
43
+
44
+ def make_edit_for_device(device)
45
+ {
46
+ editObj: {
47
+ className:"com.acres4.common.info.usher.DevSiteInfo",
48
+ body:device
49
+ },
50
+ tok:@token
51
+ }
52
+ end
53
+
54
+ def update_device(serial, description, site, default_description="Added via API")
55
+ return nil unless authenticate_if_needed
56
+ device = find_device_in_info(serial) || make_device(serial, description || default_description, site)
57
+ device[:description] = description unless description.nil?
58
+ device[:idSite] = site
59
+
60
+ result = send_message(jsonrpc_message("usherEdit", nil, "com.acres4.common.info.usher.UsherEditRequest", make_edit_for_device(device)))
61
+ dirty
62
+ response_body(result)
63
+ end
64
+
65
+ def delete_device(serial)
66
+ return nil unless authenticate_if_needed
67
+ device = find_device_in_info(serial) || make_device(serial, description || default_description, site)
68
+ return nil if device.nil?
69
+
70
+ device[:idDevSiteInfo] = -1 * device[:idDevSiteInfo]
71
+
72
+ result = send_message(jsonrpc_message("usherEdit", nil, "com.acres4.common.info.usher.UsherEditRequest", make_edit_for_device(device)))
73
+ response_body(result)
74
+ end
75
+
76
+ def datacenter(id, sync=false)
77
+ cache(:usherSystemId,sync)[:dataCenters].each { |ctr| return ctr if ctr[:idDataCenter] == id }
78
+ nil
79
+ end
80
+
81
+ def provider(id, sync=false)
82
+ cache(:usherSystemId,sync)[:systemProviders].each { |provider| return provider if provider[:idSystemProvider].to_i == id.to_i }
83
+ nil
84
+ end
85
+
86
+ def env_type(type)
87
+ case type
88
+ when 0
89
+ "Development"
90
+ when 1
91
+ "QA"
92
+ when 2
93
+ "Production"
94
+ else
95
+ "Unknown (#{type})"
96
+ end
97
+ end
98
+
99
+ def system_type(type)
100
+ case type
101
+ when -1
102
+ "All"
103
+ when -2
104
+ "Development"
105
+ when -3
106
+ "Production"
107
+ else
108
+ "Unknown (#{type})"
109
+ end
110
+ end
111
+
112
+ def host_named(hostname, sync=false)
113
+ (cache(:usherSystemId, sync)[:systemHosts].each { |host| return host if host[:hostName] == hostname }) rescue nil
114
+ nil
115
+ end
116
+
117
+ def host_with_id(host_id, sync=false)
118
+ (cache(:usherSystemId, sync)[:systemHosts].each { |host| return host if host[:idSystemHost] == host_id.to_i }) rescue nil
119
+ nil
120
+ end
121
+
122
+ def site_with_id(site_id, sync=false)
123
+ (cache(:usherSystemId, sync)[:usherSites].each { |site| return site if site[:idSite] == site_id.to_i }) rescue nil
124
+ nil
125
+ end
126
+
127
+ def site_with_name(site_name, sync=false)
128
+ (cache(:usherSystemId, sync)[:usherSites].each { |site| return site if site[:name] == site_name }) rescue nil
129
+ nil
130
+ end
131
+
132
+ def acls_for_host_id(id, sync=false)
133
+ (cache(:usherInfo, sync)[:systemAcls].select { |acl| acl[:idSystemHost] == id }) rescue nil
134
+ end
135
+
136
+ def service_for_id(id, sync=false)
137
+ (cache(:usherInfo, sync)[:services].each { |service| return service if service[:idService] == id }) rescue nil
138
+ end
139
+
140
+ def acl_for_service(host, name)
141
+ begin
142
+ host = host_named(host) if host.is_a? String
143
+ acls = acls_for_host_id(host[:idSystemHost])
144
+ acls.each do |acl|
145
+ service = service_for_id(acl[:idService])
146
+ return acl if service[:name] == name
147
+ end
148
+ rescue
149
+ host
150
+ end
151
+ nil
152
+ end
153
+
154
+ def providers_for_site(site_id)
155
+ providers = self[:usherSystemId][:systemProviders]
156
+ providers = providers.sort { |a,b| a[:product] <=> b[:product] }
157
+ providers = providers.reject { |p| p[:idSites].nil? or not p[:idSites].include?(site_id.to_i) }
158
+ end
159
+
160
+ def hosts_for_provider(provider)
161
+ internal = provider[:usherHostsInternal] || []
162
+ external = provider[:usherHostsExternal] || []
163
+ hosts = internal + external
164
+ secure = hosts.select { |host| host[:product] == provider[:product] + "-Secure" }
165
+ return hosts if secure.empty?
166
+ secure
167
+ end
168
+
169
+ def provider_for_product(site_id, product)
170
+ providers = providers_for_site(site_id)
171
+ return nil if providers.nil?
172
+ providers.each { |prov| return prov if prov[:product] == product }
173
+ nil
174
+ end
175
+
176
+ def url_for_provider(provider)
177
+ opts = hosts_for_provider(provider).map { |host| { :host => host[:host], :port => host[:port], :url => host[:url] } }
178
+ result = try_connection_options(opts)
179
+ return (result[:url] rescue nil)
180
+ end
181
+
182
+ def host_for_url(url)
183
+ url = URI(url) unless url.is_a? URI
184
+
185
+ self[:usherSystemId][:systemProviders].each do |prov|
186
+ hosts_for_provider(prov).each do |host|
187
+ return host[:hostName] if host_matches_url(host, url)
188
+ end
189
+ end
190
+
191
+ nil
192
+ end
193
+
194
+ def host_matches_url(host, url)
195
+ host_url = URI(host[:url]) rescue nil
196
+ return true if host_url and url.host == host_url.host and url.port == host_url.port and url.scheme == host_url.scheme
197
+ return true if url.host == host[:hostName] and url.port == host[:port]
198
+ false
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,24 @@
1
+ module A4Tools
2
+ class EventManager
3
+ attr_accessor :events
4
+
5
+ def initialize(events=nil)
6
+ events = File.read(File.join(File.dirname(__FILE__), "events.json")) if events.nil?
7
+ events = File.read(events) if events.is_a? String and File.exists? events
8
+ events = JSON.parse(events) if events.is_a? String
9
+
10
+ @events = transform_events(events)
11
+ end
12
+
13
+ def transform_events(events)
14
+ events.map do |event|
15
+ { code:event["code"].to_i, key:event["key"].to_sym, description:event["description"] }
16
+ end
17
+ end
18
+
19
+ def event(id)
20
+ @events.each { |event| return event if event[:code] == id.to_i or event[:key] == id.to_sym }
21
+ nil
22
+ end
23
+ end
24
+ end
@@ -0,0 +1 @@
1
+ [{"code":10,"description":"Ticket printed - cashable voucher","key":"ticket_print"},{"code":20,"description":"Cash out button pressed","key":"cash_out"},{"code":30,"description":"Ticket inserted","key":"ticket_insert"},{"code":40,"description":"Ticket redeemed","key":"ticket_redeem"},{"code":50,"description":"Card removed","key":"card_remove"},{"code":70,"description":"Player card inserted","key":"card_insert_player"},{"code":80,"description":"Bill 20 inserted","key":"bill_insert_20"},{"code":90,"description":"Bill 5 inserted","key":"bill_insert_5"},{"code":100,"description":"Cash out occurred","key":"cash_out"},{"code":110,"description":"Bill 1 inserted","key":"bill_insert_1"},{"code":120,"description":"Bill acceptor bill rejected","key":"bill_reject"},{"code":130,"description":"Machine link up","key":"machine_link_up"},{"code":140,"description":"Machine link down","key":"machine_link_down"},{"code":150,"description":"Xtra Credit Played","key":"extra_credit_played"},{"code":160,"description":"Main door closed","key":"door_closed"},{"code":170,"description":"Bill 100 inserted","key":"bill_insert_100"},{"code":180,"description":"Bill 10 inserted","key":"bill_insert_10"},{"code":190,"description":"Change light off","key":"change_light_off"},{"code":200,"description":"Change light on","key":"change_light_on"},{"code":210,"description":"Illegal machine door opened","key":"door_open_illegal"},{"code":220,"description":"General tilt","key":"tilt_general"},{"code":230,"description":"Belly door closed","key":"belly_door_closed"},{"code":240,"description":"Cash box door closed","key":"cashbox_door_close"},{"code":250,"description":"Hopper Paid Progressive","key":"hopper_paid_progressive"},{"code":260,"description":"Cash box door opened","key":"cashbox_door_open"},{"code":270,"description":"Main door opened","key":"main_door_open"},{"code":280,"description":"Employee card inserted","key":"card_insert_employee"},{"code":290,"description":"Bill acceptor removed","key":"bill_acceptor_remove"},{"code":300,"description":"Bill acceptor inserted","key":"bill_acceptor_insert"},{"code":310,"description":"Belly door opened","key":"belly_door_open"},{"code":320,"description":"Printer paper low","key":"printer_paper_low"},{"code":330,"description":"Poker Bonus","key":"poker_bonus"},{"code":340,"description":"Invalid Player card inserted","key":"card_insert_invalid"},{"code":350,"description":"Totals zeroed","key":"totals_zeroed"},{"code":360,"description":"Points -> XtraCredits","key":"points_to_credit"},{"code":370,"description":"Illegal belly door open ","key":"belly_door_open_illegal"},{"code":380,"description":"Drop door closed","key":"drop_door_close"},{"code":390,"description":"Illegal drop door opened","key":"drop_door_open_illegal"},{"code":400,"description":"New Member Player card inserted","key":"card_insert_new_player"},{"code":410,"description":"Game buffer full","key":"game_buffer_full"},{"code":420,"description":"Bill 50 inserted","key":"bill_insert_50"},{"code":430,"description":"BE2 Online","key":"be2_online"},{"code":440,"description":"Bill acceptor hardware error","key":"bill_acceptor_hardware_error"},{"code":450,"description":"Printer paper out","key":"printer_paper_out"},{"code":460,"description":"BE2 Offline","key":"be2_offline"},{"code":470,"description":"Ticket rejected - rejected by","key":"ticket_reject_1"},{"code":480,"description":"Logic cage opened","key":"logiccage_open"},{"code":490,"description":"Logic cage closed","key":"logiccage_close"},{"code":500,"description":"Hot Player","key":"hot_player"},{"code":510,"description":"Display meters entered","key":"display_meters_enter"},{"code":520,"description":"Display meters exited","key":"display_meters_exit"},{"code":530,"description":"Game power on","key":"game_power_on"},{"code":540,"description":"Printer carriage jam","key":"printer_carriage_jam"},{"code":550,"description":"Game power off","key":"game_power_off"},{"code":560,"description":"Game recall","key":"game_recall"},{"code":570,"description":"Illegal cash box door opened","key":"cashbox_door_illegal"},{"code":580,"description":"Ticket rejected - amt not mult","key":"ticket_reject_2"},{"code":590,"description":"Account PIN locked","key":"account_pin_lock"},{"code":600,"description":"Time discrepancy","key":"time_discrepency"},{"code":610,"description":"Ticket rejected - redemption d","key":"ticket_reject_3"},{"code":620,"description":"Self test entered","key":"self_test_enter"},{"code":630,"description":"Self test exited","key":"self_test_exit"},{"code":640,"description":"Card PIN locked","key":"card_pin_lock"},{"code":650,"description":"OP changed","key":"op_change"},{"code":660,"description":"Printer on","key":"printer_on"},{"code":670,"description":"BE2 reset","key":"be2_reset"},{"code":680,"description":"Account PIN unlocked","key":"account_pin_unlock"},{"code":690,"description":"Printer comm error","key":"printer_comm_error"},{"code":700,"description":"Ticket rejected - timeout","key":"ticket_reject_4"},{"code":710,"description":"Power off slot door access ","key":"door_access_power_off"},{"code":720,"description":"FJP Ticket printed","key":"fjp_ticket_print"},{"code":730,"description":"Printer off","key":"printer_off"},{"code":740,"description":"Coin-in runaway limit exceeded","key":"coinin_runaway_limit"},{"code":750,"description":"Bill acceptor jam","key":"bill_acceptor_jam"},{"code":760,"description":"Handpay reset","key":"handpay_reset"},{"code":770,"description":"Power off cashbox door access ","key":"cashbox_door_open_power_off"},{"code":780,"description":"Logic cage door closed","key":"logiccage_door_close"},{"code":790,"description":"Illegal logic cage door opened","key":"logiccage_door_open_illegal"},{"code":800,"description":"FJP Handpay Ticket","key":"fjp_handpay_ticket"},{"code":820,"description":"Ticket printed - jackpot recor","key":"ticket_print_jackpot_record"},{"code":830,"description":"Drop door opened ","key":"drop_door_open"},{"code":840,"description":"Out of service","key":"out_of_service"},{"code":850,"description":"Bill acceptor full","key":"bill_acceptor_full"},{"code":860,"description":"Ticket rejected - unable to ac","key":"ticket_reject_5"},{"code":870,"description":"Device passed CRC","key":"device_passed_crc"},{"code":880,"description":"Ticket rejected - validator fa","key":"ticket_reject_6"},{"code":890,"description":"Ticket accepted/rejected","key":"ticket_accepted_rejected"},{"code":900,"description":"Activate paytable(s) ","key":"paytable_activate"},{"code":910,"description":"FJP Cancel Credit Ticket","key":"fjp_cancel_credit_ticket"},{"code":920,"description":"Reel tilt","key":"tilt_reel"},{"code":930,"description":"Abandoned Player card inserted","key":"card_insert_abandoned"},{"code":940,"description":"Ticket rejected - amt > credit","key":"ticket_reject_7"},{"code":950,"description":"XC used during session","key":"extra_credit_used_during_session"},{"code":960,"description":"Cancel credit reset","key":"cancel_credit_reset"},{"code":970,"description":"Coin test card inserted","key":"card_insert_cointest"},{"code":980,"description":"Abandoned Card","key":"abandoned_card"},{"code":990,"description":"Bonus changed","key":"bonus_changed"},{"code":1000,"description":"Ticket printed - handpay recor","key":"ticket_print_handpay_record"},{"code":1010,"description":"Reel disconnected","key":"reel_disconnected"},{"code":1020,"description":"Cancel credit pending","key":"cancel_credit_pending"},{"code":1030,"description":"Reel 3 tilt","key":"tilt_reel_3"},{"code":1040,"description":"Deactivate paytable(s) ","key":"paytable_deactivate"},{"code":1050,"description":"Ticket rejected - out of cycle","key":"ticket_reject_8"},{"code":1060,"description":"KDC node added","key":"kdc_node_add"},{"code":1070,"description":"Memory error reset","key":"memory_error_reset"},{"code":1080,"description":"KDC node removed","key":"kdc_node_remove"},{"code":1090,"description":"Reel 5 tilt","key":"tilt_reel_5"},{"code":1100,"description":"EGM removed from bonus","key":"egm_remove_from_bonus"},{"code":1110,"description":"Meter zeroed","key":"meter_zeroed"},{"code":1120,"description":"FJP Short Pay Ticket","key":"fjp_short_pay_ticket"},{"code":1140,"description":"Power off card cage access ","key":"card_cage_access_power_off"},{"code":1150,"description":"Progressive Jackpot pending W2","key":"progressive_jackpot_pending_w2"},{"code":1160,"description":"Power off drop door access ","key":"drop_door_open_power_off"},{"code":1170,"description":"Ticket rejected - bad transfer","key":"ticket_reject_9"},{"code":1180,"description":"Low battery","key":"low_battery"},{"code":1190,"description":"EGM added to bonus","key":"egm_add_to_bonus"},{"code":1200,"description":"FJP Progressive Ticket","key":"fjp_progressive_jackpot"},{"code":1210,"description":"Reel 2 tilt","key":"tilt_reel_2"},{"code":1220,"description":"Progressive Link failure","key":"progressive_link_failure"},{"code":1230,"description":"KDC node updated","key":"kdc_node_update"},{"code":1240,"description":"Card Inserted","key":"card_insert"},{"code":1250,"description":"Coin in tilt","key":"tilt_coin_in"},{"code":1260,"description":"Reel 1 tilt","key":"tilt_reel_1"},{"code":1270,"description":"Pay out reset","key":"pay_out_reset"},{"code":1280,"description":"Jackpot pending","key":"jackpot_pending"},{"code":1281,"description":"Tilt: Reel #1","key":"tilt_reel_1a"},{"code":1282,"description":"Tilt: Reel #2","key":"tilt_reel_2a"},{"code":1283,"description":"Tilt: Reel #3","key":"tilt_reel_3a"},{"code":1284,"description":"Tilt: Reel #4","key":"tilt_reel_4a"},{"code":1285,"description":"Tilt: Reel #5","key":"tilt_reel_5a"},{"code":1290,"description":"Reel 4 tilt","key":"tilt_reel_4"},{"code":1300,"description":"Node on line","key":"node_online"},{"code":1310,"description":"Enabled games or denoms changed ","key":"change_game_config"},{"code":1320,"description":"Node off line","key":"node_offline"},{"code":1330,"description":"Logic cage door opened","key":"logiccage_door_open"},{"code":1340,"description":"Unknown handpay","key":"unknown_handpay"},{"code":1350,"description":"Logic cage ram error data recovered","key":"logiccage_ram_error_recover"},{"code":1360,"description":"Eprom data error","key":"eprom_data_error"},{"code":1370,"description":"Device passed SHA","key":"device_passed_sha"},{"code":1380,"description":"Hopper full","key":"hopper_full"},{"code":1390,"description":"No response to SHA challenge","key":"sha_no_response"},{"code":1400,"description":"Bill acceptor bill reversed","key":"bill_acceptor_bill_reverse"},{"code":1410,"description":"Reverse coin in","key":"coin_in_reverse"},{"code":1420,"description":"BE2 door opened","key":"be2_door_open"},{"code":1430,"description":"Logic cage ram error data lost","key":"logiccage_ram_error_lost"},{"code":1440,"description":"Ticket rejected - number doesn","key":"ticket_reject_10"},{"code":1450,"description":"Cashout Ticket Printed","key":"ticket_print_cashout"},{"code":1460,"description":"PEprom bad checksum version","key":"eprom_checksum_error"},{"code":1500,"description":"Bonus Card Out","key":"bonus_card_out"},{"code":1510,"description":"Cash Transfer Tracking","key":"cash_transfer_tracking"},{"code":1520,"description":"Hopper low","key":"hopper_low"},{"code":1530,"description":"Jackpot Reset Key","key":"jackpot_reset_key"},{"code":1550,"description":"Mechanic In","key":"mechanic_in"},{"code":1560,"description":"Mechanic Out","key":"mechanic_out"},{"code":1570,"description":"Meter Comparison In","key":"meter_comparison_in"},{"code":1580,"description":"Meter Comparison Out","key":"meter_comparison_out"},{"code":1590,"description":"Personal Banker","key":"personal_banker"},{"code":1600,"description":"Player Update","key":"player_update"},{"code":1610,"description":"Possible Bad Card Reader","key":"cardreader_bad_reader"},{"code":1620,"description":"Progressive JP - Hopper Paid","key":"progressive_jackpot_hopper_paid"},{"code":1630,"description":"Progressive Level 0","key":"progressive_level_0"},{"code":1640,"description":"Progressive Level 1","key":"progressive_level_1"},{"code":1650,"description":"Progressive Level 2","key":"progressive_level_2"},{"code":1660,"description":"Progressive Level 3","key":"progressive_level_3"},{"code":1670,"description":"Progressive Level 4","key":"progressive_level_4"},{"code":1680,"description":"Progressive Level 5","key":"progressive_level_5"},{"code":1690,"description":"Progressive Level 6","key":"progressive_level_6"},{"code":1700,"description":"Progressive Level 7","key":"progressive_level_7"},{"code":1710,"description":"Progressive Level 8","key":"progressive_level_8"},{"code":1720,"description":"Progressive Level 9","key":"progressive_level_9"},{"code":1730,"description":"Request system validation #","key":"request_system_validation"},{"code":1740,"description":"Request Ticket Information","key":"request_ticket_information"},{"code":1750,"description":"Ticket Processing","key":"ticket_processing"},{"code":1760,"description":"Ticket Printed, System Val #","key":"ticket_printed"},{"code":1770,"description":"Comp Ticket Printed","key":"comp_ticket_printed"},{"code":1780,"description":"Machine rejected voucher","key":"voucher_rejected"},{"code":1790,"description":"Ticket confiscated by machine","key":"ticket_confiscated"},{"code":1800,"description":"Print status unknown","key":"print_status_unknown"},{"code":1810,"description":"Game timeout awaiting val #","key":"game_timeout_waiting"},{"code":1820,"description":"Invalid print message","key":"print_message_invalid"},{"code":1830,"description":"Printer failure, unable to print","key":"printer_failure_no_print"},{"code":1840,"description":"Unknow vend ticket status","key":"ticket_status"},{"code":1850,"description":"Reply timeout","key":"reply_timeout"},{"code":1860,"description":"Incompatible denomination","key":"incompatible_denomination"},{"code":1870,"description":"Ticket over limit","key":"ticket_over_limit"},{"code":1880,"description":"Ticket over credit limit","key":"ticket_over_credit_limit"},{"code":1890,"description":"Validator failure","key":"validator_failure"},{"code":1900,"description":"Vend request denied by DPU","key":"vend_request_denied"},{"code":1910,"description":"Val # request denied by DPU","key":"val_request_denied"},{"code":1920,"description":"ROM warning, version change","key":"rom_warning_version"},{"code":1930,"description":"Send Configuration","key":"configuration_send"},{"code":1940,"description":"Sentinel On, Memory OK","key":"sentinel_on"},{"code":1950,"description":"Serial Communications Down","key":"serial_comm_down"},{"code":1960,"description":"Serial Communications Up","key":"serial_comm_up"},{"code":1970,"description":"Soft Drop In","key":"soft_drop_in"},{"code":1980,"description":"Soft Drop Out","key":"soft_drop_out"},{"code":1990,"description":"Stacker Installed","key":"stacker_installed"},{"code":2000,"description":"Stacker Removed","key":"stacker_removed"},{"code":2010,"description":"Tilt: Hopper","key":"tilt_hopper"},{"code":2020,"description":"Tilt: Printer hardware failure","key":"tilt_printer_hardware_failure"},{"code":2030,"description":"Top Award","key":"top_award"},{"code":2040,"description":"Unknown","key":"unknown"},{"code":2050,"description":"Hopper Empty","key":"hopper_empty"}]
@@ -0,0 +1,312 @@
1
+ module A4Tools
2
+ class BuiltinCommand
3
+ attr_accessor :input, :error, :output, :args, :shell, :params
4
+ attr_reader :status, :result
5
+
6
+ class << self
7
+ attr_reader :category_text, :description_text, :usage_text, :help_text, :validator, :tab_completors, :run_block, :opts, :is_user_defined
8
+ attr_accessor :sha1, :filepath, :command
9
+
10
+ def setup
11
+ @description_text = ""
12
+ @usage_text = ""
13
+ @help_text = ""
14
+ @category_text = "General"
15
+ @validator = proc { true }
16
+ @tab_completors = { default: proc { [] } }
17
+ @run_block = proc { "" }
18
+ @opts = []
19
+ end
20
+
21
+ ## Command category.
22
+ ## Used to sort items in help.
23
+ def category(category)
24
+ @category_text = category
25
+ end
26
+
27
+ ## Summary of command
28
+ ## One-line description of command for use in help
29
+ def description(description)
30
+ @description_text = description
31
+ end
32
+
33
+ ## Command line usage
34
+ ## Added to end of usage argment. e.g. return "arg1 arg2" to get a string like "usage: my_command arg1 arg2"
35
+ def usage(usage)
36
+ @usage_text = usage
37
+ end
38
+
39
+ ## Help text
40
+ ## Supplemental help added to end of --help.
41
+ def help(help)
42
+ @help_text = help
43
+ end
44
+
45
+ ## Command line validation
46
+ ## Return true to indicate command line is valid.
47
+ ## Return false to generate error and return usage help.
48
+ ## Return a string to generate error and display the returned string.
49
+ def validate(&validator)
50
+ @validator = validator
51
+ end
52
+
53
+ ## Tab completion
54
+ ## Return an array of possible values. You are not responsible for filtering these values for those matching the current argument.
55
+ ## If an index is supplied, the block will only be invoked for that argument.
56
+ def tab(index=nil, &tab_completor)
57
+ if index.nil? then
58
+ @tab_completors[:default] = tab_completor
59
+ else
60
+ @tab_completors[index] = tab_completor
61
+ end
62
+ end
63
+
64
+ ## Defines a command line argument. Identical syntax to Trollop.
65
+ ## opt :name, "Supplies a name", :type => :string
66
+ def opt(key, description, params={})
67
+ @opts.push({ key:key, description:description, params:params })
68
+ end
69
+
70
+ ## Actual code block to execute when the command is run
71
+ def run(&block)
72
+ @run_block = block
73
+ end
74
+
75
+ ###
76
+ # Load from a file (don't call this directly)
77
+ def load_command(file, userdefined=false)
78
+ cmdname = File.basename(file.to_s, ".rb")
79
+ subclass = Class.new(A4Tools::BuiltinCommand) {}
80
+ contents = IO.read(file)
81
+
82
+ subclass.setup
83
+ subclass.command = cmdname
84
+ subclass.filepath = file
85
+ subclass.sha1 = Digest::SHA1.hexdigest contents
86
+ subclass.user_defined if userdefined
87
+ subclass.class_eval( contents, file )
88
+ subclass
89
+ end
90
+
91
+ # Identify a command as user-defined (called automatically)
92
+ def user_defined
93
+ @is_user_defined = true
94
+ end
95
+ end
96
+
97
+
98
+ ####
99
+ # convenience methods you might want to be aware of
100
+
101
+ def usher
102
+ if @shell.shared[:usher].nil? then
103
+ @shell.shared[:usher] = A4Tools::UsherClient.new()
104
+ end
105
+ @shell.shared[:usher]
106
+ end
107
+
108
+ def usherm
109
+ @shell.client(:usherm)
110
+ end
111
+
112
+ def client
113
+ @shell.active_client
114
+ end
115
+
116
+ def deployment
117
+ @shell.client(:deployment)
118
+ end
119
+
120
+ def qa
121
+ @shell.client(:qa)
122
+ end
123
+
124
+ def kaiconfig
125
+ @shell.client(:kaiconfig)
126
+ end
127
+
128
+ def show_error(msg)
129
+ @error.write "!!".style(:error) + " #{args[0].style(:command)}: #{msg}\n"
130
+ return "", 1
131
+ end
132
+
133
+ def show_exception(exception)
134
+ @error.write "\n"
135
+ @error.write "!!".style(:error) + "#{command} crashed: #{exception.class.to_s} #{exception.message}\n"
136
+ @error.write "Stack trace: #{exception.backtrace.map {|l| " #{l}\n"}.join}"
137
+ ""
138
+ end
139
+
140
+ ####
141
+ # don't override these unless you really know what you're doing and have a good reason
142
+
143
+ def initialize(shell, input=nil, output=nil, error=nil)
144
+ @shell = shell
145
+ @parser = parser
146
+
147
+ @input = input || StandardInput.new
148
+ @output = output || StandardOutput.new
149
+ @error = error || StandardOutput.new
150
+ end
151
+
152
+ def category
153
+ self.class.category_text
154
+ end
155
+
156
+ def command
157
+ self.class.command
158
+ end
159
+
160
+ def description
161
+ self.class.description_text
162
+ end
163
+
164
+ def usage
165
+ self.class.usage_text
166
+ end
167
+
168
+ def help
169
+ self.class.help_text
170
+ end
171
+
172
+ def validate
173
+ block_call(&self.class.validator)
174
+ end
175
+
176
+ def user_defined?
177
+ self.class.is_user_defined
178
+ end
179
+
180
+ def block_call(&block)
181
+ self.class.send(:define_method, :__block_call, &block)
182
+ self.class.send(:instance_method, :__block_call).bind(self).call
183
+ end
184
+
185
+ def sym_for_param(param)
186
+ param[2..-1].to_sym rescue ""
187
+ end
188
+
189
+ def tab
190
+ # only include --command-arguments if we already have a dash
191
+ param_mix = []
192
+ param_mix = all_opts.map { |opt| "--" + opt[:key].to_s.gsub("_","-") } if @realargs.last[0] == '-'
193
+
194
+ key = if @realargs.length >= 2 and self.class.tab_completors.has_key? sym_for_param(@realargs[-2])
195
+ sym_for_param(@realargs[-2])
196
+ elsif self.class.tab_completors.has_key?(args.length-2)
197
+ args.length - 2
198
+ else
199
+ :default
200
+ end
201
+
202
+ param_mix + block_call(&(self.class.tab_completors[key]))
203
+ end
204
+
205
+ def perform
206
+ return [educate, 1] if params[:help]
207
+
208
+ errmsg = validate
209
+ return show_error(errmsg) if errmsg.is_a? String
210
+ return show_error(usage_msg) if errmsg.nil? or errmsg == false
211
+
212
+ begin
213
+ block_call(&self.class.run_block)
214
+ rescue Interrupt
215
+ @error.write "Killed\n"
216
+ return ["", 1]
217
+ rescue SystemExit # allow commands to call exit
218
+ raise
219
+ rescue Exception => exception
220
+ return show_exception(exception)
221
+ end
222
+ end
223
+
224
+ def execute(input, output, error, args)
225
+ @input = input
226
+ @output = output
227
+ @error = error
228
+ parse(args)
229
+
230
+ r = perform
231
+ r = [r, 0] unless r.is_a? Array
232
+ @result = r[0] || ""
233
+ @status = r[1]
234
+
235
+ txt = @result.to_s
236
+ unless txt.empty? then
237
+ txt += "\n" unless txt.end_with? "\n"
238
+ @output.write txt
239
+ end
240
+
241
+ @status
242
+ end
243
+
244
+ def global_opts
245
+ [ { key: :help, description:"Show help", params:{} } ]
246
+ end
247
+
248
+ def all_opts
249
+ global_opts + self.class.opts
250
+ end
251
+
252
+ def parser
253
+ Trollop::Parser.new(all_opts) do |opts|
254
+ opts.each do |option|
255
+ opt option[:key], option[:description], option[:params]
256
+ end
257
+ end
258
+ end
259
+
260
+ def parse(args)
261
+ @realargs = Array.new(args)
262
+
263
+ begin
264
+ @params = @parser.parse(args)
265
+ rescue Trollop::HelpNeeded
266
+ @params = {help:true}
267
+ rescue Trollop::VersionNeeded
268
+ @params = {help:true}
269
+ rescue Trollop::CommandlineError
270
+ @params = {help:true}
271
+ end
272
+ @args = @parser.leftovers
273
+ @args = args if @args.nil? or @args.empty?
274
+ end
275
+
276
+ def usage_msg
277
+ u = usage
278
+ if usage.is_a? Array then
279
+ "usage:\n" + (u.map { |line| "\t#{command} [flags] #{line}" }).join("\n")
280
+ else
281
+ "usage: #{command} [flags] #{usage}"
282
+ end
283
+ end
284
+
285
+ def educate
286
+ buffer = PipeBuffer.new
287
+ @parser.educate buffer
288
+ intro_line = "#{command.style(:command)}: #{description}"
289
+ userdef_line = user_defined? ? "User defined".style(:userdefined) : nil
290
+
291
+ top_section = [intro_line, category.style(:category), userdef_line ].compact.join("\n")
292
+
293
+ [top_section+"\n", usage_msg+"\n", buffer.buffer, help].compact.join("\n")
294
+ end
295
+
296
+ def print(s="")
297
+ @output.print s
298
+ end
299
+
300
+ def puts(s="")
301
+ @output.puts s
302
+ end
303
+
304
+ def console_puts(s)
305
+ $stdout.puts s.gsub("\n","\r\n")
306
+ end
307
+
308
+ def console_print(s)
309
+ $stdout.print s.gsub("\n","\r\n")
310
+ end
311
+ end
312
+ end