cirrocumulus 0.9.7 → 0.9.8
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.
@@ -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
|