a4tools 1.2.7

Sign up to get free protection for your applications and to get access to all the features.
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