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,21 @@
1
+ category "Usher"
2
+ description "Connect to UsherM"
3
+ usage "[username] [password]"
4
+
5
+ help <<-EOS
6
+ Connects to UsherM server. This connection is not related to the connection opened in #{"connect".style(:command)}; only the #{"usherm".style(:command)} family of commands make use of this connection.
7
+
8
+ If username and password are omitted, they are defaulted from the #{"usherm_user".style(:environment)} and #{"usherm_pass".style(:environment)} environment variables, if set.
9
+
10
+ If the #{"usherm_user".style(:environment)} and #{"usherm_pass".style(:environment)} environment variables are set when the shell starts, this connection is created automatically.
11
+ EOS
12
+
13
+ run do
14
+ cmd_user = args[1] rescue nil
15
+ cmd_pass = args[2] rescue nil
16
+ username = cmd_user || @shell.get_env(:usherm_user)
17
+ password = cmd_pass || @shell.get_env(:usherm_pass)
18
+ return show_error(usage_msg) unless password
19
+ @shell.set_client(:usherm, UsherMgmtClient.new(nil, username, password))
20
+ ""
21
+ end
@@ -0,0 +1,149 @@
1
+ require 'colorize'
2
+
3
+ class String
4
+ def style_category
5
+ return self.colorize(:blue).bold
6
+ end
7
+
8
+ def style_class
9
+ return self.colorize(:light_black) if self == "none"
10
+
11
+ comps = split(".")
12
+ (comps.map do |comp|
13
+ if comp == comps.last then
14
+ comp.colorize(:red).bold
15
+ else
16
+ comp.colorize(:light_black)
17
+ end
18
+
19
+ end).join(".")
20
+ end
21
+
22
+ def style_constant_name
23
+ self.colorize(:red)
24
+ end
25
+
26
+ def style_constant_value
27
+ self.colorize(:green).bold
28
+ end
29
+
30
+ def style_collection_name
31
+ comps = split(".")
32
+ (comps.map do |comp|
33
+ if comp == comps.last then
34
+ comp.colorize(:green).bold
35
+ else
36
+ comp.colorize(:light_black)
37
+ end
38
+
39
+ end).join(".")
40
+ end
41
+
42
+ def style_protocol_name
43
+ self.colorize(:light_blue).bold
44
+ end
45
+
46
+ def style_method_name
47
+ self.colorize(:blue)
48
+ end
49
+
50
+ def style_field_name
51
+ self.colorize(:red)
52
+ end
53
+
54
+ def style_field_datatype
55
+ self.colorize(:magenta)
56
+ end
57
+
58
+ def style_origin
59
+ self.colorize(:magenta)
60
+ end
61
+
62
+ def style_command
63
+ self.colorize(:magenta).bold
64
+ end
65
+
66
+ def style_environment
67
+ self.colorize(:red)
68
+ end
69
+
70
+ def style_datacenter
71
+ self.colorize(:green)
72
+ end
73
+
74
+ def style_host
75
+ self.colorize(:red)
76
+ end
77
+
78
+ def style_ip
79
+ self.colorize(:blue)
80
+ end
81
+
82
+ def style_service
83
+ self.colorize(:magenta)
84
+ end
85
+
86
+ def style_product
87
+ self.colorize(:red).bold
88
+ end
89
+
90
+ def style_event_code
91
+ self.colorize(:blue).bold
92
+ end
93
+
94
+ def style_event_key
95
+ self.colorize(:red)
96
+ end
97
+
98
+ def style_error
99
+ self.colorize(:red).bold
100
+ end
101
+
102
+ def style_userdefined
103
+ self.colorize(:light_black).bold
104
+ end
105
+
106
+ def style_id
107
+ self.colorize(:green)
108
+ end
109
+
110
+ def style_build_name
111
+ self.bold
112
+ end
113
+
114
+ def style_branch
115
+ self.colorize(:red)
116
+ end
117
+
118
+ def style_timestamp
119
+ self.colorize(:blue)
120
+ end
121
+
122
+ def style_author
123
+ self.colorize(:light_black)
124
+ end
125
+
126
+ def style_cidr
127
+ ip, whack = self.split("/")
128
+ return self.colorize(:red) if ip.nil? or whack.nil?
129
+ ip.colorize(:red) + "/" + whack.colorize(:magenta)
130
+ end
131
+
132
+ def style_heading
133
+ self.bold
134
+ end
135
+
136
+ def style_client
137
+ self.bold
138
+ end
139
+
140
+ def style(type)
141
+ method = ("style_" + type.to_s).to_sym
142
+ return send(method) if self.methods.include?(method)
143
+ self
144
+ end
145
+
146
+ def unstyle
147
+ self.uncolorize
148
+ end
149
+ end
@@ -0,0 +1,97 @@
1
+ require 'trollop'
2
+
3
+ module A4Tools
4
+ class Command
5
+ attr_accessor :args, :input, :output, :error, :shell
6
+ attr_reader :status
7
+
8
+ def initialize(args, input=nil, output=nil, error=nil, shell=nil)
9
+ @input = input || StandardInput.new
10
+ @output = output || StandardOutput.new
11
+ @error = error || StandardOutput.new
12
+ @args = args
13
+ @shell = shell
14
+ end
15
+
16
+ def is_built_in?
17
+ built_in_methods.include? args[0].to_sym
18
+ end
19
+
20
+ def run_built_in
21
+ built_in = @shell.built_in(args[0]).new(@shell)
22
+ built_in.execute(@input, @output, @error, args)
23
+
24
+ @status = built_in.status
25
+ end
26
+
27
+ def built_in_methods
28
+ @shell.built_ins
29
+ end
30
+
31
+ def tab_complete_built_in
32
+ case args.length
33
+ when 0..1
34
+ built_in_methods
35
+ else
36
+ @shell.tab_complete_built_in(args)
37
+ end
38
+ end
39
+
40
+ def get_option_set
41
+ if args.length <= 1 or is_built_in?
42
+ tab_complete_built_in.map { |opt| opt.to_s || "" }
43
+ else
44
+ []
45
+ end
46
+ end
47
+
48
+ def tab_complete
49
+ fragment = args.last || ""
50
+ get_option_set.select { |opt| opt.to_s.start_with? fragment }
51
+ end
52
+
53
+ def make_commandline(args)
54
+ (args.map do |arg|
55
+ if arg.match(/\s/).nil? then
56
+ arg
57
+ else
58
+ arg.shellescape
59
+ end
60
+ end).join(" ")
61
+ end
62
+
63
+ def run_external
64
+ begin
65
+ cmdline = make_commandline(args)
66
+ Open3.popen3(cmdline) do |stdin, stdout, stderr, wait_thr|
67
+ begin
68
+ pid = wait_thr[:pid]
69
+
70
+ stdin.write(@input.read)
71
+ stdin.close
72
+
73
+ @status = wait_thr.value
74
+
75
+ @output.write(stdout.read)
76
+ stdout.close
77
+ stderr.close
78
+ rescue Errno::EPIPE
79
+ @error.write("-netshell: #{args[0]}: #{stderr.read}\n")
80
+ @status = 127
81
+ end
82
+ end
83
+ rescue Errno::ENOENT
84
+ @output.write("-netshell: #{args[0]}: command not found\n")
85
+ @status = 127
86
+ end
87
+
88
+ @status
89
+ end
90
+
91
+ def run
92
+ return "" if args.empty? or args[0].nil?
93
+ return run_built_in if is_built_in?
94
+ return run_external
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,132 @@
1
+ require 'open3'
2
+
3
+ class StringBuffer
4
+ attr_accessor :string
5
+ def initialize
6
+ @string = ""
7
+ end
8
+
9
+ end
10
+
11
+ module A4Tools
12
+ class StandardOutput
13
+ attr_accessor :color
14
+
15
+ def write(s)
16
+ s = s.unstyle unless @color
17
+ $stdout.write s.gsub("\t", " ").gsub("\n","\r\n")
18
+ end
19
+
20
+ def close
21
+ end
22
+
23
+ def print(s="")
24
+ write s.to_s
25
+ end
26
+
27
+ def puts(s="")
28
+ write s.to_s+"\n"
29
+ end
30
+ end
31
+
32
+ class PipeBuffer
33
+ attr_accessor :color
34
+ attr_reader :buffer
35
+
36
+ def initialize
37
+ @buffer = ""
38
+ end
39
+
40
+ def read
41
+ @color ? @buffer : @buffer.unstyle
42
+ end
43
+
44
+ def read_all
45
+ @color ? @buffer : @buffer.unstyle
46
+ end
47
+
48
+ def write(s)
49
+ @buffer += s
50
+ end
51
+
52
+ def puts(s)
53
+ if s.is_a? Array then
54
+ s.each { |e| puts e.to_s }
55
+ else
56
+ write(s.to_s+"\n")
57
+ end
58
+ end
59
+
60
+ def printf(s, *a)
61
+ write(sprintf(s.to_s, *a))
62
+ end
63
+
64
+ def print(s="")
65
+ write(s.to_s)
66
+ end
67
+
68
+ def close
69
+ end
70
+ end
71
+
72
+ class FileOverwriteOutput < StandardOutput
73
+ def initialize(filename)
74
+ @filename = filename
75
+ end
76
+
77
+ def access_type
78
+ "w"
79
+ end
80
+
81
+ def write(s)
82
+ s = s.unstyle unless @color
83
+ @fd ||= File.open(@filename, access_type)
84
+ @fd.write(s)
85
+ @fd.flush
86
+ end
87
+
88
+ def close
89
+ @fd.close
90
+ end
91
+ end
92
+
93
+ class FileAppendOutput < FileOverwriteOutput
94
+ def access_type
95
+ "a"
96
+ end
97
+ end
98
+
99
+ class StandardInput
100
+ def read
101
+ begin
102
+ STDIN.read_nonblock(256)
103
+ rescue IO::WaitReadable
104
+ ""
105
+ rescue EOFError
106
+ nil
107
+ end
108
+ end
109
+
110
+ def read_all
111
+ buffer = ""
112
+ while (line = read) != nil
113
+ buffer += line
114
+ end
115
+ buffer.chomp
116
+ end
117
+ end
118
+
119
+ class FileReadInput
120
+ def initialize(filename)
121
+ @filename = filename
122
+ end
123
+
124
+ def read
125
+ IO.read(@filename)
126
+ end
127
+
128
+ def read_all
129
+ IO.read(@filename)
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,396 @@
1
+ require 'io/console'
2
+ require 'net_shell/command'
3
+ require 'net_shell/io'
4
+ require 'net_shell/colors'
5
+ require 'net_shell/prompt'
6
+ require 'net_shell/builtin_command.rb'
7
+ require 'digest/sha1'
8
+ require 'shellwords'
9
+
10
+ module A4Tools
11
+ class NetShell
12
+ attr_accessor :env, :shared, :processing
13
+
14
+ def initialize
15
+ @history = []
16
+ @env = {}
17
+ @shared = { traffic:[] }
18
+ $config = @env
19
+ $localtalk = File.join(config_dir, "talk.json")
20
+
21
+ set_env(:color, "1")
22
+ set_env(:show_async, "1")
23
+ set_env(:serial, stored_serial)
24
+
25
+ read_env
26
+ setup_builtins
27
+ setup_support
28
+ end
29
+
30
+ ###
31
+ # Netshell setup
32
+ ###
33
+
34
+ def setup_support
35
+ setup_stored_json
36
+ setup_deployment_connection
37
+ setup_usherm_connection
38
+ end
39
+
40
+ def setup_stored_json
41
+ ObjectBuilder.load_path(shelldir(:json))
42
+ end
43
+
44
+ def config_dir
45
+ path = File.expand_path("~/.netshell")
46
+ Dir.mkdir(path) unless File.directory? path
47
+ path
48
+ end
49
+
50
+ def shelldir(dir)
51
+ path = File.join(config_dir, dir.to_s)
52
+ Dir.mkdir(path) unless File.directory? path
53
+ path
54
+ end
55
+
56
+ ###
57
+ # Built-in commands
58
+ ###
59
+
60
+ def allow_alerts(allow=true)
61
+ @allow_alerts = true
62
+ end
63
+
64
+ def setup_builtins
65
+ @built_ins ||= {}
66
+ dir = File.expand_path("builtin_commands", File.dirname(__FILE__))
67
+ all = load_builtins_from_directory(dir, false) + load_builtins_from_directory(shelldir(:bin), true)
68
+ @built_ins.delete_if { |command, subclass| not(all.include? subclass) }
69
+ end
70
+
71
+ def load_builtins_from_directory(dir, userdef)
72
+ Dir[File.join(dir, "*.rb")].map do |file|
73
+ subclass = built_in(File.basename(file, ".rb"))
74
+ if subclass.nil? or subclass.sha1 != Digest::SHA1.hexdigest(IO.read(file))
75
+ subclass = BuiltinCommand.load_command(file, userdef)
76
+ register_built_in(subclass.command, subclass)
77
+ end
78
+ subclass
79
+ end
80
+ end
81
+
82
+ def has_built_in?(name)
83
+ return built_in(name) != nil
84
+ end
85
+
86
+ def built_in(name)
87
+ @built_ins[name.to_sym]
88
+ end
89
+
90
+ def built_ins(full=false)
91
+ full ? @built_ins.values : @built_ins.keys
92
+ end
93
+
94
+ def register_built_in(command, cls)
95
+ @built_ins[command.to_sym] = cls
96
+ end
97
+
98
+ def tab_complete_built_in(args)
99
+ return [] unless has_built_in?(args[0])
100
+
101
+ built_in = built_in(args[0]).new(self)
102
+ built_in.parse(args)
103
+ built_in.tab
104
+ end
105
+
106
+ ###
107
+ # Environment management
108
+ ###
109
+
110
+ def path_for_env(key)
111
+ File.join(shelldir(:env), key)
112
+ end
113
+
114
+ def persist_env(*keys)
115
+ keys = @env.keys if keys.empty?
116
+ keys = keys[0] if keys[0].is_a? Array
117
+
118
+ present = keys.reject { |key| get_env(key).nil? }
119
+ absent = keys.select { |key| get_env(key).nil? }
120
+ present.each { |key| File.write(path_for_env(key), get_env(key)) }
121
+ unpersist_env(absent)
122
+ end
123
+
124
+ def unpersist_env(*keys)
125
+ keys = keys[0] if keys[0].is_a? Array
126
+ keys.each do |key|
127
+ path = path_for_env(key)
128
+ File.delete(path) if File.exist? path
129
+ end
130
+ end
131
+
132
+ def read_env
133
+ Dir[File.join(shelldir(:env), "*")].each { |file| set_env(File.basename(file), File.open(file).read.chomp) }
134
+ end
135
+
136
+ def set_env(key, value)
137
+ if value.nil?
138
+ @env.delete(key.to_sym)
139
+ else
140
+ @env[key.to_sym] = value
141
+ end
142
+ end
143
+
144
+ def get_env(key)
145
+ @env[key.to_sym]
146
+ end
147
+
148
+ def env_is_true?(key)
149
+ value = get_env(key)
150
+ value != nil and value != "0"
151
+ end
152
+
153
+ ###
154
+ # Shared variables
155
+ ###
156
+
157
+ def username
158
+ @env[:usherm_user]
159
+ end
160
+
161
+ def password
162
+ @env[:usherm_pass]
163
+ end
164
+
165
+ def setup_usherm_connection
166
+ return if username.nil? or password.nil?
167
+ set_client(:usherm, UsherMgmtClient.new(nil, username, password))
168
+ puts "\rAutomatically connecting to Usher as #{username}"
169
+ end
170
+
171
+ def setup_deployment_connection
172
+ return if username.nil? or password.nil?
173
+ set_client(:deployment, DeploymentClient.new("http://deployments.acres4.net:8080/deployment/json?wrap", username, password))
174
+ puts "\rAutomatically connecting to Deployment as #{username}"
175
+ end
176
+
177
+ def clients
178
+ @clients.keys
179
+ end
180
+
181
+ def client(key)
182
+ @clients[key.to_sym]
183
+ end
184
+
185
+ def set_client(key, client)
186
+ @clients ||= {}
187
+ @clients[key] = client
188
+ client.refresh_async rescue ""
189
+ client.on(:error) { |trigger, message| alert("#{key.to_s}: #{message}") }
190
+ end
191
+
192
+ def set_active_client(key)
193
+ @shared[:client] = @clients[key.to_sym]
194
+ end
195
+
196
+ def active_client
197
+ @shared[:client]
198
+ end
199
+
200
+ def active_client_name
201
+ @clients.each { |key, client| return key if client == @shared[:client] }
202
+ nil
203
+ end
204
+
205
+ ###
206
+ # Command prompt
207
+ ###
208
+
209
+ def bad_command(args)
210
+ "Unrecognized command: #{args[0]}"
211
+ end
212
+
213
+ def is_input_redirect?(arg)
214
+ arg == "<"
215
+ end
216
+
217
+ def is_output_redirect?(arg)
218
+ [ ">", ">>" ].include? arg
219
+ end
220
+
221
+ def is_redirect?(arg)
222
+ is_input_redirect?(arg) || is_output_redirect?(arg)
223
+ end
224
+
225
+ def get_input(args)
226
+ index = args.find_index { |arg| is_input_redirect? arg }
227
+ return StandardInput.new if (index.nil? or index > args.length - 2)
228
+
229
+ case args[index]
230
+ when "<"
231
+ FileReadInput.new(args[index+1])
232
+ end
233
+ end
234
+
235
+ def get_output(args)
236
+ index = args.find_index { |arg| is_output_redirect? arg }
237
+ default = StandardOutput.new
238
+ default.color = @env[:color] != "0"
239
+ return default if (index.nil? or index > args.length - 2)
240
+
241
+ case args[index]
242
+ when ">"
243
+ FileOverwriteOutput.new(args[index+1])
244
+ when ">>"
245
+ puts "Appending to #{args[index+1]}"
246
+ FileAppendOutput.new(args[index+1])
247
+ end
248
+ end
249
+
250
+ def get_error(args)
251
+ error = StandardOutput.new
252
+ error.color = @env[:color] != "0"
253
+ error
254
+ end
255
+
256
+ def clean_args(args)
257
+ index = args.find_index { |arg| is_redirect? arg }
258
+ return args if index.nil?
259
+ args[0 .. index-1]
260
+ end
261
+
262
+ def split_args(cmdline)
263
+ return [] if cmdline.nil? or cmdline.empty?
264
+ cmdline.gsub(/`\b/, "\"`").gsub(/\b`/, "`\"").shellsplit_partial
265
+ end
266
+
267
+ def process_backtick(line)
268
+ line = line[1..-2] if line[0] == '`' and line[-1] == '`'
269
+ cmd = command_for_line(line)
270
+ cmd.input = StandardInput.new
271
+ cmd.output = PipeBuffer.new
272
+ cmd.run
273
+ cmd.output.read.chomp
274
+ end
275
+
276
+ def transform_args(args)
277
+ args.map do |arg|
278
+ if arg[0] == "$" then
279
+ get_env(arg[1..-1]) || ""
280
+ elsif arg[0] == '`' and arg[-1] == '`' then
281
+ process_backtick(arg)
282
+ else
283
+ arg
284
+ end
285
+ end
286
+ end
287
+
288
+ def command_for_line(cmdline, allow_trailing_space=false)
289
+ cmdline ||= ""
290
+ args = transform_args(split_args(cmdline))
291
+ args.push "" if allow_trailing_space and cmdline.match(/\s+$/)
292
+ Command.new(clean_args(args), get_input(args), get_output(args), get_error(args), self)
293
+ end
294
+
295
+ def exec(cmdline)
296
+ return if cmdline.match(/^\s+$/)
297
+ commands = cmdline.split("|").map { |subcommand| command_for_line(subcommand) }
298
+
299
+ last_cmd = nil
300
+ commands.each do |cmd|
301
+ cmd.input = last_cmd.output unless last_cmd.nil?
302
+ cmd.output = PipeBuffer.new unless cmd == commands.last
303
+ break if cmd.run != 0
304
+ last_cmd = cmd
305
+ end
306
+ end
307
+
308
+ def add_to_alert_queue(msg)
309
+ @alert_queue ||= []
310
+ @alert_queue.push(msg)
311
+ end
312
+
313
+ def flush_alert_queue
314
+ return if @alert_queue.nil?
315
+ @alert_queue.each { |alert_msg| alert(alert_msg) }
316
+ @alert_queue = nil
317
+ end
318
+
319
+ def alert(msg)
320
+ if @processing and not @allow_alerts
321
+ add_to_alert_queue(msg)
322
+ return
323
+ end
324
+
325
+ @prompt.clear_line
326
+ @prompt.refresh_prompt
327
+ puts "\r#{msg}"
328
+ @prompt.redraw_line if @alert_queue.nil? and not @processing
329
+ end
330
+
331
+ def prompt_text
332
+ client = self.shared[:client]
333
+ return "net> " if client.nil? or not client.ready
334
+ return "#{client.uri}> " if client.server_info.nil?
335
+
336
+ "#{client.uri} #{client.server_info[:appName]}> "
337
+ end
338
+
339
+ def enter
340
+ @prompt = Prompt.new(:history_file => File.join(config_dir, "history"))
341
+ @prompt.tab = lambda do |cmdline|
342
+ setup_builtins
343
+ command_for_line(cmdline.split("|").last, true).tab_complete
344
+ end
345
+ @prompt.prompt = lambda { prompt_text }
346
+ @processing = false
347
+
348
+ while(true) do
349
+ line = @prompt.read_line
350
+ setup_builtins
351
+ @processing = true
352
+ @allow_alerts = false
353
+ exec(line)
354
+ @processing = false
355
+ flush_alert_queue
356
+ end
357
+ end
358
+
359
+ ###
360
+ # Network listener
361
+ ###
362
+
363
+ def wrap_message(message, sender)
364
+ { time: Time.now, sender: sender, message: message }
365
+ end
366
+
367
+ def notify_outgoing_message(client, message)
368
+ end
369
+
370
+ def notify_connect(client)
371
+ return unless client == active_client
372
+ end
373
+
374
+ def notify_disconnect(client)
375
+ return unless client == active_client
376
+ alert("Disconnected from #{client.uri}")
377
+ end
378
+
379
+ def notify_incoming_message(client, message)
380
+ return unless client == active_client
381
+ alert("server:".magenta + " #{message}") if env_is_true?(:show_async)
382
+ end
383
+
384
+ def stored_serial
385
+ file = File.join(config_dir, "serial")
386
+
387
+ begin
388
+ return IO.read(file)
389
+ rescue
390
+ serial = Digest::SHA1.hexdigest(Random.new.bytes(16)).to_s
391
+ File.write(file, serial) rescue nil
392
+ return serial
393
+ end
394
+ end
395
+ end
396
+ end