durable_rules 0.34.57 → 2.00.001

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
  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