Class: A4Tools::NetShell

Inherits:
Object
  • Object
show all
Defined in:
lib/net_shell/net_shell.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeNetShell

Returns a new instance of NetShell.



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/net_shell/net_shell.rb', line 14

def initialize
  @history = []
  @env = {}
  @shared = { traffic:[] }
  $config = @env
  $localtalk = File.join(config_dir, "talk.json")

  set_env(:color, "1")
  set_env(:show_async, "1")
  set_env(:serial, stored_serial)

  read_env
  setup_builtins
  setup_support
end

Instance Attribute Details

#envObject

Returns the value of attribute env.



12
13
14
# File 'lib/net_shell/net_shell.rb', line 12

def env
  @env
end

#processingObject

Returns the value of attribute processing.



12
13
14
# File 'lib/net_shell/net_shell.rb', line 12

def processing
  @processing
end

#sharedObject

Returns the value of attribute shared.



12
13
14
# File 'lib/net_shell/net_shell.rb', line 12

def shared
  @shared
end

Instance Method Details

#active_clientObject



196
197
198
# File 'lib/net_shell/net_shell.rb', line 196

def active_client
  @shared[:client]
end

#active_client_nameObject



200
201
202
203
# File 'lib/net_shell/net_shell.rb', line 200

def active_client_name
  @clients.each { |key, client| return key if client == @shared[:client] }
  nil
end

#add_to_alert_queue(msg) ⇒ Object



308
309
310
311
# File 'lib/net_shell/net_shell.rb', line 308

def add_to_alert_queue(msg)
  @alert_queue ||= []
  @alert_queue.push(msg)
end

#alert(msg) ⇒ Object



319
320
321
322
323
324
325
326
327
328
329
# File 'lib/net_shell/net_shell.rb', line 319

def alert(msg)
  if @processing and not @allow_alerts
    add_to_alert_queue(msg)
    return
  end

  @prompt.clear_line
  @prompt.refresh_prompt
  puts "\r#{msg}"
  @prompt.redraw_line if @alert_queue.nil? and not @processing
end

#allow_alerts(allow = true) ⇒ Object

Built-in commands



60
61
62
# File 'lib/net_shell/net_shell.rb', line 60

def allow_alerts(allow=true)
  @allow_alerts = true
end

#bad_command(args) ⇒ Object

Command prompt



209
210
211
# File 'lib/net_shell/net_shell.rb', line 209

def bad_command(args)
  "Unrecognized command: #{args[0]}"
end

#built_in(name) ⇒ Object



86
87
88
# File 'lib/net_shell/net_shell.rb', line 86

def built_in(name)
  @built_ins[name.to_sym]
end

#built_ins(full = false) ⇒ Object



90
91
92
# File 'lib/net_shell/net_shell.rb', line 90

def built_ins(full=false)
  full ? @built_ins.values : @built_ins.keys
end

#clean_args(args) ⇒ Object



256
257
258
259
260
# File 'lib/net_shell/net_shell.rb', line 256

def clean_args(args)
  index = args.find_index { |arg| is_redirect? arg }
  return args if index.nil?
  args[0 .. index-1]
end

#client(key) ⇒ Object



181
182
183
# File 'lib/net_shell/net_shell.rb', line 181

def client(key)
  @clients[key.to_sym]
end

#clientsObject



177
178
179
# File 'lib/net_shell/net_shell.rb', line 177

def clients
  @clients.keys
end

#command_for_line(cmdline, allow_trailing_space = false) ⇒ Object



288
289
290
291
292
293
# File 'lib/net_shell/net_shell.rb', line 288

def command_for_line(cmdline, allow_trailing_space=false)
  cmdline ||= ""
  args = transform_args(split_args(cmdline))
  args.push "" if allow_trailing_space and cmdline.match(/\s+$/)
  Command.new(clean_args(args), get_input(args), get_output(args), get_error(args), self)
end

#config_dirObject



44
45
46
47
48
# File 'lib/net_shell/net_shell.rb', line 44

def config_dir
  path = File.expand_path("~/.netshell")
  Dir.mkdir(path) unless File.directory? path
  path
end

#enterObject



339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/net_shell/net_shell.rb', line 339

def enter
  @prompt = Prompt.new(:history_file => File.join(config_dir, "history"))
  @prompt.tab = lambda do |cmdline|
    setup_builtins
    command_for_line(cmdline.split("|").last, true).tab_complete
  end
  @prompt.prompt = lambda { prompt_text }
  @processing = false

  while(true) do
    line = @prompt.read_line
    setup_builtins
    @processing = true
    @allow_alerts = false
    exec(line)
    @processing = false
    flush_alert_queue
  end
end

#env_is_true?(key) ⇒ Boolean

Returns:

  • (Boolean)


148
149
150
151
# File 'lib/net_shell/net_shell.rb', line 148

def env_is_true?(key)
  value = get_env(key)
  value != nil and value != "0"
end

#exec(cmdline) ⇒ Object



295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/net_shell/net_shell.rb', line 295

def exec(cmdline)
  return if cmdline.match(/^\s+$/)
  commands = cmdline.split("|").map { |subcommand| command_for_line(subcommand) }

  last_cmd = nil
  commands.each do |cmd|
    cmd.input = last_cmd.output unless last_cmd.nil?
    cmd.output = PipeBuffer.new unless cmd == commands.last
    break if cmd.run != 0
    last_cmd = cmd
  end
end

#flush_alert_queueObject



313
314
315
316
317
# File 'lib/net_shell/net_shell.rb', line 313

def flush_alert_queue
  return if @alert_queue.nil?
  @alert_queue.each { |alert_msg| alert(alert_msg) }
  @alert_queue = nil
end

#get_env(key) ⇒ Object



144
145
146
# File 'lib/net_shell/net_shell.rb', line 144

def get_env(key)
  @env[key.to_sym]
end

#get_error(args) ⇒ Object



250
251
252
253
254
# File 'lib/net_shell/net_shell.rb', line 250

def get_error(args)
  error = StandardOutput.new
  error.color = @env[:color] != "0"
  error
end

#get_input(args) ⇒ Object



225
226
227
228
229
230
231
232
233
# File 'lib/net_shell/net_shell.rb', line 225

def get_input(args)
  index = args.find_index { |arg| is_input_redirect? arg }
  return StandardInput.new if (index.nil? or index > args.length - 2)

  case args[index]
  when "<"
    FileReadInput.new(args[index+1])
  end
end

#get_output(args) ⇒ Object



235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/net_shell/net_shell.rb', line 235

def get_output(args)
  index = args.find_index { |arg| is_output_redirect? arg }
  default = StandardOutput.new
  default.color = @env[:color] != "0"
  return default if (index.nil? or index > args.length - 2)

  case args[index]
  when ">"
    FileOverwriteOutput.new(args[index+1])
  when ">>"
    puts "Appending to #{args[index+1]}"
    FileAppendOutput.new(args[index+1])
  end
end

#has_built_in?(name) ⇒ Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/net_shell/net_shell.rb', line 82

def has_built_in?(name)
  return built_in(name) != nil
end

#is_input_redirect?(arg) ⇒ Boolean

Returns:

  • (Boolean)


213
214
215
# File 'lib/net_shell/net_shell.rb', line 213

def is_input_redirect?(arg)
  arg == "<"
end

#is_output_redirect?(arg) ⇒ Boolean

Returns:

  • (Boolean)


217
218
219
# File 'lib/net_shell/net_shell.rb', line 217

def is_output_redirect?(arg)
  [ ">", ">>" ].include? arg
end

#is_redirect?(arg) ⇒ Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/net_shell/net_shell.rb', line 221

def is_redirect?(arg)
  is_input_redirect?(arg) || is_output_redirect?(arg)
end

#load_builtins_from_directory(dir, userdef) ⇒ Object



71
72
73
74
75
76
77
78
79
80
# File 'lib/net_shell/net_shell.rb', line 71

def load_builtins_from_directory(dir, userdef)
  Dir[File.join(dir, "*.rb")].map do |file|
    subclass = built_in(File.basename(file, ".rb"))
    if subclass.nil? or subclass.sha1 != Digest::SHA1.hexdigest(IO.read(file))
      subclass = BuiltinCommand.load_command(file, userdef)
      register_built_in(subclass.command, subclass)
    end
    subclass
  end
end

#notify_connect(client) ⇒ Object



370
371
372
# File 'lib/net_shell/net_shell.rb', line 370

def notify_connect(client)
  return unless client == active_client
end

#notify_disconnect(client) ⇒ Object



374
375
376
377
# File 'lib/net_shell/net_shell.rb', line 374

def notify_disconnect(client)
  return unless client == active_client
  alert("Disconnected from #{client.uri}")
end

#notify_incoming_message(client, message) ⇒ Object



379
380
381
382
# File 'lib/net_shell/net_shell.rb', line 379

def notify_incoming_message(client, message)
  return unless client == active_client
  alert("server:".magenta + " #{message}") if env_is_true?(:show_async)
end

#notify_outgoing_message(client, message) ⇒ Object



367
368
# File 'lib/net_shell/net_shell.rb', line 367

def notify_outgoing_message(client, message)
end

#passwordObject



161
162
163
# File 'lib/net_shell/net_shell.rb', line 161

def password
  @env[:usherm_pass]
end

#path_for_env(key) ⇒ Object

Environment management



110
111
112
# File 'lib/net_shell/net_shell.rb', line 110

def path_for_env(key)
  File.join(shelldir(:env), key)
end

#persist_env(*keys) ⇒ Object



114
115
116
117
118
119
120
121
122
# File 'lib/net_shell/net_shell.rb', line 114

def persist_env(*keys)
  keys = @env.keys if keys.empty?
  keys = keys[0] if keys[0].is_a? Array

  present = keys.reject { |key| get_env(key).nil? }
  absent = keys.select { |key| get_env(key).nil? }
  present.each { |key| File.write(path_for_env(key), get_env(key)) }
  unpersist_env(absent)
end

#process_backtick(line) ⇒ Object



267
268
269
270
271
272
273
274
# File 'lib/net_shell/net_shell.rb', line 267

def process_backtick(line)
  line = line[1..-2] if line[0] == '`' and line[-1] == '`'
  cmd = command_for_line(line)
  cmd.input = StandardInput.new
  cmd.output = PipeBuffer.new
  cmd.run
  cmd.output.read.chomp
end

#prompt_textObject



331
332
333
334
335
336
337
# File 'lib/net_shell/net_shell.rb', line 331

def prompt_text
  client = self.shared[:client]
  return "net> " if client.nil? or not client.ready
  return "#{client.uri}> " if client.server_info.nil?

  "#{client.uri} #{client.server_info[:appName]}> "
end

#read_envObject



132
133
134
# File 'lib/net_shell/net_shell.rb', line 132

def read_env
  Dir[File.join(shelldir(:env), "*")].each { |file| set_env(File.basename(file), File.open(file).read.chomp) }
end

#register_built_in(command, cls) ⇒ Object



94
95
96
# File 'lib/net_shell/net_shell.rb', line 94

def register_built_in(command, cls)
  @built_ins[command.to_sym] = cls
end

#set_active_client(key) ⇒ Object



192
193
194
# File 'lib/net_shell/net_shell.rb', line 192

def set_active_client(key)
  @shared[:client] = @clients[key.to_sym]
end

#set_client(key, client) ⇒ Object



185
186
187
188
189
190
# File 'lib/net_shell/net_shell.rb', line 185

def set_client(key, client)
  @clients ||= {}
  @clients[key] = client
  client.refresh_async rescue ""
  client.on(:error) { |trigger, message| alert("#{key.to_s}: #{message}") }
end

#set_env(key, value) ⇒ Object



136
137
138
139
140
141
142
# File 'lib/net_shell/net_shell.rb', line 136

def set_env(key, value)
  if value.nil?
    @env.delete(key.to_sym)
  else
    @env[key.to_sym] = value
  end
end

#setup_builtinsObject



64
65
66
67
68
69
# File 'lib/net_shell/net_shell.rb', line 64

def setup_builtins
  @built_ins ||= {}
  dir = File.expand_path("builtin_commands", File.dirname(__FILE__))
  all = load_builtins_from_directory(dir, false) + load_builtins_from_directory(shelldir(:bin), true)
  @built_ins.delete_if { |command, subclass| not(all.include? subclass)  }
end

#setup_deployment_connectionObject



171
172
173
174
175
# File 'lib/net_shell/net_shell.rb', line 171

def setup_deployment_connection
  return if username.nil? or password.nil?
  set_client(:deployment, DeploymentClient.new("http://deployments.acres4.net:8080/deployment/json?wrap", username, password))
  puts "\rAutomatically connecting to Deployment as #{username}"
end

#setup_stored_jsonObject



40
41
42
# File 'lib/net_shell/net_shell.rb', line 40

def setup_stored_json
  ObjectBuilder.load_path(shelldir(:json))
end

#setup_supportObject

Netshell setup



34
35
36
37
38
# File 'lib/net_shell/net_shell.rb', line 34

def setup_support
  setup_stored_json
  setup_deployment_connection
  setup_usherm_connection
end

#setup_usherm_connectionObject



165
166
167
168
169
# File 'lib/net_shell/net_shell.rb', line 165

def setup_usherm_connection
  return if username.nil? or password.nil?
  set_client(:usherm, UsherMgmtClient.new(nil, username, password))
  puts "\rAutomatically connecting to Usher as #{username}"
end

#shelldir(dir) ⇒ Object



50
51
52
53
54
# File 'lib/net_shell/net_shell.rb', line 50

def shelldir(dir)
  path = File.join(config_dir, dir.to_s)
  Dir.mkdir(path) unless File.directory? path
  path
end

#split_args(cmdline) ⇒ Object



262
263
264
265
# File 'lib/net_shell/net_shell.rb', line 262

def split_args(cmdline)
  return [] if cmdline.nil? or cmdline.empty?
  cmdline.gsub(/`\b/, "\"`").gsub(/\b`/, "`\"").shellsplit_partial
end

#stored_serialObject



384
385
386
387
388
389
390
391
392
393
394
# File 'lib/net_shell/net_shell.rb', line 384

def stored_serial
  file = File.join(config_dir, "serial")

  begin
    return IO.read(file)
  rescue
    serial = Digest::SHA1.hexdigest(Random.new.bytes(16)).to_s
    File.write(file, serial) rescue nil
    return serial
  end
end

#tab_complete_built_in(args) ⇒ Object



98
99
100
101
102
103
104
# File 'lib/net_shell/net_shell.rb', line 98

def tab_complete_built_in(args)
  return [] unless has_built_in?(args[0])

  built_in = built_in(args[0]).new(self)
  built_in.parse(args)
  built_in.tab
end

#transform_args(args) ⇒ Object



276
277
278
279
280
281
282
283
284
285
286
# File 'lib/net_shell/net_shell.rb', line 276

def transform_args(args)
  args.map do |arg|
    if arg[0] == "$" then
      get_env(arg[1..-1]) || ""
    elsif arg[0] == '`' and arg[-1] == '`' then
      process_backtick(arg)
    else
      arg
    end
  end
end

#unpersist_env(*keys) ⇒ Object



124
125
126
127
128
129
130
# File 'lib/net_shell/net_shell.rb', line 124

def unpersist_env(*keys)
  keys = keys[0] if keys[0].is_a? Array
  keys.each do |key|
    path = path_for_env(key)
    File.delete(path) if File.exist? path
  end
end

#usernameObject

Shared variables



157
158
159
# File 'lib/net_shell/net_shell.rb', line 157

def username
  @env[:usherm_user]
end

#wrap_message(message, sender) ⇒ Object

Network listener



363
364
365
# File 'lib/net_shell/net_shell.rb', line 363

def wrap_message(message, sender)
  { time: Time.now, sender: sender, message: message }
end