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,151 @@
1
+ category "Kai"
2
+ description "Generate machine events"
3
+ usage "[event_code machine_location]"
4
+
5
+ tab do
6
+ events.events.map { |event| event[:key] }
7
+ end
8
+
9
+ tab :machine do
10
+ machine_list
11
+ end
12
+
13
+ opt :amount, "Cash value associated with event. Used for jackpot and handpays.", :type => :integer
14
+ opt :tier, "Player tier level name", :type => :string
15
+ opt :first_name, "Player first name", :type => :string
16
+ opt :last_name, "Player last name", :type => :string
17
+ opt :employee, "Employee card ID", :type => :integer
18
+ opt :patron, "Patron card I", :type => :integer
19
+ opt :machine, "Machine location", :type => :string
20
+
21
+ opt :allow_duplicate, "Allow duplicate machines when spamming with random machine IDs"
22
+ opt :spam, "Spam the event repeatedly", :type => :integer, :default => 1
23
+ opt :spam_interval, "Specify number of seconds between spams in milliseconds", :type => :integer, :default => 1000
24
+
25
+ opt :list_names, "List Kai events, alphabetized by name"
26
+
27
+ run do
28
+ if args.length == 1 then
29
+ list = events.events
30
+ (list.sort! { |a,b| a[:key] <=> b[:key] }) if params[:list_names]
31
+ (events.events.map do |event|
32
+ code = sprintf("%5d", event[:code]).style(:event_code)
33
+ key = sprintf("%35s", event[:key].to_s).style(:event_key)
34
+
35
+ "#{code} #{key} -- #{event[:description]}"
36
+ end).join("\n")
37
+ else
38
+ machine = args[2] rescue random_machine
39
+ code = event_code(args[1])
40
+ return show_error("Unknown event code #{code}") if code.nil?
41
+ return show_error("Unable to connect QA test interface") unless qa.connect_if_needed
42
+ return show_error("Only have #{machine_list.length} machines to choose from; either reduce spam count or allow duplicates") if params[:spam] > machine_list.length and not params[:allow_duplicate]
43
+
44
+ index = 0
45
+ allowed_list = machine_list
46
+ params[:spam].times do
47
+ index = index + 1
48
+ machine = params[:machine] || allowed_list.sample
49
+ allowed_list.delete(machine) unless params[:allow_duplicate]
50
+
51
+ message = build_request(args[1..-2].sample, machine)
52
+ puts "Sending event #{index} of #{params[:spam]}: #{event_description(message)}"
53
+ send_event(message)
54
+ sleep params[:spam_interval] * 1.0/1000.0 unless index == params[:spam]
55
+ end
56
+
57
+ ""
58
+ end
59
+ end
60
+
61
+ ##
62
+
63
+ def event_description(event)
64
+ name = event_name(event[:eventList][0][:event][:idEventCode]) || event[:eventList][0][:event][:idEventCode]
65
+ location = event[:eventList][0][:location]
66
+ "#{name} @ #{location}"
67
+ end
68
+
69
+ def machine_list
70
+ @shell.client(:config).machines rescue []
71
+ end
72
+
73
+ def random_machine
74
+ machine_list.sample
75
+ end
76
+
77
+ def send_event(message)
78
+ qa.inject_token(message)
79
+ jsonrpc = qa.jsonrpc_message(:qaTestEvent, "qatest", nil, message)
80
+ qa.send_message(jsonrpc).body
81
+ end
82
+
83
+ def build_request(code, machine)
84
+ {
85
+ __class: "com.acres4.common.info.mercury.qatest.QATestEventRequest",
86
+ tok:nil,
87
+ eventList:[ qa_event_table_item(code, machine) ]
88
+ }
89
+ end
90
+
91
+ def qa_event_table_item(code, machine)
92
+ {
93
+ event:event_table_item(code),
94
+ location:machine
95
+ }
96
+ end
97
+
98
+ def event_table_item(code)
99
+ {
100
+ idEventCode:code,
101
+ hostEvent:host_event(code),
102
+ collectStats:false,
103
+ receiptTime:Time.now.to_i,
104
+ playerRating:player_rating
105
+ }
106
+ end
107
+
108
+ def host_event(code)
109
+ {
110
+ priKey:0,
111
+ hostDeviceId:nil,
112
+ eventCode:code.to_s,
113
+ idPatron:params[:patron] || 0,
114
+ idEmployee:params[:employee] || 0,
115
+ amount:params[:amount] || 0,
116
+ meters:nil,
117
+ eventTime:Time.now.to_i,
118
+ hostTime:Time.now.to_i
119
+ }
120
+ end
121
+
122
+ def player_rating
123
+ return nil unless params[:patron] or params[:firstName] or params[:lastName] or params[:loyaltyTierStr]
124
+
125
+ {
126
+ idPatron:params[:patron] || 0,
127
+ firstName:params[:first_name] || "Little",
128
+ lastName:params[:last_name] || "Timmy",
129
+ loyaltyTierStr:params[:tier] || "Wood"
130
+ }
131
+ end
132
+
133
+ def event_by_identifier(identifier)
134
+ identifier ||= args[1]
135
+ identifier = identifier.to_i if identifier.is_a? String and identifier.match(/^[0-9]+$/)
136
+ events.events.each do |event|
137
+ return event if(event[:key].to_s == identifier.to_s or event[:code] == identifier)
138
+ end
139
+
140
+ pp identifier
141
+ pp args[1]
142
+ nil
143
+ end
144
+
145
+ def event_code(identifier=nil)
146
+ event_by_identifier(identifier)[:code]
147
+ end
148
+
149
+ def event_name(identifier=nil)
150
+ event_by_identifier(identifier)[:key]
151
+ end
@@ -0,0 +1,24 @@
1
+ category "Shell management"
2
+ description "Persist an environment variable"
3
+ usage "variable1 variable2 ..."
4
+
5
+ help "Causes an evironment variable to persist between netshell sessions."
6
+
7
+ tab do
8
+ @shell.env.keys.reject { |key| args.include? key.to_s }
9
+ end
10
+
11
+ validate { (args.length >= 2 and not params[:all]) or (args.length == 1 and params[:all]) }
12
+
13
+ opt :all, "Persist all variables"
14
+
15
+ run do
16
+ variables = if params[:all]
17
+ [] # causes persist to save everything
18
+ else
19
+ args[1..-1]
20
+ end
21
+
22
+ @shell.persist_env(variables)
23
+ ""
24
+ end
@@ -0,0 +1,6 @@
1
+ category "Shell management"
2
+ description "Current working directory"
3
+ help "Display current directory."
4
+
5
+ validate { args.length == 1 }
6
+ run { Dir.pwd }
@@ -0,0 +1,188 @@
1
+ category "Protocol manipulation"
2
+ description "Print message history for current connection"
3
+ usage [
4
+ "#{command} show all messages",
5
+ "#{command} n show nth message before most recent",
6
+ "#{command} start end show messages from start to end"
7
+ ]
8
+
9
+ help <<-EOS
10
+ Examples:
11
+ List all messages
12
+ #{command}
13
+
14
+ List most recent message
15
+ #{command} 0
16
+
17
+ List most recent 3 messages
18
+ #{command} 2 0
19
+
20
+ List first message in conversation
21
+ #{command} -1
22
+
23
+ List first 5 messages in conversation
24
+ #{command} -5 -1
25
+ EOS
26
+
27
+ opt :client, "Recap this history for a client other than the active client", :type => :string
28
+ opt :summary, "Only list class names in text mode"
29
+ opt :json, "Output as JSON"
30
+ opt :raw, "Don't wrap JSON objects with metadata objects."
31
+ opt :array, "Force JSON to always be an array, even if only a single object is returned"
32
+ opt :reverse, "Index messages from end of conversation (so message 0 is most recent)"
33
+
34
+ validate do
35
+ return "Must have an active client" if client.nil? and not params[:client]
36
+ return "#{params[:client]}: unknown client" if params[:client] and not @shell.clients.include? params[:client].to_sym
37
+ true
38
+ end
39
+
40
+ tab :client do
41
+ @shell.clients
42
+ end
43
+
44
+ run { use_json? ? json_output : text_output }
45
+
46
+ ###
47
+
48
+ def target_client
49
+ params[:client] ? @shell.client(params[:client]) : client
50
+ end
51
+
52
+ def messages
53
+ messages = target_client.history
54
+ end
55
+
56
+ def range_for_args(args)
57
+ case args.length
58
+ when 0,1
59
+ range = (0 .. -1)
60
+ when 2
61
+ range = args[1].to_i .. args[1].to_i
62
+ when 3
63
+ low = [args[1], args[2]].min
64
+ high = [args[1], args[2]].max
65
+ range = low.to_i .. high.to_i
66
+ end
67
+ end
68
+
69
+ def sender(msg)
70
+ case msg[:sender]
71
+ when :client
72
+ "client".light_blue
73
+ when :server
74
+ "server".magenta
75
+ end
76
+ end
77
+
78
+ def timecode(msg)
79
+ delta = msg[:time] - target_client.start_time
80
+ all_seconds = delta.to_i
81
+
82
+ milliseconds = 1000.0*(delta - all_seconds)
83
+ hours = (all_seconds / 3660).to_i
84
+ minutes = ((all_seconds - 3660*hours) / 60).to_i
85
+ seconds = (all_seconds - 3600*hours - 60*minutes).to_i
86
+
87
+ return sprintf("%3d:%02d:%02d.%03d", hours, minutes, seconds, milliseconds).light_black
88
+ end
89
+
90
+ def text_output
91
+ index = -1
92
+ set = params[:reverse] ? messages : messages.reverse
93
+ (set.reverse[range_for_args(args)].map do |msg|
94
+ index += 1
95
+ index_str = sprintf("%3d", index)
96
+ "#{index_str} #{timecode(msg)} #{sender(msg)} #{render_text(msg[:message])}"
97
+ end).join("\n")
98
+ end
99
+
100
+ def json_output
101
+ set = params[:reverse] ? messages : messages.reverse
102
+ set = (set.reverse[range_for_args(args)].map do |msg|
103
+ if params[:raw] then
104
+ msg[:message]
105
+ else
106
+ msg.reject { |k,v| k == :raw }
107
+ end
108
+ end)
109
+
110
+ set = set[0] if set.length == 1 and not params[:array]
111
+ set.to_json
112
+ end
113
+
114
+ def use_json?
115
+ params[:json] or params[:raw] or params[:array]
116
+ end
117
+
118
+ def render_text(message)
119
+ if params[:summary] then
120
+ render_summary(message)
121
+ else
122
+ message.is_a?(Hash) ? JSON.generate(message) : message
123
+ end
124
+ end
125
+
126
+ def render_summary(message)
127
+ toplevel, cls = pick_toplevel(message)
128
+ puts toplevel if cls.nil?
129
+ cls ||= talk.guess_class(toplevel)
130
+ class_name = cls.style(:class) || "Unknown"
131
+ id_str = message[:id] ? sprintf("%3d", message[:id]) : " "
132
+
133
+ sprintf("%s %20s %s %s",
134
+ id_str.style(:id),
135
+ method(message).style(:method_name),
136
+ class_name.style(:class),
137
+ human_readable_size(message.to_json.length)
138
+ )
139
+ end
140
+
141
+ def human_readable_size(size)
142
+ titles = [ "B", "KiB", "MiB", "GiB", "TiB" ]
143
+ titles.each_index do |idx|
144
+ title = titles[idx]
145
+ unit = 1024**idx
146
+ boundary = 1024*unit
147
+ return "#{size/unit} #{title}" if size < boundary or title == titles.last
148
+ end
149
+ end
150
+
151
+ def method(message)
152
+ return message[:method] if message.has_key? :method
153
+ request = find_request_with_id(message[:id])
154
+ request[:method] rescue "unknown"
155
+ end
156
+
157
+ def find_request_with_id(id)
158
+ target_client.history.each do |msg|
159
+ next if msg[:message].nil? or msg[:message][:id].nil? or not(msg[:message].has_key? :params)
160
+ return msg[:message] if msg[:message][:id].to_i == id.to_i
161
+ end
162
+
163
+ nil
164
+ end
165
+
166
+ def pick_toplevel(message)
167
+ message = symbolify(JSON.parse(message)) if message.is_a? String
168
+ if message[:jsonrpc] == "2.0" then
169
+ return bypass(message, "com.acres4.common.info.JSONRPCRequest") if message.has_key? :params
170
+ return [message, "Error"] unless message[:error].nil?
171
+ return bypass(message, "com.acres4.common.info.JSONRPCResponse") if message.has_key? :result
172
+ end
173
+
174
+ [message, talk.guess_class(message)]
175
+ end
176
+
177
+ def bypass(object, type)
178
+ case type
179
+ when "com.acres4.common.info.NamedObjectWrapper"
180
+ return bypass(object[:body], object[:className])
181
+ when "com.acres4.common.info.JSONRPCRequest"
182
+ return bypass(object[:params], talk.guess_class(object[:params]))
183
+ when "com.acres4.common.info.JSONRPCResponse"
184
+ return bypass(object[:result], talk.guess_class(object[:result]))
185
+ else
186
+ return [object, type]
187
+ end
188
+ end
@@ -0,0 +1,63 @@
1
+ category "Talk"
2
+ description "Find references to a Talk class"
3
+ usage "class_name"
4
+ help "Lists all classes and protocols referencing a particular Talk class."
5
+
6
+ validate { args.length == 2 }
7
+
8
+ tab 0 do
9
+ talk.things_named_like(args[1], [:class]).map { |thing| talk.truncated_name thing[:name] }
10
+ end
11
+
12
+ run do
13
+ search_cls = talk.class_named(args[1])
14
+ return show_error("#{args[1]}: no such class in talk") if search_cls.nil?
15
+ full_name = search_cls[:name]
16
+
17
+ methods = list_methods(full_name)
18
+ fields = list_fields(full_name)
19
+
20
+ if methods.length > 0 then
21
+ puts "Methods (#{methods.length})"
22
+ methods.each { |method| show_method(method[:protocol], method[:method]) }
23
+ end
24
+
25
+ if fields.length > 0 then
26
+ puts "Fields (#{fields.length})"
27
+ fields.each { |field| show_field(field[:class], field[:field]) }
28
+ end
29
+
30
+ ""
31
+ end
32
+
33
+ ###
34
+
35
+ def list_methods(name)
36
+ methods = []
37
+ talk.definition[:protocol].each do |proto|
38
+ proto[:method].each do |method|
39
+ methods.push({protocol:proto, method:method}) if(talk.name_matches?(name, method[:request]) or talk.name_matches?(name, method[:response]))
40
+ end
41
+ end
42
+
43
+ methods
44
+ end
45
+
46
+ def list_fields(name)
47
+ fields = []
48
+ talk.definition[:class].each do |cls|
49
+ cls[:field].each do |field|
50
+ fields.push({class:cls, field:field}) if talk.name_matches?(name, field[:type].first)
51
+ end
52
+ end
53
+
54
+ fields
55
+ end
56
+
57
+ def show_method(protocol, method)
58
+ puts "\t#{protocol[:name].style(:protcol_name)}: #{method[:name].style(:method_name)} #{method[:request].style(:class)} -> #{method[:response].style(:class)}"
59
+ end
60
+
61
+ def show_field(cls, field)
62
+ puts "\t#{cls[:name].style(:class)}: #{field[:name].style(:field_name)}#{field[:type][1..-1].join("")}"
63
+ end
@@ -0,0 +1,36 @@
1
+ category "Protocol manipulation"
2
+ description "Select a connection for console"
3
+ usage "select [conenction]"
4
+
5
+
6
+ tab(0) { @shell.clients }
7
+
8
+ run do
9
+ if args.length == 1 then
10
+ (@shell.clients.sort.map { |key| render_client(key) }).join("\n")
11
+ else
12
+ return show_error("#{args[1]}: no such client") unless @shell.clients.include?(args[1].to_sym)
13
+ @shell.set_active_client(args[1])
14
+ ""
15
+ end
16
+ end
17
+
18
+ def render_client(key)
19
+ target = @shell.client(key)
20
+ fmt_key = sprintf("%20s", key.to_s)
21
+ host = usherm.host_for_url(target.uri) || "unknown host"
22
+ info = source_id(target)
23
+
24
+ "#{fmt_key.style(:target)}: #{info} #{target.uri.to_s.style(:url)} (#{host.style(:host)})"
25
+ end
26
+
27
+ def source_id(target)
28
+ app_info = target.server_info || {}
29
+ version = target.version || app_info[:currentTalkVersion]
30
+ protocol = sprintf("%-6s", (version || "")).style(:protocol_name)
31
+ name = sprintf("%20s", ((app_info[:appName] rescue nil) || "")).style(:name)
32
+ commit = sprintf("%7s", ((app_info[:sourceRevision][0..6] rescue nil) || "")).style(:commit)
33
+ branch = sprintf("%-30s", ((app_info[:supportingRevisions].first[:branches].first rescue nil) || "")).style(:branch)
34
+
35
+ "#{protocol} #{commit} #{branch}"
36
+ end