cpee 2.1.29 → 2.1.50

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.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/cockpit/config.json +1 -1
  4. data/cockpit/css/graph.css +13 -0
  5. data/cockpit/css/track.css +1 -1
  6. data/cockpit/css/wfadaptor.css +9 -2
  7. data/cockpit/edit.html +1 -1
  8. data/cockpit/graph.html +1 -0
  9. data/cockpit/index.html +2 -2
  10. data/cockpit/js/details.js +2 -2
  11. data/cockpit/js/instance.js +162 -112
  12. data/cockpit/js/wfadaptor.js +20 -14
  13. data/cockpit/js_libs.zip +0 -0
  14. data/cockpit/templates/Coopis 2010.xml +109 -14
  15. data/cockpit/templates/Frames.xml +297 -0
  16. data/cockpit/templates/Subprocess.xml +54 -6
  17. data/cockpit/templates/Wait.xml +5 -11
  18. data/cockpit/templates/Worklist.xml +58 -26
  19. data/cockpit/themes/compact/rngs/call.rng +127 -86
  20. data/cockpit/themes/compact/rngs/callmanipulate.rng +32 -7
  21. data/cockpit/themes/compact/rngs/closed_loop_control.rng +2 -2
  22. data/cockpit/themes/compact/rngs/closed_loop_measuring.rng +3 -3
  23. data/cockpit/themes/compact/rngs/start.rng +110 -72
  24. data/cockpit/themes/compact/symbols/call_sensor.svg +9 -0
  25. data/cockpit/themes/compact/symbols/callmanipulate.svg +3 -3
  26. data/cockpit/themes/compact/symbols/callmanipulate_sensor.svg +11 -0
  27. data/cockpit/themes/compact/symbols/delete.svg +4 -0
  28. data/cockpit/themes/compact/symbols/start_event.svg +5 -0
  29. data/cockpit/themes/compact/symbols/test.svg +74 -0
  30. data/cockpit/themes/compact/theme.js +105 -9
  31. data/cockpit/themes/control/rngs/call.rng +127 -86
  32. data/cockpit/themes/control/rngs/callmanipulate.rng +32 -7
  33. data/cockpit/themes/control/rngs/closed_loop_control.rng +2 -2
  34. data/cockpit/themes/control/rngs/closed_loop_measuring.rng +3 -3
  35. data/cockpit/themes/control/rngs/start.rng +110 -72
  36. data/cockpit/themes/control/symbols/call_sensor.svg +9 -0
  37. data/cockpit/themes/control/symbols/callmanipulate.svg +3 -3
  38. data/cockpit/themes/control/symbols/callmanipulate_sensor.svg +11 -0
  39. data/cockpit/themes/control/symbols/delete.svg +4 -0
  40. data/cockpit/themes/control/symbols/start_event.svg +5 -0
  41. data/cockpit/themes/control/symbols/test.svg +74 -0
  42. data/cockpit/themes/control/theme.js +53 -7
  43. data/cockpit/themes/default/rngs/call.rng +127 -86
  44. data/cockpit/themes/default/rngs/callmanipulate.rng +32 -7
  45. data/cockpit/themes/default/rngs/closed_loop_control.rng +2 -2
  46. data/cockpit/themes/default/rngs/closed_loop_measuring.rng +3 -3
  47. data/cockpit/themes/default/rngs/start.rng +110 -72
  48. data/cockpit/themes/default/symbols/call_sensor.svg +9 -0
  49. data/cockpit/themes/default/symbols/callmanipulate.svg +3 -3
  50. data/cockpit/themes/default/symbols/callmanipulate_sensor.svg +11 -0
  51. data/cockpit/themes/default/symbols/delete.svg +4 -0
  52. data/cockpit/themes/default/symbols/start_event.svg +5 -0
  53. data/cockpit/themes/default/symbols/test.svg +74 -0
  54. data/cockpit/themes/default/theme.js +105 -9
  55. data/cockpit/themes/extended/rngs/call.rng +127 -86
  56. data/cockpit/themes/extended/rngs/callmanipulate.rng +32 -7
  57. data/cockpit/themes/extended/rngs/closed_loop_control.rng +2 -2
  58. data/cockpit/themes/extended/rngs/closed_loop_measuring.rng +3 -3
  59. data/cockpit/themes/extended/rngs/start.rng +110 -72
  60. data/cockpit/themes/extended/symbols/call_sensor.svg +9 -0
  61. data/cockpit/themes/extended/symbols/callmanipulate.svg +3 -3
  62. data/cockpit/themes/extended/symbols/callmanipulate_sensor.svg +11 -0
  63. data/cockpit/themes/extended/symbols/delete.svg +4 -0
  64. data/cockpit/themes/extended/symbols/start_event.svg +5 -0
  65. data/cockpit/themes/extended/symbols/test.svg +74 -0
  66. data/cockpit/themes/extended/theme.js +105 -9
  67. data/cockpit/themes/model/symbols/call_sensor.svg +9 -0
  68. data/cockpit/themes/model/symbols/callmanipulate.svg +3 -3
  69. data/cockpit/themes/model/symbols/callmanipulate_sensor.svg +11 -0
  70. data/cockpit/themes/model/symbols/delete.svg +4 -0
  71. data/cockpit/themes/model/symbols/start_event.svg +5 -0
  72. data/cockpit/themes/model/symbols/test.svg +74 -0
  73. data/cockpit/themes/model/theme.js +50 -4
  74. data/cockpit/themes/packed/rngs/call.rng +127 -86
  75. data/cockpit/themes/packed/rngs/callmanipulate.rng +32 -7
  76. data/cockpit/themes/packed/rngs/closed_loop_control.rng +2 -2
  77. data/cockpit/themes/packed/rngs/closed_loop_measuring.rng +3 -3
  78. data/cockpit/themes/packed/rngs/start.rng +110 -72
  79. data/cockpit/themes/packed/symbols/call_sensor.svg +9 -0
  80. data/cockpit/themes/packed/symbols/callmanipulate.svg +3 -3
  81. data/cockpit/themes/packed/symbols/callmanipulate_sensor.svg +11 -0
  82. data/cockpit/themes/packed/symbols/delete.svg +4 -0
  83. data/cockpit/themes/packed/symbols/start_event.svg +5 -0
  84. data/cockpit/themes/packed/symbols/test.svg +74 -0
  85. data/cockpit/themes/packed/theme.js +105 -9
  86. data/cockpit/themes/preset/rngs/call.rng +127 -86
  87. data/cockpit/themes/preset/rngs/callmanipulate.rng +32 -7
  88. data/cockpit/themes/preset/rngs/closed_loop_control.rng +2 -2
  89. data/cockpit/themes/preset/rngs/closed_loop_measuring.rng +3 -3
  90. data/cockpit/themes/preset/rngs/start.rng +110 -72
  91. data/cockpit/themes/preset/symbols/call_sensor.svg +9 -0
  92. data/cockpit/themes/preset/symbols/callmanipulate.svg +3 -3
  93. data/cockpit/themes/preset/symbols/callmanipulate_sensor.svg +11 -0
  94. data/cockpit/themes/preset/symbols/delete.svg +4 -0
  95. data/cockpit/themes/preset/symbols/start_event.svg +5 -0
  96. data/cockpit/themes/preset/symbols/test.svg +74 -0
  97. data/cockpit/themes/preset/theme.js +105 -9
  98. data/cpee.gemspec +6 -5
  99. data/lib/cpee/fail.rb +23 -0
  100. data/lib/cpee/implementation.rb +144 -49
  101. data/lib/cpee/implementation_callbacks.rb +11 -10
  102. data/lib/cpee/implementation_notifications.rb +4 -3
  103. data/lib/cpee/implementation_properties.rb +2 -2
  104. data/lib/cpee/message.rb +49 -15
  105. data/lib/cpee/persistence.rb +34 -12
  106. data/lib/cpee.xml +1 -1
  107. data/server/executionhandlers/ruby/backend/instance.template +1 -1
  108. data/server/executionhandlers/ruby/backend/run +4 -4
  109. data/server/executionhandlers/ruby/connection.rb +93 -34
  110. data/server/executionhandlers/ruby/controller.rb +29 -19
  111. data/server/executionhandlers/ruby/desc.xml +107 -0
  112. data/server/executionhandlers/ruby/dsl_to_dslx.xsl +67 -24
  113. data/server/executionhandlers/ruby/execution.rb +1 -0
  114. data/server/resources/states.xml +3 -0
  115. data/server/resources/test.pdf +0 -0
  116. data/server/resources/topics.xml +4 -2
  117. data/server/routing/end.pid +1 -0
  118. data/server/routing/end.rb +3 -2
  119. data/server/routing/forward-events-00.pid +1 -0
  120. data/server/routing/forward-events.rb +26 -13
  121. data/server/routing/forward-votes.pid +1 -0
  122. data/server/routing/forward-votes.rb +4 -4
  123. data/server/routing/persist.pid +1 -0
  124. data/server/routing/persist.rb +41 -31
  125. data/server/server.pid +1 -0
  126. data/tools/cpee +99 -24
  127. metadata +80 -32
  128. data/cockpit/templates/Coopis 2010.xml.active +0 -1
  129. data/cockpit/templates/Coopis 2010.xml.active-uuid +0 -1
  130. data/cockpit/templates/Subprocess.xml.active +0 -1
  131. data/cockpit/templates/Subprocess.xml.active-uuid +0 -1
  132. data/cockpit/templates/Track Test.xml.active +0 -1
  133. data/cockpit/templates/Track Test.xml.active-uuid +0 -1
  134. data/cockpit/templates/UR-VUE 2020 Solution Baseline.xml.active +0 -1
  135. data/cockpit/templates/UR-VUE 2020 Solution Baseline.xml.active-uuid +0 -1
  136. data/cockpit/templates/Wait.xml.active +0 -1
  137. data/cockpit/templates/Wait.xml.active-uuid +0 -1
  138. data/cockpit/templates/Wait.xml.attrs +0 -13
  139. data/server/executionhandlers/ruby/test.xml +0 -43
@@ -0,0 +1,74 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <svg
3
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
4
+ xmlns:cc="http://creativecommons.org/ns#"
5
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
6
+ xmlns:svg="http://www.w3.org/2000/svg"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
9
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
10
+ class="clickable"
11
+ version="1.1"
12
+ id="svg10"
13
+ sodipodi:docname="test.svg"
14
+ inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
15
+ <metadata
16
+ id="metadata16">
17
+ <rdf:RDF>
18
+ <cc:Work
19
+ rdf:about="">
20
+ <dc:format>image/svg+xml</dc:format>
21
+ <dc:type
22
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
23
+ </cc:Work>
24
+ </rdf:RDF>
25
+ </metadata>
26
+ <defs
27
+ id="defs14" />
28
+ <sodipodi:namedview
29
+ pagecolor="#ffffff"
30
+ bordercolor="#666666"
31
+ borderopacity="1"
32
+ objecttolerance="10"
33
+ gridtolerance="10"
34
+ guidetolerance="10"
35
+ inkscape:pageopacity="0"
36
+ inkscape:pageshadow="2"
37
+ inkscape:window-width="2062"
38
+ inkscape:window-height="1298"
39
+ id="namedview12"
40
+ showgrid="false"
41
+ inkscape:zoom="35.146667"
42
+ inkscape:cx="13.036699"
43
+ inkscape:cy="13.350011"
44
+ inkscape:window-x="0"
45
+ inkscape:window-y="27"
46
+ inkscape:window-maximized="0"
47
+ inkscape:current-layer="svg10" />
48
+ <rect
49
+ transform="rotate(45,14,12)"
50
+ x="7"
51
+ y="3"
52
+ width="21"
53
+ height="21"
54
+ class="cline hfill stand"
55
+ id="rect2"
56
+ style="fill:#3465a4" />
57
+ <circle
58
+ cx="15.5"
59
+ cy="15.5"
60
+ r="7"
61
+ class="stand"
62
+ id="circle4" />
63
+ <circle
64
+ cx="15.5"
65
+ cy="15.5"
66
+ r="7"
67
+ class="stand"
68
+ id="circle6" />
69
+ <path
70
+ d="m 15.500001,11.435193 3.825246,2.779205 -1.461114,4.496849 h -4.728265 l -1.461115,-4.496849 z"
71
+ class="stand"
72
+ id="path8"
73
+ style="fill:#ef2929;stroke-width:1" />
74
+ </svg>
@@ -93,7 +93,7 @@ function WFAdaptorManifestation(adaptor) {
93
93
 
94
94
  nodes = JSON.parse(nodes);
95
95
  $(nodes).each(function(key,str) {
96
- nodes[key] = $X(str);;
96
+ nodes[key] = $X(str);
97
97
  });
98
98
 
99
99
  var check1 = [];
@@ -176,14 +176,44 @@ function WFAdaptorManifestation(adaptor) {
176
176
 
177
177
  if(xml_node.get(0).tagName != 'description' && !self.elements[xml_node.get(0).tagName].neverdelete) {
178
178
  var icon = self.elements[xml_node.get(0).tagName].illustrator.svg.clone();
179
- icon.children('.rfill').addClass('menu');
179
+ icon.find('.rfill').addClass('menu');
180
+ icon.find('.hfill').addClass('menu');
180
181
  menu['Delete'] = [{
181
182
  'label': 'Remove Element',
182
- 'function_call': function(selector,target,selected){ self.adaptor.description.remove(selector,target); self.adaptor.illustrator.get_label_by_svg_id(selected).addClass('selected'); },
183
+ 'function_call': function(selector,target,selected){
184
+ del_ui_pos(target)
185
+ self.adaptor.description.remove(selector,target);
186
+ localStorage.removeItem('marked');
187
+ localStorage.removeItem('marked_from');
188
+ },
183
189
  'menu_icon': icon,
184
190
  'type': undefined,
185
191
  'params': [null, xml_node, self.selected()]
186
192
  }];
193
+ var nodes = localStorage.getItem('marked');
194
+ nodes = JSON.parse(nodes);
195
+ if (nodes && nodes.length > 0) {
196
+ var icond = self.resources['delete'].clone();
197
+ icond.children('.standfat').addClass('menu');
198
+ menu['Delete'].push({
199
+ 'label': 'Remove Marked Elements',
200
+ 'function_call': function(){
201
+ $(nodes).each(function(key,str) {
202
+ nodes[key] = $X(str);
203
+ });
204
+ $(nodes).each(function(key,node){
205
+ var target = self.adaptor.description.get_node_by_svg_id($(node).attr('svg-id'));
206
+ del_ui_pos(target)
207
+ self.adaptor.description.remove(null,target);
208
+ localStorage.removeItem('marked');
209
+ localStorage.removeItem('marked_from');
210
+ });
211
+ },
212
+ 'menu_icon': icond,
213
+ 'type': undefined,
214
+ 'params': []
215
+ })
216
+ }
187
217
  }
188
218
  if($('> code', xml_node).length > 0 && xml_node.get(0).tagName == 'call') {
189
219
  var icon = self.elements.callmanipulate.illustrator.svg.clone();
@@ -198,7 +228,7 @@ function WFAdaptorManifestation(adaptor) {
198
228
  }
199
229
  if (xml_node.get(0).tagName == "call" || xml_node.get(0).tagName == "manipulate" || xml_node.get(0).tagName == "stop") {
200
230
  var icon = self.elements.call.illustrator.svg.clone();
201
- icon.children('g.replace').addClass('active');
231
+ icon.children('g.replace').addClass('passive');
202
232
  var vtarget = self.adaptor.illustrator.get_node_by_svg_id(svgid);
203
233
  if (vtarget.length > 0) {
204
234
  if (vtarget.parents('g.activities.passive, g.activities.active').length > 0) {
@@ -223,6 +253,18 @@ function WFAdaptorManifestation(adaptor) {
223
253
  new CustomMenu(e).contextmenu(menu);
224
254
  } //}}}
225
255
 
256
+ function positionHandling(svgid) {
257
+ var xml_node = self.adaptor.description.get_node_by_svg_id(svgid);
258
+ var vtarget = self.adaptor.illustrator.get_node_by_svg_id(svgid);
259
+ if (vtarget.length > 0) {
260
+ if (vtarget.parents('g.activities.passive, g.activities.active').length > 0) {
261
+ del_ui_pos(xml_node);
262
+ } else {
263
+ add_ui_pos(xml_node);
264
+ }
265
+ }
266
+ }
267
+
226
268
  // Events
227
269
  this.events.touchend = function(svgid, e) { // {{{
228
270
  clearTimeout(self.presstimer);
@@ -234,6 +276,7 @@ function WFAdaptorManifestation(adaptor) {
234
276
  this.events.mousedown = function(svgid, e, child, sibling) { // {{{
235
277
  if(e.button == 0) { // left-click
236
278
  } else if(e.button == 1) { // middle-click
279
+ positionHandling(svgid);
237
280
  } else if(e.button == 2) { // right-click
238
281
  contextMenuHandling(svgid,e,child,sibling);
239
282
  }
@@ -266,6 +309,8 @@ function WFAdaptorManifestation(adaptor) {
266
309
  localStorage.removeItem('marked_from');
267
310
  }
268
311
  }
312
+ } else if (e && (e.shiftKey)) {
313
+ positionHandling(svgid);
269
314
  } else {
270
315
  self.adaptor.illustrator.get_elements().removeClass('marked');
271
316
  localStorage.removeItem('marked');
@@ -299,6 +344,7 @@ function WFAdaptorManifestation(adaptor) {
299
344
 
300
345
  // other resources
301
346
  this.resources.arrow = self.adaptor.theme_dir + 'symbols/arrow.svg';
347
+ this.resources.delete = self.adaptor.theme_dir + 'symbols/delete.svg';
302
348
 
303
349
  // Primitive Elements
304
350
  this.elements.call = { /*{{{*/
@@ -311,10 +357,18 @@ function WFAdaptorManifestation(adaptor) {
311
357
  },
312
358
  'info': function(node){ return { 'element-endpoint': $(node).attr('endpoint') }; },
313
359
  'resolve_symbol': function(node) {
314
- if($('code', node).length > 0) {
315
- return 'callmanipulate';
360
+ if ($('> annotations > _context_data_analysis > probes > probe', node).length > 0) {
361
+ if ($('> code', node).length > 0) {
362
+ return 'callmanipulate_sensor';
363
+ } else {
364
+ return 'call_sensor';
365
+ }
316
366
  } else {
317
- return 'call';
367
+ if ($('> code', node).length > 0) {
368
+ return 'callmanipulate';
369
+ } else {
370
+ return 'call';
371
+ }
318
372
  }
319
373
  },
320
374
  'svg': self.adaptor.theme_dir + 'symbols/call.svg'
@@ -1169,6 +1223,30 @@ function WFAdaptorManifestation(adaptor) {
1169
1223
  'expansion': function(node) {
1170
1224
  return 'vertical';
1171
1225
  },
1226
+ 'resolve_symbol': function(node) {
1227
+ let plist = []
1228
+ let dirty = false
1229
+ $('*:not(:has(*))',node).each(function(i,n) {
1230
+ let lines = n.textContent.split(/(\r\n)|\n|;/)
1231
+ for (const l of lines) {
1232
+ if (l != null) {
1233
+ let m0 = l.match(/^[^=]*data\.([a-z0-9A-Z_]+)[^=]*=/)
1234
+ if (m0 != null) {
1235
+ plist.push(m0[1])
1236
+ }
1237
+ let m1 = l.match(/=[^=].*data\.([a-z0-9A-Z_]+)/)
1238
+ let m2 = l.match(/^[^=]*data\.([a-z0-9A-Z_]+)[^=]*$/)
1239
+ if (m1 != null && !plist.includes(m1[1])) {
1240
+ dirty = true
1241
+ }
1242
+ if (m2 != null && !plist.includes(m2[1])) {
1243
+ dirty = true
1244
+ }
1245
+ }
1246
+ }
1247
+ })
1248
+ if (dirty) { return 'start_event'; }
1249
+ },
1172
1250
  'closing_symbol': 'end',
1173
1251
  'col_shift': function(node) {
1174
1252
  return true;
@@ -1242,13 +1320,31 @@ function WFAdaptorManifestation(adaptor) {
1242
1320
  // Abstract Elements
1243
1321
  // * they may only have an illustrator (or other parts)
1244
1322
  // * they HAVE TO have a parent
1323
+ this.elements.start_event = { /*{{{*/
1324
+ 'parent': 'start',
1325
+ 'illustrator': {//{{{
1326
+ 'svg': self.adaptor.theme_dir + 'symbols/start_event.svg'
1327
+ }//}}}
1328
+ }; /*}}}*/
1329
+ this.elements.call_sensor = { /*{{{*/
1330
+ 'parent': 'call',
1331
+ 'illustrator': {//{{{
1332
+ 'svg': self.adaptor.theme_dir + 'symbols/call_sensor.svg'
1333
+ }//}}}
1334
+ }; /*}}}*/
1245
1335
  this.elements.callmanipulate = { /*{{{*/
1246
1336
  'parent': 'call',
1247
1337
  'description': self.adaptor.theme_dir + 'rngs/callmanipulate.rng',
1248
1338
  'illustrator': {//{{{
1249
- 'info': function(node){ return { 'element-endpoint': $(node).attr('endpoint') }; },
1250
1339
  'svg': self.adaptor.theme_dir + 'symbols/callmanipulate.svg'
1251
- },//}}}
1340
+ }//}}}
1341
+ }; /*}}}*/
1342
+ this.elements.callmanipulate_sensor = { /*{{{*/
1343
+ 'parent': 'call',
1344
+ 'description': self.adaptor.theme_dir + 'rngs/callmanipulate.rng',
1345
+ 'illustrator': {//{{{
1346
+ 'svg': self.adaptor.theme_dir + 'symbols/callmanipulate_sensor.svg'
1347
+ }//}}}
1252
1348
  }; /*}}}*/
1253
1349
  this.elements.loop_head = { /*{{{*/
1254
1350
  'parent': 'loop',
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.29"
3
+ s.version = "2.1.50"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.license = "LGPL-3.0"
6
6
  s.summary = "Preliminary release of cloud process execution engine (cpee.org). If you just need workflow execution, without a rest service exposing it, then use WEEL."
@@ -21,12 +21,13 @@ Gem::Specification.new do |s|
21
21
  s.email = 'juergen.mangler@gmail.com'
22
22
  s.homepage = 'http://cpee.org/'
23
23
 
24
- s.add_runtime_dependency 'riddl', '~> 0.114'
25
- s.add_runtime_dependency 'weel', '~> 1.99', '>= 1.99.99'
24
+ s.add_runtime_dependency 'riddl', '~> 0.126'
25
+ s.add_runtime_dependency 'weel', '~> 1.99', '>= 1.99.111'
26
26
  s.add_runtime_dependency 'highline', '~> 2.0'
27
- s.add_runtime_dependency 'json', '~>2.1'
28
- s.add_runtime_dependency 'redis', '~> 4.1'
27
+ s.add_runtime_dependency 'redis', '~> 5.0'
29
28
  s.add_runtime_dependency 'rubyzip', '~>2'
30
29
  s.add_runtime_dependency 'charlock_holmes', '~>0'
31
30
  s.add_runtime_dependency 'mimemagic', '~>0'
31
+ s.add_runtime_dependency 'get_process_mem', '~>0.2'
32
+ s.add_runtime_dependency 'webrick', '~>1.7'
32
33
  end
data/lib/cpee/fail.rb ADDED
@@ -0,0 +1,23 @@
1
+
2
+ # This file is part of CPEE.
3
+ #
4
+ # CPEE is free software: you can redistribute it and/or modify it under the terms
5
+ # of the GNU General Public License as published by the Free Software Foundation,
6
+ # either version 3 of the License, or (at your option) any later version.
7
+ #
8
+ # CPEE is distributed in the hope that it will be useful, but WITHOUT ANY
9
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10
+ # PARTICULAR PURPOSE. See the GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License along with
13
+ # CPEE (file COPYING in the main directory). If not, see
14
+ # <http://www.gnu.org/licenses/>.
15
+
16
+ module CPEE
17
+ class FAIL < Riddl::Implementation #{{{
18
+ def response
19
+ @status = 404
20
+ nil
21
+ end
22
+ end #}}}
23
+ end
@@ -16,6 +16,7 @@ require 'fileutils'
16
16
  require 'redis'
17
17
  require 'riddl/server'
18
18
  require 'riddl/client'
19
+ require_relative 'fail'
19
20
  require_relative 'redis'
20
21
  require_relative 'message'
21
22
  require_relative 'persistence'
@@ -53,6 +54,8 @@ module CPEE
53
54
  /p:properties/p:attributes/p:*
54
55
  }
55
56
  def self::implementation(opts)
57
+ opts[:see_instances] ||= opts[:see_instances].nil? ? false : opts[:see_instances]
58
+
56
59
  opts[:instances] ||= File.expand_path(File.join(__dir__,'..','..','server','instances'))
57
60
  opts[:global_executionhandlers] ||= File.expand_path(File.join(__dir__,'..','..','server','executionhandlers'))
58
61
  opts[:executionhandlers] ||= ''
@@ -66,6 +69,12 @@ module CPEE
66
69
  opts[:watchdog_frequency] ||= 7
67
70
  opts[:watchdog_start_off] ||= false
68
71
  opts[:infinite_loop_stop] ||= 10000
72
+ opts[:workers] ||= 1
73
+ opts[:workers_single] ||= ['end','persist','forward-votes']
74
+ opts[:workers_multi] ||= ['forward-events']
75
+
76
+ opts[:dashing_frequency] ||= 3
77
+ opts[:dashing_target] ||= nil
69
78
 
70
79
  ### set redis_cmd to nil if you want to do global
71
80
  ### at least redis_path or redis_url and redis_db have to be set if you do global
@@ -83,7 +92,7 @@ module CPEE
83
92
  opts[:sse_connections] = {}
84
93
 
85
94
  opts[:statemachine] = CPEE::StateMachine.new opts[:states], %w{running simulating replaying finishing stopping abandoned finished} do |id|
86
- opts[:redis].get("instance:#{id}/state")
95
+ CPEE::Persistence::extract_item(id,opts,"state")
87
96
  end
88
97
 
89
98
  opts[:runtime_cmds] << [
@@ -101,11 +110,12 @@ module CPEE
101
110
  Dir[File.join(opts[:executionhandlers],'*','execution.rb')].each do |h|
102
111
  require h
103
112
  end unless opts[:executionhandlers].nil? || opts[:executionhandlers].strip == ''
113
+ CPEE::Message::set_workers(opts[:workers])
104
114
 
105
115
  parallel do
106
- CPEE::watch_services(opts[:watchdog_start_off],opts[:redis_url],File.join(opts[:basepath],opts[:redis_path]),opts[:redis_db])
116
+ CPEE::watch_services(opts[:watchdog_start_off],opts[:redis_url],File.join(opts[:basepath],opts[:redis_path]),opts[:redis_db],opts[:workers],opts[:workers_single],opts[:workers_multi])
107
117
  EM.add_periodic_timer(opts[:watchdog_frequency]) do ### start services
108
- CPEE::watch_services(opts[:watchdog_start_off],opts[:redis_url],File.join(opts[:basepath],opts[:redis_path]),opts[:redis_db])
118
+ CPEE::watch_services(opts[:watchdog_start_off],opts[:redis_url],File.join(opts[:basepath],opts[:redis_path]),opts[:redis_db],opts[:workers],opts[:workers_single],opts[:workers_multi])
109
119
  end
110
120
  EM.defer do ### catch all sse connections
111
121
  CPEE::Notifications::sse_distributor(opts)
@@ -113,6 +123,55 @@ module CPEE
113
123
  EM.add_periodic_timer(opts[:sse_keepalive_frequency]) do
114
124
  CPEE::Notifications::sse_heartbeat(opts)
115
125
  end
126
+
127
+ if opts[:dashing_target]
128
+ cpu_last = 0
129
+ idl_last = 0
130
+ EM.add_periodic_timer(opts[:dashing_frequency]) do
131
+ src = `cat /proc/stat | head -n 1`.split("\n")
132
+ srm = `cat /proc/meminfo`.split("\n")
133
+ sc = {}
134
+ sm = {}
135
+ src.each do |e|
136
+ x = e.split(' ')
137
+ sc[x[0]] = x[1..-1].map{|r| r.to_i}
138
+ end
139
+ srm.each do |e|
140
+ x = e.split(/\s+/)
141
+ sm[x[0].chop] = x[1].to_i
142
+ end
143
+ scc = 0
144
+ sci = 0
145
+ sc.each do |_,e|
146
+ scc = e[0..4].sum
147
+ sci = e[3]
148
+ end
149
+ cpu_delta = scc - cpu_last
150
+ cpu_idle = sci - idl_last
151
+ cpu_used = cpu_delta - cpu_idle
152
+ cpu_usage = '%.2f' % (100 * cpu_used / cpu_delta.to_f)
153
+ mem_tot = '%.1f' % (sm['MemTotal']/1024.0)
154
+ mem_fre = '%.1f' % (sm['MemFree']/1024.0)
155
+ mem_ava = '%.1f' % (sm['MemAvailable']/1024.0)
156
+ mem_buc = '%.1f' % ((sm['Buffers'] + sm['Cached'] + sm['SReclaimable'])/1024.0)
157
+ mem_usd = '%.1f' % ((sm['MemTotal'] - sm['MemFree'] - sm['Buffers'] - sm['Cached'] - sm['SReclaimable'])/1024.0)
158
+
159
+ # puts "CPU usage at #{cpu_usage}%"
160
+ # puts "Mem usage at #{mem_tot}/#{mem_fre}/#{mem_usd}/#{mem_buc}/#{mem_ava}"
161
+ content = {}
162
+ content['cpu_usage'] = cpu_usage
163
+ content['mem_total'] = mem_tot
164
+ content['mem_free'] = mem_fre
165
+ content['mem_available'] = mem_ava
166
+ content['mem_bufferedandcached'] = mem_buc
167
+ content['mem_used'] = mem_usd
168
+ CPEE::Message::send_url(:event,'node/resource_utilization',File.join(opts[:url],'/'),content,File.join(opts[:dashing_target],'/dash/events'))
169
+
170
+ # Keep this as last for our next read
171
+ idl_last = sci
172
+ cpu_last = scc
173
+ end
174
+ end
116
175
  end
117
176
 
118
177
  cleanup do
@@ -145,50 +204,75 @@ module CPEE
145
204
  end
146
205
  end
147
206
 
148
- def self::watch_services(watchdog_start_off,url,path,db)
207
+ def self::watch_services(watchdog_start_off,url,path,db,workers,workers_single,workers_multi)
149
208
  return if watchdog_start_off
150
- EM.defer do
151
- Dir[File.join(__dir__,'..','..','server','routing','*.rb')].each do |s|
152
- s = s.sub(/\.rb$/,'')
153
- pid = (File.read(s + '.pid').to_i rescue nil)
154
- if (pid.nil? || !(Process.kill(0, pid) rescue false)) && !File.exist?(s + '.lock')
155
- if url.nil?
156
- system "#{s}.rb -p \"#{path}\" -d #{db} restart 1>/dev/null 2>&1"
157
- else
158
- system "#{s}.rb -u \"#{url}\" -d #{db} restart 1>/dev/null 2>&1"
159
- end
160
- puts "➡ Service #{File.basename(s,'.rb')} started ..."
161
- end
162
- end
209
+ EM.defer do
210
+ workers_single.each do |s|
211
+ s = File.join(__dir__,'..','..','server','routing',s)
212
+ next if File.exist?(s + '.lock')
213
+ pid = (File.read(s + '.pid').to_i rescue nil)
214
+ if (pid.nil? || !(Process.kill(0, pid) rescue false))
215
+ cmd = if url.nil?
216
+ "-p \"#{path}\" -d #{db} -w #{workers} restart 1>/dev/null 2>&1"
217
+ else
218
+ "-u \"#{url}\" -d #{db} -w #{workers} restart 1>/dev/null 2>&1"
219
+ end
220
+ system "#{s}.rb " + cmd + " 1>/dev/null 2>&1"
221
+ puts "➡ Service #{File.basename(s)} (#{cmd}) started ..."
222
+ end
223
+ end
224
+ workers_multi.each do |s|
225
+ s = File.join(__dir__,'..','..','server','routing',s.to_s)
226
+ next if File.exist?(s + '.lock')
227
+ (0...workers).each do |w|
228
+ w = '%02i' % w
229
+ pid = (File.read(s + '-' + w + '.pid').to_i rescue nil)
230
+ if (pid.nil? || !(Process.kill(0, pid) rescue false))
231
+ cmd = if url.nil?
232
+ "-p \"#{path}\" -d #{db} -w #{w} restart"
233
+ else
234
+ "-u \"#{url}\" -d #{db} -w #{w} restart"
235
+ end
236
+ system "#{s}.rb " + cmd + " 1>/dev/null 2>&1"
237
+ puts "➡ Service #{File.basename(s)}-#{w} (#{cmd}) started ..."
238
+ end
239
+ end
240
+ end
163
241
  end
164
242
  end
165
243
  def self::cleanup_services(watchdog_start_off)
166
244
  return if watchdog_start_off
167
- Dir[File.join(__dir__,'..','..','server','routing','*.rb')].each do |s|
168
- s = s.sub(/\.rb$/,'')
169
- pid = (File.read(s + '.pid').to_i rescue nil)
245
+ Dir[File.join(__dir__,'..','..','server','routing','*.pid')].each do |s|
246
+ pid = (File.read(s).to_i rescue nil)
170
247
  if !pid.nil? || (Process.kill(0, pid) rescue false)
171
- system "#{s}.rb stop 1>/dev/null 2>&1"
172
- puts "➡ Service #{File.basename(s,'.rb')} stopped ..."
248
+ f = s.sub(/(-(\d+))?\.pid$/,'.rb')
249
+ if $2.nil?
250
+ system "#{f} stop 1>/dev/null 2>&1"
251
+ else
252
+ system "#{f} -w #{$2} stop 1>/dev/null 2>&1"
253
+ end
254
+ puts "➡ Service #{File.basename(s,'.pid')} stopped ..."
173
255
  end
174
256
  end
175
257
  end
176
258
 
177
259
  class Instances < Riddl::Implementation #{{{
178
260
  def response
179
- redis = @a[0][:redis]
180
- Riddl::Parameter::Complex.new("wis","text/xml") do
181
- ins = XML::Smart::string('<instances/>')
182
- redis.zrevrange('instances',0,-1).each do |instance|
183
- statekey = "instance:#{instance}/state"
184
- attributes = "instance:#{instance}/attributes/"
185
- info = redis.get(attributes + 'info')
186
- uuid = redis.get(attributes + 'uuid')
187
- state = redis.get(statekey)
188
- state_changed = redis.get(File.join(statekey,'@changed'))
189
- ins.root.add('instance', info, 'uuid' => uuid, 'id' => instance, 'state' => state, 'state_changed' => state_changed )
261
+ opts = @a[0]
262
+ if opts[:see_instances] || @h['SEE_INSTANCES'] == 'true'
263
+ Riddl::Parameter::Complex.new("wis","text/xml") do
264
+ ins = XML::Smart::string('<instances/>')
265
+ CPEE::Persistence::each_object(opts) do |instance|
266
+ info = CPEE::Persistence::extract_item(instance,opts,'attributes/info')
267
+ uuid = CPEE::Persistence::extract_item(instance,opts,'attributes/uuid')
268
+ state = CPEE::Persistence::extract_item(instance,opts,'state')
269
+ state_changed = CPEE::Persistence::extract_item(instance,opts,'state/@changed')
270
+ ins.root.add('instance', info, 'uuid' => uuid, 'id' => instance, 'state' => state, 'state_changed' => state_changed )
271
+ end
272
+ ins.to_s
190
273
  end
191
- ins.to_s
274
+ else
275
+ Riddl::Parameter::Complex.new("wis","text/xml",'<instances><!-- instances list disabled. --></instances>')
192
276
  end
193
277
  end
194
278
  end #}}}
@@ -209,9 +293,9 @@ module CPEE
209
293
  doc = XML::Smart::open_unprotected(opts[:properties_init])
210
294
  doc.register_namespace 'p', 'http://cpee.org/ns/properties/2.0'
211
295
  name = @p[0].value
212
- id = redis.zrevrange('instances', 0, 0).first.to_i + 1
296
+ id = CPEE::Persistence::new_object(opts)
213
297
  uuid = SecureRandom.uuid
214
- instance = 'instance:' + id.to_s
298
+ instance = CPEE::Persistence::obj + ':' + id.to_s
215
299
  redis.multi do |multi|
216
300
  multi.zadd('instances',id,id)
217
301
  doc.root.find(PROPERTIES_PATHS_FULL.join(' | ')).each do |e|
@@ -235,12 +319,12 @@ module CPEE
235
319
  doc.register_namespace 'np', 'http://riddl.org/ns/common-patterns/notifications-producer/2.0'
236
320
  key = File.basename(File.dirname(f))
237
321
  url = doc.find('string(/np:subscription/@url)')
238
- multi.sadd("instance:#{id}/handlers",key)
239
- multi.set("instance:#{id}/handlers/#{key}/url",url)
322
+ multi.sadd(CPEE::Persistence::obj + ":#{id}/handlers",key)
323
+ multi.set(CPEE::Persistence::obj + ":#{id}/handlers/#{key}/url",url)
240
324
  doc.find('/np:subscription/np:topic/*').each do |e|
241
325
  c = File.join(e.parent.attributes['id'],e.qname.name,e.text)
242
- multi.sadd("instance:#{id}/handlers/#{key}",c)
243
- multi.sadd("instance:#{id}/handlers/#{c}",key)
326
+ multi.sadd(CPEE::Persistence::obj + ":#{id}/handlers/#{key}",c)
327
+ multi.sadd(CPEE::Persistence::obj + ":#{id}/handlers/#{c}",key)
244
328
  end
245
329
  end rescue nil # all the ones that are not ok, are ignored
246
330
  end
@@ -251,6 +335,12 @@ module CPEE
251
335
  multi.set(File.join(instance, 'state', '@changed'), Time.now.xmlschema(3))
252
336
  end
253
337
 
338
+ content = {
339
+ :state => 'ready',
340
+ :attributes => CPEE::Persistence::extract_list(id,opts,'attributes').to_h
341
+ }
342
+ CPEE::Message::send(:event,'state/change',File.join(opts[:url],'/'),id,uuid,name,content,redis)
343
+
254
344
  @headers << Riddl::Header.new("CPEE-INSTANCE", id.to_s)
255
345
  @headers << Riddl::Header.new("CPEE-INSTANCE-URL", File.join(opts[:url].to_s,id.to_s,'/'))
256
346
  @headers << Riddl::Header.new("CPEE-INSTANCE-UUID", uuid)
@@ -289,19 +379,24 @@ module CPEE
289
379
  @status = 404
290
380
  return
291
381
  end
292
- empt = redis.keys("instance:#{id}/*").to_a
382
+
383
+ content = {
384
+ :state => 'purged',
385
+ :attributes => CPEE::Persistence::extract_list(id,opts,'attributes').to_h
386
+ }
387
+ state = CPEE::Persistence::extract_item(id,opts,'state')
388
+ if state == 'stopped' || state == 'ready'
389
+ CPEE::Message::send(:event,'state/change',File.join(opts[:url],'/'),id,content[:attributes]['uuid'],content[:attributes]['info'],content,redis)
390
+ end
391
+
392
+ empt = CPEE::Persistence::keys(id,opts).to_a
293
393
  redis.multi do |multi|
294
- multi.del empt
394
+ empt.each do |e|
395
+ multi.expire e, 30
396
+ end
295
397
  multi.zrem 'instances', id
296
398
  end
297
399
  end
298
400
  end #}}}
299
401
 
300
- class FAIL < Riddl::Implementation #{{{
301
- def response
302
- @status = 404
303
- nil
304
- end
305
- end #}}}
306
-
307
402
  end