Class: MrMurano::Exchange

Inherits:
Business show all
Includes:
AccountBase, Verbose
Defined in:
lib/MrMurano/Exchange.rb

Overview

The Exchange class represents an end user’s Murano IoT Exchange Elements.

Constant Summary

Constants included from Verbose

Verbose::TABULARIZE_DATA_FORMAT_ERROR

Constants included from AccountBase

AccountBase::LOGIN_ADVICE, AccountBase::LOGIN_NOTICE

Constants inherited from Business

Business::ALLOWED_TYPES

Instance Attribute Summary

Attributes inherited from Business

#bid, #billing, #members, #meta, #network, #network_status, #owner, #role, #tier

Instance Method Summary collapse

Methods included from Verbose

ask_yes_no, #ask_yes_no, #assert, assert, cmd_confirm_delete!, #cmd_confirm_delete!, debug, #debug, dump_file_json, dump_file_plain, dump_file_yaml, #dump_output_file, #error, error, #error_file_format!, fancy_ticks, #fancy_ticks, #load_file_json, #load_file_plain, #load_file_yaml, #load_input_file, outf, #outf, #outformat_engine, #pluralize?, pluralize?, #prepare_hash_csv, #read_hashf!, #tabularize, tabularize, verbose, #verbose, warning, #warning, #whirly_interject, whirly_interject, #whirly_linger, whirly_linger, #whirly_msg, whirly_msg, #whirly_pause, whirly_pause, #whirly_start, whirly_start, #whirly_stop, whirly_stop, #whirly_unpause, whirly_unpause

Methods included from AccountBase

#add_headers, #ask_for_password!, #ask_for_user!, #cfg_clear_user_and_business, #credentials_reset, #initialize, #invalidate_token, #login_info, #logout, #must_prompt_if_logged_off!, #token, #token_reset, #verify_cfg_auth!, #verify_cfg_auth_persist, #verify_cfg_auth_scheme!, #verify_cfg_auth_ttl, #verify_set, warn_configfile_env_maybe

Methods included from Http

#add_headers, #curldebug, curldebug_after, curldebug_elapsed, curldebug_log, #delete, #endpoint, #host, #http, #http_reset, #isJSON, #json_opts, #patch, #post, #postf, #showHttpError, #user, #workit, #workit_response

Methods inherited from Business

#==, #add_member_to_child_business, #add_network_child_business, #applications, #bizid, #check_if_biz_network_capable, #check_if_member_is_in_biz, #cid, #configure_business_network, #contact=, #delete_application, #delete_child_business, #delete_product, #delete_solution, #email=, #fetch_member, #fetch_network, #fetch_network_info_parent, #fetch_owner, #fetch_tier, #get_business_network, #initialize, #invite_member, #maybe_add_network_info_child, missing_business_id_msg, missing_child_msg, #must_business_id!, #must_child_id!, must_not_be_managed!, #name, #name=, #new_application, #new_product, #new_solution!, #new_solution_prepare!, #overview, #prepare_details_info, #prepare_network_info, #pretty_name_and_id, #products, #remove_member, #remove_member_from_child_business, #solution_from_type!, #solutions, #sort_solutions!, #valid?, #view_child_businesses, #write

Instance Method Details

#element(element_id) ⇒ Object



27
28
29
# File 'lib/MrMurano/Exchange.rb', line 27

def element(element_id)
  element_by_id(element_id)
end

#element_by_id(element_id) ⇒ Object



31
32
33
34
35
# File 'lib/MrMurano/Exchange.rb', line 31

def element_by_id(element_id)
  ret = get('exchange/' + bid + '/element/' + element_id)
  return nil unless ret.is_a?(Hash) && !ret.key?(:error)
  ret
end

#element_quick(element_id) ⇒ Object



37
38
39
40
41
42
# File 'lib/MrMurano/Exchange.rb', line 37

def element_quick(element_id)
  # Check if ID, a 24-character hexadecimal string.
  smells_like_id = element_id =~ /^[\h]{24}$/
  return element_by_id(element_id) if smells_like_id
  nil
end

#elements(skip_purchased: false, **opts) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/MrMurano/Exchange.rb', line 44

def elements(skip_purchased: false, **opts)
  # Get the user's Business tier data.
  @tier = fetch_tier if @tier.nil?

  elems = nil
  id_maybe = opts[:filter_id] || opts[:filter_fuzzy]
  if id_maybe && skip_purchased
    elem = element_quick(id_maybe)
    elems = [MrMurano::ExchangeElement.new(elem)] unless elem.nil?
  end
  elems = elements_all(skip_purchased: skip_purchased) if elems.nil?

  prepare_elements(elems, **opts)
end

#elements_all(skip_purchased: false) ⇒ Object



59
60
61
62
63
64
# File 'lib/MrMurano/Exchange.rb', line 59

def elements_all(skip_purchased: false)
  lookp = {}
  elems = fetch_elements(lookp)
  fetch_purchased(lookp) unless skip_purchased
  elems
end

#fetch_elements(lookp) ⇒ Object



66
67
68
69
70
71
72
73
74
75
# File 'lib/MrMurano/Exchange.rb', line 66

def fetch_elements(lookp)
  # Fetch the list of Elements, including Added, Available, and Upgradeable.
  items = fetch_type('/element/')
  # Prepare a lookup of the Elements.
  items.map do |meta|
    elem = MrMurano::ExchangeElement.new(meta)
    lookp[elem.elementId] = elem
    elem
  end
end

#fetch_purchased(lookp = nil, services_only: false) ⇒ Object



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
# File 'lib/MrMurano/Exchange.rb', line 77

def fetch_purchased(lookp=nil, services_only: false)
  query = [%w[type service]] if services_only
  # Fetch the list of Purchased elements.
  items = fetch_type('/purchase/', query)
  return items if lookp.nil?
  # Update the list of all Elements to indicate which have been purchased.
  items.each do |meta|
    elem = lookp[meta[:elementId]]
    if !elem.nil?
      elem.purchaseId = meta[:purchaseId]
      # Sanity check.
      meta[:element].each do |key, val|
        next if verify_purchase_vs_element(elem, key, val)
        verbose(
          'Unexpected: Exchange Purchase element meta differs: ' \
          "key: #{key} / elem: #{elem.send(key)} / purchase: #{val}"
        )
      end
    else
      warning(
        "No Exchange Element for Purchase: elementId: #{meta[:elementId]}"
      )
    end
  end
end

#fetch_type(part, query = nil) ⇒ Object



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/MrMurano/Exchange.rb', line 103

def fetch_type(part, query=nil)
  # [lb] not super happy about mixing presentation with other logic
  # but this is quick and dirty.
  case part
  when '/element/'
    qualifier = 'All'
  when '/purchase/'
    qualifier = 'Purchased'
  else
    raise 'Unexpected error'
  end
  whirly_start("Fetching #{qualifier} Elements...")

  # FIXME/2017-09-27: Support Pagination. BizAPI accepts four settings:
  #                     type, offset, limit, and select.
  #                   <bizapi>/lib/api/route/exchange/schemas/element.js
  ret = get('exchange/' + bid + part, query) do |request, http|
    response = http.request(request)
    case response
    when Net::HTTPSuccess
      workit_response(response)
    else
      showHttpError(request, response)
    end
  end
  whirly_stop
  return [] unless ret.is_a?(Hash) && !ret.key?(:error)
  return [] unless ret.key?(:items)
  unless ret[:count] == ret[:items].length
    warning(
      'Unexpected: ret[:count] != ret[:items].length: ' \
      "#{ret[:count]} != #{ret[:items].length}"
    )
  end
  ret[:items]
end

#get(path = '', query = nil, &block) ⇒ Object



19
20
21
# File 'lib/MrMurano/Exchange.rb', line 19

def get(path='', query=nil, &block)
  super
end

#prepare_elements(elems, filter_id: nil, filter_name: nil, filter_fuzzy: nil) ⇒ Object



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/MrMurano/Exchange.rb', line 149

def prepare_elements(elems, filter_id: nil, filter_name: nil, filter_fuzzy: nil)
  if filter_id || filter_name || filter_fuzzy
    elems.select! do |elem|
      if (
        (filter_id && elem.elementId == filter_id) || \
        (filter_name && elem.name == filter_name) || \
        (filter_fuzzy &&
          (
            elem.elementId =~ /#{Regexp.escape(filter_fuzzy)}/i || \
            elem.name =~ /#{Regexp.escape(filter_fuzzy)}/i
          )
        )
      )
        true
      else
        false
      end
    end
  end

  available = []
  purchased = []
  elems.sort_by(&:name)
  elems.each do |elem|
    if elem.purchaseId.nil?
      available.push(elem)
      if !@tier.nil? && elem.tiers.include?(@tier[:id])
        elem.statusable = :available
      else
        elem.statusable = :upgrade
      end
    else
      purchased.push(elem)
      elem.statusable = :added
    end
  end

  [elems, available, purchased]
end

#purchase(element_id) ⇒ Object



189
190
191
192
193
194
195
196
197
198
199
# File 'lib/MrMurano/Exchange.rb', line 189

def purchase(element_id)
  whirly_start('Purchasing Element...')
  ret = post(
    'exchange/' + bid + '/purchase/',
    elementId: element_id,
  )
  # Returns, e.g.,
  #  { bizid: "XXX", elementId: "YYY", purchaseId: "ZZZ" }
  whirly_stop
  ret
end

#put(element_id, body = {}, &block) ⇒ Object



23
24
25
# File 'lib/MrMurano/Exchange.rb', line 23

def put(element_id, body={}, &block)
  super('exchange/' + bid + '/element/' + element_id, body, &block)
end

#verify_purchase_vs_element(elem, key, val) ⇒ Object



140
141
142
143
144
145
146
147
# File 'lib/MrMurano/Exchange.rb', line 140

def verify_purchase_vs_element(elem, key, val)
  elem.send(key) == val
rescue NoMethodError
  verbose(
    "Unexpected: Exchange Element missing key found in Purchase Element: #{key}"
  )
  true
end