cpee 2.1.121 → 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: 80d909f1d5117cf3439add6bcfb46571778c8c6c482bc7cd308eb3c2a9c4431f
4
- data.tar.gz: fc2d8deeb972a5a57b16b8ebdc2db982b284871386fedbd402dceb9429f8fc10
3
+ metadata.gz: 63c48292c70c40336ce8385bb86fbea2722ebb3becbfe091843f5d7f60268d0c
4
+ data.tar.gz: 8b53f0ea495c73ccc423ad1cbca5c764928fdee41ab7af9c853f725c3dc3ed34
5
5
  SHA512:
6
- metadata.gz: a929aa173158993c2f96eacea72c1c5fd74302d820493e581f39a00f017303149357a3eedb19a1346d96b3050b29ddc3bacf7b2b873bac4c5fc3f1208dc5b99d
7
- data.tar.gz: cde8af038d7911aa40825f71cca4cdd22e8e04767c9840992453bc4cc0d6e297f8d9de94f6e7a6921d66cf3826b3435791384cade92639f62532bf6973e91f0e
6
+ metadata.gz: 977f66a12107bd16c154d55320a3d1f42bf15713419e50dcf1456532dffd332b6d465ec97f2721b61b3ec0d50aab5768b3dabb77a8ecc87ae3e78f63aa63ac77
7
+ data.tar.gz: 6038b1ba120f2b8ca11e53f5b00987658c6789f33382c215be5bcf5b252f88d3e215c3a4281d614236a40bd93926e2bd4ab90ddb49f97195f67fdead80b5411d
@@ -1172,25 +1172,6 @@ async function set_testset(testset,exec) {// {{{
1172
1172
  await Promise.all(promises);
1173
1173
 
1174
1174
  document.dispatchEvent(model_loaded);
1175
-
1176
- $.ajax({
1177
- type: "GET",
1178
- url: url + "/properties/state/",
1179
- dataType: "text",
1180
- success: function(res){
1181
- $.ajax({
1182
- type: "PUT",
1183
- url: url + "/properties/state/",
1184
- data: ({value: res}),
1185
- error: report_failure,
1186
- success: function(res){
1187
- if (exec) start_instance();
1188
- }
1189
- });
1190
- }
1191
- });
1192
-
1193
-
1194
1175
  }// }}}
1195
1176
 
1196
1177
  function load_testsetfile_after() { //{{{
@@ -143,10 +143,11 @@ function modifiers_select() {
143
143
  let top = $(r).attr('data-resource');
144
144
  let it = $(s).attr('value');
145
145
  $('select',r).val(it);
146
- modifiers_display_ui(rep + 'modifiers/',top,it,save['modifiers_active'][top] == it);
147
- if (save['modifiers_active'][top] != it) {
148
- modifiers_update({"target": $('select',r)});
146
+ if (typeof(save['modifiers_active'][top]) == "undefined") {
147
+ // set for page load
148
+ save['modifiers_active'][top] = it;
149
149
  }
150
+ modifiers_display_ui(rep + 'modifiers/',top,it,save['modifiers_active'][top] == it);
150
151
  save['modifiers_active'][top] = it;
151
152
  }
152
153
  });
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.121"
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."
@@ -32,6 +32,7 @@ Gem::Specification.new do |s|
32
32
  s.add_runtime_dependency 'mimemagic', '~>0'
33
33
  s.add_runtime_dependency 'get_process_mem', '~>0.2'
34
34
  s.add_runtime_dependency 'webrick', '~>1.7'
35
+ s.add_runtime_dependency 'msgpack', '~>1.8'
35
36
  s.add_runtime_dependency 'by', '~> 1.1', '>= 1.1.0'
36
37
  s.add_runtime_dependency 'concurrent-ruby', '~> 1.3', '>= 1.3.5'
37
38
  end
@@ -158,7 +158,11 @@ module CPEE
158
158
  CPEE::Properties::PutStatus::set id, opts, node.first.dump
159
159
  end
160
160
  if (node = doc.find('/p:properties/p:executionhandler')).any?
161
- CPEE::Properties::PutExecutionHandler::set id, opts, node.first.text
161
+ if doc.find('/p:properties/p:description/*').any?
162
+ CPEE::Properties::PutExecutionHandler::set id, opts, node.first.text, false
163
+ else
164
+ CPEE::Properties::PutExecutionHandler::set id, opts, node.first.text
165
+ end
162
166
  end
163
167
 
164
168
  %w{dataelements endpoints attributes}.each do |item|
@@ -424,10 +428,7 @@ module CPEE
424
428
  doc.find("/*/*").each do |ele|
425
429
  val[ele.qname.name] = ele.text unless val.has_key?(ele.qname.name)
426
430
  end
427
- oldkeys = CPEE::Persistence::extract_list(id,opts,item).to_h.keys
428
- newkeys = val.keys
429
- del = oldkeys - newkeys
430
- CPEE::Persistence::set_list(id,opts,item,val,del)
431
+ CPEE::Persistence::set_list(id,opts,item,val,true,true)
431
432
  end
432
433
 
433
434
  def response
@@ -514,7 +515,7 @@ module CPEE
514
515
  @status = 410
515
516
  else
516
517
  if CPEE::Persistence::extract_item(id,opts,@r.join('/'))
517
- CPEE::Persistence::set_list(id,opts,item,val,val.keys)
518
+ CPEE::Persistence::set_list(id,opts,item,val,false,true,val.keys)
518
519
  else
519
520
  @status = 404
520
521
  end
@@ -12,6 +12,7 @@
12
12
  # CPEE (file COPYING in the main directory). If not, see
13
13
  # <http://www.gnu.org/licenses/>.
14
14
 
15
+ require 'msgpack'
15
16
  require_relative 'attributes_helper'
16
17
  require_relative 'message'
17
18
 
@@ -30,26 +31,60 @@ module CPEE
30
31
  CPEE::Message::wait(opts[:redis],opts[:redis_dyn].call('Temporary Storage Transaction Subscriber'))
31
32
  end
32
33
 
33
- def self::set_list(id,opts,item,values,deleted=[]) #{{{
34
+ def self::set_list(id,opts,item,values,diff=false,delete=false,deletions=[]) #{{{
34
35
  ah = AttributesHelper.new
35
36
  attributes = Persistence::extract_list(id,opts,'attributes').to_h
36
37
  dataelements = Persistence::extract_list(id,opts,'dataelements').to_h
37
38
  endpoints = Persistence::extract_list(id,opts,'endpoints').to_h
39
+ oldvalues = case item
40
+ when 'attributes' then attributes
41
+ when 'endpoints' then endpoints
42
+ when 'dataelements' then dataelements
43
+ end
44
+ sort = []
45
+ if diff
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
50
+ values.delete_if do |k,v|
51
+ oldvalues[k] && oldvalues[k] == v
52
+ end
53
+ end
54
+ payload = {
55
+ :values => oldvalues.merge(values).transform_values{|val| JSON::parse(val) rescue val },
56
+ :attributes => ah.translate(attributes,dataelements,endpoints)
57
+ }
38
58
  CPEE::Message::send(
39
59
  :event,
40
- File.join(item,'change'),
60
+ File.join(item,'modify'),
41
61
  opts[:url],
42
62
  id,
43
63
  Persistence::extract_item(id,opts,'attributes/uuid'),
44
64
  Persistence::extract_item(id,opts,'attributes/info'),
45
- {
46
- :changed => values.keys,
47
- :deleted => deleted,
48
- :values => values.transform_values{|val| JSON::parse(val) rescue val },
49
- :attributes => ah.translate(attributes,dataelements,endpoints),
50
- },
65
+ payload,
51
66
  opts[:redis]
52
67
  )
68
+ payload[:values] = values.transform_values{|val| JSON::parse(val) rescue val }
69
+ payload[:changed] = values.keys
70
+ if delete
71
+ payload[:deleted] = deletions
72
+ end
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
53
88
  end #}}}
54
89
  def self::extract_set(id,opts,item) #{{{
55
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
 
@@ -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)
@@ -96,7 +99,7 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
96
99
  }
97
100
  end #}}}
98
101
 
99
- def proto_curl(parameters) #{{{
102
+ def proto_curl(parameters, dataelements) #{{{
100
103
  params = []
101
104
  callback = SecureRandom.hex(16)
102
105
  (parameters[:arguments] || []).each do |s|
@@ -200,11 +203,11 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
200
203
  headers['CPEE_SALVAGE'] = true
201
204
  c = result[0]&.value
202
205
  c = c.read if c.respond_to? :read
203
- 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)
204
207
  else
205
208
  if headers['CPEE_CALLBACK'] && headers['CPEE_CALLBACK'] == 'true' && result.any?
206
209
  headers['CPEE_UPDATE'] = true
207
- callback result, headers
210
+ callback result, headers, dataelements
208
211
  elsif headers['CPEE_CALLBACK'] && headers['CPEE_CALLBACK'] == 'true' && result.empty?
209
212
  if headers['CPEE_INSTANTIATION']
210
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']))
@@ -214,19 +217,19 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
214
217
  end
215
218
  # do nothing, later on things will happend
216
219
  else
217
- callback result, headers
220
+ callback result, headers, dataelements
218
221
  end
219
222
  end
220
223
  end #}}}
221
224
 
222
- def activity_handle(passthrough, parameters) # {{{
225
+ def activity_handle(passthrough, parameters, dataelements) # {{{
223
226
  raise "Wrong endpoint" if @handler_endpoint.nil? || @handler_endpoint.empty?
224
227
  @label = parameters[:label]
225
228
  @anno = parameters.delete(:annotations) rescue nil
226
229
  @controller.notify("activity/calling", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :passthrough => passthrough, :endpoint => @handler_endpoint, :parameters => parameters)
227
230
  @controller.notify("activity/annotation", :'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position, :annotations => @anno)
228
231
  if passthrough.to_s.empty?
229
- proto_curl parameters
232
+ proto_curl parameters, dataelements
230
233
  else
231
234
  @controller.callback(self,passthrough,:'activity-uuid' => @handler_activity_uuid, :label => @label, :activity => @handler_position)
232
235
  @handler_passthrough = passthrough
@@ -271,6 +274,9 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
271
274
  unless changed_dataelements.nil? || changed_dataelements.empty?
272
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))) }
273
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
274
280
  end
275
281
  unless changed_endpoints.nil? || changed_endpoints.empty?
276
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))
@@ -284,7 +290,7 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
284
290
  @controller.vote("activity/syncing_before", :'activity-uuid' => @handler_activity_uuid, :endpoint => @handler_endpoint, :activity => @handler_position, :label => @label, :parameters => parameters)
285
291
  end # }}}
286
292
 
287
- def callback(result=nil,options={}) #{{{
293
+ def callback(result=nil,options={}, dataelements) #{{{
288
294
  status, ret, headers = Riddl::Client.new(@controller.url_result_transformation).request 'put' => result
289
295
  recv = if status >= 200 && status < 300
290
296
  JSON::parse(ret[0].value.read)
@@ -293,6 +299,9 @@ class ConnectionWrapper < WEEL::ConnectionWrapperBase
293
299
  end
294
300
 
295
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
296
305
 
297
306
  @guard_files += result
298
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
 
@@ -50,6 +50,7 @@
50
50
  </topic>
51
51
  <topic id='dataelements'>
52
52
  <event>change</event>
53
+ <event>modify</event>
53
54
  </topic>
54
55
  <topic id='endpoints'>
55
56
  <event>change</event>
@@ -1 +1 @@
1
- 26491
1
+ 1283631
@@ -1 +1 @@
1
- 26511
1
+ 1283649
@@ -1 +1 @@
1
- 26505
1
+ 1283643
@@ -1 +1 @@
1
- 26499
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.121
4
+ version: 2.1.123
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juergen eTM Mangler
@@ -171,6 +171,20 @@ dependencies:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
173
  version: '1.7'
174
+ - !ruby/object:Gem::Dependency
175
+ name: msgpack
176
+ requirement: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '1.8'
181
+ type: :runtime
182
+ prerelease: false
183
+ version_requirements: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '1.8'
174
188
  - !ruby/object:Gem::Dependency
175
189
  name: by
176
190
  requirement: !ruby/object:Gem::Requirement
@@ -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