cpee 2.1.122 → 2.1.123

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5d819e511b5c747cc2fc238f83e6c94aa9fc263e15906b4d62af4bbb7323f52e
4
- data.tar.gz: bab3b37ada5e2739d779bda8b19ddf24a307ca95f154b32c0c91e7c3f292ca82
3
+ metadata.gz: 63c48292c70c40336ce8385bb86fbea2722ebb3becbfe091843f5d7f60268d0c
4
+ data.tar.gz: 8b53f0ea495c73ccc423ad1cbca5c764928fdee41ab7af9c853f725c3dc3ed34
5
5
  SHA512:
6
- metadata.gz: c674196d5cef21fa056cdfb64a2ef64ca9381cb68f424de9cddcf6a1d493fcc1e9c7eb618708d2994fd84d76aa6bb20ebb7264bed643b5c7fcdac9bca7486958
7
- data.tar.gz: 3cfd5b3ca1df014bd09a2f826f4c80cc112a496fe5750762610c6935874c71a24edae18be0219633eb3348bb0f927717a637b3733e48a73d0eff773691bac00d
6
+ metadata.gz: 977f66a12107bd16c154d55320a3d1f42bf15713419e50dcf1456532dffd332b6d465ec97f2721b61b3ec0d50aab5768b3dabb77a8ecc87ae3e78f63aa63ac77
7
+ data.tar.gz: 6038b1ba120f2b8ca11e53f5b00987658c6789f33382c215be5bcf5b252f88d3e215c3a4281d614236a40bd93926e2bd4ab90ddb49f97195f67fdead80b5411d
data/cpee.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "cpee"
3
- s.version = "2.1.122"
3
+ s.version = "2.1.123"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.license = "LGPL-3.0-or-later"
6
6
  s.summary = "The cloud process execution engine (cpee.org). If you just need workflow execution, without a rest service exposing it, then use WEEL."
@@ -41,15 +41,19 @@ module CPEE
41
41
  when 'endpoints' then endpoints
42
42
  when 'dataelements' then dataelements
43
43
  end
44
+ sort = []
44
45
  if diff
45
46
  deletions = oldvalues.keys - values.keys
47
+ if oldvalues.length > 1 && oldvalues.length == values.length && deletions.length == 0 && oldvalues.keys != values.keys
48
+ sort = values.keys
49
+ end
46
50
  values.delete_if do |k,v|
47
51
  oldvalues[k] && oldvalues[k] == v
48
52
  end
49
53
  end
50
54
  payload = {
51
55
  :values => oldvalues.merge(values).transform_values{|val| JSON::parse(val) rescue val },
52
- :attributes => ah.translate(attributes,dataelements,endpoints),
56
+ :attributes => ah.translate(attributes,dataelements,endpoints)
53
57
  }
54
58
  CPEE::Message::send(
55
59
  :event,
@@ -66,16 +70,21 @@ module CPEE
66
70
  if delete
67
71
  payload[:deleted] = deletions
68
72
  end
69
- CPEE::Message::send(
70
- :event,
71
- File.join(item,'change'),
72
- opts[:url],
73
- id,
74
- Persistence::extract_item(id,opts,'attributes/uuid'),
75
- Persistence::extract_item(id,opts,'attributes/info'),
76
- payload,
77
- opts[:redis]
78
- )
73
+ if sort.any?
74
+ payload[:sort] = sort
75
+ end
76
+ if values.any? || deletions.any? || sort.any?
77
+ CPEE::Message::send(
78
+ :event,
79
+ File.join(item,'change'),
80
+ opts[:url],
81
+ id,
82
+ Persistence::extract_item(id,opts,'attributes/uuid'),
83
+ Persistence::extract_item(id,opts,'attributes/info'),
84
+ payload,
85
+ opts[:redis]
86
+ )
87
+ end
79
88
  end #}}}
80
89
  def self::extract_set(id,opts,item) #{{{
81
90
  opts[:redis].smembers(@@obj + ":#{id}/#{item}").map do |e|
@@ -29,9 +29,12 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
29
29
  tso + 2 > tsn && count > 100
30
30
  end # }}}
31
31
 
32
- def self::inform_state_change(arguments,newstate) # {{{
32
+ def self::inform_state_change(arguments,newstate,data) # {{{
33
33
  controller = arguments[0]
34
- controller.notify("state/change", :state => newstate)
34
+ controller.notify('state/change', :state => newstate)
35
+ if newstate == :stopped || newstate == :finished
36
+ controller.notify('dataelements/modify', :eid => 'ex-post', :values => data)
37
+ end
35
38
  end # }}}
36
39
  def self::inform_syntax_error(arguments,err,code)# {{{
37
40
  # TODO extract spot (code) where error happened for better error handling (ruby 3.1 only)
@@ -0,0 +1 @@
1
+ ../ruby/controller.rb
@@ -19,21 +19,22 @@ module CPEE
19
19
 
20
20
  module ExecutionHandler
21
21
 
22
- module Eval
23
- BACKEND_INSTANCE = 'instance.rb'
24
- DSL_TO_DSLX_XSL = File.expand_path(File.join(__dir__,'dsl_to_dslx.xsl'))
25
- BACKEND_RUN = File.expand_path(File.join(__dir__,'backend','run.rb'))
26
- BACKEND_OPTS = File.expand_path(File.join(__dir__,'backend','opts.yaml'))
27
- BACKEND_TEMPLATE = File.expand_path(File.join(__dir__,'backend','instance.template'))
22
+ self.const_set File.basename(__dir__).capitalize, Module.new {
23
+ self::BACKEND_INSTANCE = 'instance.rb'
24
+ self::DSL_TO_DSLX_XSL = File.expand_path(File.join(__dir__,'dsl_to_dslx.xsl'))
25
+ self::BACKEND_RUN = File.expand_path(File.join(__dir__,'backend','run.rb'))
26
+ self::BACKEND_OPTS = File.expand_path(File.join(__dir__,'backend','opts.yaml'))
27
+ self::BACKEND_TEMPLATE = File.expand_path(File.join(__dir__,'backend','instance.template'))
28
28
 
29
29
  def self::dslx_to_dsl(dslx,ep) # transpile
30
- trans = XML::Smart::open_unprotected(ExecutionHandler::Eval::DSL_TO_DSLX_XSL)
30
+ trans = XML::Smart::open_unprotected(self::DSL_TO_DSLX_XSL)
31
31
  dslx.transform_with(trans).to_s
32
32
  end
33
33
 
34
34
  def self::prepare(id,opts) # write result to disk
35
+ FileUtils.rm_rf(Dir.glob(File.join(opts[:instances],id.to_s,'*')) + Dir.glob(File.join(opts[:instances],id.to_s,'.remote')))
35
36
  Dir.mkdir(File.join(opts[:instances],id.to_s)) rescue nil
36
- FileUtils.copy(ExecutionHandler::Eval::BACKEND_RUN,File.join(opts[:instances],id.to_s))
37
+ FileUtils.copy(self::BACKEND_RUN,File.join(opts[:instances],id.to_s))
37
38
  dsl = CPEE::Persistence::extract_item(id,opts,'dsl')
38
39
  hw = CPEE::Persistence::extract_item(id,opts,'executionhandler')
39
40
  endpoints = CPEE::Persistence::extract_list(id,opts,'endpoints')
@@ -43,7 +44,8 @@ module CPEE
43
44
  positions.map! do |k, v|
44
45
  [ k, v, CPEE::Persistence::extract_item(id,opts,File.join('positions',k,'@passthrough')) ]
45
46
  end
46
- iopts = YAML::load_file(ExecutionHandler::Eval::BACKEND_OPTS)
47
+ iopts = YAML::load_file(self::BACKEND_OPTS)
48
+ iopts[:instance_id] = id
47
49
  iopts[:host] = opts[:host]
48
50
  iopts[:url] = opts[:url]
49
51
  iopts[:redis_url] = opts[:redis_url]
@@ -57,13 +59,26 @@ module CPEE
57
59
  iopts[:executionhandlers] = opts[:executionhandlers]
58
60
  iopts[:global_executionhandlers] = opts[:global_executionhandlers]
59
61
  end
62
+ iopts[:attributes] = attributes
63
+ iopts[:votes] = {}
64
+ CPEE::Persistence::extract_handlers(id,opts).each do |de|
65
+ if de[1] && de[1]&.empty?.!
66
+ CPEE::Persistence::extract_handler(id,opts,de[0]).each do |ele|
67
+ topic, type, name = ele.split('/')
68
+ if type == 'vote'
69
+ iopts[:votes][ele] ||= []
70
+ iopts[:votes][ele] << de[0]
71
+ end
72
+ end
73
+ end
74
+ end
60
75
 
61
- File.open(File.join(opts[:instances],id.to_s,File.basename(ExecutionHandler::Eval::BACKEND_OPTS)),'w') do |f|
76
+ File.open(File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_OPTS)),'w') do |f|
62
77
  YAML::dump(iopts,f)
63
78
  end
64
- template = ERB.new(File.read(ExecutionHandler::Eval::BACKEND_TEMPLATE), trim_mode: '-')
79
+ template = ERB.new(File.read(self::BACKEND_TEMPLATE), trim_mode: '-')
65
80
  res = template.result_with_hash(dsl: dsl, dataelements: dataelements, endpoints: endpoints, positions: positions)
66
- File.write(File.join(opts[:instances],id.to_s,ExecutionHandler::Eval::BACKEND_INSTANCE),res)
81
+ File.write(File.join(opts[:instances],id.to_s,self::BACKEND_INSTANCE),res)
67
82
  if attributes.has_key?('remote')
68
83
  uri = URI::parse(attributes['remote'])
69
84
  Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
@@ -77,12 +92,12 @@ module CPEE
77
92
  def self::run(id,opts)
78
93
  if File.exist? File.join(opts[:instances],id.to_s,'.remote')
79
94
  uri = URI::parse(File.read(File.join(opts[:instances],id.to_s,'.remote')))
80
- exe = File.join(uri.path,id.to_s,File.basename(BACKEND_RUN))
95
+ exe = File.join(uri.path,id.to_s,File.basename(self::BACKEND_RUN))
81
96
  Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
82
97
  ssh.exec!("ruby #{exe} >#{exe}.out 2>#{exe}.err &")
83
98
  end
84
99
  else
85
- exe = File.join(opts[:instances],id.to_s,File.basename(ExecutionHandler::Eval::BACKEND_RUN))
100
+ exe = File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_RUN))
86
101
  pid = Kernel.spawn(opts[:libs_preloaderrun] + ' ' + exe , :pgroup => true, :in => '/dev/null', :out => exe + '.out', :err => exe + '.err')
87
102
  Process.detach pid
88
103
  File.write(exe + '.pid',pid)
@@ -92,7 +107,7 @@ module CPEE
92
107
  def self::stop(id,opts) ### return: bool to tell if manually changing redis is necessary
93
108
  if File.exist? File.join(opts[:instances],id.to_s,'.remote')
94
109
  uri = URI::parse(File.read(File.join(opts[:instances],id.to_s,'.remote')))
95
- exe = File.join(uri.path,id.to_s,File.basename(BACKEND_RUN))
110
+ exe = File.join(uri.path,id.to_s,File.basename(self::BACKEND_RUN))
96
111
  Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
97
112
  pid = ssh.exec!("cat #{exe}.pid 2>/dev/null")
98
113
  if pid != '' && ssh.exec!("kill -0 #{pid} >/dev/null 2>&1; echo $?").strip == '0'
@@ -104,7 +119,7 @@ module CPEE
104
119
  end
105
120
  end
106
121
  else
107
- exe = File.join(opts[:instances],id.to_s,File.basename(ExecutionHandler::Eval::BACKEND_RUN))
122
+ exe = File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_RUN))
108
123
  pid = File.read(exe + '.pid') rescue nil
109
124
  if pid && (Process.kill(0, pid.to_i) rescue false)
110
125
  Process.kill('HUP', pid.to_i) rescue nil
@@ -115,7 +130,7 @@ module CPEE
115
130
  end
116
131
  end
117
132
  end
118
- end
133
+ }
119
134
 
120
135
  end
121
136
 
@@ -99,7 +99,7 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
99
99
  }
100
100
  end #}}}
101
101
 
102
- def proto_curl(parameters) #{{{
102
+ def proto_curl(parameters, dataelements) #{{{
103
103
  params = []
104
104
  callback = SecureRandom.hex(16)
105
105
  (parameters[:arguments] || []).each do |s|
@@ -203,11 +203,11 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
203
203
  headers['CPEE_SALVAGE'] = true
204
204
  c = result[0]&.value
205
205
  c = c.read if c.respond_to? :read
206
- callback([ Riddl::Parameter::Complex.new('error','application/json',StringIO.new(JSON::generate({ 'status' => status, 'error' => c }))) ], headers)
206
+ callback([ Riddl::Parameter::Complex.new('error','application/json',StringIO.new(JSON::generate({ 'status' => status, 'error' => c }))) ], headers, dataelements)
207
207
  else
208
208
  if headers['CPEE_CALLBACK'] && headers['CPEE_CALLBACK'] == 'true' && result.any?
209
209
  headers['CPEE_UPDATE'] = true
210
- callback result, headers
210
+ callback result, headers, dataelements
211
211
  elsif headers['CPEE_CALLBACK'] && headers['CPEE_CALLBACK'] == 'true' && result.empty?
212
212
  if headers['CPEE_INSTANTIATION']
213
213
  @controller.notify("task/instantiation", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :endpoint => @handler_endpoint, :received => CPEE::ValueHelper.parse(headers['CPEE_INSTANTIATION']))
@@ -217,19 +217,19 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
217
217
  end
218
218
  # do nothing, later on things will happend
219
219
  else
220
- callback result, headers
220
+ callback result, headers, dataelements
221
221
  end
222
222
  end
223
223
  end #}}}
224
224
 
225
- def activity_handle(passthrough, parameters) # {{{
225
+ def activity_handle(passthrough, parameters, dataelements) # {{{
226
226
  raise "Wrong endpoint" if @handler_endpoint.nil? || @handler_endpoint.empty?
227
227
  @label = parameters[:label]
228
228
  @anno = parameters.delete(:annotations) rescue nil
229
229
  @controller.notify("activity/calling", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :passthrough => passthrough, :endpoint => @handler_endpoint, :parameters => parameters)
230
230
  @controller.notify("activity/annotation", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :annotations => @anno)
231
231
  if passthrough.to_s.empty?
232
- proto_curl parameters
232
+ proto_curl parameters, dataelements
233
233
  else
234
234
  @controller.callback(self,passthrough,:'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position)
235
235
  @handler_passthrough = passthrough
@@ -274,6 +274,9 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
274
274
  unless changed_dataelements.nil? || changed_dataelements.empty?
275
275
  de = dataelements.slice(*changed_dataelements).transform_values { |v| enc = CPEE::EvalRuby::Translation::detect_encoding(v); (enc == 'OTHER' ? v : (v.encode('UTF-8',enc) rescue CPEE::EvalRuby::Translation::convert_to_base64(v))) }
276
276
  @controller.notify("dataelements/change", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :label => @label, :activity => @handler_position, :changed => changed_dataelements, :values => de)
277
+ if @anno && @anno[:_context_data_analysis] && @anno[:_context_data_analysis][:probes] && @anno[:_context_data_analysis][:probes].find{ |p| p.dig(:probe,:extractor_type) == 'intrinsic' }
278
+ @controller.notify("task/probe", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :label => @label, :activity => @handler_position, :data => dataelements, :probes => @anno[:_context_data_analysis][:probes])
279
+ end
277
280
  end
278
281
  unless changed_endpoints.nil? || changed_endpoints.empty?
279
282
  @controller.notify("endpoints/change", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :label => @label, :activity => @handler_position, :changed => changed_endpoints, :values => endpoints.slice(*changed_endpoints))
@@ -287,7 +290,7 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
287
290
  @controller.vote("activity/syncing_before", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :activity => @handler_position, :label => @label, :parameters => parameters)
288
291
  end # }}}
289
292
 
290
- def callback(result=nil,options={}) #{{{
293
+ def callback(result=nil,options={}, dataelements) #{{{
291
294
  status, ret, headers = Riddl::Client.new(@controller.url_result_transformation).request 'put' => result
292
295
  recv = if status >= 200 && status < 300
293
296
  JSON::parse(ret[0].value.read)
@@ -296,6 +299,9 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
296
299
  end
297
300
 
298
301
  @controller.notify("activity/receiving", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :endpoint => @handler_endpoint, :received => recv)
302
+ if @anno[:_context_data_analysis] && @anno[:_context_data_analysis][:probes] && @anno[:_context_data_analysis][:probes].find{ |p| p.dig(:probe,:extractor_type) == 'extrinsic' }
303
+ @controller.notify("task/probe", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :endpoint => @handler_endpoint, :received => recv, :data => dataelements, :probes => @anno[:_context_data_analysis]&.[](:probes))
304
+ end
299
305
 
300
306
  @guard_files += result
301
307
  @guard_files += ret
@@ -21,7 +21,6 @@ require 'cpee/value_helper'
21
21
  require 'cpee/attributes_helper'
22
22
  require 'cpee/message'
23
23
  require 'cpee/redis'
24
- require 'cpee/persistence'
25
24
  require 'get_process_mem'
26
25
 
27
26
  require 'ostruct'
@@ -42,12 +41,9 @@ class Controller
42
41
 
43
42
  @id = id
44
43
 
45
- @attributes = {}
46
- CPEE::Persistence::extract_list(id,opts,'attributes').each do |de|
47
- @attributes[de[0]] = de[1]
48
- end
49
-
44
+ @attributes = opts[:attributes]
50
45
  @attributes_helper = AttributesHelper.new
46
+
51
47
  @thread = nil
52
48
  @opts = opts
53
49
  @instance = nil
@@ -74,7 +70,7 @@ class Controller
74
70
  resp << Riddl::Parameter::Complex.new(e[0],e[1][1],e[1][2])
75
71
  end
76
72
  end
77
- @callback_keys[identifier].send(:callback,resp,m['content']['headers'])
73
+ @callback_keys[identifier].send(:callback,resp,m['content']['headers'],dataelements)
78
74
  end
79
75
  end
80
76
  if pat == 'callback-end:*'
@@ -183,7 +179,7 @@ class Controller
183
179
  handler = File.join(topic,'vote',name)
184
180
  votes = []
185
181
 
186
- CPEE::Persistence::extract_handler(id,@opts,handler).each do |client|
182
+ @opts[:votes][handler]&.each do |client|
187
183
  voteid = SecureRandom.hex(16)
188
184
  content[:key] = voteid
189
185
  content[:attributes] = attributes_translated
@@ -91,9 +91,12 @@
91
91
  </xsl:if>
92
92
  <xsl:if test="name()='manipulate'">
93
93
  <xsl:if test="@label">
94
- <xsl:text>, { :label => "</xsl:text>
95
- <xsl:value-of select="@label"/>
96
- <xsl:text>" }</xsl:text>
94
+ <xsl:text>, { </xsl:text>
95
+ <xsl:text>:label => "</xsl:text>
96
+ <xsl:value-of select="@label"/>
97
+ <xsl:text>", </xsl:text>
98
+ <xsl:apply-templates select="d:annotations" mode="annotations"/>
99
+ <xsl:text> }</xsl:text>
97
100
  </xsl:if>
98
101
  <xsl:call-template name="print-mcontent">
99
102
  <xsl:with-param name="myspace">
@@ -19,22 +19,22 @@ module CPEE
19
19
 
20
20
  module ExecutionHandler
21
21
 
22
- module Ruby
23
- BACKEND_INSTANCE = 'instance.rb'
24
- DSL_TO_DSLX_XSL = File.expand_path(File.join(__dir__,'dsl_to_dslx.xsl'))
25
- BACKEND_RUN = File.expand_path(File.join(__dir__,'backend','run.rb'))
26
- BACKEND_OPTS = File.expand_path(File.join(__dir__,'backend','opts.yaml'))
27
- BACKEND_TEMPLATE = File.expand_path(File.join(__dir__,'backend','instance.template'))
22
+ self.const_set File.basename(__dir__).capitalize, Module.new {
23
+ self::BACKEND_INSTANCE = 'instance.rb'
24
+ self::DSL_TO_DSLX_XSL = File.expand_path(File.join(__dir__,'dsl_to_dslx.xsl'))
25
+ self::BACKEND_RUN = File.expand_path(File.join(__dir__,'backend','run.rb'))
26
+ self::BACKEND_OPTS = File.expand_path(File.join(__dir__,'backend','opts.yaml'))
27
+ self::BACKEND_TEMPLATE = File.expand_path(File.join(__dir__,'backend','instance.template'))
28
28
 
29
29
  def self::dslx_to_dsl(dslx,ep) # transpile
30
- trans = XML::Smart::open_unprotected(ExecutionHandler::Ruby::DSL_TO_DSLX_XSL)
30
+ trans = XML::Smart::open_unprotected(self::DSL_TO_DSLX_XSL)
31
31
  dslx.transform_with(trans).to_s
32
32
  end
33
33
 
34
34
  def self::prepare(id,opts) # write result to disk
35
35
  FileUtils.rm_rf(Dir.glob(File.join(opts[:instances],id.to_s,'*')) + Dir.glob(File.join(opts[:instances],id.to_s,'.remote')))
36
36
  Dir.mkdir(File.join(opts[:instances],id.to_s)) rescue nil
37
- FileUtils.copy(ExecutionHandler::Ruby::BACKEND_RUN,File.join(opts[:instances],id.to_s))
37
+ FileUtils.copy(self::BACKEND_RUN,File.join(opts[:instances],id.to_s))
38
38
  dsl = CPEE::Persistence::extract_item(id,opts,'dsl')
39
39
  hw = CPEE::Persistence::extract_item(id,opts,'executionhandler')
40
40
  endpoints = CPEE::Persistence::extract_list(id,opts,'endpoints')
@@ -44,7 +44,8 @@ module CPEE
44
44
  positions.map! do |k, v|
45
45
  [ k, v, CPEE::Persistence::extract_item(id,opts,File.join('positions',k,'@passthrough')) ]
46
46
  end
47
- iopts = YAML::load_file(ExecutionHandler::Ruby::BACKEND_OPTS)
47
+ iopts = YAML::load_file(self::BACKEND_OPTS)
48
+ iopts[:instance_id] = id
48
49
  iopts[:host] = opts[:host]
49
50
  iopts[:url] = opts[:url]
50
51
  iopts[:redis_url] = opts[:redis_url]
@@ -58,13 +59,26 @@ module CPEE
58
59
  iopts[:executionhandlers] = opts[:executionhandlers]
59
60
  iopts[:global_executionhandlers] = opts[:global_executionhandlers]
60
61
  end
62
+ iopts[:attributes] = attributes
63
+ iopts[:votes] = {}
64
+ CPEE::Persistence::extract_handlers(id,opts).each do |de|
65
+ if de[1] && de[1]&.empty?.!
66
+ CPEE::Persistence::extract_handler(id,opts,de[0]).each do |ele|
67
+ topic, type, name = ele.split('/')
68
+ if type == 'vote'
69
+ iopts[:votes][ele] ||= []
70
+ iopts[:votes][ele] << de[0]
71
+ end
72
+ end
73
+ end
74
+ end
61
75
 
62
- File.open(File.join(opts[:instances],id.to_s,File.basename(ExecutionHandler::Ruby::BACKEND_OPTS)),'w') do |f|
76
+ File.open(File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_OPTS)),'w') do |f|
63
77
  YAML::dump(iopts,f)
64
78
  end
65
- template = ERB.new(File.read(ExecutionHandler::Ruby::BACKEND_TEMPLATE), trim_mode: '-')
79
+ template = ERB.new(File.read(self::BACKEND_TEMPLATE), trim_mode: '-')
66
80
  res = template.result_with_hash(dsl: dsl, dataelements: dataelements, endpoints: endpoints, positions: positions)
67
- File.write(File.join(opts[:instances],id.to_s,ExecutionHandler::Ruby::BACKEND_INSTANCE),res)
81
+ File.write(File.join(opts[:instances],id.to_s,self::BACKEND_INSTANCE),res)
68
82
  if attributes.has_key?('remote')
69
83
  uri = URI::parse(attributes['remote'])
70
84
  Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
@@ -78,12 +92,12 @@ module CPEE
78
92
  def self::run(id,opts)
79
93
  if File.exist? File.join(opts[:instances],id.to_s,'.remote')
80
94
  uri = URI::parse(File.read(File.join(opts[:instances],id.to_s,'.remote')))
81
- exe = File.join(uri.path,id.to_s,File.basename(BACKEND_RUN))
95
+ exe = File.join(uri.path,id.to_s,File.basename(self::BACKEND_RUN))
82
96
  Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
83
97
  ssh.exec!("ruby #{exe} >#{exe}.out 2>#{exe}.err &")
84
98
  end
85
99
  else
86
- exe = File.join(opts[:instances],id.to_s,File.basename(ExecutionHandler::Ruby::BACKEND_RUN))
100
+ exe = File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_RUN))
87
101
  pid = Kernel.spawn(opts[:libs_preloaderrun] + ' ' + exe , :pgroup => true, :in => '/dev/null', :out => exe + '.out', :err => exe + '.err')
88
102
  Process.detach pid
89
103
  File.write(exe + '.pid',pid)
@@ -93,7 +107,7 @@ module CPEE
93
107
  def self::stop(id,opts) ### return: bool to tell if manually changing redis is necessary
94
108
  if File.exist? File.join(opts[:instances],id.to_s,'.remote')
95
109
  uri = URI::parse(File.read(File.join(opts[:instances],id.to_s,'.remote')))
96
- exe = File.join(uri.path,id.to_s,File.basename(BACKEND_RUN))
110
+ exe = File.join(uri.path,id.to_s,File.basename(self::BACKEND_RUN))
97
111
  Net::SSH.start(uri.host,uri.user,:keys => [ opts[:ssh_key] ] ) do |ssh|
98
112
  pid = ssh.exec!("cat #{exe}.pid 2>/dev/null")
99
113
  if pid != '' && ssh.exec!("kill -0 #{pid} >/dev/null 2>&1; echo $?").strip == '0'
@@ -105,7 +119,7 @@ module CPEE
105
119
  end
106
120
  end
107
121
  else
108
- exe = File.join(opts[:instances],id.to_s,File.basename(ExecutionHandler::Ruby::BACKEND_RUN))
122
+ exe = File.join(opts[:instances],id.to_s,File.basename(self::BACKEND_RUN))
109
123
  pid = File.read(exe + '.pid') rescue nil
110
124
  if pid && (Process.kill(0, pid.to_i) rescue false)
111
125
  Process.kill('HUP', pid.to_i) rescue nil
@@ -116,7 +130,7 @@ module CPEE
116
130
  end
117
131
  end
118
132
  end
119
- end
133
+ }
120
134
 
121
135
  end
122
136
 
@@ -1 +1 @@
1
- 741834
1
+ 1283631
@@ -1 +1 @@
1
- 741857
1
+ 1283649
@@ -1 +1 @@
1
- 741846
1
+ 1283643
@@ -1 +1 @@
1
- 741840
1
+ 1283637
@@ -88,10 +88,18 @@ Daemonite.new do |opts|
88
88
  end
89
89
  when /event:\d+:dataelements\/change/, /event:\d+:endpoints\/change/, /event:\d+:attributes\/change/
90
90
  topic = mess.dig('topic')
91
+ max = opts[:redis].zrange("instance:#{instance}/#{topic}", -1, -1, :withscores => true)&.dig(0,1).to_i
92
+ if (eles = mess.dig('content','sort'))&.any?
93
+ opts[:redis].multi do |multi|
94
+ eles.each_with_index do |e,i|
95
+ multi.zadd("instance:#{instance}/#{topic}",i,e,xx: true)
96
+ end
97
+ end
98
+ end
91
99
  opts[:redis].multi do |multi|
92
100
  mess.dig('content','changed')&.each_with_index do |c,i|
93
101
  unless what =~ /event:\d+:attributes\/change/ && c == 'uuid'
94
- multi.zadd("instance:#{instance}/#{topic}",i,c)
102
+ multi.zadd("instance:#{instance}/#{topic}",max + 1 + i,c,nx: true)
95
103
  if what =~ /event:\d+:dataelements\/change/
96
104
  multi.set("instance:#{instance}/#{topic}/#{c}",CPEE::ValueHelper::generate(mess.dig('content','values',c)))
97
105
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cpee
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.122
4
+ version: 2.1.123
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juergen eTM Mangler
@@ -1,226 +0,0 @@
1
- # This file is part of CPEE.
2
- #
3
- # CPEE is free software: you can redistribute it and/or modify it under the terms
4
- # of the GNU General Public License as published by the Free Software Foundation,
5
- # either version 3 of the License, or (at your option) any later version.
6
- #
7
- # CPEE is distributed in the hope that it will be useful, but WITHOUT ANY
8
- # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9
- # PARTICULAR PURPOSE. See the GNU General Public License for more details.
10
- #
11
- # You should have received a copy of the GNU General Public License along with
12
- # CPEE (file COPYING in the main directory). If not, see
13
- # <http://www.gnu.org/licenses/>.
14
-
15
- require 'weel'
16
- require 'json'
17
- require 'redis'
18
- require 'securerandom'
19
- require 'riddl/client'
20
- require 'cpee/value_helper'
21
- require 'cpee/attributes_helper'
22
- require 'cpee/message'
23
- require 'cpee/redis'
24
- require 'cpee/persistence'
25
- require 'get_process_mem'
26
-
27
- require 'ostruct'
28
- class ParaStruct < OpenStruct
29
- def to_json(*a)
30
- table.to_json
31
- end
32
- end
33
- def ⭐(a); ParaStruct.new(a); end
34
-
35
- class Controller
36
- def initialize(id,dir,opts)
37
- CPEE::redis_connect(opts,"Instance #{id}")
38
- CPEE::Message::set_workers(opts[:workers])
39
-
40
- @redis = opts[:redis]
41
- @votes = []
42
-
43
- @id = id
44
-
45
- @attributes = {}
46
- CPEE::Persistence::extract_list(id,opts,'attributes').each do |de|
47
- @attributes[de[0]] = de[1]
48
- end
49
-
50
- @attributes_helper = AttributesHelper.new
51
- @thread = nil
52
- @opts = opts
53
- @instance = nil
54
- @loop_guard = {}
55
-
56
- @callback_keys = {}
57
-
58
- @subs = Thread.new do
59
- @psredis = @opts[:redis_dyn].call "Instance #{@id} Callback Response"
60
- @psredis.psubscribe('callback-response:*','callback-end:*') do |on|
61
- on.pmessage do |pat, what, message|
62
- if pat == 'callback-response:*'
63
- _, worker, identifier = what.split(':')
64
- if @callback_keys.has_key?(identifier)
65
- index = message.index(' ')
66
- mess = message[index+1..-1]
67
- instance, uuid = message[0...index].split(',')
68
- m = JSON.parse(mess)
69
- resp = []
70
- m['content']['values'].each do |e|
71
- if e[1][0] == 'simple'
72
- resp << Riddl::Parameter::Simple.new(e[0],e[1][1])
73
- elsif e[1][0] == 'complex'
74
- resp << Riddl::Parameter::Complex.new(e[0],e[1][1],e[1][2])
75
- end
76
- end
77
- @callback_keys[identifier].send(:callback,resp,m['content']['headers'])
78
- end
79
- end
80
- if pat == 'callback-end:*'
81
- _, worker, identifier = what.split(':')
82
- @callback_keys.delete(identifier)
83
- end
84
- end
85
- end
86
- @psredis.close
87
- rescue => e
88
- sleep 1
89
- retry
90
- end
91
- Thread.new do
92
- while true
93
- notify("status/resource_utilization", :mib => GetProcessMem.new.mb, **Process.times.to_h)
94
- sleep 3
95
- end
96
- end
97
- end
98
-
99
- attr_reader :id
100
- attr_reader :attributes
101
- attr_reader :loop_guard
102
-
103
- def attributes_translated
104
- @attributes_translated || @attributes_translated = @attributes_helper.translate(attributes,dataelements,endpoints)
105
- end
106
-
107
- def uuid
108
- @attributes['uuid']
109
- end
110
- def host
111
- @opts[:host]
112
- end
113
- def base_url
114
- File.join(@opts[:url],'/')
115
- end
116
- def instance_url
117
- File.join(@opts[:url].to_s,@id.to_s,'/')
118
- end
119
- def instance_id
120
- @id
121
- end
122
- def base
123
- base_url
124
- end
125
- def instance=(inst)
126
- @instance = inst
127
- end
128
- def endpoints
129
- @instance.endpoints
130
- end
131
- def dataelements
132
- @instance.data
133
- end
134
- def url_result_transformation
135
- @opts[:url_result_transformation]
136
- end
137
- def url_code
138
- @opts[:url_code]
139
- end
140
-
141
- def start
142
- if vote("state/change", :state => 'running')
143
- @thread = @instance.start
144
- @thread.join
145
- else
146
- @thread = @instance.stop
147
- @thread.join
148
- end
149
- end
150
-
151
- def sim
152
- if vote("state/change", :state => 'simulating')
153
- @thread = @instance.sim
154
- @thread.join
155
- else
156
- @thread = @instance.stop
157
- @thread.join
158
- end
159
- end
160
-
161
- def stop
162
- ### tell the instance to stop
163
- @instance.stop
164
- ### end all votes or it will not work
165
- Thread.new do # doing stuff in trap context is a nono. but in a thread its fine :-)
166
- @votes.each do |key|
167
- CPEE::Message::send(:'vote-response',key,base,@id,uuid,info,true,@redis)
168
- end
169
- end
170
- end
171
-
172
- def info
173
- @attributes['info']
174
- end
175
-
176
- def notify(what,content={})
177
- content[:attributes] = attributes_translated
178
- CPEE::Message::send(:event,what,base,@id,uuid,info,content,@redis)
179
- end
180
-
181
- def vote(what,content={})
182
- topic, name = what.split('/')
183
- handler = File.join(topic,'vote',name)
184
- votes = []
185
-
186
- CPEE::Persistence::extract_handler(id,@opts,handler).each do |client|
187
- voteid = SecureRandom.hex(16)
188
- content[:key] = voteid
189
- content[:attributes] = attributes_translated
190
- content[:subscription] = client
191
- votes << voteid
192
- CPEE::Message::send(:vote,what,base,@id,uuid,info,content,@redis)
193
- end
194
-
195
- if votes.length > 0
196
- @votes += votes
197
- psredis = @opts[:redis_dyn].call "Instance #{@id} Vote"
198
- collect = []
199
- psredis.subscribe(votes.map{|e| ['vote-response:00:' + e.to_s] }.flatten) do |on|
200
- on.message do |what, message|
201
- index = message.index(' ')
202
- mess = message[index+1..-1]
203
- m = JSON.parse(mess)
204
- collect << ((m['content'] == true || m['content'] == 'true') || false)
205
- @votes.delete m['name']
206
- cancel_callback m['name']
207
- if collect.length >= votes.length
208
- psredis.unsubscribe
209
- end
210
- end
211
- end
212
- !collect.include?(false)
213
- else
214
- true
215
- end
216
- end
217
-
218
- def callback(hw,key,content)
219
- CPEE::Message::send(:callback,'activity/content',base,@id,uuid,info,content.merge(:key => key),@redis)
220
- @callback_keys[key] = hw
221
- end
222
-
223
- def cancel_callback(key)
224
- CPEE::Message::send(:'callback-end',key,base,@id,uuid,info,{},@redis)
225
- end
226
- end