durable_rules 0.34.57 → 2.00.001

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 498fdfaaecffebdf986536f05cdf517d8e1388f1
4
- data.tar.gz: 2eaf9c77fa2b171c8263d9eb408aaf434b211d10
3
+ metadata.gz: b1ff02cb5295388fa03591c60be41a6811cdf865
4
+ data.tar.gz: 9a1ae40e88a89a431cb56006ce17f055550f7db3
5
5
  SHA512:
6
- metadata.gz: 1677ae9c1459c7dd6310aa7c26502af432ddc2e69b5a8254541d7c633f7694a2f7df1459d53813ba4049a3e0a59f49a68da9515f4a5e85f5dd2d976b542175c2
7
- data.tar.gz: 32eef26b4e7d94155664a9d85d2e217cd446fb9abb52a7b43940783b90a16ba367575cef1be028f71f024ffcc353f05202450797b91a10e48e52a09c764d0763
6
+ metadata.gz: 2315a2ffc3fc93ba364e94972453dcb7dd51c0ad62b1c8df275929e4fe45dfd52e2d98bbd3f3e38877e86bbde0f5efffcfeead3bcdfe5c02df04a393010c4c62
7
+ data.tar.gz: 9b23715b2d7a5a1e4bd73fee299e73cf27c124065b6677eefd8868b1499fc9010a552c0b96266714f18e01e8b6dae92c90f97e1f750be6cbdebbdb58210895fb
data/librb/durable.rb CHANGED
@@ -1,49 +1,71 @@
1
1
  require_relative "engine"
2
- require_relative "interface"
3
2
 
4
3
  module Durable
5
4
  @@rulesets = {}
6
- @@start_blocks = []
5
+ @@main_host = nil
7
6
 
8
- def self.create_queue(ruleset_name, database = {:host => 'localhost', :port => 6379, :password => nil, :db => 0}, state_cache_size = 1024)
9
- Engine::Queue.new ruleset_name, database, state_cache_size
10
- end
7
+ def self.get_host()
8
+ if !@@main_host
9
+ @@main_host = Engine::Host.new
10
+ end
11
11
 
12
- def self.create_host(databases = [{:host => 'localhost', :port => 6379, :password => nil, :db => 0}], state_cache_size = 1024)
13
- main_host = Engine::Host.new @@rulesets, databases, state_cache_size
14
- for block in @@start_blocks
15
- main_host.instance_exec main_host, &block
12
+ for name, ruleset in @@rulesets
13
+ @@main_host.set_ruleset name, ruleset
16
14
  end
17
- main_host.start!
18
- main_host
15
+
16
+ @@rulesets = {}
17
+ @@main_host
19
18
  end
20
19
 
21
- def self.run_all(databases = [{:host => 'localhost', :port => 6379, :password => nil, :db => 0}], host_name = nil, port = nil, run = nil, state_cache_size = 1024)
22
- main_host = self.create_host databases, state_cache_size
23
- Interface::Application.set_host main_host
24
- if run
25
- run(main_host, Interface::Application)
26
- else
27
- Interface::Application.run!
28
- end
20
+ def self.post(ruleset_name, message, complete = nil)
21
+ self.get_host().post ruleset_name, message, complete
22
+ end
23
+
24
+ def self.post_batch(ruleset_name, messages, complete = nil)
25
+ self.get_host().post_batch ruleset_name, messages, complete
26
+ end
27
+
28
+ def self.assert(ruleset_name, fact, complete = nil)
29
+ self.get_host().assert ruleset_name, fact, complete
30
+ end
31
+
32
+ def self.assert_facts(ruleset_name, facts, complete = nil)
33
+ self.get_host().assert_facts ruleset_name, facts, complete
34
+ end
35
+
36
+ def self.retract(ruleset_name, fact, complete = nil)
37
+ self.get_host().retract ruleset_name, fact, complete
38
+ end
39
+
40
+ def self.retract_facts(ruleset_name, facts, complete = nil)
41
+ self.get_host().retract_facts ruleset_name, facts, complete
42
+ end
43
+
44
+ def self.update_state(ruleset_name, state, complete = nil)
45
+ self.get_host().update_state ruleset_name, state, complete
46
+ end
47
+
48
+ def self.get_state(ruleset_name, sid)
49
+ self.get_host().get_state ruleset_name, sid
50
+ end
51
+
52
+ def self.delete_state(ruleset_name, sid)
53
+ self.get_host().delete_state ruleset_name, sid
29
54
  end
30
55
 
31
56
  def self.ruleset(name, &block)
32
57
  ruleset = Ruleset.new name, block
33
58
  @@rulesets[name] = ruleset.rules
34
- @@start_blocks << ruleset.start if ruleset.start
35
59
  end
36
60
 
37
61
  def self.statechart(name, &block)
38
62
  statechart = Statechart.new name, block
39
63
  @@rulesets[name.to_s + "$state"] = statechart.states
40
- @@start_blocks << statechart.start if statechart.start
41
64
  end
42
65
 
43
66
  def self.flowchart(name, &block)
44
67
  flowchart = Flowchart.new name, block
45
68
  @@rulesets[name.to_s + "$flow"] = flowchart.stages
46
- @@start_blocks << flowchart.start if flowchart.start
47
69
  end
48
70
 
49
71
  class Arithmetic
@@ -454,14 +476,10 @@ module Durable
454
476
  end
455
477
 
456
478
  def timeout(name)
457
- expression = Expression.new(:$m, :$t)
458
- expression == name
479
+ all(c.base = Expression.new(:$m, "$timerName") == name,
480
+ c.timeout = Expression.new(:$m, "$time") >= Arithmetic.new(:base, "$baseTime"))
459
481
  end
460
482
 
461
- def sref(sid = nil)
462
- Arithmetic.new :$s, nil, sid
463
- end
464
-
465
483
  protected
466
484
 
467
485
  def get_options(*args)
data/librb/engine.rb CHANGED
@@ -4,57 +4,27 @@ require_relative "../src/rulesrb/rules"
4
4
 
5
5
  module Engine
6
6
 
7
- class Closure_Queue
8
- attr_reader :_queued_posts, :_queued_asserts, :_queued_retracts
9
-
10
- def initialize()
11
- @_queued_posts = []
12
- @_queued_asserts = []
13
- @_queued_retracts = []
14
- end
15
-
16
- def post(message)
17
- if message.kind_of? Content
18
- message = message._d
19
- end
20
-
21
- @_queued_posts << message
7
+ class MessageNotHandledError < StandardError
8
+ def initialize(message)
9
+ super("Could not handle message: #{JSON.generate(message)}")
22
10
  end
11
+ end
23
12
 
24
- def assert(message)
25
- if message.kind_of? Content
26
- message = message._d
27
- end
28
-
29
- @_queued_asserts << message
30
- end
31
-
32
- def retract(message)
33
- if message.kind_of? Content
34
- message = message._d
35
- end
36
-
37
- @_queued_retracts << message
13
+ class MessageObservedError < StandardError
14
+ def initialize(message)
15
+ super("Message has already been observed: #{JSON.generate(message)}")
38
16
  end
39
17
  end
40
18
 
41
19
  class Closure
42
- attr_reader :host, :handle, :ruleset_name, :_timers, :_cancelled_timers, :_branches, :_messages, :_queues, :_facts, :_retract, :_deletes, :_deleted
20
+ attr_reader :host, :handle, :_timers, :_cancelled_timers, :_messages, :_facts, :_retract, :_deleted
43
21
  attr_accessor :s
44
22
 
45
- def initialize(host, state, message, handle, ruleset_name)
23
+ def initialize(host, ruleset, state, message, handle)
46
24
  @s = Content.new(state)
47
- @ruleset_name = ruleset_name
48
25
  @handle = handle
49
26
  @host = host
50
- @_timers = {}
51
- @_cancelled_timers = {}
52
- @_messages = {}
53
- @_queues = {}
54
- @_deletes = {}
55
- @_branches = {}
56
- @_facts = {}
57
- @_retract = {}
27
+ @_ruleset = ruleset
58
28
  @_start_time = Time.now
59
29
  @_completed = false
60
30
  @_deleted = false
@@ -69,61 +39,86 @@ module Engine
69
39
  @m << Content.new(one_message)
70
40
  end
71
41
  end
42
+
43
+ if !s.sid
44
+ s.sid = "0"
45
+ end
72
46
  end
73
47
 
74
48
  def post(ruleset_name, message = nil)
75
- if !message
49
+ if message
50
+ if message.kind_of? Content
51
+ message = message._d
52
+ end
53
+
54
+ if !(message.key? :sid) && !(message.key? "sid")
55
+ message[:sid] = @s.sid
56
+ end
57
+
58
+ @host.assert_event ruleset_name, message
59
+ else
76
60
  message = ruleset_name
77
- ruleset_name = @ruleset_name
78
- end
61
+ if message.kind_of? Content
62
+ message = message._d
63
+ end
79
64
 
80
- if message.kind_of? Content
81
- message = message._d
65
+ if !(message.key? :sid) && !(message.key? "sid")
66
+ message[:sid] = @s.sid
67
+ end
68
+
69
+ @_ruleset.assert_event message
82
70
  end
71
+ end
83
72
 
84
- if !(message.key? :sid) && !(message.key? "sid")
85
- message[:sid] = @s.sid
86
- end
73
+ def assert(ruleset_name, fact = nil)
74
+ if fact
75
+ if fact.kind_of? Content
76
+ fact = fact._d
77
+ end
87
78
 
88
- message_list = []
89
- if @_messages.key? ruleset_name
90
- message_list = @_messages[ruleset_name]
79
+ if !(fact.key? :sid) && !(fact.key? "sid")
80
+ fact[:sid] = @s.sid
81
+ end
82
+
83
+ @host.assert_fact ruleset_name, fact
91
84
  else
92
- @_messages[ruleset_name] = message_list
93
- end
94
- message_list << message
95
- end
85
+ fact = ruleset_name
86
+ if fact.kind_of? Content
87
+ fact = fact._d
88
+ end
96
89
 
97
- def delete(ruleset_name = nil, sid = nil)
98
- if !ruleset_name
99
- ruleset_name = @ruleset_name
100
- end
90
+ if !(fact.key? :sid) && !(fact.key? "sid")
91
+ fact[:sid] = @s.sid
92
+ end
101
93
 
102
- if !sid
103
- sid = @s.sid
94
+ @_ruleset.assert_fact fact
104
95
  end
96
+ end
105
97
 
106
- if (ruleset_name == @ruleset_name) && (sid == @s.sid)
107
- @_deleted = true
108
- end
98
+ def retract(ruleset_name, fact = nil)
99
+ if fact
100
+ if fact.kind_of? Content
101
+ fact = fact._d
102
+ end
109
103
 
110
- sid_list = []
111
- if @_deletes.key? ruleset_name
112
- sid_list = @_deletes[ruleset_name]
104
+ if !(fact.key? :sid) && !(fact.key? "sid")
105
+ fact[:sid] = @s.sid
106
+ end
107
+
108
+ @host.retract_fact ruleset_name, fact
113
109
  else
114
- @_deletes[ruleset_name] = sid_list
115
- end
116
- sid_list << sid
117
- end
110
+ fact = ruleset_name
111
+ if fact.kind_of? Content
112
+ fact = fact._d
113
+ end
118
114
 
119
- def get_queue(ruleset_name)
120
- if !@_queues.key? ruleset_name
121
- @_queues[ruleset_name] = Closure_Queue.new
115
+ if !(fact.key? :sid) && !(fact.key? "sid")
116
+ fact[:sid] = @s.sid
117
+ end
118
+ @_ruleset.retract_fact fact
122
119
  end
123
-
124
- @_queues[ruleset_name]
125
120
  end
126
-
121
+
127
122
  def start_timer(timer_name, duration, manual_reset = false)
128
123
  if manual_reset
129
124
  manual_reset = 1
@@ -131,87 +126,24 @@ module Engine
131
126
  manual_reset = 0
132
127
  end
133
128
 
134
- if @_timers.key? timer_name
135
- raise ArgumentError, "Timer with name #{timer_name} already added"
136
- else
137
- timer = {:sid => @s.sid, :$t => timer_name}
138
- @_timers[timer_id] = [timer, duration, manual_reset]
139
- end
129
+ @_ruleset.start_timer @s.sid, timer_name, duration, manual_reset
140
130
  end
141
131
 
142
132
  def cancel_timer(timer_name)
143
- if @_cancelled_timers.key? timer_name
144
- raise ArgumentError, "Timer with id #{timer_name} already cancelled"
145
- else
146
- @_cancelled_timers[timer_name] = true
147
- end
148
- end
149
-
150
- def reset_timer(timer_name)
151
- if @m.kind_of? Hash
152
- retract_timer timer_name, @m
153
- else
154
- for m in @m do
155
- return true if retract_timer(timer_name, m)
156
- end
157
-
158
- return false
159
- end
160
- end
161
-
162
- def assert(ruleset_name, fact = nil)
163
- if !fact
164
- fact = ruleset_name
165
- ruleset_name = @ruleset_name
166
- end
167
-
168
- if fact.kind_of? Content
169
- fact = fact._d.dup
170
- end
171
-
172
- if !(fact.key? :sid) && !(fact.key? "sid")
173
- fact[:sid] = @s.sid
174
- end
175
-
176
- fact_list = []
177
- if @_facts.key? ruleset_name
178
- fact_list = @_facts[ruleset_name]
179
- else
180
- @_facts[ruleset_name] = fact_list
181
- end
182
- fact_list << fact
183
- end
184
-
185
- def retract(ruleset_name, fact = nil)
186
- if !fact
187
- fact = ruleset_name
188
- ruleset_name = @ruleset_name
189
- end
190
-
191
- if fact.kind_of? Content
192
- fact = fact._d.dup
193
- end
194
-
195
- if !(fact.key? :sid) && !(fact.key? "sid")
196
- fact[:sid] = @s.sid
197
- end
198
-
199
- fact_list = []
200
- if @_retract.key? ruleset_name
201
- fact_list = @_retract[ruleset_name]
202
- else
203
- @_retract[ruleset_name] = fact_list
204
- end
205
- fact_list << fact
133
+ @_ruleset.cancel_timer @s.sid, timer_name
206
134
  end
207
135
 
208
136
  def renew_action_lease()
209
137
  if Time.now - @_start_time < 10000
210
138
  @_start_time = Time.now
211
- @host.renew_action_lease @ruleset_name, @s.sid
139
+ @_ruleset.renew_action_lease @s.sid
212
140
  end
213
141
  end
214
142
 
143
+ def delete()
144
+ @_deleted = true
145
+ end
146
+
215
147
  def has_completed()
216
148
  if Time.now - @_start_time > 10000
217
149
  @_completed = true
@@ -223,22 +155,6 @@ module Engine
223
155
 
224
156
  private
225
157
 
226
- def retract_timer(timer_name, message)
227
- if ((message.key? :$t) && (message[:$t] == timer_name)) ||
228
- ((message.key? '$t') && (message['$t'] == timer_name))
229
- retract(message)
230
- return true
231
- end
232
-
233
- for property_name, property_value in message do
234
- if (property_value.kind_of? Hash) && retract_timer(timer_name, property_value)
235
- return true
236
- end
237
- end
238
-
239
- return false
240
- end
241
-
242
158
  def handle_property(name, value=nil)
243
159
  name = name.to_s
244
160
  if name.end_with? '?'
@@ -259,7 +175,6 @@ module Engine
259
175
 
260
176
  end
261
177
 
262
-
263
178
  class Content
264
179
  attr_reader :_d
265
180
 
@@ -331,7 +246,7 @@ module Engine
331
246
  begin
332
247
  @func.call c
333
248
  rescue Exception => e
334
- c.s.exception = e.to_s
249
+ c.s.exception = "#{e.to_s}, #{e.backtrace}"
335
250
  end
336
251
 
337
252
  if @next
@@ -409,7 +324,7 @@ module Engine
409
324
  class Ruleset
410
325
  attr_reader :definition
411
326
 
412
- def initialize(name, host, ruleset_definition, state_cache_size)
327
+ def initialize(name, host, ruleset_definition)
413
328
  @actions = {}
414
329
  @name = name
415
330
  @host = host
@@ -435,102 +350,45 @@ module Engine
435
350
  end
436
351
  end
437
352
 
438
- @handle = Rules.create_ruleset name, JSON.generate(ruleset_definition), state_cache_size
353
+ @handle = Rules.create_ruleset name, JSON.generate(ruleset_definition)
439
354
  @definition = ruleset_definition
440
355
  end
441
356
 
442
- def bind(databases)
443
- for db in databases do
444
- if db.kind_of? String
445
- Rules.bind_ruleset @handle, db, 0, nil, 0
446
- else
447
- if !db.key? :password
448
- db[:password] = nil
449
- end
450
-
451
- if !db.key? :db
452
- db[:db] = 0
453
- end
454
-
455
- Rules.bind_ruleset @handle, db[:host], db[:port], db[:password], db[:db]
456
- end
457
- end
458
- end
459
-
460
357
  def assert_event(message)
461
- Rules.assert_event @handle, JSON.generate(message)
462
- end
463
-
464
- def queue_assert_event(sid, ruleset_name, message)
465
- Rules.queue_assert_event @handle, sid.to_s, ruleset_name.to_s, JSON.generate(message)
466
- end
467
-
468
- def start_assert_event(message)
469
- Rules.start_assert_event @handle, JSON.generate(message)
358
+ handle_result Rules.assert_event(@handle, JSON.generate(message)), message
470
359
  end
471
360
 
472
361
  def assert_events(messages)
473
- Rules.assert_events @handle, JSON.generate(messages)
474
- end
475
-
476
- def start_assert_events(messages)
477
- Rules.start_assert_events @handle, JSON.generate(messages)
478
- end
479
-
480
- def start_timer(sid, timer, timer_duration, manual_reset)
481
- Rules.start_timer @handle, sid.to_s, timer_duration, manual_reset, JSON.generate(timer)
482
- end
483
-
484
- def cancel_timer(sid, timer_name)
485
- Rules.cancel_timer @handle, sid.to_s, timer_name.to_s
362
+ handle_result Rules.assert_events(@handle, JSON.generate(messages)), messages
486
363
  end
487
364
 
488
365
  def assert_fact(fact)
489
- Rules.assert_fact @handle, JSON.generate(fact)
490
- end
491
-
492
- def queue_assert_fact(sid, ruleset_name, message)
493
- Rules.queue_assert_fact @handle, sid.to_s, ruleset_name.to_s, JSON.generate(message)
494
- end
495
-
496
- def start_assert_fact(fact)
497
- Rules.start_assert_fact @handle, JSON.generate(fact)
366
+ handle_result Rules.assert_fact(@handle, JSON.generate(fact)), fact
498
367
  end
499
368
 
500
369
  def assert_facts(facts)
501
- Rules.assert_facts @handle, JSON.generate(facts)
502
- end
503
-
504
- def start_assert_facts(facts)
505
- Rules.start_assert_facts @handle, JSON.generate(facts)
370
+ handle_result Rules.assert_facts(@handle, JSON.generate(facts)), facts
506
371
  end
507
372
 
508
373
  def retract_fact(fact)
509
- Rules.retract_fact @handle, JSON.generate(fact)
374
+ handle_result Rules.retract_fact(@handle, JSON.generate(fact)), fact
510
375
  end
511
376
 
512
- def queue_retract_fact(sid, ruleset_name, message)
513
- Rules.queue_retract_fact @handle, sid.to_s, ruleset_name.to_s, JSON.generate(message)
514
- end
515
-
516
- def start_retract_fact(fact)
517
- Rules.start_retract_fact @handle, JSON.generate(fact)
377
+ def retract_facts(facts)
378
+ handle_result Rules.retract_facts(@handle, JSON.generate(facts)), facts
518
379
  end
519
380
 
520
- def retract_facts(facts)
521
- Rules.assert_facts @handle, JSON.generate(facts)
381
+ def start_timer(sid, timer, timer_duration, manual_reset)
382
+ Rules.start_timer @handle, sid.to_s, timer_duration, manual_reset, timer
522
383
  end
523
384
 
524
- def start_retract_facts(facts)
525
- Rules.start_retract_facts @handle, JSON.generate(facts)
385
+ def cancel_timer(sid, timer_name)
386
+ Rules.cancel_timer @handle, sid.to_s, timer_name.to_s
526
387
  end
527
388
 
528
- def assert_state(state)
529
- if state.key? :sid
530
- Rules.assert_state @handle, state[:sid].to_s, JSON.generate(state)
531
- else
532
- Rules.assert_state @handle, state["sid"].to_s, JSON.generate(state)
533
- end
389
+ def update_state(state)
390
+ state["$s"] = 1
391
+ Rules.update_state @handle, JSON.generate(state)
534
392
  end
535
393
 
536
394
  def get_state(sid)
@@ -545,70 +403,68 @@ module Engine
545
403
  Rules.renew_action_lease @handle, sid.to_s
546
404
  end
547
405
 
548
- def Ruleset.create_rulesets(parent_name, host, ruleset_definitions, state_cache_size)
406
+ def Ruleset.create_rulesets(parent_name, host, ruleset_definitions)
549
407
  branches = {}
550
408
  for name, definition in ruleset_definitions do
551
409
  name = name.to_s
552
410
  if name.end_with? "$state"
553
411
  name = name[0..-7]
554
412
  name = "#{parent_name}.#{name}" if parent_name
555
- branches[name] = Statechart.new name, host, definition, state_cache_size
413
+ branches[name] = Statechart.new name, host, definition
556
414
  elsif name.end_with? "$flow"
557
415
  name = name[0..-6]
558
416
  name = "#{parent_name}.#{name}" if parent_name
559
- branches[name] = Flowchart.new name, host, definition, state_cache_size
417
+ branches[name] = Flowchart.new name, host, definition
560
418
  else
561
419
  name = "#{parent_name}.#{name}" if parent_name
562
- branches[name] = Ruleset.new name, host, definition, state_cache_size
420
+ branches[name] = Ruleset.new name, host, definition
563
421
  end
564
422
  end
565
423
 
566
424
  branches
567
425
  end
568
426
 
569
- def dispatch_timers(complete)
427
+ def dispatch_timers()
428
+ Rules.assert_timers @handle
429
+ end
430
+
431
+ def to_json
432
+ JSON.generate @definition
433
+ end
434
+
435
+ def do_actions(state_handle, complete)
570
436
  begin
571
- if !(Rules.assert_timers @handle)
572
- complete.call nil, false
437
+ result = Rules.start_action_for_state(@handle, state_handle)
438
+ if !result
439
+ complete.call(nil, nil)
573
440
  else
574
- complete.call nil, true
441
+ flush_actions JSON.parse(result[0]), {:message => JSON.parse(result[1])}, state_handle, complete
575
442
  end
576
443
  rescue Exception => e
577
- complete.call e, true
578
- return
444
+ complete.call(e, nil)
579
445
  end
580
446
  end
581
447
 
582
- def dispatch(complete, async_result = nil)
583
- state = nil
584
- action_handle = nil
585
- action_binding = nil
586
- result_container = {}
587
- if async_result
588
- state = async_result[0]
589
- result_container = {:message => JSON.parse(async_result[1])}
590
- action_handle = async_result[2]
591
- action_binding = async_result[3]
592
- else
593
- begin
594
- result = Rules.start_action @handle
595
- if !result
596
- complete.call nil, true
597
- return
598
- else
599
- state = JSON.parse result[0]
600
- result_container = {:message => JSON.parse(result[1])}
601
- action_handle = result[2]
602
- action_binding = result[3]
603
- end
604
- rescue Exception => e
605
- puts "start action exception #{e}"
606
- puts e.backtrace
607
- complete.call e, true
608
- return
609
- end
448
+ def dispatch_ruleset()
449
+ result = Rules.start_action(@handle)
450
+ if result
451
+ flush_actions JSON.parse(result[0]), {:message => JSON.parse(result[1])}, result[2], -> e, s { }
610
452
  end
453
+ end
611
454
 
455
+ private
456
+
457
+ def handle_result(result, message)
458
+ if result[0] == 1
459
+ raise MessageNotHandledError, message
460
+ elsif result[0] == 2
461
+ raise MessageObservedError, message
462
+ end
463
+
464
+ result[1]
465
+ end
466
+
467
+ def flush_actions(state, result_container, state_offset, complete)
612
468
  while result_container.key? :message do
613
469
  action_name = nil
614
470
  for action_name, message in result_container[:message] do
@@ -616,11 +472,7 @@ module Engine
616
472
  end
617
473
 
618
474
  result_container.delete :message
619
- c = Closure.new @host, state, message, action_handle, @name
620
-
621
- if result_container.key? :async
622
- result_container.delete :async
623
- end
475
+ c = Closure.new @host, self, state, message, state_offset
624
476
 
625
477
  @actions[action_name].run c, -> e {
626
478
  if c.has_completed
@@ -629,136 +481,46 @@ module Engine
629
481
 
630
482
  if e
631
483
  Rules.abandon_action @handle, c.handle
632
- complete.call e, true
484
+ complete.call e, nil
633
485
  else
634
486
  begin
635
- for timer_name, timer_value in c._cancelled_timers do
636
- cancel_timer c.s.sid, timer_name
637
- end
638
-
639
- for timer_id, timer_tuple in c._timers do
640
- start_timer c.s.sid, timer_tuple[0], timer_tuple[1], timer_tuple[2]
641
- end
642
-
643
- for ruleset_name, q in c._queues do
644
- for message in q._queued_posts do
645
- sid = (message.key? :sid) ? message[:sid]: message['sid']
646
- queue_assert_event sid.to_s, ruleset_name, message
647
- end
648
-
649
- for message in q._queued_asserts do
650
- sid = (message.key? :sid) ? message[:sid]: message['sid']
651
- queue_assert_fact sid.to_s, ruleset_name, message
652
- end
653
-
654
- for message in q._queued_retracts do
655
- sid = (message.key? :sid) ? message[:sid]: message['sid']
656
- queue_retract_fact sid.to_s, ruleset_name, message
657
- end
658
- end
659
-
660
- for ruleset_name, sid in c._deletes do
661
- @host.delete_state ruleset_name, sid
662
- end
663
-
664
- binding = 0
665
- replies = 0
666
- pending = {action_binding => 0}
667
- for ruleset_name, facts in c._retract do
668
- if facts.length == 1
669
- binding, replies = @host.start_retract ruleset_name, facts[0]
670
- else
671
- binding, replies = @host.start_retract_facts ruleset_name, facts
672
- end
673
- if pending.key? binding
674
- pending[binding] = pending[binding] + replies
675
- else
676
- pending[binding] = replies
677
- end
678
- end
679
- for ruleset_name, facts in c._facts do
680
- if facts.length == 1
681
- binding, replies = @host.start_assert ruleset_name, facts[0]
682
- else
683
- binding, replies = @host.start_assert_facts ruleset_name, facts
684
- end
685
- if pending.key? binding
686
- pending[binding] = pending[binding] + replies
687
- else
688
- pending[binding] = replies
689
- end
690
- end
691
- for ruleset_name, messages in c._messages do
692
- if messages.length == 1
693
- binding, replies = @host.start_post ruleset_name, messages[0]
694
- else
695
- binding, replies = @host.start_post_batch ruleset_name, messages
696
- end
697
- if pending.key? binding
698
- pending[binding] = pending[binding] + replies
699
- else
700
- pending[binding] = replies
701
- end
702
- end
703
- binding, replies = Rules.start_update_state @handle, c.handle, JSON.generate(c.s._d)
704
- if pending.key? binding
705
- pending[binding] = pending[binding] + replies
487
+ Rules.update_state @handle, JSON.generate(c.s._d)
488
+
489
+ new_result = Rules.complete_and_start_action @handle, c.handle
490
+ if new_result
491
+ result_container[:message] = JSON.parse new_result
706
492
  else
707
- pending[binding] = replies
708
- end
709
-
710
- for binding, replies in pending do
711
- if binding != 0
712
- if binding != action_binding
713
- Rules.complete(binding, replies)
714
- else
715
- new_result = Rules.complete_and_start_action @handle, replies, c.handle
716
- if new_result
717
- if result_container.key? :async
718
- dispatch -> e, wait {}, [state, new_result, action_handle, action_binding]
719
- else
720
- result_container[:message] = JSON.parse new_result
721
- end
722
- end
723
- end
724
- end
493
+ complete.call nil, state
725
494
  end
726
495
  rescue Exception => e
727
- Rules.abandon_action @handle, c.handle
728
496
  puts "unknown exception #{e}"
729
497
  puts e.backtrace
730
- complete.call e, true
498
+ Rules.abandon_action @handle, c.handle
499
+ complete.call e, nil
731
500
  end
732
501
 
733
502
  if c._deleted
734
503
  begin
735
504
  delete_state c.s.sid
736
505
  rescue Exception => e
737
- complete.call e, true
738
506
  end
739
507
  end
740
-
741
508
  end
742
509
  }
743
510
  result_container[:async] = true
744
511
  end
745
- complete.call nil, false
746
- end
747
-
748
- def to_json
749
- JSON.generate @definition
750
512
  end
751
513
 
752
514
  end
753
515
 
754
516
  class Statechart < Ruleset
755
517
 
756
- def initialize(name, host, chart_definition, state_cache_size)
518
+ def initialize(name, host, chart_definition)
757
519
  @name = name
758
520
  @host = host
759
521
  ruleset_definition = {}
760
522
  transform nil, nil, nil, chart_definition, ruleset_definition
761
- super name, host, ruleset_definition, state_cache_size
523
+ super name, host, ruleset_definition
762
524
  @definition = chart_definition
763
525
  @definition[:$type] = "stateChart"
764
526
  end
@@ -933,12 +695,12 @@ module Engine
933
695
 
934
696
  class Flowchart < Ruleset
935
697
 
936
- def initialize(name, host, chart_definition, state_cache_size)
698
+ def initialize(name, host, chart_definition)
937
699
  @name = name
938
700
  @host = host
939
701
  ruleset_definition = {}
940
702
  transform chart_definition, ruleset_definition
941
- super name, host, ruleset_definition, state_cache_size
703
+ super name, host, ruleset_definition
942
704
  @definition = chart_definition
943
705
  @definition["$type"] = "flowChart"
944
706
  end
@@ -1109,12 +871,41 @@ module Engine
1109
871
 
1110
872
  class Host
1111
873
 
1112
- def initialize(ruleset_definitions = nil, databases = [{:host => 'localhost', :port => 6379, :password => nil, :db => 0}], state_cache_size = 1024)
874
+ def initialize(ruleset_definitions = nil)
1113
875
  @ruleset_directory = {}
1114
876
  @ruleset_list = []
1115
- @databases = databases
1116
- @state_cache_size = state_cache_size
877
+
878
+ @assert_event_func = Proc.new do |rules, arg|
879
+ rules.assert_event arg
880
+ end
881
+
882
+ @assert_events_func = Proc.new do |rules, arg|
883
+ rules.assert_events arg
884
+ end
885
+
886
+ @assert_fact_func = Proc.new do |rules, arg|
887
+ rules.assert_fact arg
888
+ end
889
+
890
+ @assert_facts_func = Proc.new do |rules, arg|
891
+ rules.assert_facts arg
892
+ end
893
+
894
+ @retract_fact_func = Proc.new do |rules, arg|
895
+ rules.retract_fact arg
896
+ end
897
+
898
+ @retract_facts_func = Proc.new do |rules, arg|
899
+ rules.retract_facts arg
900
+ end
901
+
902
+ @update_state_func = Proc.new do |rules, arg|
903
+ rules.update_state arg
904
+ end
905
+
1117
906
  register_rulesets nil, ruleset_definitions if ruleset_definitions
907
+ start_dispatch_ruleset_thread
908
+ start_dispatch_timers_thread
1118
909
  end
1119
910
 
1120
911
  def get_action(action_name)
@@ -1139,84 +930,63 @@ module Engine
1139
930
  end
1140
931
 
1141
932
  def set_ruleset(ruleset_name, ruleset_definition)
1142
- register_rulesets nil, ruleset_definition
933
+ register_rulesets nil, { ruleset_name => ruleset_definition }
1143
934
  save_ruleset ruleset_name, ruleset_definition
1144
935
  end
1145
936
 
1146
- def get_state(ruleset_name, sid)
1147
- get_ruleset(ruleset_name).get_state sid
1148
- end
1149
-
1150
- def delete_state(ruleset_name, sid)
1151
- get_ruleset(ruleset_name).delete_state sid
1152
- end
1153
-
1154
- def post_batch(ruleset_name, *events)
1155
- get_ruleset(ruleset_name).assert_events events
1156
- end
1157
-
1158
- def start_post_batch(ruleset_name, *events)
1159
- get_ruleset(ruleset_name).start_assert_events events
1160
- end
1161
-
1162
- def post(ruleset_name, event)
937
+ def post(ruleset_name, event, complete = nil)
1163
938
  if event.kind_of? Array
1164
939
  return post_batch ruleset_name, event
1165
940
  end
1166
941
 
1167
- get_ruleset(ruleset_name).assert_event event
942
+ rules = get_ruleset(ruleset_name)
943
+ handle_function rules, @assert_event_func, event, complete
1168
944
  end
1169
945
 
1170
- def start_post(ruleset_name, event)
1171
- if event.kind_of? Array
1172
- return start_post_batch ruleset_name, event
1173
- end
1174
-
1175
- get_ruleset(ruleset_name).start_assert_event event
946
+ def post_batch(ruleset_name, events, complete = nil)
947
+ rules = get_ruleset(ruleset_name)
948
+ handle_function rules, @assert_events_func, events, complete
1176
949
  end
1177
950
 
1178
- def assert(ruleset_name, fact)
951
+ def assert(ruleset_name, fact, complete = nil)
1179
952
  if fact.kind_of? Array
1180
953
  return assert_facts ruleset_name, fact
1181
954
  end
1182
955
 
1183
- get_ruleset(ruleset_name).assert_fact fact
956
+ rules = get_ruleset(ruleset_name)
957
+ handle_function rules, @assert_fact_func, fact, complete
1184
958
  end
1185
959
 
1186
- def start_assert(ruleset_name, fact)
1187
- if fact.kind_of? Array
1188
- return start_assert_facts ruleset_name, fact
1189
- end
1190
-
1191
- get_ruleset(ruleset_name).start_assert_fact fact
960
+ def assert_facts(ruleset_name, facts, complete = nil)
961
+ rules = get_ruleset(ruleset_name)
962
+ handle_function rules, @assert_facts_func, facts, complete
1192
963
  end
1193
964
 
1194
- def assert_facts(ruleset_name, *facts)
1195
- get_ruleset(ruleset_name).assert_facts facts
1196
- end
1197
-
1198
- def start_assert_facts(ruleset_name, *facts)
1199
- get_ruleset(ruleset_name).start_assert_facts facts
1200
- end
965
+ def retract(ruleset_name, fact, complete = nil)
966
+ if fact.kind_of? Array
967
+ return retract_facts ruleset_name, fact
968
+ end
1201
969
 
1202
- def retract(ruleset_name, fact)
1203
- get_ruleset(ruleset_name).retract_fact fact
970
+ rules = get_ruleset(ruleset_name)
971
+ handle_function rules, @retract_fact_func, fact, complete
1204
972
  end
1205
973
 
1206
- def start_retract(ruleset_name, fact)
1207
- get_ruleset(ruleset_name).start_retract_fact fact
974
+ def retract_facts(ruleset_name, facts, complete = nil)
975
+ rules = get_ruleset(ruleset_name)
976
+ handle_function rules, @retract_facts_func, facts, complete
1208
977
  end
1209
978
 
1210
- def retract_facts(ruleset_name, *facts)
1211
- get_ruleset(ruleset_name).retract_facts facts
979
+ def update_state(ruleset_name, state, complete = nil)
980
+ rules = get_ruleset(ruleset_name)
981
+ handle_function rules, @update_state_func, state, complete
1212
982
  end
1213
983
 
1214
- def start_retract_facts(ruleset_name, *facts)
1215
- get_ruleset(ruleset_name).start_retract_facts facts
984
+ def get_state(ruleset_name, sid)
985
+ get_ruleset(ruleset_name).get_state sid
1216
986
  end
1217
987
 
1218
- def patch_state(ruleset_name, state)
1219
- get_ruleset(ruleset_name).assert_state state
988
+ def delete_state(ruleset_name, sid)
989
+ get_ruleset(ruleset_name).delete_state sid
1220
990
  end
1221
991
 
1222
992
  def renew_action_lease(ruleset_name, sid)
@@ -1224,7 +994,7 @@ module Engine
1224
994
  end
1225
995
 
1226
996
  def register_rulesets(parent_name, ruleset_definitions)
1227
- rulesets = Ruleset.create_rulesets(parent_name, self, ruleset_definitions, @state_cache_size)
997
+ rulesets = Ruleset.create_rulesets(parent_name, self, ruleset_definitions)
1228
998
  for ruleset_name, ruleset in rulesets do
1229
999
  if @ruleset_directory.key? ruleset_name
1230
1000
  raise ArgumentError, "Ruleset with name #{ruleset_name} already registered"
@@ -1232,65 +1002,68 @@ module Engine
1232
1002
 
1233
1003
  @ruleset_directory[ruleset_name] = ruleset
1234
1004
  @ruleset_list << ruleset
1235
- ruleset.bind @databases
1236
1005
  end
1237
1006
 
1238
1007
  rulesets.keys
1239
1008
  end
1240
1009
 
1241
- def start!
1010
+ private
1242
1011
 
1243
- start_dispatch_ruleset_thread
1012
+ def handle_function(rules, func, args, complete)
1013
+ error = nil
1014
+ result = nil
1244
1015
 
1245
- start_dispatch_timers_thread
1016
+ if not complete
1017
+ rules.do_actions func.call(rules, args), -> e, s {
1018
+ error = e
1019
+ result = s
1020
+ }
1246
1021
 
1247
- end
1022
+ if error
1023
+ raise error
1024
+ end
1248
1025
 
1249
- private
1026
+ result
1027
+ else
1028
+ begin
1029
+ rules.do_actions func.call(rules, args), complete
1030
+ rescue Exception => e
1031
+ complete.call e, nil
1032
+ end
1033
+ end
1034
+ end
1250
1035
 
1251
1036
  def start_dispatch_timers_thread
1252
1037
 
1253
1038
  timer = Timers::Group.new
1254
1039
 
1255
1040
  thread_lambda = -> c {
1256
-
1257
- callback = -> e, w {
1258
- inner_wait = Thread.current[:wait]
1259
- if e
1260
- puts "unexpected error #{e}"
1261
- elsif !w
1262
- inner_wait = false
1041
+ if @ruleset_list.empty?
1042
+ timer.after 0.5, &thread_lambda
1043
+ else
1044
+ ruleset = @ruleset_list[Thread.current[:index]]
1045
+ begin
1046
+ ruleset.dispatch_timers
1047
+ rescue Exception => e
1048
+ puts e.backtrace
1049
+ puts "Error #{e}"
1263
1050
  end
1264
-
1265
- if (Thread.current[:index] == (@ruleset_list.length-1)) & inner_wait
1266
- Thread.current[:index] = (Thread.current[:index] + 1) % @ruleset_list.length
1267
- Thread.current[:wait] = inner_wait
1268
- timer.after 0.25, &thread_lambda
1269
- else
1270
- Thread.current[:index] = (Thread.current[:index] + 1) % @ruleset_list.length
1271
- Thread.current[:wait] = inner_wait
1272
- timer.after 0, &thread_lambda
1051
+
1052
+ timeout = 0
1053
+ if (Thread.current[:index] == (@ruleset_list.length-1))
1054
+ timeout = 0.2
1273
1055
  end
1274
- }
1275
-
1276
- if @ruleset_list.length > 0
1277
- ruleset = @ruleset_list[Thread.current[:index]]
1278
- Thread.current[:wait] = true unless Thread.current[:index] > 0
1279
- ruleset.dispatch_timers callback
1280
- else
1281
- timer.after 0.5, &thread_lambda
1056
+ Thread.current[:index] = (Thread.current[:index] + 1) % @ruleset_list.length
1057
+ timer.after timeout, &thread_lambda
1282
1058
  end
1283
-
1284
1059
  }
1285
1060
 
1286
1061
  timer.after 0.1, &thread_lambda
1287
1062
 
1288
1063
  Thread.new do
1289
1064
  Thread.current[:index] = 0
1290
- Thread.current[:wait] = 0
1291
1065
  loop { timer.wait }
1292
1066
  end
1293
-
1294
1067
  end
1295
1068
 
1296
1069
  def start_dispatch_ruleset_thread
@@ -1298,96 +1071,32 @@ module Engine
1298
1071
  timer = Timers::Group.new
1299
1072
 
1300
1073
  thread_lambda = -> c {
1301
-
1302
- callback = -> e, w {
1303
- inner_wait = Thread.current[:wait]
1304
- if e
1305
- puts "unexpected error #{e}"
1306
- puts e.backtrace
1307
- elsif !w
1308
- inner_wait = false
1309
- end
1310
- if (Thread.current[:index] == (@ruleset_list.length-1)) & inner_wait
1311
- Thread.current[:index] = ( Thread.current[:index] + 1 ) % @ruleset_list.length
1312
- Thread.current[:wait] = inner_wait
1313
- timer.after 0.25, &thread_lambda
1314
- else
1315
- Thread.current[:index] = ( Thread.current[:index] + 1 ) % @ruleset_list.length
1316
- Thread.current[:wait] = inner_wait
1317
- timer.after 0, &thread_lambda
1318
- end
1319
- }
1320
-
1321
1074
  if @ruleset_list.empty?
1322
1075
  timer.after 0.5, &thread_lambda
1323
1076
  else
1324
1077
  ruleset = @ruleset_list[Thread.current[:index]]
1325
- Thread.current[:wait] = true if (Thread.current[:index] > 0)
1326
- ruleset.dispatch callback
1078
+ begin
1079
+ ruleset.dispatch_ruleset
1080
+ rescue Exception => e
1081
+ puts e.backtrace
1082
+ puts "Error #{e}"
1083
+ end
1084
+
1085
+ timeout = 0
1086
+ if (Thread.current[:index] == (@ruleset_list.length-1))
1087
+ timeout = 0.2
1088
+ end
1089
+ Thread.current[:index] = (Thread.current[:index] + 1) % @ruleset_list.length
1090
+ timer.after timeout, &thread_lambda
1327
1091
  end
1328
-
1329
1092
  }
1330
1093
 
1331
1094
  timer.after 0.1, &thread_lambda
1332
1095
 
1333
1096
  Thread.new do
1334
1097
  Thread.current[:index] = 0
1335
- Thread.current[:wait] = 0
1336
1098
  loop { timer.wait }
1337
1099
  end
1338
-
1339
- end
1340
-
1341
- end
1342
-
1343
- class Queue
1344
-
1345
- def initialize(ruleset_name, database = {:host => "localhost", :port => 6379, :password => nil, :db => 0}, state_cache_size = 1024)
1346
- @_ruleset_name = ruleset_name.to_s
1347
- @handle = Rules.create_client @_ruleset_name, state_cache_size
1348
- if database.kind_of? String
1349
- Rules.bind_ruleset @handle, database, 0, nil, 0
1350
- else
1351
- Rules.bind_ruleset @handle, database[:host], database[:port], database[:password], database[:db]
1352
- end
1353
- end
1354
-
1355
- def isClosed()
1356
- @handle == 0
1357
- end
1358
-
1359
- def post(message)
1360
- if @handle == 0
1361
- raise "Queue has already been closed"
1362
- end
1363
-
1364
- sid = (message.key? :sid) ? message[:sid]: message['sid']
1365
- Rules.queue_assert_event @handle, sid.to_s, @_ruleset_name, JSON.generate(message)
1366
- end
1367
-
1368
- def assert(message)
1369
- if @handle == 0
1370
- raise "Queue has already been closed"
1371
- end
1372
-
1373
- sid = (message.key? :sid) ? message[:sid]: message['sid']
1374
- Rules.queue_assert_fact @handle, sid.to_s, @_ruleset_name, JSON.generate(message)
1375
- end
1376
-
1377
- def retract(message)
1378
- if @handle == 0
1379
- raise "Queue has already been closed"
1380
- end
1381
-
1382
- sid = (message.key? :sid) ? message[:sid]: message['sid']
1383
- Rules.queue_retract_fact @handle, sid.to_s, @_ruleset_name, JSON.generate(message)
1384
- end
1385
-
1386
- def close()
1387
- if @handle != 0
1388
- Rules.delete_client @handle
1389
- @handle = 0
1390
- end
1391
1100
  end
1392
1101
  end
1393
1102