agent_xmpp 0.1.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/.document +5 -0
- data/.gitignore +11 -0
- data/LICENSE +20 -0
- data/README.rdoc +417 -0
- data/Rakefile +75 -0
- data/VERSION +1 -0
- data/agent_xmpp.gemspec +144 -0
- data/lib/agent_xmpp.rb +22 -0
- data/lib/agent_xmpp/admin.rb +113 -0
- data/lib/agent_xmpp/client.rb +7 -0
- data/lib/agent_xmpp/client/boot.rb +83 -0
- data/lib/agent_xmpp/client/client.rb +64 -0
- data/lib/agent_xmpp/client/connection.rb +108 -0
- data/lib/agent_xmpp/client/controller.rb +394 -0
- data/lib/agent_xmpp/client/message_delegate.rb +720 -0
- data/lib/agent_xmpp/client/message_pipe.rb +193 -0
- data/lib/agent_xmpp/client/response.rb +102 -0
- data/lib/agent_xmpp/config.rb +48 -0
- data/lib/agent_xmpp/main.rb +175 -0
- data/lib/agent_xmpp/models.rb +7 -0
- data/lib/agent_xmpp/models/contact.rb +85 -0
- data/lib/agent_xmpp/models/message.rb +152 -0
- data/lib/agent_xmpp/models/publication.rb +53 -0
- data/lib/agent_xmpp/models/roster.rb +107 -0
- data/lib/agent_xmpp/models/service.rb +91 -0
- data/lib/agent_xmpp/models/subscription.rb +61 -0
- data/lib/agent_xmpp/models/table_definitions.rb +107 -0
- data/lib/agent_xmpp/patches.rb +7 -0
- data/lib/agent_xmpp/patches/array.rb +32 -0
- data/lib/agent_xmpp/patches/float.rb +10 -0
- data/lib/agent_xmpp/patches/hash.rb +13 -0
- data/lib/agent_xmpp/patches/object.rb +15 -0
- data/lib/agent_xmpp/patches/rexml.rb +69 -0
- data/lib/agent_xmpp/patches/string.rb +15 -0
- data/lib/agent_xmpp/xmpp.rb +18 -0
- data/lib/agent_xmpp/xmpp/element.rb +158 -0
- data/lib/agent_xmpp/xmpp/entry.rb +36 -0
- data/lib/agent_xmpp/xmpp/error_response.rb +189 -0
- data/lib/agent_xmpp/xmpp/iq.rb +90 -0
- data/lib/agent_xmpp/xmpp/iq_command.rb +54 -0
- data/lib/agent_xmpp/xmpp/iq_disco.rb +206 -0
- data/lib/agent_xmpp/xmpp/iq_pubsub.rb +270 -0
- data/lib/agent_xmpp/xmpp/iq_roster.rb +183 -0
- data/lib/agent_xmpp/xmpp/iq_version.rb +89 -0
- data/lib/agent_xmpp/xmpp/jid.rb +150 -0
- data/lib/agent_xmpp/xmpp/message.rb +82 -0
- data/lib/agent_xmpp/xmpp/presence.rb +127 -0
- data/lib/agent_xmpp/xmpp/sasl.rb +241 -0
- data/lib/agent_xmpp/xmpp/stanza.rb +107 -0
- data/lib/agent_xmpp/xmpp/x_data.rb +357 -0
- data/test/app/app.rb +339 -0
- data/test/cases/test_application_message_processing.rb +65 -0
- data/test/cases/test_errors.rb +24 -0
- data/test/cases/test_presence_management.rb +139 -0
- data/test/cases/test_roster_management.rb +214 -0
- data/test/cases/test_service_discovery.rb +168 -0
- data/test/cases/test_session_management.rb +120 -0
- data/test/cases/test_version_discovery.rb +67 -0
- data/test/helpers/matchers.rb +23 -0
- data/test/helpers/mocks.rb +82 -0
- data/test/helpers/test_case_extensions.rb +45 -0
- data/test/helpers/test_client.rb +44 -0
- data/test/helpers/test_delegate.rb +60 -0
- data/test/helpers/test_helper.rb +91 -0
- data/test/messages/application_messages.rb +206 -0
- data/test/messages/error_messages.rb +35 -0
- data/test/messages/presence_messages.rb +66 -0
- data/test/messages/roster_messages.rb +126 -0
- data/test/messages/service_discovery_messages.rb +201 -0
- data/test/messages/session_messages.rb +158 -0
- data/test/messages/version_discovery_messages.rb +69 -0
- data/test/peer/peer.rb +21 -0
- metadata +187 -0
@@ -0,0 +1,720 @@
|
|
1
|
+
##############################################################################################################
|
2
|
+
module AgentXmpp
|
3
|
+
|
4
|
+
#####-------------------------------------------------------------------------------------------------------
|
5
|
+
class MessageDelegate
|
6
|
+
|
7
|
+
#####-------------------------------------------------------------------------------------------------------
|
8
|
+
class << self
|
9
|
+
|
10
|
+
#.........................................................................................................
|
11
|
+
attr_reader :pubsub_service
|
12
|
+
|
13
|
+
#---------------------------------------------------------------------------------------------------------
|
14
|
+
# event flow delegate methods
|
15
|
+
#.........................................................................................................
|
16
|
+
# process command
|
17
|
+
#.........................................................................................................
|
18
|
+
def on_command_set(pipe, stanza)
|
19
|
+
command = stanza.command
|
20
|
+
params = {:xmlns => 'jabber:x:data', :action => command.action || :execute, :to => stanza.from.to_s,
|
21
|
+
:from => stanza.from.to_s, :node => command.node, :id => stanza.id,
|
22
|
+
:sessionid => command.sessionid}
|
23
|
+
(data = command.x) ? params.update(:data=>data.to_params, :x_data_type => data.type) : params.update(:data=>{})
|
24
|
+
AgentXmpp.logger.info "RECEIVED COMMAND NODE: #{command.node}, FROM: #{stanza.from.to_s}"
|
25
|
+
if BaseController.commands_list[params[:sessionid]]
|
26
|
+
BaseController.commands_list[params[:sessionid]][:controller].next(params).invoke_command_next
|
27
|
+
else
|
28
|
+
Controller.new(pipe, params).invoke_command
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
#.........................................................................................................
|
33
|
+
# process chat messages
|
34
|
+
#.........................................................................................................
|
35
|
+
def on_message_chat(pipe, stanza)
|
36
|
+
params = {:xmlns => 'message:chat', :to => stanza.from.to_s, :from => stanza.from.to_s,
|
37
|
+
:id => stanza.id, :body => stanza.body}
|
38
|
+
AgentXmpp.logger.info "RECEIVED CHAT MESSAGE FROM: #{stanza.from.to_s}"
|
39
|
+
Controller.new(pipe, params).invoke_chat
|
40
|
+
end
|
41
|
+
|
42
|
+
#.........................................................................................................
|
43
|
+
# process normal messages
|
44
|
+
#.........................................................................................................
|
45
|
+
def on_message_normal(pipe, stanza)
|
46
|
+
AgentXmpp.logger.info "RECEIVED NORMAL MESSAGE FROM: #{stanza.from.to_s}"
|
47
|
+
if event = stanza.event
|
48
|
+
on_pubsub_event(pipe, event, stanza.to.to_s, stanza.from.to_s)
|
49
|
+
else
|
50
|
+
on_unsupported_message(pipe, stanza)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#.........................................................................................................
|
55
|
+
# process headline messages
|
56
|
+
#.........................................................................................................
|
57
|
+
def on_message_headline(pipe, stanza)
|
58
|
+
AgentXmpp.logger.info "RECEIVED HEADLINE MESSAGE FROM: #{stanza.from.to_s}"
|
59
|
+
if event = stanza.event
|
60
|
+
on_pubsub_event(pipe, event, stanza.to.to_s, stanza.from.to_s)
|
61
|
+
else
|
62
|
+
on_unsupported_message(pipe, stanza)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
#.........................................................................................................
|
67
|
+
# process events
|
68
|
+
#.........................................................................................................
|
69
|
+
def on_pubsub_event(pipe, event, to, from)
|
70
|
+
AgentXmpp.logger.info "RECEIVED EVENT FROM: #{from.to_s}"
|
71
|
+
event.items.each do |is|
|
72
|
+
src = is.node.split('/')
|
73
|
+
src_jid = "#{src[3]}@#{src[2]}"
|
74
|
+
is.item.each do |i|
|
75
|
+
if Message.update_received_event_item(i, from, is.node)
|
76
|
+
params = {
|
77
|
+
:xmlns => 'http://jabber.org/protocol/pubsub#event',
|
78
|
+
:to => to, :pubsub => from, :node => is.node, :from => src_jid, :id => i.id,
|
79
|
+
:resources => Roster.find_all_by_contact_jid_and_status(Xmpp::Jid.new(src_jid), :available)}
|
80
|
+
if data = i.x and data.type.eql?(:result)
|
81
|
+
params.update(:data => data.to_native)
|
82
|
+
Controller.new(pipe, params).invoke_event
|
83
|
+
elsif entry = i.entry
|
84
|
+
params.update(:data => entry.title)
|
85
|
+
Controller.new(pipe, params).invoke_event
|
86
|
+
else
|
87
|
+
on_unsupported_message(pipe, event)
|
88
|
+
end
|
89
|
+
else
|
90
|
+
on_unsupported_message(pipe, event)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#.........................................................................................................
|
97
|
+
# errors
|
98
|
+
#.........................................................................................................
|
99
|
+
def on_unsupported_message(pipe, stanza)
|
100
|
+
AgentXmpp.logger.info "RECEIVED UNSUPPORTED MESSAGE: #{stanza.to_s}"
|
101
|
+
if stanza.class.eql?(AgentXmpp::Xmpp::Iq)
|
102
|
+
Xmpp::ErrorResponse.feature_not_implemented(stanza)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#.........................................................................................................
|
107
|
+
# connection
|
108
|
+
#.........................................................................................................
|
109
|
+
def on_connect(pipe)
|
110
|
+
AgentXmpp.logger.info "CONNECTED"
|
111
|
+
end
|
112
|
+
|
113
|
+
#.........................................................................................................
|
114
|
+
def on_disconnect(pipe)
|
115
|
+
AgentXmpp.logger.warn "DISCONNECTED"
|
116
|
+
EventMachine::stop_event_loop
|
117
|
+
end
|
118
|
+
|
119
|
+
#.........................................................................................................
|
120
|
+
def on_did_not_connect(pipe)
|
121
|
+
AgentXmpp.logger.warn "CONNECTION FAILED"
|
122
|
+
end
|
123
|
+
|
124
|
+
#.........................................................................................................
|
125
|
+
# authentication
|
126
|
+
#.........................................................................................................
|
127
|
+
def on_bind(pipe)
|
128
|
+
AgentXmpp.logger.info "DID BIND TO RESOURCE: #{AgentXmpp.jid.resource}"
|
129
|
+
Xmpp::Iq.session(pipe) if pipe.stream_features.has_key?('session')
|
130
|
+
end
|
131
|
+
|
132
|
+
#.........................................................................................................
|
133
|
+
def on_preauthenticate_features(pipe)
|
134
|
+
AgentXmpp.logger.info "SESSION INITIALIZED"
|
135
|
+
Xmpp::SASL.authenticate(pipe.stream_mechanisms)
|
136
|
+
end
|
137
|
+
|
138
|
+
#.........................................................................................................
|
139
|
+
def on_authenticate(pipe)
|
140
|
+
AgentXmpp.logger.info "AUTHENTICATED"
|
141
|
+
end
|
142
|
+
|
143
|
+
#.........................................................................................................
|
144
|
+
def on_did_not_authenticate(pipe)
|
145
|
+
AgentXmpp.logger.info "AUTHENTICATION FAILED"
|
146
|
+
raise AgentXmppError, "authentication failed"
|
147
|
+
end
|
148
|
+
|
149
|
+
#.........................................................................................................
|
150
|
+
def on_postauthenticate_features(pipe)
|
151
|
+
AgentXmpp.logger.info "SESSION STARTED"
|
152
|
+
Xmpp::Iq.bind(pipe) if pipe.stream_features.has_key?('bind')
|
153
|
+
end
|
154
|
+
|
155
|
+
#.........................................................................................................
|
156
|
+
def on_start_session(pipe)
|
157
|
+
AgentXmpp.logger.info "SESSION STARTED"
|
158
|
+
add_send_command_request_method(pipe)
|
159
|
+
add_send_chat_method(pipe)
|
160
|
+
[Send(Xmpp::Presence.new(nil, nil, AgentXmpp.priority)), Xmpp::IqRoster.get(pipe),
|
161
|
+
Xmpp::IqDiscoInfo.get(pipe, AgentXmpp.jid.domain)]
|
162
|
+
end
|
163
|
+
|
164
|
+
#.........................................................................................................
|
165
|
+
# presence
|
166
|
+
#.........................................................................................................
|
167
|
+
def on_presence(pipe, presence)
|
168
|
+
from_jid = presence.from
|
169
|
+
if Contact.has_jid?(presence.from) or AgentXmpp.is_account_jid?(from_jid)
|
170
|
+
Roster.update(presence)
|
171
|
+
AgentXmpp.logger.info "RECEIVED PRESENCE FROM: #{from_jid.to_s}"
|
172
|
+
response = []
|
173
|
+
unless from_jid.to_s.eql?(AgentXmpp.jid.to_s)
|
174
|
+
Boot.call_if_implemented(:call_received_presence, from_jid.to_s, :available)
|
175
|
+
response << Xmpp::IqVersion.get(pipe, from_jid) unless Roster.has_version?(from_jid)
|
176
|
+
unless Service.has_jid?(from_jid)
|
177
|
+
response << Xmpp::IqDiscoInfo.get(pipe, from_jid)
|
178
|
+
response << Xmpp::IqDiscoItems.get(pipe, from_jid, 'http://jabber.org/protocol/commands')
|
179
|
+
end
|
180
|
+
end; response
|
181
|
+
else
|
182
|
+
AgentXmpp.logger.warn "RECEIVED PRESENCE FROM JID NOT IN ROSTER: #{from_jid}" unless from_jid.to_s.eql?(AgentXmpp.jid.to_s)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
#.........................................................................................................
|
187
|
+
def on_presence_subscribe(pipe, presence)
|
188
|
+
from_jid = presence.from.to_s
|
189
|
+
if Contact.has_jid?(presence.from)
|
190
|
+
AgentXmpp.logger.info "RECEIVED SUBSCRIBE REQUEST: #{from_jid}"
|
191
|
+
Xmpp::Presence.accept(from_jid)
|
192
|
+
else
|
193
|
+
AgentXmpp.logger.warn "RECEIVED SUBSCRIBE REQUEST FROM JID NOT IN ROSTER: #{from_jid}"
|
194
|
+
Xmpp::Presence.decline(from_jid)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
#.........................................................................................................
|
199
|
+
def on_presence_subscribed(pipe, presence)
|
200
|
+
AgentXmpp.logger.info "SUBSCRIPTION ACCEPTED: #{presence.from.to_s}"
|
201
|
+
end
|
202
|
+
|
203
|
+
#.........................................................................................................
|
204
|
+
def on_presence_unavailable(pipe, presence)
|
205
|
+
from_jid = presence.from
|
206
|
+
if Contact.has_jid?(from_jid) or AgentXmpp.is_account_jid?(from_jid)
|
207
|
+
Roster.update(presence)
|
208
|
+
Boot.call_if_implemented(:call_received_presence, from_jid.to_s, :unavailable)
|
209
|
+
AgentXmpp.logger.info "RECEIVED UNAVAILABLE PRESENCE FROM: #{from_jid.to_s }"
|
210
|
+
else
|
211
|
+
AgentXmpp.logger.warn "RECEIVED UNAVAILABLE PRESENCE FROM JID NOT IN ROSTER: #{from_jid}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
#.........................................................................................................
|
216
|
+
def on_presence_unsubscribed(pipe, presence)
|
217
|
+
from_jid = presence.from
|
218
|
+
if Contact.has_jid?(from_jid)
|
219
|
+
Contact.destroy_by_jid(from_jid)
|
220
|
+
AgentXmpp.logger.info "RECEIVED UNSUBSCRIBED REQUEST: #{from_jid.to_s}"
|
221
|
+
Xmpp::IqRoster.remove(pipe, from_jid)
|
222
|
+
else
|
223
|
+
AgentXmpp.logger.warn "RECEIVED UNSUBSCRIBED REQUEST FROM JID NOT IN ROSTER: #{from_jid.to_s}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
#.........................................................................................................
|
228
|
+
def on_presence_error(pipe, presence)
|
229
|
+
from_jid = presence.from
|
230
|
+
AgentXmpp.logger.warn "RECEIVED PRESENCE ERROR FROM: #{presence.from.to_s}"
|
231
|
+
if Contact.has_jid?(presence.from) or AgentXmpp.is_account_jid?(from_jid)
|
232
|
+
AgentXmpp.logger.warn "REMOVING '#{presence.from.to_s}' FROM ROSTER"
|
233
|
+
Xmpp::IqRoster.remove(pipe, from_jid.to_s)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
#.........................................................................................................
|
238
|
+
# roster management
|
239
|
+
#.........................................................................................................
|
240
|
+
def on_roster_result(pipe, stanza)
|
241
|
+
process_roster_items(pipe, stanza)
|
242
|
+
end
|
243
|
+
|
244
|
+
#.........................................................................................................
|
245
|
+
def on_roster_set(pipe, stanza)
|
246
|
+
process_roster_items(pipe, stanza)
|
247
|
+
end
|
248
|
+
|
249
|
+
#.........................................................................................................
|
250
|
+
def on_roster_item(pipe, roster_item)
|
251
|
+
roster_item_jid = roster_item.jid
|
252
|
+
AgentXmpp.logger.info "RECEIVED ROSTER ITEM: #{roster_item_jid.to_s}"
|
253
|
+
if Contact.has_jid?(roster_item_jid)
|
254
|
+
case roster_item.subscription
|
255
|
+
when :none
|
256
|
+
if roster_item.ask.eql?(:subscribe)
|
257
|
+
AgentXmpp.logger.info "CONTACT SUBSCRIPTION PENDING: #{roster_item_jid.to_s}"
|
258
|
+
roster_item.subscription = :ask
|
259
|
+
else
|
260
|
+
AgentXmpp.logger.info "CONTACT ADDED TO ROSTER: #{roster_item_jid.to_s}"
|
261
|
+
roster_item.subscription = :added
|
262
|
+
end
|
263
|
+
when :to
|
264
|
+
AgentXmpp.logger.info "SUBSCRIBED TO CONTACT PRESENCE: #{roster_item_jid.to_s}"
|
265
|
+
when :from
|
266
|
+
AgentXmpp.logger.info "CONTACT SUBSCRIBED TO PRESENCE: #{roster_item_jid.to_s}"
|
267
|
+
when :both
|
268
|
+
AgentXmpp.logger.info "CONTACT SUBSCRIPTION BIDIRECTIONAL: #{roster_item_jid.to_s}"
|
269
|
+
end
|
270
|
+
Contact.update_with_roster_item(roster_item)
|
271
|
+
check_roster_item_group(pipe, roster_item)
|
272
|
+
else
|
273
|
+
AgentXmpp.logger.info "REMOVING ROSTER ITEM: #{roster_item_jid.to_s}"
|
274
|
+
Xmpp::IqRoster.remove(pipe, roster_item_jid)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
#.........................................................................................................
|
279
|
+
def on_remove_roster_item(pipe, roster_item)
|
280
|
+
AgentXmpp.logger.info "REMOVE ROSTER ITEM"
|
281
|
+
roster_item_jid = roster_item.jid
|
282
|
+
if Contact.has_jid?(roster_item_jid)
|
283
|
+
AgentXmpp.logger.info "REMOVED ROSTER ITEM: #{roster_item_jid.to_s}"
|
284
|
+
Contact.destroy_by_jid(roster_item_jid)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
#.........................................................................................................
|
289
|
+
def on_all_roster_items(pipe)
|
290
|
+
AgentXmpp.logger.info "RECEIVED ALL ROSTER ITEMS"
|
291
|
+
Contact.find_all_by_subscription(:new).map do |r|
|
292
|
+
AgentXmpp.logger.info "ADDING CONTACT: #{r[:jid]}"
|
293
|
+
[Xmpp::IqRoster.update(pipe, r[:jid], r[:groups].split(/,/)), Xmpp::Presence.subscribe(r[:jid])]
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
#.........................................................................................................
|
298
|
+
def on_update_roster_item_result(pipe, roster_item_jid)
|
299
|
+
AgentXmpp.logger.info "UPDATE ROSTER ITEM ACKNOWLEDEGED FROM: #{roster_item_jid}"
|
300
|
+
end
|
301
|
+
|
302
|
+
#.........................................................................................................
|
303
|
+
def on_update_roster_item_error(pipe, roster_item_jid)
|
304
|
+
AgentXmpp.logger.info "UPDATE ROSTER ITEM RECEIVED ERROR REMOVING: #{roster_item_jid}"
|
305
|
+
end
|
306
|
+
|
307
|
+
#.........................................................................................................
|
308
|
+
def on_remove_roster_item_result(pipe, roster_item_jid)
|
309
|
+
AgentXmpp.logger.info "REMOVE ROSTER ITEM ACKNOWLEDEGED FROM: #{roster_item_jid}"
|
310
|
+
end
|
311
|
+
|
312
|
+
#.........................................................................................................
|
313
|
+
def on_remove_roster_item_error(pipe, roster_item_jid)
|
314
|
+
AgentXmpp.logger.info "REMOVE ROSTER ITEM RECEIVED ERROR REMOVING: #{roster_item_jid}"
|
315
|
+
end
|
316
|
+
|
317
|
+
#.........................................................................................................
|
318
|
+
# service discovery management
|
319
|
+
#.........................................................................................................
|
320
|
+
def on_version_result(pipe, version)
|
321
|
+
from_jid, query = version.from, version.query
|
322
|
+
AgentXmpp.logger.info "RECEIVED VERSION RESULT: #{from_jid.to_s}, #{query.iname}, #{query.version}"
|
323
|
+
Roster.update(query, from_jid)
|
324
|
+
end
|
325
|
+
|
326
|
+
#.........................................................................................................
|
327
|
+
def on_version_get(pipe, request)
|
328
|
+
from_jid = request.from
|
329
|
+
if Contact.has_jid?(from_jid) or AgentXmpp.is_account_jid?(from_jid)
|
330
|
+
AgentXmpp.logger.info "RECEIVED VERSION REQUEST: #{request.from.to_s}"
|
331
|
+
Xmpp::IqVersion.result(pipe, request)
|
332
|
+
else
|
333
|
+
AgentXmpp.logger.warn "RECEIVED VERSION REQUEST FROM JID NOT IN ROSTER: #{request.from.to_s}"
|
334
|
+
Xmpp::ErrorResponse.service_unavailable(request)
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
#.........................................................................................................
|
339
|
+
def on_version_error(pipe, result)
|
340
|
+
from_jid = result.from
|
341
|
+
AgentXmpp.logger.warn "RECEIVED VERSION ERROR FROM: #{from_jid.to_s}"
|
342
|
+
end
|
343
|
+
|
344
|
+
#.........................................................................................................
|
345
|
+
def on_discoinfo_get(pipe, request)
|
346
|
+
from_jid = request.from
|
347
|
+
if Contact.has_jid?(from_jid) or AgentXmpp.is_account_jid?(from_jid)
|
348
|
+
if request.query.node.nil?
|
349
|
+
AgentXmpp.logger.info "RECEIVED DISCO INFO REQUEST FROM: #{from_jid.to_s}"
|
350
|
+
Xmpp::IqDiscoInfo.result(pipe, request)
|
351
|
+
else
|
352
|
+
AgentXmpp.logger.info "RECEIVED DISCO INFO REQUEST FOR UNSUPPORTED NODE FROM: #{from_jid.to_s}"
|
353
|
+
Xmpp::ErrorResponse.item_not_found(request)
|
354
|
+
end
|
355
|
+
else
|
356
|
+
AgentXmpp.logger.warn "RECEIVED DISCO INFO REQUEST FROM JID NOT IN ROSTER: #{from_jid.to_s}"
|
357
|
+
Xmpp::ErrorResponse.service_unavailable(request)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
#.........................................................................................................
|
362
|
+
def on_discoinfo_result(pipe, discoinfo)
|
363
|
+
from_jid = discoinfo.from
|
364
|
+
do_discoitems = true
|
365
|
+
request = []
|
366
|
+
q = discoinfo.query
|
367
|
+
AgentXmpp.logger.info "RECEIVED DISCO INFO RESULT FROM: #{from_jid.to_s}" + (q.node.nil? ? '' : ", NODE: #{q.node}")
|
368
|
+
Service.update(discoinfo)
|
369
|
+
q.identities.each do |i|
|
370
|
+
AgentXmpp.logger.info " IDENTITY: NAME:#{i.iname}, CATEGORY:#{i.category}, TYPE:#{i.type}"
|
371
|
+
request << case i.category
|
372
|
+
when 'server' then Xmpp::IqDiscoItems.get(pipe, from_jid.to_s, q.node)
|
373
|
+
when 'pubsub' then process_pubsub_discoinfo(i.type, pipe, from_jid, q.node)
|
374
|
+
when 'conference'
|
375
|
+
when 'proxy'
|
376
|
+
when 'directory'
|
377
|
+
when 'client'
|
378
|
+
when 'automation'
|
379
|
+
when 'auth'
|
380
|
+
when 'collaboration'
|
381
|
+
when 'componenet'
|
382
|
+
when 'gateway'
|
383
|
+
when 'hierarchy'
|
384
|
+
when 'headline'
|
385
|
+
when 'store'
|
386
|
+
end
|
387
|
+
end
|
388
|
+
q.features.each do |f|
|
389
|
+
AgentXmpp.logger.info " FEATURE: #{f}"
|
390
|
+
end
|
391
|
+
request.smash
|
392
|
+
end
|
393
|
+
|
394
|
+
#.........................................................................................................
|
395
|
+
def on_discoinfo_error(pipe, result)
|
396
|
+
from_jid = result.from
|
397
|
+
AgentXmpp.logger.warn "RECEIVED DISCO INFO ERROR FROM: #{from_jid.to_s}, #{result.query.node}"
|
398
|
+
end
|
399
|
+
|
400
|
+
#.........................................................................................................
|
401
|
+
def on_discoitems_get(pipe, request)
|
402
|
+
from_jid = request.from
|
403
|
+
if Contact.has_jid?(from_jid) or AgentXmpp.is_account_jid?(from_jid)
|
404
|
+
if request.query.node.eql?('http://jabber.org/protocol/commands')
|
405
|
+
AgentXmpp.logger.info "RECEIVED COMMAND NODE DISCO ITEMS REQUEST FROM: #{from_jid.to_s}"
|
406
|
+
Xmpp::IqDiscoItems.result_command_nodes(pipe, request)
|
407
|
+
elsif request.query.node.nil?
|
408
|
+
AgentXmpp.logger.info "RECEIVED DISCO ITEMS REQUEST FROM: #{from_jid.to_s}"
|
409
|
+
Xmpp::IqDiscoItems.result(pipe, request)
|
410
|
+
else
|
411
|
+
AgentXmpp.logger.info "RECEIVED DISCO INFO REQUEST FOR UNSUPPORTED NODE FROM: #{from_jid.to_s}"
|
412
|
+
Xmpp::ErrorResponse.item_not_found(request)
|
413
|
+
end
|
414
|
+
else
|
415
|
+
AgentXmpp.logger.warn "RECEIVED DISCO ITEMS REQUEST FROM JID NOT IN ROSTER: #{from_jid.to_s}"
|
416
|
+
Xmpp::ErrorResponse.service_unavailable(request)
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
#.........................................................................................................
|
421
|
+
def on_discoitems_result(pipe, discoitems)
|
422
|
+
from_jid = discoitems.from
|
423
|
+
q = discoitems.query
|
424
|
+
AgentXmpp.logger.info "RECEIVED DISCO ITEMS RESULT FROM: #{from_jid.to_s}" + (q.node.nil? ? '' : ", NODE: #{q.node}")
|
425
|
+
Service.update(discoitems)
|
426
|
+
case q.node
|
427
|
+
when 'http://jabber.org/protocol/commands'
|
428
|
+
Boot.call_if_implemented(:call_discovered_command_nodes, from_jid.to_s, q.items.map{|i| i.node}) unless q.items.empty?
|
429
|
+
else
|
430
|
+
msgs = if from_jid.to_s.eql?(pubsub_service.to_s) and q.node.eql?(AgentXmpp.pubsub_root)
|
431
|
+
create_user_pubsub_root(pipe, from_jid, q.items)
|
432
|
+
else ; []; end
|
433
|
+
if from_jid.to_s.eql?(pubsub_service.to_s) and q.node.eql?(AgentXmpp.user_pubsub_root)
|
434
|
+
msgs += update_publish_nodes(pipe, from_jid, q.items)
|
435
|
+
end
|
436
|
+
q.items.inject(msgs) do |r,i|
|
437
|
+
AgentXmpp.logger.info " ITEM JID: #{i.jid}" + (i.node.nil? ? '' : ", NODE: #{i.node}")
|
438
|
+
r << Xmpp::IqDiscoInfo.get(pipe, i.jid, i.node)
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
#.........................................................................................................
|
444
|
+
def on_discoitems_error(pipe, result)
|
445
|
+
from_jid = result.from
|
446
|
+
AgentXmpp.logger.warn "RECEIVED DISCO ITEMS ERROR FROM: #{from_jid.to_s}"
|
447
|
+
end
|
448
|
+
|
449
|
+
#.........................................................................................................
|
450
|
+
# pubsub
|
451
|
+
#.........................................................................................................
|
452
|
+
def on_publish_result(pipe, result, node)
|
453
|
+
AgentXmpp.logger.info "PUBLISH TO NODE ACKNOWLEDEGED: #{node}, #{result.from.to_s}"
|
454
|
+
end
|
455
|
+
|
456
|
+
#.........................................................................................................
|
457
|
+
def on_publish_error(pipe, result, node)
|
458
|
+
AgentXmpp.logger.info "ERROR PUBLISING TO NODE: #{node}, #{result.from.to_s}"
|
459
|
+
end
|
460
|
+
|
461
|
+
#.........................................................................................................
|
462
|
+
def on_discovery_of_pupsub_service(pipe, jid)
|
463
|
+
AgentXmpp.logger.info "DISCOVERED PUBSUB SERVICE: #{jid}"
|
464
|
+
req = [Xmpp::IqPubSub.subscriptions(pipe, jid.to_s)]
|
465
|
+
if /#{AgentXmpp.jid.domain}/.match(jid.to_s)
|
466
|
+
add_publish_methods(pipe, jid)
|
467
|
+
@pubsub_service = jid
|
468
|
+
req += [Xmpp::IqDiscoItems.get(pipe, jid.to_s)] + init_remote_services(pipe)
|
469
|
+
end; req
|
470
|
+
end
|
471
|
+
|
472
|
+
#.........................................................................................................
|
473
|
+
def on_discovery_of_pupsub_collection(pipe, jid, node)
|
474
|
+
AgentXmpp.logger.info "DISCOVERED PUBSUB COLLECTION: #{jid}, #{node}"
|
475
|
+
Xmpp::IqDiscoItems.get(pipe, jid, node) if pubsub_service.eql?(jid)
|
476
|
+
end
|
477
|
+
|
478
|
+
#.........................................................................................................
|
479
|
+
def on_discovery_of_pupsub_leaf(pipe, jid, node)
|
480
|
+
AgentXmpp.logger.info "DISCOVERED PUBSUB LEAF: #{jid}, #{node}"
|
481
|
+
if node.eql?(AgentXmpp.pubsub_root) or node.eql?(AgentXmpp.user_pubsub_root)
|
482
|
+
Xmpp::IqDiscoItems.get(pipe, jid, node)
|
483
|
+
else
|
484
|
+
Boot.call_if_implemented(:call_discovered_pubsub_node, jid, node)
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
#.........................................................................................................
|
489
|
+
def on_discovery_of_user_pubsub_root(pipe, pubsub, node)
|
490
|
+
AgentXmpp.logger.info "DISCOVERED USER PUBSUB ROOT: #{pubsub.to_s}, #{node}"
|
491
|
+
end
|
492
|
+
|
493
|
+
#.........................................................................................................
|
494
|
+
def on_pubsub_subscriptions_result(pipe, result)
|
495
|
+
from_jid = result.from.to_s
|
496
|
+
AgentXmpp.logger.info "RECEIVED SUBSCRIPTIONS FROM: #{from_jid}"
|
497
|
+
app_subs = BaseController.subscriptions(result.from.domain)
|
498
|
+
srvr_subs = result.pubsub.subscriptions.map do |s|
|
499
|
+
AgentXmpp.logger.info "SUBSCRIBED TO NODE: #{from_jid}, #{s.node}"
|
500
|
+
Subscription.update(s, s.node, from_jid); s.node
|
501
|
+
end
|
502
|
+
reqs = app_subs.inject([]) do |r,s|
|
503
|
+
unless srvr_subs.include?(s)
|
504
|
+
AgentXmpp.logger.info "SUBSCRIBING TO NODE: #{from_jid}, #{s}"
|
505
|
+
r << Xmpp::IqPubSub.subscribe(pipe, from_jid, s)
|
506
|
+
end; r
|
507
|
+
end
|
508
|
+
srvr_subs.inject(reqs) do |r,s|
|
509
|
+
unless app_subs.include?(s)
|
510
|
+
AgentXmpp.logger.warn "UNSUBSCRIBING FROM NODE: #{from_jid}, #{s}"
|
511
|
+
r << Xmpp::IqPubSub.unsubscribe(pipe, from_jid, s)
|
512
|
+
end; r
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
#.........................................................................................................
|
517
|
+
def on_pubsub_subscriptions_error(pipe, result)
|
518
|
+
from_jid = result.from
|
519
|
+
AgentXmpp.logger.warn "RECEIVED ERROR ON SUBSCRIPTION REQUEST FROM: #{from_jid}"
|
520
|
+
end
|
521
|
+
|
522
|
+
#.........................................................................................................
|
523
|
+
def on_pubsub_affiliations_result(pipe, result)
|
524
|
+
from_jid = result.from
|
525
|
+
AgentXmpp.logger.info "RECEIVED AFFILIATIONS FROM: #{from_jid}"
|
526
|
+
end
|
527
|
+
|
528
|
+
#.........................................................................................................
|
529
|
+
def on_pubsub_affiliations_error(pipe, result)
|
530
|
+
from_jid = result.from
|
531
|
+
AgentXmpp.logger.info "RECEIVED ERROR ON AFFILIATIONS REQUEST FROM: #{from_jid}"
|
532
|
+
end
|
533
|
+
|
534
|
+
#.........................................................................................................
|
535
|
+
def on_pubsub_create_node_result(pipe, result, node)
|
536
|
+
from_jid = result.from
|
537
|
+
Publication.update_status(node, :active)
|
538
|
+
Boot.call_if_implemented(:call_discovered_pubsub_node, from_jid, node)
|
539
|
+
AgentXmpp.logger.info "RECEIVED CREATE NODE RESULT FROM: #{from_jid.to_s}, #{node}"
|
540
|
+
if node.eql?(AgentXmpp.user_pubsub_root)
|
541
|
+
[on_discovery_of_user_pubsub_root(pipe, from_jid, node), Xmpp::IqDiscoInfo.get(pipe, from_jid.to_s, node)]
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
#.........................................................................................................
|
546
|
+
def on_pubsub_create_node_error(pipe, result, node)
|
547
|
+
from_jid = result.from
|
548
|
+
Publication.update_status(node, :error)
|
549
|
+
AgentXmpp.logger.info "RECEIVED CREATE NODE ERROR FROM: #{from_jid.to_s}, #{node}"
|
550
|
+
end
|
551
|
+
|
552
|
+
#.........................................................................................................
|
553
|
+
def on_pubsub_delete_node_result(pipe, result, node)
|
554
|
+
from_jid = result.from
|
555
|
+
AgentXmpp.logger.info "RECEIVED DELETE NODE RESULT FROM: #{from_jid.to_s}, #{node}"
|
556
|
+
end
|
557
|
+
|
558
|
+
#.........................................................................................................
|
559
|
+
def on_pubsub_delete_node_error(pipe, result, node)
|
560
|
+
from_jid = result.from
|
561
|
+
AgentXmpp.logger.info "RECEIVED DELETE NODE ERROR FROM: #{from_jid.to_s}, #{node}"
|
562
|
+
end
|
563
|
+
|
564
|
+
#.........................................................................................................
|
565
|
+
def on_pubsub_subscribe_result(pipe, result, node)
|
566
|
+
from_jid = result.from.to_s
|
567
|
+
Subscription.update(result, node, from_jid)
|
568
|
+
AgentXmpp.logger.info "RECEIVED SUBSCRIBE RESULT FROM: #{from_jid}, #{node}"
|
569
|
+
end
|
570
|
+
|
571
|
+
#.........................................................................................................
|
572
|
+
def on_pubsub_subscribe_error(pipe, result, node)
|
573
|
+
from_jid = result.from
|
574
|
+
AgentXmpp.logger.warn "RECEIVED SUBSCRIBE ERROR FROM: #{from_jid.to_s}, #{node}"
|
575
|
+
on_pubsub_subscribe_error_item_not_found(pipe, result, node) if result.error.error.eql?('item-not-found')
|
576
|
+
end
|
577
|
+
|
578
|
+
#.........................................................................................................
|
579
|
+
def on_pubsub_subscribe_error_item_not_found(pipe, result, node)
|
580
|
+
from_jid = result.from
|
581
|
+
AgentXmpp.logger.warn "RECEIVED SUBSCRIBE ERROR ITEM-NOT-FOUND FROM: #{from_jid.to_s}, #{node}; " +
|
582
|
+
"RETRYING SUBSCRIPTION IN #{AgentXmpp::SUBSCRIBE_RETRY_PERIOD}s"
|
583
|
+
EventMachine::Timer.new(AgentXmpp::SUBSCRIBE_RETRY_PERIOD) do
|
584
|
+
pipe.send_resp(Xmpp::IqPubSub.subscribe(pipe, from_jid.to_s, node))
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
#.........................................................................................................
|
589
|
+
def on_pubsub_unsubscribe_result(pipe, result, node)
|
590
|
+
from_jid = result.from
|
591
|
+
Subscription.destroy_by_node(node)
|
592
|
+
AgentXmpp.logger.info "RECEIVED UNSUBSCRIBE RESULT FROM: #{from_jid.to_s}, #{node}"
|
593
|
+
end
|
594
|
+
|
595
|
+
#.........................................................................................................
|
596
|
+
def on_pubsub_unsubscribe_error(pipe, result, node)
|
597
|
+
from_jid = result.from
|
598
|
+
AgentXmpp.logger.info "RECEIVED UNSUBSCRIBE ERROR FROM: #{from_jid.to_s}, #{node}"
|
599
|
+
end
|
600
|
+
|
601
|
+
#.........................................................................................................
|
602
|
+
# private
|
603
|
+
#.........................................................................................................
|
604
|
+
def check_roster_item_group(pipe, roster_item)
|
605
|
+
roster_item_jid = roster_item.jid
|
606
|
+
roster_item_groups = Contact.find_by_jid(roster_item_jid)[:groups].split(/,/).sort
|
607
|
+
unless roster_item.groups.sort.eql?(roster_item_groups)
|
608
|
+
AgentXmpp.logger.info "CHANGE IN ROSTER ITEM GROUP FOUND UPDATING: #{roster_item_jid.to_s} to '#{roster_item_groups.join(', ')}'"
|
609
|
+
Xmpp::IqRoster.update(pipe, roster_item_jid.to_s, roster_item_groups)
|
610
|
+
end
|
611
|
+
end
|
612
|
+
|
613
|
+
#.........................................................................................................
|
614
|
+
def process_pubsub_discoinfo(type, pipe, from, node)
|
615
|
+
case type
|
616
|
+
when 'service' then pipe.broadcast_to_delegates(:on_discovery_of_pupsub_service, pipe, from)
|
617
|
+
when 'collection' then pipe.broadcast_to_delegates(:on_discovery_of_pupsub_collection, pipe, from, node)
|
618
|
+
when 'leaf' then pipe.broadcast_to_delegates(:on_discovery_of_pupsub_leaf, pipe, from, node)
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
#.........................................................................................................
|
623
|
+
def process_roster_items(pipe, stanza)
|
624
|
+
[stanza.query.inject([]) do |r, i|
|
625
|
+
method = i.subscription.eql?(:remove) ? :on_remove_roster_item : :on_roster_item
|
626
|
+
r.push(pipe.broadcast_to_delegates(method, pipe, i))
|
627
|
+
end, pipe.broadcast_to_delegates(:on_all_roster_items, pipe)].smash
|
628
|
+
end
|
629
|
+
|
630
|
+
#.........................................................................................................
|
631
|
+
def add_publish_methods(pipe, pubsub)
|
632
|
+
Publication.find_all.each do |pub|
|
633
|
+
if pub[:node]
|
634
|
+
meth = ("publish_" + pub[:node].gsub(/-/,'_')).to_sym
|
635
|
+
unless AgentXmpp.respond_to?(meth)
|
636
|
+
AgentXmpp.define_meta_class_method(meth) do |payload|
|
637
|
+
pipe.send_resp(Xmpp::IqPublish.set(pipe, :node => pub[:node], :to => pubsub, :payload => payload.to_x_data))
|
638
|
+
end
|
639
|
+
AgentXmpp.logger.info "ADDED PUBLISH METHOD FOR NODE: #{pub[:node]}, #{pubsub}"
|
640
|
+
Delegator.delegate(AgentXmpp, meth)
|
641
|
+
else
|
642
|
+
AgentXmpp.logger.warn "PUBLISH METHOD FOR NODE EXISTS: #{pub[:node]}, #{pubsub}"
|
643
|
+
end
|
644
|
+
else
|
645
|
+
AgentXmpp.logger.warn "NODE NOT SPECIFIED FOR PUBSUB PUBLISH CONFIGURATION"
|
646
|
+
end
|
647
|
+
end
|
648
|
+
end
|
649
|
+
|
650
|
+
#.........................................................................................................
|
651
|
+
def add_send_command_request_method(pipe)
|
652
|
+
AgentXmpp.define_meta_class_method(:send_command_request) do |args, &blk|
|
653
|
+
pipe.send_resp(Xmpp::IqCommand.send_command(:to=>args[:to], :node=>args[:node], :iq_type=>:set,
|
654
|
+
:action=>:execute, :payload=>args[:payload], &blk))
|
655
|
+
end
|
656
|
+
Delegator.delegate(AgentXmpp, :send_command_request)
|
657
|
+
AgentXmpp.logger.info "ADDED SEND_COMMAND_REQUEST METHOD"
|
658
|
+
end
|
659
|
+
|
660
|
+
#.........................................................................................................
|
661
|
+
def add_send_chat_method(pipe)
|
662
|
+
AgentXmpp.define_meta_class_method(:send_chat) do |args|
|
663
|
+
raise ArgmentError ':to and :body are required' unless args[:to] and args[:body]
|
664
|
+
message = Xmpp::Message.new(args[:to], args[:body])
|
665
|
+
message.type = args[:type] || :chat
|
666
|
+
pipe.send_resp(Send(message))
|
667
|
+
end
|
668
|
+
Delegator.delegate(AgentXmpp, :send_chat)
|
669
|
+
AgentXmpp.logger.info "ADDED MESSAGE METHOD"
|
670
|
+
end
|
671
|
+
|
672
|
+
#.........................................................................................................
|
673
|
+
def create_user_pubsub_root(pipe, pubsub, items)
|
674
|
+
if (roots = items.select{|i| i.node.eql?(AgentXmpp.user_pubsub_root)}).empty?
|
675
|
+
AgentXmpp.logger.info "USER PUBSUB ROOT NOT FOUND CREATING NODE: #{pubsub.to_s}, #{AgentXmpp.user_pubsub_root}"
|
676
|
+
[Xmpp::IqPubSub.create_node(pipe, pubsub.to_s, AgentXmpp.user_pubsub_root)]
|
677
|
+
else
|
678
|
+
AgentXmpp.logger.info "USER PUBSUB ROOT FOUND: #{pubsub.to_s}, #{AgentXmpp.user_pubsub_root}"
|
679
|
+
on_discovery_of_user_pubsub_root(pipe, pubsub, AgentXmpp.user_pubsub_root); []
|
680
|
+
end
|
681
|
+
end
|
682
|
+
|
683
|
+
#.........................................................................................................
|
684
|
+
def update_publish_nodes(pipe, pubsub, items)
|
685
|
+
disco_nodes = items.map{|i| i.node}
|
686
|
+
config_nodes = Publication.find_all.map{|pub| "#{AgentXmpp.user_pubsub_root}/#{pub[:node]}"}
|
687
|
+
updates = disco_nodes.inject([]) do |u,n|
|
688
|
+
unless config_nodes.include?(n)
|
689
|
+
AgentXmpp.logger.warn "DELETING PUBSUB NODE: #{pubsub.to_s}, #{n}"
|
690
|
+
u << Xmpp::IqPubSubOwner.delete_node(pipe, pubsub.to_s, n)
|
691
|
+
end; u
|
692
|
+
end
|
693
|
+
config_nodes.inject(updates) do |u,n|
|
694
|
+
unless disco_nodes.include?(n)
|
695
|
+
AgentXmpp.logger.info "ADDING PUBSUB NODE: #{pubsub.to_s}, #{n}"
|
696
|
+
u << Xmpp::IqPubSub.create_node(pipe, pubsub.to_s, n)
|
697
|
+
end; u
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
#.........................................................................................................
|
702
|
+
def init_remote_services(pipe)
|
703
|
+
(BaseController.event_domains-[AgentXmpp.jid.domain]).map do |d|
|
704
|
+
Xmpp::IqDiscoInfo.get(pipe, d)
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
#.........................................................................................................
|
709
|
+
private :init_remote_services, :update_publish_nodes, :create_user_pubsub_root, :add_send_chat_method,
|
710
|
+
:add_send_command_request_method, :add_publish_methods, :process_roster_items, :process_pubsub_discoinfo,
|
711
|
+
:check_roster_item_group
|
712
|
+
|
713
|
+
#### self
|
714
|
+
end
|
715
|
+
|
716
|
+
#### MessagePipe
|
717
|
+
end
|
718
|
+
|
719
|
+
#### AgentXmpp
|
720
|
+
end
|