cirrocumulus 0.5.2 → 0.6.0
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.
- data/.idea/.name +1 -0
- data/.idea/.rakeTasks +7 -0
- data/.idea/cirrocumulus.iml +87 -0
- data/.idea/encodings.xml +5 -0
- data/.idea/misc.xml +5 -0
- data/.idea/modules.xml +9 -0
- data/.idea/scopes/scope_settings.xml +5 -0
- data/.idea/vcs.xml +7 -0
- data/.idea/workspace.xml +624 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +43 -0
- data/Rakefile +2 -18
- data/VERSION +1 -1
- data/cirrocumulus.gemspec +27 -10
- data/lib/.gitignore +5 -0
- data/lib/cirrocumulus.rb +1 -3
- data/lib/cirrocumulus/agent.rb +79 -29
- data/lib/cirrocumulus/agent_wrapper.rb +5 -6
- data/lib/cirrocumulus/jabber_bus.rb +140 -0
- data/lib/cirrocumulus/message.rb +67 -0
- data/lib/cirrocumulus/ontology.rb +5 -3
- data/lib/cirrocumulus/rules/engine.rb +31 -5
- data/lib/cirrocumulus/saga.rb +7 -4
- data/lib/test.rb +68 -0
- data/lib/test2.rb +30 -0
- metadata +56 -35
- data/lib/cirrocumulus/engine.rb +0 -271
- data/lib/cirrocumulus/kb.rb +0 -44
data/lib/cirrocumulus/engine.rb
DELETED
@@ -1,271 +0,0 @@
|
|
1
|
-
require 'systemu'
|
2
|
-
require 'thread'
|
3
|
-
|
4
|
-
class Cirrocumulus
|
5
|
-
# Message. Used by agents to communicate
|
6
|
-
class Message
|
7
|
-
attr_accessor :sender, :act, :content
|
8
|
-
attr_accessor :receiver, :reply_with, :in_reply_to, :conversation_id
|
9
|
-
attr_accessor :ontology
|
10
|
-
|
11
|
-
def initialize(sender, act, content)
|
12
|
-
@sender = sender
|
13
|
-
@act = act
|
14
|
-
@content = content
|
15
|
-
end
|
16
|
-
|
17
|
-
def failed?
|
18
|
-
act == 'failure' || act == 'refuse'
|
19
|
-
end
|
20
|
-
|
21
|
-
def context
|
22
|
-
Context.new(@sender, @reply_with)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.parse_params(content, subroutine = false)
|
26
|
-
return parse_params(content.size == 1 ? content[0] : content, true) if !subroutine
|
27
|
-
|
28
|
-
return [] if content.nil?
|
29
|
-
return content if !content.is_a?(Array)
|
30
|
-
return [] if content.size == 0
|
31
|
-
return {content[0] => []} if content.size == 1
|
32
|
-
return {content[0] => parse_params(content[1], true)} if content.size == 2
|
33
|
-
|
34
|
-
res = {content[0] => []}
|
35
|
-
|
36
|
-
if content.all? {|item| !item.is_a?(Array)}
|
37
|
-
content.each_with_index do |item,i|
|
38
|
-
if i == 0
|
39
|
-
res[content[0]] = []
|
40
|
-
else
|
41
|
-
res[content[0]] << item
|
42
|
-
end
|
43
|
-
end
|
44
|
-
else
|
45
|
-
content.each_with_index do |item,i|
|
46
|
-
if i == 0
|
47
|
-
res[content[0]] = {}
|
48
|
-
else
|
49
|
-
res[content[0]].merge!(parse_params(item, true))
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
res
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Message context. Includes sender, reply-with and conversation-id
|
59
|
-
class Context
|
60
|
-
attr_reader :sender
|
61
|
-
attr_reader :reply_with
|
62
|
-
attr_reader :conversation_id
|
63
|
-
|
64
|
-
def initialize(sender, reply_with, conversation_id = nil)
|
65
|
-
@sender = sender
|
66
|
-
@reply_with = reply_with
|
67
|
-
@conversation_id = conversation_id
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Gets current platform (linux, freebsd, etc)
|
72
|
-
def self.platform
|
73
|
-
if RUBY_PLATFORM =~ /freebsd/
|
74
|
-
return 'freebsd'
|
75
|
-
elsif RUBY_PLATFORM =~ /linux/
|
76
|
-
return 'linux'
|
77
|
-
end
|
78
|
-
|
79
|
-
return 'unknown'
|
80
|
-
end
|
81
|
-
|
82
|
-
attr_reader :jid
|
83
|
-
|
84
|
-
def initialize(suffix, generate_jid = true)
|
85
|
-
Log4r::Logger['cirrocumulus'].info 'platform: ' + Cirrocumulus::platform
|
86
|
-
@suffix = suffix
|
87
|
-
@generate_jid = generate_jid
|
88
|
-
@send_queue = Queue.new
|
89
|
-
end
|
90
|
-
|
91
|
-
# Sends message to other agents
|
92
|
-
def send_message(message)
|
93
|
-
@send_queue << message
|
94
|
-
end
|
95
|
-
|
96
|
-
=begin
|
97
|
-
def inform(receiver, answer, ontology = nil)
|
98
|
-
msg = "<fipa-message ontology=\"#{ontology || @ontology}\" receiver=\"#{receiver}\" act=\"inform\"><content>#{answer}</content></fipa-message>"
|
99
|
-
@im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&').gsub('<', '<').gsub('>', '>')}</body></message>")
|
100
|
-
end
|
101
|
-
|
102
|
-
def refuse(receiver, action, reason, ontology = nil)
|
103
|
-
msg = "<fipa-message ontology=\"#{ontology || @ontology}\" receiver=\"#{receiver}\" act=\"refuse\"><content>(#{action} #{reason})</content></fipa-message>"
|
104
|
-
@im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&').gsub('<', '<').gsub('>', '>')}</body></message>")
|
105
|
-
end
|
106
|
-
|
107
|
-
def failure(receiver, action, ontology = nil)
|
108
|
-
msg = "<fipa-message ontology=\"#{ontology || @ontology}\" receiver=\"#{receiver}\" act=\"failure\"><content>#{action}</content></fipa-message>"
|
109
|
-
@im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&').gsub('<', '<').gsub('>', '>')}</body></message>")
|
110
|
-
end
|
111
|
-
|
112
|
-
def request(receiver, action, ontology = nil)
|
113
|
-
msg = "<fipa-message ontology=\"#{ontology || @ontology}\" receiver=\"#{receiver}\" act=\"request\"><content>#{action}</content></fipa-message>"
|
114
|
-
@im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&').gsub('<', '<').gsub('>', '>')}</body></message>")
|
115
|
-
end
|
116
|
-
=end
|
117
|
-
|
118
|
-
# Main loop. Connects to other agents and processes all incoming messages
|
119
|
-
def run(agent, kb, sniff = false)
|
120
|
-
connect(generate_jid(agent))
|
121
|
-
|
122
|
-
Log4r::Logger['cirrocumulus'].info("entering main loop")
|
123
|
-
agent.restore_state()
|
124
|
-
agent.start()
|
125
|
-
|
126
|
-
s = Sexpistol.new
|
127
|
-
should_be_running = true
|
128
|
-
|
129
|
-
while should_be_running do
|
130
|
-
kb.collect_knowledge()
|
131
|
-
|
132
|
-
begin
|
133
|
-
connect(generate_jid(agent)) if !connected?
|
134
|
-
rescue Exception => e
|
135
|
-
puts e.to_s
|
136
|
-
sleep 5
|
137
|
-
end
|
138
|
-
|
139
|
-
next if !connected?
|
140
|
-
|
141
|
-
# process incoming messages from queue
|
142
|
-
@im.received_messages do |message|
|
143
|
-
process_incoming_message(agent, kb, message, s, sniff)
|
144
|
-
end
|
145
|
-
|
146
|
-
# send all queued messages
|
147
|
-
process_send_queue()
|
148
|
-
|
149
|
-
sleep 0.5 # TODO: do we need this stuff?
|
150
|
-
end
|
151
|
-
|
152
|
-
@im.disconnect
|
153
|
-
end
|
154
|
-
|
155
|
-
private
|
156
|
-
|
157
|
-
# Flatterns incoming message if is bounded into multiple arrays
|
158
|
-
def flatten_message_content(message)
|
159
|
-
if !message.content.is_a?(Array)
|
160
|
-
message.content = [message.content]
|
161
|
-
else
|
162
|
-
while message.content.is_a?(Array) && message.content.size == 1 && message.content.first.is_a?(Array)
|
163
|
-
message.content = message.content.first
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
# Generates JID for self identification
|
169
|
-
def generate_jid(agent)
|
170
|
-
suffix = agent.default_ontology ? agent.default_ontology.gsub('cirrocumulus-', '') : @suffix
|
171
|
-
if @generate_jid
|
172
|
-
_, hostname = systemu('hostname')
|
173
|
-
hostname.strip!
|
174
|
-
"%s-%s" % [hostname, suffix]
|
175
|
-
else
|
176
|
-
suffix
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
# Checks if agent is connected to Jabber conference
|
181
|
-
def connected?
|
182
|
-
@im && @im.connected?
|
183
|
-
end
|
184
|
-
|
185
|
-
# Connects to Jabber server and joins the conference
|
186
|
-
def connect(jid)
|
187
|
-
@jid = jid
|
188
|
-
Log4r::Logger['cirrocumulus'].info "logging as " + @jid
|
189
|
-
|
190
|
-
begin
|
191
|
-
@im.disconnect if @im && @im.connected?
|
192
|
-
full_jid = @jid + "@" + JABBER_SERVER
|
193
|
-
@im = Jabber::Simple.new(full_jid, JABBER_DEFAULT_PASSWORD)
|
194
|
-
rescue Jabber::ClientAuthenticationFailure => ex
|
195
|
-
Log4r::Logger['cirrocumulus'].warn ex.to_s
|
196
|
-
Log4r::Logger['cirrocumulus'].info "registering new account with default password"
|
197
|
-
|
198
|
-
client = Jabber::Client.new(full_jid)
|
199
|
-
client.connect()
|
200
|
-
client.register(JABBER_DEFAULT_PASSWORD) #, {'username' => full_jid, 'password' => JABBER_DEFAULT_PASSWORD})
|
201
|
-
client.close()
|
202
|
-
@im = Jabber::Simple.new(full_jid, JABBER_DEFAULT_PASSWORD)
|
203
|
-
rescue Exception => ex
|
204
|
-
puts ex
|
205
|
-
#puts ex.backtrace.to_s
|
206
|
-
end
|
207
|
-
|
208
|
-
if !@im.nil? && @im.connected?
|
209
|
-
Log4r::Logger['cirrocumulus'].info 'joining ' + JABBER_CONFERENCE
|
210
|
-
@im.send!("<presence to='#{JABBER_CONFERENCE}/#{@jid}' />")
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
def process_incoming_message(agent, kb, message, s, sniff)
|
215
|
-
return if !message.x('jabber:x:delay').nil?
|
216
|
-
|
217
|
-
begin
|
218
|
-
xml = Hash.from_xml(message.body)['fipa_message']
|
219
|
-
|
220
|
-
ontology = xml['ontology']
|
221
|
-
sender = message.from.resource
|
222
|
-
receiver = xml['receiver']
|
223
|
-
supported_ontology = agent.handles_ontology?(ontology)
|
224
|
-
|
225
|
-
if (supported_ontology && (receiver == @jid || receiver.blank?)) || receiver == @jid || sniff
|
226
|
-
content_raw = xml['content']
|
227
|
-
content = s.parse_string(content_raw)
|
228
|
-
msg = Cirrocumulus::Message.new(sender, xml['act'], content)
|
229
|
-
msg.receiver = receiver
|
230
|
-
msg.ontology = ontology
|
231
|
-
msg.reply_with = xml['reply_with']
|
232
|
-
msg.in_reply_to = xml['in_reply_to']
|
233
|
-
msg.conversation_id = xml['conversation_id']
|
234
|
-
|
235
|
-
flatten_message_content(msg)
|
236
|
-
Log4r::Logger['cirrocumulus'].debug(msg.inspect)
|
237
|
-
agent.handle_message(msg)
|
238
|
-
else # ignore message
|
239
|
-
#Log4r::Logger['cirrocumulus'].debug("unhandled ontology: %s" % [ontology])
|
240
|
-
end
|
241
|
-
rescue Exception => e # exception while parsing; possibly it is not XML (humans speaking!)
|
242
|
-
Log4r::Logger['cirrocumulus'].error "%s\n%s" % [e.to_s, e.backtrace.to_s]
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
# Processes send queue and sends all pending messages
|
247
|
-
def process_send_queue()
|
248
|
-
while !@send_queue.empty? do
|
249
|
-
message = @send_queue.pop
|
250
|
-
actual_send(message)
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
# Sends message to Jabber conference
|
255
|
-
def actual_send(message)
|
256
|
-
msg = "<fipa-message ontology=\"#{message.ontology}\""
|
257
|
-
msg += " receiver=\"#{message.receiver}\"" if message.receiver
|
258
|
-
msg += " act=\"#{message.act}\""
|
259
|
-
msg += " reply-with=\"#{message.reply_with}\"" if message.reply_with
|
260
|
-
msg += " in-reply-to=\"#{message.in_reply_to}\"" if message.in_reply_to
|
261
|
-
msg += " conversation-id=\"#{message.conversation_id}\"" if message.conversation_id
|
262
|
-
message_content = message.content if message.content.is_a?(String)
|
263
|
-
message_content = Sexpistol.new.to_sexp(message.content) if message.content.is_a? Array
|
264
|
-
msg += "><content>#{message_content}</content></fipa-message>"
|
265
|
-
@im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&').gsub('<', '<').gsub('>', '>')}</body></message>")
|
266
|
-
true
|
267
|
-
rescue
|
268
|
-
false
|
269
|
-
end
|
270
|
-
|
271
|
-
end
|
data/lib/cirrocumulus/kb.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
class Kb
|
2
|
-
def initialize
|
3
|
-
@knowledge = []
|
4
|
-
end
|
5
|
-
|
6
|
-
def add_fact(key, value)
|
7
|
-
s = Sexpistol.new
|
8
|
-
key_str = s.to_sexp(key)
|
9
|
-
#puts "add: #{key_str}"
|
10
|
-
@knowledge << {:key => key_str, :value => value}
|
11
|
-
end
|
12
|
-
|
13
|
-
def query_fact(key)
|
14
|
-
s = Sexpistol.new
|
15
|
-
key_str = s.to_sexp(key)
|
16
|
-
|
17
|
-
#puts "query: #{key}"
|
18
|
-
@knowledge.each do |h|
|
19
|
-
if h[:key] == key_str
|
20
|
-
#puts "found: #{h[:value]}"
|
21
|
-
return h[:value]
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
nil
|
26
|
-
end
|
27
|
-
|
28
|
-
def remove_fact(key)
|
29
|
-
#puts "remove fact: #{key}"
|
30
|
-
@knowledge.delete(key)
|
31
|
-
end
|
32
|
-
|
33
|
-
def keys
|
34
|
-
res = []
|
35
|
-
@knowledge.each do |h|
|
36
|
-
res << h[:key]
|
37
|
-
end
|
38
|
-
|
39
|
-
res
|
40
|
-
end
|
41
|
-
|
42
|
-
def collect_knowledge()
|
43
|
-
end
|
44
|
-
end
|