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
|
-
|
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
|
-
|
162
|
+
Logger['channels::factory'].warn "No active Jabber clients."
|
162
163
|
end
|
163
164
|
end
|
164
165
|
|
165
|
-
|
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
|
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
|
-
|
70
|
-
|
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
|
101
|
-
@@
|
102
|
+
def password(pass)
|
103
|
+
@@password = pass
|
102
104
|
end
|
103
105
|
|
104
|
-
def
|
105
|
-
@@
|
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
|
127
|
-
@full_jid = "%s@%s" % [jid,
|
128
|
+
def connect(jid)
|
129
|
+
@full_jid = "%s@%s" % [jid, @server]
|
128
130
|
@jid = jid
|
129
131
|
|
130
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
27
|
+
Log4r::Logger['agent'].info "Adding #{ontology_instance.name} ontology"
|
26
28
|
@ontologies << ontology_instance
|
27
29
|
end
|
28
30
|
|
data/lib/cirrocumulus/facts.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
55
|
+
@queue.push :marker
|
56
|
+
|
57
|
+
while (entry = pop) != :marker do
|
46
58
|
next if entry.state == :finished
|
47
|
-
|
48
|
-
|
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
|
-
|
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
|
-
|
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
|