Module: MaxCube::Network::TCP::Client::Commands

Included in:
MaxCube::Network::TCP::Client
Defined in:
lib/maxcube/network/tcp/client/commands.rb

Overview

Provides handling of concrete commands from shell command line.

Constant Summary

COMMANDS =

List of commands and their aliases.

{
  'usage' => %w[? h help],
  'data' => %w[B buffer d],
  'history' => %w[H hist],
  'clear' => %w[C],
  'dump' => %w[D],
  'list' => %w[l],
  'config' => %w[c],
  'send' => %w[cmd s set],
  'pair' => %w[n],
  'ntp' => %w[N f],
  'url' => %w[U u],
  'wake' => %w[w z],
  'metadata' => %w[m meta],
  'delete' => %w[del],
  'reset' => %w[],
  'verbose' => %w[V],
  'save' => %w[S],
  'load' => %w[L],
  'persist' => %w[P],
  'quit' => %w[q],
}.freeze

Instance Method Summary collapse

Instance Method Details

#assign_hash(hash) ⇒ Object (private)



309
310
311
312
313
314
# File 'lib/maxcube/network/tcp/client/commands.rb', line 309

def assign_hash(hash)
  valid_hash = !hash.nil?
  @hash = hash if valid_hash
  @hash_set |= valid_hash
  valid_hash
end

#cmd_clearObject (private)

Clears all buffered received data (i.e. moves them to history).



163
164
165
166
167
168
# File 'lib/maxcube/network/tcp/client/commands.rb', line 163

def cmd_clear
  %i[data hashes].each do |sym|
    @history[:recv][sym] += @buffer[:recv][sym]
    @buffer[:recv][sym].clear
  end
end

#cmd_configObject (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 'c' (configuration message request).



184
185
186
# File 'lib/maxcube/network/tcp/client/commands.rb', line 184

def cmd_config
  send_msg('c')
end

#cmd_dataObject (private)

Calls #list_hashes without history.



152
153
154
# File 'lib/maxcube/network/tcp/client/commands.rb', line 152

def cmd_data
  list_hashes(false)
end

#cmd_delete(*args) ⇒ Object (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 't' (delete a device request) and args, and last_array and array_nonempty options.

Parameters:

  • args (Array<String>)

    arguments from command line.



240
241
242
# File 'lib/maxcube/network/tcp/client/commands.rb', line 240

def cmd_delete(*args)
  send_msg('t', *args, last_array: true, array_nonempty: true)
end

#cmd_dumpObject (private)

Calls #cmd_data and #cmd_clear.



171
172
173
174
# File 'lib/maxcube/network/tcp/client/commands.rb', line 171

def cmd_dump
  cmd_data
  cmd_clear
end

#cmd_historyObject (private)

Calls #list_hashes with history.



157
158
159
# File 'lib/maxcube/network/tcp/client/commands.rb', line 157

def cmd_history
  list_hashes(true)
end

#cmd_listObject (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 'l' (device list request).



178
179
180
# File 'lib/maxcube/network/tcp/client/commands.rb', line 178

def cmd_list
  send_msg('l')
end

#cmd_load(path = nil) ⇒ Object (private)



316
317
318
319
320
321
# File 'lib/maxcube/network/tcp/client/commands.rb', line 316

def cmd_load(path = nil)
  hash = load_hash(path)
  return false unless assign_hash(hash)
  print_hash(hash)
  true
end

#cmd_metadata(*args) ⇒ Object (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 'm' (metadata message) and args and load_only option.

Parameters:

  • args (Array<String>)

    arguments from command line.



232
233
234
# File 'lib/maxcube/network/tcp/client/commands.rb', line 232

def (*args)
  send_msg('m', *args, load_only: true)
end

#cmd_ntp(*args) ⇒ Object (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 'f' (NTP servers message) and args and last_array option.

Parameters:

  • args (Array<String>)

    arguments from command line.



216
217
218
# File 'lib/maxcube/network/tcp/client/commands.rb', line 216

def cmd_ntp(*args)
  send_msg('f', *args, last_array: true)
end

#cmd_pair(*args) ⇒ Object (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 'n' (new device request) and args.

Parameters:

  • args (Array<String>)

    arguments from command line.



200
201
202
# File 'lib/maxcube/network/tcp/client/commands.rb', line 200

def cmd_pair(*args)
  send_msg('n', *args)
end

#cmd_persistObject (private)

Calls #toggle with persist mode variable.



339
340
341
342
# File 'lib/maxcube/network/tcp/client/commands.rb', line 339

def cmd_persist
  @persist = toggle('persist', @persist)
  @hash_set = @persist if @hash
end

#cmd_quitObject (private)

Manages to close the client gracefully (it should lead to MaxCube::Network::TCP::Client#close).

Raises:

  • (Interrupt)


346
347
348
# File 'lib/maxcube/network/tcp/client/commands.rb', line 346

def cmd_quit
  raise Interrupt
end

#cmd_resetObject (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 'a' (factory reset request).



246
247
248
# File 'lib/maxcube/network/tcp/client/commands.rb', line 246

def cmd_reset
  send_msg('a')
end

#cmd_save(what = nil) ⇒ Object (private)



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/maxcube/network/tcp/client/commands.rb', line 250

def cmd_save(what = nil)
  buffer = !what
  all = %w[a A all].include?(what)
  unless all || buffer
    puts "Unrecognized argument: '#{what}'"
    return
  end

  dir = @save_data_dir + Time.now.strftime('%Y%m%d-%H%M')
  dir.mkpath

  %i[recv sent].each do |sym|
    data_fn = dir + (sym.to_s << '.data')
    File.open(data_fn, 'w') do |f|
      f.puts(buffer(sym, :data, all).join)
    end

    hashes_fn = dir + (sym.to_s << '.yaml')
    File.open(hashes_fn, 'w') do |f|
      buffer(sym, :hashes, all).to_yaml(f)
    end
  end

  which = buffer ? 'Buffered' : 'All'
  puts "#{which} received and sent raw data and hashes" \
       " saved into '#{dir}'"
rescue SystemCallError => e
  puts "Files could not been saved:\n#{e}"
end

#cmd_send(*args) ⇒ Object (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 's' (send command message) and args and load_only option.

Parameters:

  • args (Array<String>)

    arguments from command line.



192
193
194
# File 'lib/maxcube/network/tcp/client/commands.rb', line 192

def cmd_send(*args)
  send_msg('s', *args, load_only: true)
end

#cmd_url(*args) ⇒ Object (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 'u' (set portal URL message) and args.

Parameters:

  • args (Array<String>)

    arguments from command line.



208
209
210
# File 'lib/maxcube/network/tcp/client/commands.rb', line 208

def cmd_url(*args)
  send_msg('u', *args)
end

#cmd_usageObject (private)

Prints usage message composed mainly from particular #usage_cmd calls.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/maxcube/network/tcp/client/commands.rb', line 63

def cmd_usage
  puts "\nUSAGE: <command> [<arguments...>]\nCOMMADS:\n" <<
       usage_cmd('usage', '',
                 'Prints this message') <<
       usage_cmd('data', '',
                 'Lists buffered received data (hashes)') <<
       usage_cmd('history', '',
                 'Lists all received data incl. the cleared') <<
       usage_cmd('clear', '',
                 "Clears collected data\n" \
                 '(resp. moves it to history)') <<
       usage_cmd('dump', '',
                 "Shortcut for 'data' + 'clear'") <<
       usage_cmd('list', '',
                 'Requests for new list of devices', 'l', 'L') <<
       usage_cmd('config', '',
                 'Requests for configuration message', 'c', 'C') <<
       usage_cmd('send', '{}',
                 'Sends settings to connected devices',
                 's', 'S') <<
       usage_cmd('pair', '{<timeout>}',
                 'Sets device into pairing mode' \
                 " with optional timeout\n" \
                 '(request for a new device)', 'n', 'N') <<
       usage_cmd('ntp', '{<NTP servers...>}',
                 'Requests for NTP servers' \
                 ' and optionally updates them',
                 'f', 'F') <<
       usage_cmd('url', '{<URL> <port>}',
                 'Configures Cube\'s portal URL', 'u') <<
       usage_cmd('wake', '{<time> <scope> [<ID>]}',
                 'Wake-ups the Cube',
                 'z', 'A') <<
       usage_cmd('metadata', '{}',
                 'Serializes metadata for the Cube',
                 'm', 'M') <<
       usage_cmd('delete', '{<count> <force> <RF addresses...>}',
                 'Deletes one or more devices from the Cube (!)',
                 't', 'A') <<
       usage_cmd('reset', '',
                 'Requests for factory reset (!)', 'a', 'A') <<
       usage_cmd('verbose', '',
                 "Toggles verbose mode (whether is incoming data\n" \
                 'printed immediately or is not printed)') <<
       usage_cmd('save', '[a|A|all]',
                 "Saves buffered [all] received and sent data\n" \
                 "into files at '#{@save_data_dir}'") <<
       usage_cmd('load', '[<path>]',
                 'Loads first hash from YAML file' \
                 " to internal variable\n" \
                 "-> to pass data with outgoing message\n" \
                 'If path is relative,' \
                 " it looks in '#{@load_data_dir}'\n" \
                 "(loads previous valid hash if no file given)\n" \
                 '(command can be combined' \
                 " using '#{ARGS_FROM_HASH}'\n" \
                 ' with other commands' \
                 " which have '{}' arguments)") <<
       usage_cmd('persist', '',
                 'Toggles persistent mode' \
                 "(whether is internal hash\n" \
                 'not invalidated after use)') <<
       usage_cmd('quit', '',
                 "Shuts the client down gracefully\n" \
                 '(SIGINT and EOF also work)', 'q') <<
       "\n[<arg>] means optional argument <arg>" \
       "\n[<args...>] means multiple arguments <args...> or none" \
       "\n  (<args...> requires at least one)" \
       "\n{<arg>} means that either <arg>" \
       " or '#{ARGS_FROM_HASH}' is expected" \
       "\n  (when '#{ARGS_FROM_HASH}' specified as first argument," \
       ' internal hash is used' \
       "\n   -> 'load' command is called with rest arguments)" \
       "\n  ({} means that only internal hash can be used," \
       "\n   '#{ARGS_FROM_HASH}' is not necessary in this case)"
end

#cmd_verboseObject (private)

Calls #toggle with verbose mode variable.



334
335
336
# File 'lib/maxcube/network/tcp/client/commands.rb', line 334

def cmd_verbose
  @verbose = toggle('verbose', @verbose)
end

#cmd_wake(*args) ⇒ Object (private)

Calls MaxCube::Network::TCP::Client#send_msg with message type 'z' (wake-up message) and args.

Parameters:

  • args (Array<String>)

    arguments from command line.



224
225
226
# File 'lib/maxcube/network/tcp/client/commands.rb', line 224

def cmd_wake(*args)
  send_msg('z', *args)
end

#list_hashes(history) ⇒ Object (private)

Displays received hashes optionally with history. Calls MaxCube::Network::TCP::Client#buffer.

Parameters:

  • history (Boolean)

    whether to include history.



143
144
145
146
147
148
149
# File 'lib/maxcube/network/tcp/client/commands.rb', line 143

def list_hashes(history)
  buffer(:recv, :hashes, history).each_with_index do |h, i|
    puts "<#{i + 1}>"
    print_hash(h)
    puts
  end
end

#load_hash(path = nil) ⇒ Object (private)



293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/maxcube/network/tcp/client/commands.rb', line 293

def load_hash(path = nil)
  if path
    path = Pathname.new(path)
    path = @load_data_dir + path if path.relative?
    return parse_hash(path)
  end
  return @hash if @hash && @hash_set

  if @hash
    puts 'Internal hash is not set'
  else
    puts 'No internal hash loaded yet'
    cmd_usage
  end
end

#parse_hash(path) ⇒ Object (private)



280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/maxcube/network/tcp/client/commands.rb', line 280

def parse_hash(path)
  unless path.file? && path.readable?
    return puts "File is not readable: '#{path}'"
  end

  hash = YAML.load_file(path)
  hash = hash.first while hash.is_a?(Array)
  raise YAML::SyntaxError unless hash.is_a?(Hash)
  hash
rescue YAML::SyntaxError => e
  puts "File '#{path}' does not contain proper YAML hash", e
end

#toggle(name, flag) ⇒ Boolean (private)

Helper method that 'toggles' boolean value and prints context info. (It actually does not modify flag.)

Parameters:

  • name (String)

    variable name.

  • flag (Boolean)

    boolean value to be 'toggled'.

Returns:

  • (Boolean)

    negated value of flag.



328
329
330
331
# File 'lib/maxcube/network/tcp/client/commands.rb', line 328

def toggle(name, flag)
  puts "#{name}: #{flag} -> #{!flag}"
  !flag
end

#usage_cmd(command, args, description, message = nil, response = nil) ⇒ String (private)

Returns usage message for a single command.

Parameters:

  • command (String)

    command key from COMMANDS.

  • args (String)

    arguments accepted by command.

  • description (String)

    description of command.

  • message (String, nil) (defaults to: nil)

    optional message type that is about to be sent by the command.

  • response (String, nil) (defaults to: nil)

    optional message type of expected response to this message.

Returns:

  • (String)

    usage message for command.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/maxcube/network/tcp/client/commands.rb', line 43

def usage_cmd(command, args, description,
              message = nil, response = nil)
  cmds_str = (COMMANDS[command].dup << command).join('|')
  cmds_str << ' ' << args unless args.empty?

  description, *rest = description.split("\n")
  rest << "[#{message} message]" if message
  rest << "[#{response} response]" if response
  rest = if rest.empty?
           ''
         else
           rest.map { |s| ' ' * 52 + s }.join("\n") << "\n"
         end

  '  ' << cmds_str << ' ' * (48 - cmds_str.size) <<
    description << "\n" << rest
end