omf_sfa 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/bin/brite2rspec.rb +0 -0
- data/lib/omf-sfa/am.rb +4 -1
- data/lib/omf-sfa/am/am-rest/promise_handler.rb +119 -0
- data/lib/omf-sfa/am/am-rest/rest_handler.rb +301 -45
- data/lib/omf-sfa/resource.rb +3 -1
- data/lib/omf-sfa/resource/gurn.rb +5 -3
- data/lib/omf-sfa/resource/node.rb +1 -1
- data/lib/omf-sfa/resource/oproperty.rb +13 -14
- data/lib/omf-sfa/resource/oresource.rb +14 -5
- data/lib/omf-sfa/resource/sfa_base.rb +3 -1
- data/lib/omf-sfa/util/graph_json.rb +34 -14
- data/lib/omf-sfa/util/promise.rb +325 -0
- data/lib/omf-sfa/version.rb +1 -2
- data/omf_sfa.gemspec +1 -1
- metadata +64 -117
data/lib/omf-sfa/resource.rb
CHANGED
@@ -3,6 +3,8 @@ require 'omf_base/lobject'
|
|
3
3
|
|
4
4
|
module OMF::SFA::Resource
|
5
5
|
#
|
6
|
+
class GurnMalformedException < ResourceException; end
|
7
|
+
|
6
8
|
class GURN #< OMF::Base::MObject
|
7
9
|
|
8
10
|
@@def_domain = "urn:publicid:IDN+acme.org"
|
@@ -19,7 +21,7 @@ module OMF::SFA::Resource
|
|
19
21
|
def self.create(name, opts = {})
|
20
22
|
return name if name.kind_of? self
|
21
23
|
unless name
|
22
|
-
raise "No name given"
|
24
|
+
raise GurnMalformedException.new "No name given"
|
23
25
|
end
|
24
26
|
#puts "GUID: #{name}###{opts}"
|
25
27
|
|
@@ -58,11 +60,11 @@ module OMF::SFA::Resource
|
|
58
60
|
prefix, name = a
|
59
61
|
type = nil
|
60
62
|
else
|
61
|
-
raise "unknown format '#{urn_str}' for GURN (#{a.inspect})."
|
63
|
+
raise GurnMalformedException.new "unknown format '#{urn_str}' for GURN (#{a.inspect})."
|
62
64
|
end
|
63
65
|
@@name2obj[urn_str] = self.new(name, type, prefix)
|
64
66
|
else
|
65
|
-
raise "unknown format '#{urn_str}' for GURN - expected it to start with 'urn:publicid:IDN'."
|
67
|
+
raise GurnMalformedException.new "unknown format '#{urn_str}' for GURN - expected it to start with 'urn:publicid:IDN'."
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
@@ -14,7 +14,7 @@ module OMF::SFA::Resource
|
|
14
14
|
oproperty :available, Boolean, :default => true
|
15
15
|
oproperty :sliver_type, SliverType, :required => false # Is this required?
|
16
16
|
oproperty :interfaces, :interface, :functional => false, :inverse => :node
|
17
|
-
oproperty :exclusive, Boolean, :default =>
|
17
|
+
oproperty :exclusive, Boolean, :default => false
|
18
18
|
oproperty :services, OMF::SFA::Resource::AbstractService, functional: false
|
19
19
|
|
20
20
|
#belongs_to :sliver
|
@@ -62,7 +62,7 @@ module OMF::SFA::Resource
|
|
62
62
|
if l = opts[:limit]
|
63
63
|
q += " LIMIT #{l} OFFSET #{opts[:offset] || 0}"
|
64
64
|
end
|
65
|
-
|
65
|
+
debug "prop_all q: #{q}"
|
66
66
|
res = repository(:default).adapter.select(q)
|
67
67
|
ores = res.map do |qr|
|
68
68
|
if resource_class
|
@@ -93,7 +93,9 @@ module OMF::SFA::Resource
|
|
93
93
|
# TODO: THIS IS REALLY BROKEN! Need to define what a query is in this context
|
94
94
|
#
|
95
95
|
def self._build_query(query, resource_class = nil)
|
96
|
+
#puts ">>>QUERY>>> #{query}"
|
96
97
|
i = 0
|
98
|
+
resource = nil
|
97
99
|
where = query.map do |pn, v|
|
98
100
|
tbl = "p#{i}"
|
99
101
|
case pn.to_sym
|
@@ -101,34 +103,31 @@ module OMF::SFA::Resource
|
|
101
103
|
unless v.is_a? OResource
|
102
104
|
raise "Expected type OResource for :resource, but got '#{v}::#{v.class}'"
|
103
105
|
end
|
104
|
-
|
105
|
-
|
106
|
-
"#{tbl}.
|
106
|
+
resource = v
|
107
|
+
"r.id = #{resource.id}"
|
108
|
+
#"#{tbl}.o_resource_id = #{v.id}"
|
109
|
+
# resource property 'name' is not stored as a property but as a column in the resource
|
110
|
+
# when :name
|
111
|
+
# "r.name = '#{v}'"
|
107
112
|
else
|
108
113
|
h = _analyse_value(v)
|
109
114
|
i += 1
|
110
115
|
if (val = h[:v]).is_a? String
|
111
116
|
val = "'#{val}'"
|
112
117
|
end
|
113
|
-
|
118
|
+
op = (h[:t] == 's' ? 'LIKE' : '=')
|
119
|
+
# TODO: Would also need to add a where clause "#{tbl}.name = #{pn} "
|
120
|
+
"#{tbl}.#{h[:f]} #{op} #{val}"
|
114
121
|
end
|
115
122
|
end
|
116
123
|
|
117
|
-
# TODO: Hack!!!
|
118
|
-
unless i <= 1
|
119
|
-
raise "Are you using the query facility on OProperties correctly? (#{i})"
|
120
|
-
else
|
121
|
-
i = 1
|
122
|
-
end
|
123
|
-
|
124
124
|
i.times do |j|
|
125
125
|
where << "r.id = p#{j}.o_resource_id"
|
126
126
|
end
|
127
127
|
where << "r.type = '#{resource_class}'" if resource_class
|
128
|
-
|
129
128
|
table = storage_names[:default]
|
130
129
|
from = i.times.map {|j| "#{table} AS p#{j}" }
|
131
|
-
from << "omf_sfa_resource_o_resources AS r" # TODO: Shouldn't hard-code that
|
130
|
+
from << "omf_sfa_resource_o_resources AS r" # TODO: Shouldn't hard-code that (why not?)
|
132
131
|
[from, where]
|
133
132
|
end
|
134
133
|
|
@@ -177,7 +177,7 @@ module OMF::SFA::Resource
|
|
177
177
|
elsif v.respond_to?(m = "#{rev_m}=".to_sym)
|
178
178
|
v.send(m, self)
|
179
179
|
else
|
180
|
-
raise "Can't find any setter '#{rev_m}' on '#{v}'"
|
180
|
+
raise "Can't find any setter '#{rev_m}' on '#{v}:#{v.class}'"
|
181
181
|
end
|
182
182
|
else
|
183
183
|
# TODO: should remove this one form the reverse side
|
@@ -489,6 +489,9 @@ module OMF::SFA::Resource
|
|
489
489
|
op.each do |k, v|
|
490
490
|
k = k.to_sym
|
491
491
|
unless (value = send(k)).nil?
|
492
|
+
if value.is_a?(OMF::SFA::Util::Promise) && value.resolved?
|
493
|
+
value = value.value
|
494
|
+
end
|
492
495
|
#puts "OPROPS_TO_HAHS(#{k}): #{value}::#{value.class}--#{oproperty_get(k)}"
|
493
496
|
#puts "OPROPS_TO_HAHS(#{k}): #{opts[:level]} >= #{opts[:max_level]}"
|
494
497
|
if value.is_a? OResource
|
@@ -501,13 +504,19 @@ module OMF::SFA::Resource
|
|
501
504
|
end
|
502
505
|
if value.kind_of? Array
|
503
506
|
next if value.empty?
|
504
|
-
opts = opts.merge(level: opts[:level] + 1)
|
505
507
|
value = value.collect do |e|
|
506
|
-
#
|
507
|
-
|
508
|
+
#puts "LEVLE: #{opts[:level]} - #{opts[:max_level]}"
|
509
|
+
if e.kind_of? OResource
|
510
|
+
if opts[:level] >= opts[:max_level]
|
511
|
+
e.href
|
512
|
+
else
|
513
|
+
e.to_hash(objs, opts.merge(level: opts[:level] + 2))
|
514
|
+
end
|
515
|
+
else
|
516
|
+
e
|
517
|
+
end
|
508
518
|
end
|
509
519
|
end
|
510
|
-
|
511
520
|
h[k] = value
|
512
521
|
end
|
513
522
|
end
|
@@ -14,6 +14,7 @@ module OMF::SFA
|
|
14
14
|
module Base
|
15
15
|
|
16
16
|
SFA_NAMESPACE_URI = "http://www.geni.net/resources/rspec/3"
|
17
|
+
OMF_NAMESPACE_URI = "http://schema.mytestbed.net/rspec/3"
|
17
18
|
|
18
19
|
module ClassMethods
|
19
20
|
|
@@ -62,6 +63,7 @@ module OMF::SFA
|
|
62
63
|
def sfa_add_namespaces_to_document(doc)
|
63
64
|
root = doc.root
|
64
65
|
root.add_namespace(nil, SFA_NAMESPACE_URI)
|
66
|
+
root.add_namespace('omf', OMF_NAMESPACE_URI)
|
65
67
|
@@sfa_namespaces.each do |name, opts|
|
66
68
|
root.add_namespace(name.to_s, opts[:urn]) #'omf', 'http://tenderlovemaking.com')
|
67
69
|
end
|
@@ -478,7 +480,7 @@ module OMF::SFA
|
|
478
480
|
end
|
479
481
|
|
480
482
|
unless opts[:suppress_uuid] || self.class.sfa_suppress_uuid?
|
481
|
-
new_element.set_attribute('uuid', self.uuid) #if detail_level > 0
|
483
|
+
new_element.set_attribute('omf:uuid', self.uuid) #if detail_level > 0
|
482
484
|
end
|
483
485
|
|
484
486
|
#if href = self.href(opts)
|
@@ -12,7 +12,7 @@ module OMF::SFA::Util
|
|
12
12
|
end
|
13
13
|
|
14
14
|
|
15
|
-
# This class handles the
|
15
|
+
# This class handles the conversion between GraphJson
|
16
16
|
# and a set of resources.
|
17
17
|
#
|
18
18
|
# Usage:
|
@@ -25,6 +25,17 @@ module OMF::SFA::Util
|
|
25
25
|
self.new.parse(JSON.parse(content, symbolize_names: true), opts)
|
26
26
|
end
|
27
27
|
|
28
|
+
# Parse a hash following the GraphJSON format and return a
|
29
|
+
# list od resources.
|
30
|
+
#
|
31
|
+
# * opts
|
32
|
+
# - :node_services Services to add to each node (default: [])
|
33
|
+
# - :create_new_uuids Don't use '_id' for UUID, create new ones
|
34
|
+
#
|
35
|
+
def self.parse(descr_hash, opts = {})
|
36
|
+
self.new.parse(descr_hash, opts)
|
37
|
+
end
|
38
|
+
|
28
39
|
# Parse a hash following the GraphJSON format and return a
|
29
40
|
# list od resources.
|
30
41
|
#
|
@@ -68,12 +79,17 @@ module OMF::SFA::Util
|
|
68
79
|
@defaults = {node: {}, interface: {}, network: {}}
|
69
80
|
(graph[:defaults] || {}).each do |type, h|
|
70
81
|
type_def = @defaults[type.to_sym] ||= {}
|
71
|
-
h.each do |name,
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
82
|
+
h.each do |name, vh|
|
83
|
+
puts "DEFAULTS>>> #{type} - #{name} => #{vh}"
|
84
|
+
if ref_id = vh[:ref]
|
85
|
+
unless ref = @id2descr[ref_id]
|
86
|
+
raise GraphJSONException.new "Defaults refer to unknown id '#{id}' - #{@id2descr.keys}"
|
87
|
+
end
|
88
|
+
unless val = ref[name]
|
89
|
+
raise GraphJSONException.new "Defaults refer to unspecified property '#{name}' in '#{ref_id}' - #{ref}"
|
90
|
+
end
|
91
|
+
elsif (val = vh[:value]).nil?
|
92
|
+
raise GraphJSONException.new "Default '#{name}' for '#{type}' has no value defined - #{vh}"
|
77
93
|
end
|
78
94
|
type_def[name] = val
|
79
95
|
#puts "#{type}::#{name} ===> #{val}"
|
@@ -105,7 +121,7 @@ module OMF::SFA::Util
|
|
105
121
|
end
|
106
122
|
opts[:uuid] = id unless @create_new_uuids
|
107
123
|
opts[:name] = node[:name]
|
108
|
-
parse_value(node, :
|
124
|
+
parse_value(node, :am_urn, el_defaults, opts, true, :component_manager)
|
109
125
|
parse_value(node, :urn, el_defaults, opts, false)
|
110
126
|
opts[:sliver_type] = parse_sliver_type(node, el_defaults)
|
111
127
|
|
@@ -145,6 +161,7 @@ module OMF::SFA::Util
|
|
145
161
|
next unless n_descr[:_type] == "node"
|
146
162
|
node_id = n_descr[:_id]
|
147
163
|
if_a = n_descr[:__ifs]
|
164
|
+
next unless if_a
|
148
165
|
|
149
166
|
# Add names to all interfaces
|
150
167
|
names = if_a.map {|ifd| ifd[:name] }.compact
|
@@ -226,23 +243,26 @@ module OMF::SFA::Util
|
|
226
243
|
|
227
244
|
def parse_sliver_type(node, el_defaults)
|
228
245
|
sliver_type = parse_value(node, :sliver_type, el_defaults, nil, true)
|
229
|
-
disk_image_url = parse_value(node, :disk_image, el_defaults, nil,
|
230
|
-
id = "#{sliver_type}-#{disk_image_url}"
|
246
|
+
disk_image_url = parse_value(node, :disk_image, el_defaults, nil, false)
|
247
|
+
id = "#{sliver_type}-#{disk_image_url || '__none'}"
|
231
248
|
unless st_res = @sliver_types[id]
|
232
|
-
|
233
|
-
|
249
|
+
opts = {name: sliver_type}
|
250
|
+
if disk_image_url
|
251
|
+
opts[:disk_image] = DiskImage.create(url: disk_image_url)
|
252
|
+
end
|
253
|
+
st_res = @sliver_types[id] = SliverType.create(opts)
|
234
254
|
end
|
235
255
|
st_res
|
236
256
|
end
|
237
257
|
|
238
258
|
|
239
|
-
def parse_value(el, name, defaults, opts, is_mandatory = false)
|
259
|
+
def parse_value(el, name, defaults, opts, is_mandatory = false, opts_name = nil)
|
240
260
|
val = el[name] || defaults[name]
|
241
261
|
if is_mandatory && val.nil?
|
242
262
|
raise GraphJSONException.new "Can't find value for mandatory property '#{name}' in '#{el}'"
|
243
263
|
end
|
244
264
|
if opts && !val.nil?
|
245
|
-
opts[name.to_sym] = val
|
265
|
+
opts[(opts_name || name).to_sym] = val
|
246
266
|
end
|
247
267
|
val
|
248
268
|
end
|
@@ -0,0 +1,325 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
module OMF::SFA
|
5
|
+
module Util
|
6
|
+
class UtilException < Exception; end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module OMF::SFA::Util
|
11
|
+
|
12
|
+
class PromiseException < UtilException
|
13
|
+
attr_reader :promise
|
14
|
+
|
15
|
+
def initialize(promise)
|
16
|
+
@promise = promise
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class PromiseUnresolvedException < PromiseException
|
21
|
+
attr_reader :promise, :uuid
|
22
|
+
|
23
|
+
def initialize(promise)
|
24
|
+
@promise = promise
|
25
|
+
end
|
26
|
+
|
27
|
+
def uuid
|
28
|
+
@uuid ||= UUIDTools::UUID.random_create
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class PromiseAlreadySetException < PromiseException; end
|
33
|
+
|
34
|
+
class Promise < OMF::Base::LObject
|
35
|
+
|
36
|
+
# Returns a promise which fires when all dependencies
|
37
|
+
def self.all(*promises)
|
38
|
+
count = promises.length
|
39
|
+
results = []
|
40
|
+
new_promise = self.new()
|
41
|
+
if count == 0
|
42
|
+
new_promise.resolve(results)
|
43
|
+
else
|
44
|
+
already_rejected = false
|
45
|
+
promises.each_with_index do |p, i|
|
46
|
+
p.on_success do |v|
|
47
|
+
results[i] = v
|
48
|
+
if (count -= 1) <= 0
|
49
|
+
new_promise.resolve(results)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
p.on_error do |err_code, msg|
|
53
|
+
unless already_rejected
|
54
|
+
already_rejected = true
|
55
|
+
new_promise.reject(err_code, msg)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
new_promise
|
61
|
+
end
|
62
|
+
|
63
|
+
def value(exception_on_unresolved = PromiseUnresolvedException)
|
64
|
+
if @status == :resolved
|
65
|
+
@value
|
66
|
+
else
|
67
|
+
ex = exception_on_unresolved
|
68
|
+
raise ex.is_a?(PromiseException) ? ex.new(self) : ex
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def error_msg(exception_on_unresolved = PromiseUnresolvedException)
|
73
|
+
if @status == :rejected
|
74
|
+
@value
|
75
|
+
else
|
76
|
+
ex = exception_on_unresolved
|
77
|
+
raise ex.is_a?(PromiseException) ? ex.new(self) : ex
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def error_code(exception_on_unresolved = PromiseUnresolvedException)
|
82
|
+
if @status == :rejected
|
83
|
+
@err_code
|
84
|
+
else
|
85
|
+
ex = exception_on_unresolved
|
86
|
+
raise ex.is_a?(PromiseException) ? ex.new(self) : ex
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Resolve the promise.
|
91
|
+
#
|
92
|
+
# @param [Object] value of promise
|
93
|
+
#
|
94
|
+
def resolve(value)
|
95
|
+
raise PromiseAlreadySetException.new(self) unless @status == :pending
|
96
|
+
|
97
|
+
#puts "--------RESOLVE-#{@name}-#{@status}(#{@resolved_handlers.inspect}>>> "
|
98
|
+
if value.is_a? self.class
|
99
|
+
@status = :proxy
|
100
|
+
@proxy = value
|
101
|
+
@proxy.on_success {|v| _resolve(v)}
|
102
|
+
@proxy.on_error {|e, m| _reject(e, m)}
|
103
|
+
else
|
104
|
+
_resolve(value)
|
105
|
+
end
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
# Resolve the promise.
|
110
|
+
#
|
111
|
+
# @param [Object] Reject message
|
112
|
+
#
|
113
|
+
def reject(err_code, msg = nil)
|
114
|
+
unless msg
|
115
|
+
# no error code
|
116
|
+
msg = err_code
|
117
|
+
err_code = 999
|
118
|
+
end
|
119
|
+
unless @status == :pending
|
120
|
+
warn "No longer pending - #{self.inspect} - #{@value}"
|
121
|
+
raise PromiseAlreadySetException.new(self)
|
122
|
+
end
|
123
|
+
_reject(err_code, msg)
|
124
|
+
self
|
125
|
+
end
|
126
|
+
|
127
|
+
# Call block to allow modifications to the 'resolve' value
|
128
|
+
#
|
129
|
+
def filter(&block)
|
130
|
+
if @filter_block
|
131
|
+
raise "Can only define one filter block - previous #{@filter_block}"
|
132
|
+
end
|
133
|
+
@filter_block = block
|
134
|
+
if @status == :resolved
|
135
|
+
unless @resolved_handlers.empty?
|
136
|
+
warn "Attached filter after promise was already resolved and reported to 'on_success'"
|
137
|
+
end
|
138
|
+
_resolve(@value)
|
139
|
+
end
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
# To track the progress towards resolving or rejecting the promise
|
144
|
+
# the various tasks can report on their progress through this method.
|
145
|
+
# Calling it with an empty message will return an array of progress
|
146
|
+
# messages
|
147
|
+
#
|
148
|
+
def progress(msg = nil, timestamp = nil)
|
149
|
+
if msg
|
150
|
+
@progress << [timestamp ||= Time.now, msg]
|
151
|
+
if @progress_handlers
|
152
|
+
_call('on_progress', @progress_handlers, [timestamp, " #{msg}"], false)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
@progress
|
156
|
+
end
|
157
|
+
|
158
|
+
# Register block to call on success, or other promise to
|
159
|
+
# 'upcall' on success.
|
160
|
+
#
|
161
|
+
def on_success(other_promise = nil, &block)
|
162
|
+
if other_promise
|
163
|
+
raise "can't have block as well" if block
|
164
|
+
block = lambda {|v| other_promise.resolve(v) }
|
165
|
+
end
|
166
|
+
if @status == :resolved
|
167
|
+
_call('on_success', [block], [@value])
|
168
|
+
else
|
169
|
+
@resolved_handlers << block
|
170
|
+
end
|
171
|
+
self
|
172
|
+
end
|
173
|
+
|
174
|
+
# Register block to call on error, or other promise to
|
175
|
+
# 'upcall' on error.
|
176
|
+
#
|
177
|
+
def on_error(other_promise = nil, &block)
|
178
|
+
if other_promise
|
179
|
+
raise "can't have block as well" if block
|
180
|
+
block = lambda {|c, m| other_promise.reject(c, m) }
|
181
|
+
end
|
182
|
+
if @status == :rejected
|
183
|
+
_call('on_error', [block], [@err_code, @value])
|
184
|
+
else
|
185
|
+
@rejected_handlers << block
|
186
|
+
end
|
187
|
+
self
|
188
|
+
end
|
189
|
+
|
190
|
+
# Register block to call whenever this promise transitions
|
191
|
+
# out of 'pending'.
|
192
|
+
#
|
193
|
+
def on_always(&block)
|
194
|
+
if @status == :pending
|
195
|
+
@always_handlers << block
|
196
|
+
else
|
197
|
+
_call('on_always', [block], nil, false)
|
198
|
+
end
|
199
|
+
self
|
200
|
+
end
|
201
|
+
|
202
|
+
# Register block to call whenever a new progress message is being reported
|
203
|
+
#
|
204
|
+
def on_progress(other_promise = nil, prefix = nil, &block)
|
205
|
+
if other_promise
|
206
|
+
raise "can't have block as well" if block
|
207
|
+
block = lambda do |ts, m|
|
208
|
+
m = " #{prefix ? "[#{prefix}] " : ''}#{m}"
|
209
|
+
other_promise.progress(m, ts)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
@progress.each do |ts, m|
|
213
|
+
#_call('on_progress', [block], [ts, " #{prefix ? "#{prefix}: " : ''}#{m}"], false)
|
214
|
+
_call('on_progress', [block], [ts, m], false)
|
215
|
+
end
|
216
|
+
(@progress_handlers ||= []) << block
|
217
|
+
self
|
218
|
+
end
|
219
|
+
|
220
|
+
def resolved?
|
221
|
+
(@status == :proxy) ? @proxy.resolved? : (@status == :resolved)
|
222
|
+
end
|
223
|
+
|
224
|
+
def pending?
|
225
|
+
(@status == :proxy) ? @proxy.pending? : (@status == :pending)
|
226
|
+
end
|
227
|
+
|
228
|
+
def status
|
229
|
+
(@status == :proxy) ? @proxy.status : @status
|
230
|
+
end
|
231
|
+
|
232
|
+
def to_html
|
233
|
+
case @status
|
234
|
+
when :pending
|
235
|
+
'.... pending'
|
236
|
+
when :resolved
|
237
|
+
@value.to_s
|
238
|
+
else
|
239
|
+
"ERROR(#{@err_code}: #{@value}"
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
# def to_json(*a)
|
244
|
+
# to_str().to_json(*a)
|
245
|
+
# end
|
246
|
+
|
247
|
+
def to_json(*a)
|
248
|
+
puts ">>> JSONIFY PROMISE - #{self.to_s} - #{@value}"
|
249
|
+
if @status == :resolved
|
250
|
+
@value.to_json(*a)
|
251
|
+
else
|
252
|
+
raise PromiseUnresolvedException.new(self)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def to_s
|
257
|
+
"#<#{self.class}:#{@name}-#{@status}>"
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
attr_reader :name
|
262
|
+
|
263
|
+
def initialize(name = nil)
|
264
|
+
@pretty_name = name
|
265
|
+
@name = "p#{hash()}"
|
266
|
+
@name += "-#{name}" if name
|
267
|
+
@status = :pending
|
268
|
+
@resolved_handlers = []
|
269
|
+
@rejected_handlers = []
|
270
|
+
@always_handlers = []
|
271
|
+
@progress = []
|
272
|
+
@progress_handlers = nil
|
273
|
+
progress "#{@pretty_name} started" if @pretty_name
|
274
|
+
end
|
275
|
+
|
276
|
+
private
|
277
|
+
|
278
|
+
def _resolve(value)
|
279
|
+
@status = :resolved
|
280
|
+
value = @filter_block.call(value) if @filter_block
|
281
|
+
@value = value
|
282
|
+
progress("#{@pretty_name} resolved") if @pretty_name
|
283
|
+
_call('on_success', @resolved_handlers, [value])
|
284
|
+
value
|
285
|
+
end
|
286
|
+
|
287
|
+
def _reject(err_code, msg)
|
288
|
+
@status = :rejected
|
289
|
+
#puts ">>>> REJECT MSG - #{msg.inspect} -- #{msg.respond_to? :pretty_print}"
|
290
|
+
if msg.respond_to? :pretty_print
|
291
|
+
msg = msg.pretty_print
|
292
|
+
end
|
293
|
+
@value = msg
|
294
|
+
@err_code = err_code
|
295
|
+
progress("#{@pretty_name} rejected") if @pretty_name
|
296
|
+
_call('on_error', @rejected_handlers, [err_code, msg])
|
297
|
+
nil
|
298
|
+
end
|
299
|
+
|
300
|
+
def _call(name, blocks, args, call_always_on_as_well = true)
|
301
|
+
blocks.each do |block|
|
302
|
+
begin
|
303
|
+
block.call(*args)
|
304
|
+
rescue Exception => ex
|
305
|
+
warn "(#{@name}) Exception while calling '#{name}' - #{ex} - #{block} - #{args}"
|
306
|
+
debug ex.backtrace.join("\n\t")
|
307
|
+
if name == 'on_success'
|
308
|
+
#return _call('on_error', @rejected_handlers, [-1, ex])
|
309
|
+
# TODO: Clarify this. Currently we could have multiple
|
310
|
+
# 'on_success' handlers, but the current logic will call
|
311
|
+
# all 'on_error' handles if one 'on_success' throws an
|
312
|
+
# exception and turns this promise into 'rejected'
|
313
|
+
return _reject(-1, ex)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
if call_always_on_as_well
|
318
|
+
_call('on_always', @always_handlers, nil, false)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
|
323
|
+
|
324
|
+
end
|
325
|
+
end
|