Class: MaxCube::Network::TCP::Client

Inherits:
Object
  • Object
show all
Includes:
Commands
Defined in:
lib/maxcube/network/tcp/client.rb,
lib/maxcube/network/tcp/client/commands.rb

Overview

Fundamental class that provides TCP communication with Cube gateway and connected devices. After connecting to Cube (#connect), interactive shell is launched.

Communication with Cube is performed via messages, whereas client works with hashes, which have particular message contents divided and is human readable. An issue is how to pass contents of hashes as arguments of message serialization. For simple hashes client provides and option to pass arguments explicitly on command line. This would be difficult to accomplish for large hashes with subhashes, so YAML files are used in these cases, which are able to be generated both automatically and manually. This file has to be loaded into internal hash before each such message.

Client interactive shell contains quite detailed usage message.

Defined Under Namespace

Modules: Commands

Constant Summary collapse

DEFAULT_VERBOSE =

Default verbose mode on startup.

true
DEFAULT_PERSIST =

Default persist mode on startup.

true

Instance Method Summary collapse

Constructor Details

#initialize(verbose: DEFAULT_VERBOSE, persist: DEFAULT_PERSIST) ⇒ Client

Creates all necessary internal variables. Internal hash is invalid on startup.

Parameters:

  • verbose (Boolean) (defaults to: DEFAULT_VERBOSE)

    verbose mode on startup.

  • persist (Boolean) (defaults to: DEFAULT_PERSIST)

    persist mode on startup.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/maxcube/network/tcp/client.rb', line 37

def initialize(verbose: DEFAULT_VERBOSE, persist: DEFAULT_PERSIST)
  @parser = Messages::TCP::Parser.new
  @serializer = Messages::TCP::Serializer.new
  @queue = Queue.new

  @buffer = { recv: { hashes: [], data: [] },
              sent: { hashes: [], data: [] } }
  @history = { recv: { hashes: [], data: [] },
               sent: { hashes: [], data: [] } }

  @hash = nil
  @hash_set = false

  @data_dir = Pathname.new(MaxCube.data_dir)
  @load_data_dir = @data_dir + 'load'
  @save_data_dir = @data_dir + 'save'

  @verbose = verbose
  @persist = persist
end

Instance Method Details

#closeObject

Closes client gracefully.



119
120
121
122
123
124
# File 'lib/maxcube/network/tcp/client.rb', line 119

def close
  STDIN.close
  send_msg('q')
  @socket.close
  @thread.join
end

#connect(host = LOCALHOST, port = PORT) ⇒ Object

Connects to concrete address and starts interactive shell (#shell). Calls #receiver in separate thread to receive all incoming messages.

Parameters:

  • host (defaults to: LOCALHOST)

    remote host address.

  • port (defaults to: PORT)

    remote host port.



62
63
64
65
66
# File 'lib/maxcube/network/tcp/client.rb', line 62

def connect(host = LOCALHOST, port = PORT)
  @socket = TCPSocket.new(host, port)
  @thread = Thread.new(self, &:receiver)
  shell
end

#receiverObject

Routine started in separate thread that receives and parses all incoming messages in loop and stores them info thread-safe queue. Parsing is done via Messages::TCP::Parser#parse_tcp_msg. It should close gracefully on any IOError or on shell’s initiative.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/maxcube/network/tcp/client.rb', line 75

def receiver
  puts '<Starting receiver thread ...>'
  while (data = @socket.gets)
    hashes = @parser.parse_tcp_data(data)
    if @verbose
      hashes.each { |h| print_hash(h) }
      puts
    end
    @queue << [data, hashes]
  end
  raise IOError
rescue IOError
  STDIN.close
  puts '<Closing receiver thread ...>'
rescue Messages::InvalidMessage => e
  puts e.to_s.capitalize
end

#shellObject

Interactive shell that maintains all operations with Cube. It is yet only simple STDIN parser without any command history and other features that possess all decent shells. It calls #command on every input. It provides quite detailed usage message (MaxCube::Network::TCP::Client::Commands#cmd_usage).

It should close gracefully from user’s will, when connection closes, or when soft interrupt appears. Calls #close when closing.



104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/maxcube/network/tcp/client.rb', line 104

def shell
  puts "Welcome to interactive shell!\n" \
       "Type 'help' for list of commands.\n\n"
  STDIN.each do |line|
    refresh_buffer
    command(line)
    puts
  end
  raise Interrupt
rescue IOError, Interrupt
  puts "\nClosing shell ..."
  close
end