cirrocumulus 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,4 @@
1
+ require 'log4r'
1
2
  require_relative 'channels/jabber'
2
3
 
3
4
  #
@@ -150,7 +151,7 @@ class ChannelFactory
150
151
  if ontology_instance
151
152
  return ThreadChannel.new(Ontology.query_ontology_instance(agent))
152
153
  else
153
- puts "[WARN] Thread-local ontology not found for identifier=%s" % agent.to_s
154
+ Logger['channels::factory'].warn "Thread-local ontology not found for identifier=%s" % agent.to_s
154
155
  end
155
156
  elsif agent.is_a?(RemoteIdentifier)
156
157
  jabber_client = JabberChannel.query_client(instance.to_s)
@@ -158,11 +159,11 @@ class ChannelFactory
158
159
  if jabber_client
159
160
  return NetworkChannel.new(jabber_client, agent.to_s)
160
161
  else
161
- puts "[WARN] No active Jabber clients."
162
+ Logger['channels::factory'].warn "No active Jabber clients."
162
163
  end
163
164
  end
164
165
 
165
- puts "[WARN] No suitable channel found for #{agent.to_s} (#{agent.class.name})"
166
+ Logger['channels::factory'].warn "No suitable channel found for #{agent.to_s} (#{agent.class.name})"
166
167
  nil
167
168
  end
168
169
  end
@@ -7,7 +7,7 @@ class JabberIdentifier < RemoteIdentifier
7
7
  def initialize(jid)
8
8
  @jid = "#{Cirrocumulus::Environment.current.name}-#{jid}"
9
9
  @channel = JabberChannel.new()
10
- @channel.connect(@jid, 'q1w2e3r4')
10
+ @channel.connect(@jid)
11
11
  @thrd = Thread.new do
12
12
  parser = Sexpistol.new
13
13
  while true do
@@ -66,8 +66,10 @@ class JabberIdentifier < RemoteIdentifier
66
66
  instance.handle_failure(id, action_content[0], action_content[1], options)
67
67
  end
68
68
  rescue Exception => ex
69
- puts ex.message
70
- puts ex.backtrace.to_s
69
+ Log4r::Logger['channels'].warn("Failed to process incoming message")
70
+ Log4r::Logger['channels'].debug("Message body: #{msg.body}")
71
+ Log4r::Logger['channels'].debug("Exception: #{ex.message}")
72
+ Log4r::Logger['channels'].debug("Backtrace: #{ex.backtrace.join("\n")}")
71
73
  end
72
74
  end
73
75
  end
@@ -97,12 +99,12 @@ class JabberChannel
97
99
  @@server = server
98
100
  end
99
101
 
100
- def conference(conf)
101
- @@conference = conf
102
+ def password(pass)
103
+ @@password = pass
102
104
  end
103
105
 
104
- def jid_suffix(suffix)
105
- @@jid_suffix = suffix
106
+ def conference(conf)
107
+ @@conference = conf
106
108
  end
107
109
  end
108
110
 
@@ -123,24 +125,26 @@ class JabberChannel
123
125
  @jabber && @jabber.connected?
124
126
  end
125
127
 
126
- def connect(jid, password)
127
- @full_jid = "%s@%s" % [jid, @@jid_suffix || @server]
128
+ def connect(jid)
129
+ @full_jid = "%s@%s" % [jid, @server]
128
130
  @jid = jid
129
131
 
130
- puts "Using jid #{@jid}"
132
+ Log4r::Logger['channels::jabber'].info "Server: #{@server}"
133
+ Log4r::Logger['channels::jabber'].info "JID: '#{@jid}'"
131
134
 
132
135
  begin
133
- @jabber = Jabber::Simple.new(@full_jid, password)
136
+ @jabber = Jabber::Simple.new(@full_jid, @@password)
134
137
  rescue Jabber::ClientAuthenticationFailure => ex
135
- puts ex.class.name
136
- puts ex.to_s
138
+ Log4r::Logger['channels::jabber'].debug('Received Jabber::ClientAuthenticationFailure, registering new account')
137
139
  client = Jabber::Client.new(@full_jid)
138
140
  client.connect()
139
141
  client.register(password)
140
142
  client.close()
141
- @jabber = Jabber::Simple.new(@full_jid, password)
143
+ @jabber = Jabber::Simple.new(@full_jid, @@password)
142
144
  rescue Exception => ex
143
- puts ex.to_s
145
+ Log4::Logger['channels::jabber'].fatal('Failed to register new account or connect.')
146
+ Log4::Logger['channels::jabber'].fatal("Received exception: #{ex.to_s}")
147
+ return false
144
148
  end
145
149
 
146
150
  join_conference(@conference) if connected?
@@ -182,6 +186,7 @@ class JabberChannel
182
186
  protected
183
187
 
184
188
  def join_conference(conference)
185
- @jabber.send!("<presence to='#{conference}@conference.#{@@jid_suffix || @server}/#{@jid}' />")
189
+ Log4r::Logger['channels::jabber'].info "Joining conference '#{conference}'"
190
+ @jabber.send!("<presence to='#{conference}@conference.#{@server}/#{@jid}' />")
186
191
  end
187
192
  end
@@ -1,3 +1,5 @@
1
+ require 'log4r'
2
+
1
3
  module Cirrocumulus
2
4
  #
3
5
  # Cirrocumulus environment. It is a container where all ontologies will be loaded.
@@ -11,7 +13,7 @@ module Cirrocumulus
11
13
  attr_reader :name
12
14
 
13
15
  def initialize(name)
14
- puts "Loading #{name} Cirrocumulus environment."
16
+ Log4r::Logger['agent'].info "Loading #{name} Cirrocumulus environment"
15
17
 
16
18
  @name = name
17
19
  @ontologies = []
@@ -22,7 +24,7 @@ module Cirrocumulus
22
24
  # Loads ontology instance into environment.
23
25
  #
24
26
  def load_ontology(ontology_instance)
25
- puts "Adding #{ontology_instance.name} ontology."
27
+ Log4r::Logger['agent'].info "Adding #{ontology_instance.name} ontology"
26
28
  @ontologies << ontology_instance
27
29
  end
28
30
 
@@ -74,9 +74,9 @@ class KnowledgeClass
74
74
  def to_template
75
75
  description = @@classes[self.name]
76
76
  fact = [description.name.to_sym]
77
- fact << description.primary_key.upcase.to_sym
77
+ fact << description.primary_key.upcase.to_sym if description.primary_key
78
78
  description.properties.each do |k|
79
- next if k == description.primary_key
79
+ next if k == description.primary_key && description.primary_key
80
80
 
81
81
  fact << k.to_sym
82
82
  fact << k.upcase.to_sym
@@ -106,7 +106,7 @@ class KnowledgeClass
106
106
  @values = {}
107
107
 
108
108
  description = @@classes[self.class.name]
109
- if options.has_key?(description.primary_key.to_sym)
109
+ if description.primary_key && options.has_key?(description.primary_key.to_sym)
110
110
  @values[description.primary_key] = options[description.primary_key.to_sym]
111
111
  end
112
112
 
@@ -120,7 +120,7 @@ class KnowledgeClass
120
120
  def to_template
121
121
  description = @@classes[self.class.name]
122
122
  fact = [description.name.to_sym]
123
- fact << values[description.primary_key]
123
+ fact << values[description.primary_key] if description.primary_key
124
124
  description.properties.each do |k|
125
125
  next if k == description.primary_key
126
126
 
@@ -134,9 +134,9 @@ class KnowledgeClass
134
134
  def to_params
135
135
  description = @@classes[self.class.name]
136
136
  fact = [description.name.to_sym]
137
- fact << (values.has_key?(description.primary_key) ? values[description.primary_key] : description.primary_key.upcase.to_sym)
137
+ fact << (values.has_key?(description.primary_key) ? values[description.primary_key] : description.primary_key.upcase.to_sym) if description.primary_key
138
138
  description.properties.each do |k|
139
- next if k == description.primary_key
139
+ next if k == description.primary_key && description.primary_key
140
140
 
141
141
  fact << k.to_sym
142
142
  fact << (values.has_key?(k) ? values[k] : k.upcase.to_sym)
@@ -95,6 +95,7 @@ class Ontology
95
95
  @classes = []
96
96
  @last_saga_id = 0
97
97
  @sagas = []
98
+ @last_tick_time = Time.now
98
99
 
99
100
  self.class.register_ontology_instance(self)
100
101
  @mutex = Mutex.new
@@ -112,6 +113,12 @@ class Ontology
112
113
  while self.running do
113
114
  ontology.timeout_facts
114
115
  @rule_queue.run_queued_rules
116
+
117
+ if Time.now - @last_tick_time > 1
118
+ ontology.tick
119
+ @last_tick_time = Time.now
120
+ end
121
+
115
122
  sleep 0.1
116
123
  end
117
124
  end
@@ -219,7 +226,7 @@ class Ontology
219
226
  # Inform another agent about a fact. Normally, it will be added to it's KB.
220
227
  #
221
228
  def inform(agent, fact, options = {})
222
- puts "%25s | inform %s about %s %s" % [identifier, agent, Sexpistol.new.to_sexp(fact), print_message_options(options)]
229
+ info "%25s | inform %s about %s %s" % [identifier, agent, Sexpistol.new.to_sexp(fact), print_message_options(options)]
223
230
 
224
231
  channel = ChannelFactory.retrieve(identifier, agent)
225
232
  channel.inform(identifier, fact, options) if channel
@@ -233,7 +240,7 @@ class Ontology
233
240
  # The action of agreeing to perform some action, possibly in the future.
234
241
  #
235
242
  def agree(agent, action, options = {})
236
- puts "%25s | agree with %s to perform %s %s" % [identifier, agent, Sexpistol.new.to_sexp(action), print_message_options(options)]
243
+ info "%25s | agree with %s to perform %s %s" % [identifier, agent, Sexpistol.new.to_sexp(action), print_message_options(options)]
237
244
 
238
245
  channel = ChannelFactory.retrieve(identifier, agent)
239
246
  channel.agree(identifier, action, options) if channel
@@ -243,7 +250,7 @@ class Ontology
243
250
  # The action of refusing to perform a given action, and explaining the reason for the refusal.
244
251
  #
245
252
  def refuse(agent, action, reason, options = {})
246
- puts "%25s | refuse %s to perform %s because %s %s" % [identifier, agent, Sexpistol.new.to_sexp(action), Sexpistol.new.to_sexp(reason), print_message_options(options)]
253
+ info "%25s | refuse %s to perform %s because %s %s" % [identifier, agent, Sexpistol.new.to_sexp(action), Sexpistol.new.to_sexp(reason), print_message_options(options)]
247
254
 
248
255
  channel = ChannelFactory.retrieve(identifier, agent)
249
256
  channel.refuse(identifier, action, reason, options) if channel
@@ -253,7 +260,7 @@ class Ontology
253
260
  # The action of telling another agent that an action was attempted but the attempt failed.
254
261
  #
255
262
  def failure(agent, action, reason = true , options = {})
256
- puts "%25s | inform %s that action %s failed with reason %s %s" % [identifier, agent, Sexpistol.new.to_sexp(action), Sexpistol.new.to_sexp(reason), print_message_options(options)]
263
+ info "%25s | inform %s that action %s failed with reason %s %s" % [identifier, agent, Sexpistol.new.to_sexp(action), Sexpistol.new.to_sexp(reason), print_message_options(options)]
257
264
 
258
265
  channel = ChannelFactory.retrieve(identifier, agent)
259
266
  channel.failure(identifier, action, reason, options) if channel
@@ -263,7 +270,7 @@ class Ontology
263
270
  # Send request to another agent.
264
271
  #
265
272
  def request(agent, contents, options = {})
266
- puts "%25s | %s -> %s" % [identifier.to_s, Sexpistol.new.to_sexp(contents), agent.to_s]
273
+ info "%25s | %s -> %s" % [identifier.to_s, Sexpistol.new.to_sexp(contents), agent.to_s]
267
274
 
268
275
  channel = ChannelFactory.retrieve(identifier, agent)
269
276
  channel.request(identifier, contents) if channel
@@ -274,7 +281,7 @@ class Ontology
274
281
  end
275
282
 
276
283
  def query(agent, expression, options = {})
277
- puts "%25s | query %s about %s %s" % [identifier, agent, Sexpistol.new.to_sexp(expression), print_message_options(options)]
284
+ info "%25s | query %s about %s %s" % [identifier, agent, Sexpistol.new.to_sexp(expression), print_message_options(options)]
278
285
 
279
286
  channel = ChannelFactory.retrieve(identifier, agent)
280
287
  channel.query(identifier, expression, options) if channel
@@ -297,6 +304,11 @@ class Ontology
297
304
  #
298
305
  def restore_state; end
299
306
 
307
+ #
308
+ # Tick. Every second.
309
+ #
310
+ def tick; end
311
+
300
312
  #
301
313
  # Handles incoming fact. By default, just adds this fact to KB or redirects its processing to corresponding saga
302
314
  #
@@ -325,19 +337,19 @@ class Ontology
325
337
 
326
338
  def handle_agree(sender, action, options = {})
327
339
  if !handle_saga_reply(sender, :agree, action, options)
328
- puts "%25s | %s agreed to perform %s %s" % [identifier, sender, Sexpistol.new.to_sexp(action), print_message_options(options)]
340
+ info "%25s | %s agreed to perform %s %s" % [identifier, sender, Sexpistol.new.to_sexp(action), print_message_options(options)]
329
341
  end
330
342
  end
331
343
 
332
344
  def handle_refuse(sender, action, reason, options = {})
333
345
  if !handle_saga_reply(sender, :refuse, [action, reason], options)
334
- puts "%25s | %s refused to perform %s because %s %s" % [identifier, sender, Sexpistol.new.to_sexp(action), Sexpistol.new.to_sexp(reason), print_message_options(options)]
346
+ info "%25s | %s refused to perform %s because %s %s" % [identifier, sender, Sexpistol.new.to_sexp(action), Sexpistol.new.to_sexp(reason), print_message_options(options)]
335
347
  end
336
348
  end
337
349
 
338
350
  def handle_failure(sender, action, reason, options = {})
339
351
  if !handle_saga_reply(sender, :failure, [action, reason], options)
340
- puts "%25s | %s failed to perform %s because %s %s" % [identifier, sender, Sexpistol.new.to_sexp(action), Sexpistol.new.to_sexp(reason), print_message_options(options)]
352
+ info "%25s | %s failed to perform %s because %s %s" % [identifier, sender, Sexpistol.new.to_sexp(action), Sexpistol.new.to_sexp(reason), print_message_options(options)]
341
353
  end
342
354
  end
343
355
 
@@ -346,12 +358,12 @@ class Ontology
346
358
  #
347
359
  def handle_request(sender, contents, options = {})
348
360
  if !handle_saga_reply(sender, :request, contents, options)
349
- puts "%25s | %s requests to perform %s %s" % [identifier, sender, Sexpistol.new.to_sexp(contents), print_message_options(options)]
361
+ info "%25s | %s requests to perform %s %s" % [identifier, sender, Sexpistol.new.to_sexp(contents), print_message_options(options)]
350
362
  end
351
363
  end
352
364
 
353
365
  def handle_query(sender, expression, options = {})
354
- puts "%25s | %s queries %s %s" % [identifier, sender, Sexpistol.new.to_sexp(expression), print_message_options(options)] unless handle_saga_reply(sender, :query, expression, options)
366
+ info "%25s | %s queries %s %s" % [identifier, sender, Sexpistol.new.to_sexp(expression), print_message_options(options)] unless handle_saga_reply(sender, :query, expression, options)
355
367
  end
356
368
 
357
369
  #
@@ -425,8 +437,12 @@ class Ontology
425
437
  "[%s]" % options.map {|k,v| "%s=%s" % [k, v]}.join(',')
426
438
  end
427
439
 
440
+ def info(msg)
441
+ Log4r::Logger['ontology'].info(msg)
442
+ end
443
+
428
444
  def debug(msg)
429
- puts "[DBG] %s" % msg
445
+ Log4r::Logger['ontology'].debug(msg)
430
446
  end
431
447
 
432
448
  end
@@ -25,7 +25,17 @@ class RuleQueue
25
25
 
26
26
  def push(entry)
27
27
  @mutex.synchronize do
28
- @queue.push(QueueEntry.new(entry)) unless @queue.find {|e| e.state != :finished && e.run_data == entry}
28
+ return if @queue.find {|e| e != :marker && e.state != :finished && e.run_data == entry}
29
+
30
+ if entry.rule.options.has_key?(:for)
31
+ delay = entry.rule.options[:for]
32
+ run_at = Time.now + delay
33
+ debug("Enqueued rule #{entry.rule.name}#{entry.parameters.inspect}")
34
+ debug("And will execute this rule after #{delay} sec (at #{run_at.strftime("%H:%M:%S %d.%m.%Y")})")
35
+ @queue.push(QueueEntry.new(entry, run_at))
36
+ else
37
+ @queue.push(QueueEntry.new(entry))
38
+ end
29
39
  end
30
40
  end
31
41
 
@@ -42,10 +52,13 @@ class RuleQueue
42
52
  end
43
53
 
44
54
  def run_queued_rules
45
- while (entry = pop) != nil do
55
+ @queue.push :marker
56
+
57
+ while (entry = pop) != :marker do
46
58
  next if entry.state == :finished
47
- if entry.run_at && (entry.run_at < Time.now)
48
- push(entry)
59
+
60
+ if !entry.run_at.nil? && (entry.run_at > Time.now)
61
+ @queue.push(entry)
49
62
  next
50
63
  end
51
64
 
@@ -55,7 +68,7 @@ class RuleQueue
55
68
  entry.rule.code.call(@ontology_instance, entry.params)
56
69
  entry.state
57
70
  rescue Exception => e
58
- puts "[WARN] Exception while executing rule: %s\n%s" % [e.to_s, e.backtrace.to_s]
71
+ warn "Exception while executing rule: %s\n%s" % [e.to_s, e.backtrace.to_s]
59
72
  end
60
73
  end
61
74
  end
@@ -64,6 +77,11 @@ class RuleQueue
64
77
  private
65
78
 
66
79
  def debug(msg)
67
- puts msg
80
+ Log4r::Logger['ontology::run_queue'].debug(msg)
68
81
  end
82
+
83
+ def warn(msg)
84
+ Log4r::Logger['ontology::run_queue'].warn(msg)
85
+ end
86
+
69
87
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cirrocumulus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: