Module: Arborist::TreeAPI

Extended by:
HashUtilities, MethodUtilities, Loggability
Defined in:
lib/arborist/tree_api.rb

Constant Summary collapse

PROTOCOL_VERSION =

The version of the application protocol

1

Class Method Summary collapse

Methods included from HashUtilities

compact_hash, hash_matches, merge_recursively, stringify_keys, symbolify_keys

Methods included from MethodUtilities

attr_predicate, attr_predicate_accessor, dsl_accessor, singleton_attr_accessor, singleton_attr_reader, singleton_attr_writer, singleton_method_alias, singleton_predicate_accessor, singleton_predicate_reader

Class Method Details

.check_body(body) ⇒ Object

Check the given body for validity, raising an Arborist::MessageError if it isn’t.



108
109
110
111
112
113
114
115
# File 'lib/arborist/tree_api.rb', line 108

def self::check_body( body )
  unless body.is_a?( Hash ) ||
       body.nil? ||
         ( body.is_a?(Array) && body.all? {|obj| obj.is_a?(Hash) } )
    self.log.error "Invalid message body: %p" % [ body]
    raise Arborist::MessageError, "body must be Nil, a Map, or an Array of Maps"
  end
end

.check_header(header) ⇒ Object

Check the given header for validity, raising an Arborist::MessageError if it isn’t.



96
97
98
99
100
101
102
103
# File 'lib/arborist/tree_api.rb', line 96

def self::check_header( header )
  raise Arborist::MessageError, "header is not a Map" unless
    header.is_a?( Hash )
  version = header['version'] or
    raise Arborist::MessageError, "missing required header 'version'"
  raise Arborist::MessageError, "unknown protocol version %p" % [version] unless
    version == PROTOCOL_VERSION
end

.decode(msg) ⇒ Object

Return the header and body from the TreeAPI request or response in the specified msg (a CZTop::Message).



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/arborist/tree_api.rb', line 45

def self::decode( msg )
  raw_message = msg.pop or raise Arborist::MessageError, "empty message"

  parts = begin
    MessagePack.unpack( raw_message )
  rescue => err
    raise Arborist::MessageError, err.message
  end

  raise Arborist::MessageError, 'not an Array' unless parts.is_a?( Array )
  raise Arborist::MessageError,
    "malformed message: expected 1-2 parts, got %d" % [ parts.length ] unless
    parts.length.between?( 1, 2 )

  header = parts.shift or
    raise Arborist::MessageError, "no header"
  self.check_header( header )

  body = parts.shift
  self.check_body( body )

  return header, body
end

.encode(header, body = nil) ⇒ Object

Return a CZTop::Message with a payload containing the specified header and body.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/arborist/tree_api.rb', line 25

def self::encode( header, body=nil )
  raise Arborist::MessageError, "header is not a Map" unless
    header.is_a?( Hash )

  self.log.debug "Encoding header: %p with body: %p" % [ header, body ]
  header = stringify_keys( header )
  header['version'] = PROTOCOL_VERSION

  self.check_header( header )
  self.check_body( body )

  payload = MessagePack.pack([ header, body ])

  self.log.debug "Making zmq message with payload: %p" % [ payload ]
  return CZTop::Message.new( payload )
end

.error_response(category, reason) ⇒ Object

Build an error response message for the specified category and reason.



83
84
85
# File 'lib/arborist/tree_api.rb', line 83

def self::error_response( category, reason )
  return self.encode({ category: category, reason: reason, success: false })
end

.request(verb, *data) ⇒ Object

Return a CZTop::Message containing a TreeAPI request with the specified verb and data.



72
73
74
75
76
77
78
79
# File 'lib/arborist/tree_api.rb', line 72

def self::request( verb, *data )
  body   = data.pop
  header = data.pop || {}

  header.merge!( action: verb )

  return self.encode( header, body )
end

.successful_response(body) ⇒ Object

Build a successful response with the specified body.



89
90
91
# File 'lib/arborist/tree_api.rb', line 89

def self::successful_response( body )
  return self.encode({ success: true }, body )
end