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.
Files changed (73) hide show
  1. data/.document +5 -0
  2. data/.gitignore +11 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +417 -0
  5. data/Rakefile +75 -0
  6. data/VERSION +1 -0
  7. data/agent_xmpp.gemspec +144 -0
  8. data/lib/agent_xmpp.rb +22 -0
  9. data/lib/agent_xmpp/admin.rb +113 -0
  10. data/lib/agent_xmpp/client.rb +7 -0
  11. data/lib/agent_xmpp/client/boot.rb +83 -0
  12. data/lib/agent_xmpp/client/client.rb +64 -0
  13. data/lib/agent_xmpp/client/connection.rb +108 -0
  14. data/lib/agent_xmpp/client/controller.rb +394 -0
  15. data/lib/agent_xmpp/client/message_delegate.rb +720 -0
  16. data/lib/agent_xmpp/client/message_pipe.rb +193 -0
  17. data/lib/agent_xmpp/client/response.rb +102 -0
  18. data/lib/agent_xmpp/config.rb +48 -0
  19. data/lib/agent_xmpp/main.rb +175 -0
  20. data/lib/agent_xmpp/models.rb +7 -0
  21. data/lib/agent_xmpp/models/contact.rb +85 -0
  22. data/lib/agent_xmpp/models/message.rb +152 -0
  23. data/lib/agent_xmpp/models/publication.rb +53 -0
  24. data/lib/agent_xmpp/models/roster.rb +107 -0
  25. data/lib/agent_xmpp/models/service.rb +91 -0
  26. data/lib/agent_xmpp/models/subscription.rb +61 -0
  27. data/lib/agent_xmpp/models/table_definitions.rb +107 -0
  28. data/lib/agent_xmpp/patches.rb +7 -0
  29. data/lib/agent_xmpp/patches/array.rb +32 -0
  30. data/lib/agent_xmpp/patches/float.rb +10 -0
  31. data/lib/agent_xmpp/patches/hash.rb +13 -0
  32. data/lib/agent_xmpp/patches/object.rb +15 -0
  33. data/lib/agent_xmpp/patches/rexml.rb +69 -0
  34. data/lib/agent_xmpp/patches/string.rb +15 -0
  35. data/lib/agent_xmpp/xmpp.rb +18 -0
  36. data/lib/agent_xmpp/xmpp/element.rb +158 -0
  37. data/lib/agent_xmpp/xmpp/entry.rb +36 -0
  38. data/lib/agent_xmpp/xmpp/error_response.rb +189 -0
  39. data/lib/agent_xmpp/xmpp/iq.rb +90 -0
  40. data/lib/agent_xmpp/xmpp/iq_command.rb +54 -0
  41. data/lib/agent_xmpp/xmpp/iq_disco.rb +206 -0
  42. data/lib/agent_xmpp/xmpp/iq_pubsub.rb +270 -0
  43. data/lib/agent_xmpp/xmpp/iq_roster.rb +183 -0
  44. data/lib/agent_xmpp/xmpp/iq_version.rb +89 -0
  45. data/lib/agent_xmpp/xmpp/jid.rb +150 -0
  46. data/lib/agent_xmpp/xmpp/message.rb +82 -0
  47. data/lib/agent_xmpp/xmpp/presence.rb +127 -0
  48. data/lib/agent_xmpp/xmpp/sasl.rb +241 -0
  49. data/lib/agent_xmpp/xmpp/stanza.rb +107 -0
  50. data/lib/agent_xmpp/xmpp/x_data.rb +357 -0
  51. data/test/app/app.rb +339 -0
  52. data/test/cases/test_application_message_processing.rb +65 -0
  53. data/test/cases/test_errors.rb +24 -0
  54. data/test/cases/test_presence_management.rb +139 -0
  55. data/test/cases/test_roster_management.rb +214 -0
  56. data/test/cases/test_service_discovery.rb +168 -0
  57. data/test/cases/test_session_management.rb +120 -0
  58. data/test/cases/test_version_discovery.rb +67 -0
  59. data/test/helpers/matchers.rb +23 -0
  60. data/test/helpers/mocks.rb +82 -0
  61. data/test/helpers/test_case_extensions.rb +45 -0
  62. data/test/helpers/test_client.rb +44 -0
  63. data/test/helpers/test_delegate.rb +60 -0
  64. data/test/helpers/test_helper.rb +91 -0
  65. data/test/messages/application_messages.rb +206 -0
  66. data/test/messages/error_messages.rb +35 -0
  67. data/test/messages/presence_messages.rb +66 -0
  68. data/test/messages/roster_messages.rb +126 -0
  69. data/test/messages/service_discovery_messages.rb +201 -0
  70. data/test/messages/session_messages.rb +158 -0
  71. data/test/messages/version_discovery_messages.rb +69 -0
  72. data/test/peer/peer.rb +21 -0
  73. metadata +187 -0
@@ -0,0 +1,7 @@
1
+ require 'agent_xmpp/models/table_definitions'
2
+ require 'agent_xmpp/models/contact'
3
+ require 'agent_xmpp/models/roster'
4
+ require 'agent_xmpp/models/service'
5
+ require 'agent_xmpp/models/publication'
6
+ require 'agent_xmpp/models/subscription'
7
+ require 'agent_xmpp/models/message'
@@ -0,0 +1,85 @@
1
+ ##############################################################################################################
2
+ module AgentXmpp
3
+
4
+ #####-------------------------------------------------------------------------------------------------------
5
+ class Contact
6
+
7
+ #####-------------------------------------------------------------------------------------------------------
8
+ class << self
9
+
10
+ #.........................................................................................................
11
+ def contacts
12
+ @contacts ||= AgentXmpp.agent_xmpp_db[:contacts]
13
+ end
14
+
15
+ #.........................................................................................................
16
+ def load_config
17
+ if AgentXmpp.config['roster'].kind_of?(Array)
18
+ AgentXmpp.config['roster'].each {|c| update(c)}
19
+ end
20
+ end
21
+
22
+ #.........................................................................................................
23
+ def update(contact)
24
+ groups = contact['groups'].kind_of?(Array) ? contact['groups'].join(",") : contact['groups']
25
+ begin
26
+ contacts << {:jid => contact['jid'], :groups => groups, :subscription => 'new', :ask => 'new'}
27
+ rescue
28
+ contacts.filter(:jid => contact['jid']).update(:groups => groups)
29
+ end
30
+ end
31
+
32
+ #.........................................................................................................
33
+ def update_with_roster_item(roster_item)
34
+ from_jid, subscription, ask = roster_item.jid.to_s, roster_item.subscription.to_s, roster_item.ask.to_s
35
+ contacts.filter(:jid => from_jid).update(:subscription => subscription, :ask => ask)
36
+ end
37
+
38
+ #.........................................................................................................
39
+ def find_all
40
+ contacts.all
41
+ end
42
+
43
+ #.........................................................................................................
44
+ def find_by_jid(jid)
45
+ contacts[:jid => AgentXmpp.bare_jid_to_s(jid)]
46
+ end
47
+
48
+ #.........................................................................................................
49
+ def find_all_by_subscription(subscription)
50
+ contacts.filter(:subscription => subscription.to_s).all
51
+ end
52
+
53
+ #.........................................................................................................
54
+ def has_jid?(jid)
55
+ contacts.filter(:jid => AgentXmpp.bare_jid_to_s(jid)).count > 0
56
+ end
57
+
58
+ #.........................................................................................................
59
+ def message_stats
60
+ find_all.map do |c|
61
+ stats = AgentXmpp.agent_xmpp_db["SELECT count(id) AS count, max(created_at) AS last FROM messages WHERE from_jid LIKE '#{c[:jid]}%'"].first
62
+ {:jid=>c[:jid], :count=>stats[:count], :last=>stats[:last].nil? ? 'Never' : Time.parse(stats[:last]).strftime("%y/%m/%d %H:%M")}
63
+ end
64
+ end
65
+
66
+ #.........................................................................................................
67
+ def destroy_by_jid(jid)
68
+ contact = contacts.filter(:jid => AgentXmpp.bare_jid_to_s(jid))
69
+ Roster.destroy_by_contact_id(contact.first[:id])
70
+ contact.delete
71
+ end
72
+
73
+ #.........................................................................................................
74
+ def method_missing(meth, *args, &blk)
75
+ contacts.send(meth, *args, &blk)
76
+ end
77
+
78
+ #### self
79
+ end
80
+
81
+ #### Contact
82
+ end
83
+
84
+ #### AgentXmpp
85
+ end
@@ -0,0 +1,152 @@
1
+ ##############################################################################################################
2
+ module AgentXmpp
3
+
4
+ #####-------------------------------------------------------------------------------------------------------
5
+ class Message
6
+
7
+ #####-------------------------------------------------------------------------------------------------------
8
+ class << self
9
+
10
+ #.........................................................................................................
11
+ def messages(renew=false)
12
+ @messages ||= AgentXmpp.agent_xmpp_db[:messages]
13
+ end
14
+
15
+ #.........................................................................................................
16
+ def update(stanza)
17
+ case stanza
18
+ when AgentXmpp::Xmpp::Message
19
+ if stanza.type.eql?(:chat)
20
+ update_with_chat_message(stanza)
21
+ end
22
+ when AgentXmpp::Xmpp::Iq
23
+ if cmd = stanza.command
24
+ if data = cmd.x
25
+ update_with_command_data(stanza, data, cmd.node)
26
+ else
27
+ update_with_command_request(stanza, cmd.node)
28
+ end
29
+ elsif (pubsub = stanza.pubsub).kind_of?(AgentXmpp::Xmpp::IqPubSub) and pub = pubsub.publish and item = pub.item
30
+ if data = item.x
31
+ update_with_published_data(stanza, data, pub.node)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ #.........................................................................................................
38
+ def update_received_event_item(item, from, node)
39
+ (event_item = item.entry || item.x) if item.respond_to?(:entry) and item.respond_to?(:x)
40
+ event_item.nil? ? false : update_with_event_item(event_item, from, node, item.id)
41
+ end
42
+
43
+ #.........................................................................................................
44
+ def find_by_item_id(item_id)
45
+ item_id.nil? ? nil : messages[:item_id => item_id]
46
+ end
47
+
48
+ #.........................................................................................................
49
+ def count_by_from_jid(from_jid)
50
+ end
51
+
52
+ #.........................................................................................................
53
+ def count_by_content_type(content_type)
54
+ messages.filter(:content_type => content_type).count
55
+ end
56
+
57
+ #.........................................................................................................
58
+ def stats_by_message_type
59
+ AgentXmpp.agent_xmpp_db['SELECT message_type AS type, count(id) AS count, max(created_at) AS last FROM messages GROUP BY message_type'].all.map do |s|
60
+ {:type=>s[:type], :count=>s[:count], :last=>Time.parse(s[:last]).strftime("%y/%m/%d %H:%M")}
61
+ end
62
+ end
63
+
64
+ #.........................................................................................................
65
+ def stats_by_node(node)
66
+ stats = AgentXmpp.agent_xmpp_db["SELECT node, count(id) AS count, max(created_at) AS last FROM messages WHERE node = ?", node].first
67
+ {:node=>node, :count=>stats[:count], :last=>stats[:last].nil? ? 'Never' : Time.parse(stats[:last]).strftime("%y/%m/%d %H:%M")}
68
+ end
69
+
70
+ #.........................................................................................................
71
+ def stats_by_command_node
72
+ BaseController.command_nodes.map{|n| stats_by_node(n)}
73
+ end
74
+
75
+ #.........................................................................................................
76
+ # private
77
+ #.........................................................................................................
78
+ def update_with_chat_message(stanza)
79
+ from_jid = stanza.from || AgentXmpp.jid
80
+ messages << {
81
+ :message_text => stanza.body,
82
+ :content_type => 'text',
83
+ :message_type => 'chat',
84
+ :to_jid => stanza.to.to_s,
85
+ :from_jid => from_jid.to_s,
86
+ :created_at => Time.now}
87
+ end
88
+
89
+ #.........................................................................................................
90
+ def update_with_command_request(stanza, node)
91
+ from_jid = stanza.from || AgentXmpp.jid
92
+ messages << {
93
+ :content_type => 'command_request',
94
+ :message_type => 'command',
95
+ :to_jid => stanza.to.to_s,
96
+ :from_jid => from_jid.to_s,
97
+ :node => node,
98
+ :created_at => Time.now}
99
+ end
100
+
101
+ #.........................................................................................................
102
+ def update_with_command_data(stanza, data, node)
103
+ from_jid = stanza.from || AgentXmpp.jid
104
+ messages << {
105
+ :message_text => data.to_s,
106
+ :content_type => 'x',
107
+ :message_type => 'command',
108
+ :to_jid => stanza.to.to_s,
109
+ :from_jid => from_jid.to_s,
110
+ :node => node,
111
+ :created_at => Time.now}
112
+ end
113
+
114
+ #.........................................................................................................
115
+ def update_with_published_data(stanza, data, node)
116
+ from_jid = stanza.from || AgentXmpp.jid
117
+ messages << {
118
+ :message_text => data.to_s,
119
+ :content_type => 'x',
120
+ :message_type => 'event',
121
+ :to_jid => stanza.to.to_s,
122
+ :from_jid => from_jid.to_s,
123
+ :node => node,
124
+ :created_at => Time.now}
125
+ end
126
+
127
+ #.........................................................................................................
128
+ def update_with_event_item(event_item, from, node, item_id)
129
+ unless find_by_item_id(item_id)
130
+ messages << {
131
+ :message_text => event_item.to_s,
132
+ :content_type => event_item.name,
133
+ :message_type => 'event',
134
+ :to_jid => AgentXmpp.jid.to_s,
135
+ :from_jid => from.to_s,
136
+ :node => node,
137
+ :item_id => item_id,
138
+ :created_at => Time.now}; true
139
+ else; false; end
140
+ end
141
+
142
+ #.........................................................................................................
143
+ private :update_with_chat_message, :update_with_command_data, :update_with_published_data, :update_with_command_request
144
+
145
+ #### self
146
+ end
147
+
148
+ #### Message
149
+ end
150
+
151
+ #### AgentXmpp
152
+ end
@@ -0,0 +1,53 @@
1
+ ##############################################################################################################
2
+ module AgentXmpp
3
+
4
+ #####-------------------------------------------------------------------------------------------------------
5
+ class Publication
6
+
7
+ #####-------------------------------------------------------------------------------------------------------
8
+ class << self
9
+
10
+ #.........................................................................................................
11
+ def publications(renew=false)
12
+ @publications ||= AgentXmpp.in_memory_db[:publications]
13
+ end
14
+
15
+ #.........................................................................................................
16
+ def load_config
17
+ if AgentXmpp.config['publish'].kind_of?(Array)
18
+ AgentXmpp.config['publish'].each do |pub|
19
+ publications << AgentXmpp::DEFAULT_PUBSUB_CONFIG.inject({}) do |f, (a, v)|
20
+ f.merge(a => pub[a.to_s] || v)
21
+ end.merge(:status => 'new', :node => pub['node'])
22
+ end
23
+ end
24
+ end
25
+
26
+ #.........................................................................................................
27
+ def find_by_node(node)
28
+ publications[:node => node]
29
+ end
30
+
31
+ #.........................................................................................................
32
+ def find_all
33
+ publications.all
34
+ end
35
+
36
+ #.........................................................................................................
37
+ def update_status(node, status)
38
+ publications.filter(:node => node).update(:status => status.to_s)
39
+ end
40
+
41
+ #.........................................................................................................
42
+ def stats_by_node
43
+ find_all.map{|p| Message.stats_by_node("#{AgentXmpp.user_pubsub_root}/#{p[:node]}").update(:node=>p[:node].split('/').last)}
44
+ end
45
+
46
+ #### self
47
+ end
48
+
49
+ #### Publication
50
+ end
51
+
52
+ #### AgentXmpp
53
+ end
@@ -0,0 +1,107 @@
1
+ ##############################################################################################################
2
+ module AgentXmpp
3
+
4
+ #####-------------------------------------------------------------------------------------------------------
5
+ class Roster
6
+
7
+ #####-------------------------------------------------------------------------------------------------------
8
+ class << self
9
+
10
+ #.........................................................................................................
11
+ def roster(renew=false)
12
+ @roster ||= AgentXmpp.in_memory_db[:roster]
13
+ end
14
+
15
+ #.........................................................................................................
16
+ def update(msg, from=nil)
17
+ case msg
18
+ when AgentXmpp::Xmpp::Presence then update_with_presence(msg)
19
+ when AgentXmpp::Xmpp::IqVersion then update_with_version(msg, from)
20
+ end
21
+ end
22
+
23
+ #.........................................................................................................
24
+ def update_status(jid, status)
25
+ roster.filter(:jid => AgentXmpp.full_jid_to_s(jid)).update(:status => status.to_s)
26
+ end
27
+
28
+ #.........................................................................................................
29
+ def find_all
30
+ roster.all
31
+ end
32
+
33
+ #.........................................................................................................
34
+ def find_by_jid(jid)
35
+ roster[:jid => AgentXmpp.full_jid_to_s(jid)]
36
+ end
37
+
38
+ #.........................................................................................................
39
+ def find_all_by_status(status)
40
+ roster.filter(:status => status.to_s).all
41
+ end
42
+
43
+ #.........................................................................................................
44
+ def find_all_by_contact_jid(jid)
45
+ if contact = Contact.find_by_jid(jid)
46
+ roster.filter(:contact_id => contact[:contact_id]).all
47
+ else; []; end
48
+ end
49
+
50
+ #.........................................................................................................
51
+ def find_all_by_contact_jid_and_status(jid, status)
52
+ if contact = Contact.find_by_jid(jid)
53
+ roster.filter(:contact_id => contact[:id]).all
54
+ else; []; end
55
+ end
56
+
57
+ #.........................................................................................................
58
+ def destroy_by_contact_id(contact_id)
59
+ roster.filter(:contact_id => contact_id).delete
60
+ end
61
+
62
+ #.........................................................................................................
63
+ def has_version?(jid)
64
+ if item = find_by_jid(jid)
65
+ not (item[:client_name].nil? or item[:client_version].nil?)
66
+ else; false; end
67
+ end
68
+
69
+ #.........................................................................................................
70
+ def method_missing(meth, *args, &blk)
71
+ roster.send(meth, *args, &blk)
72
+ end
73
+
74
+ #.........................................................................................................
75
+ # private
76
+ #.........................................................................................................
77
+ def update_with_presence(presence)
78
+ from_jid = presence.from.to_s
79
+ contact = Contact.find_by_jid(presence.from)
80
+ status = presence.type.nil? ? 'available' : presence.type.to_s
81
+ if (contact)
82
+ begin
83
+ roster << {:jid => from_jid, :status => status, :contact_id => contact[:id]}
84
+ rescue
85
+ roster.filter(:jid => from_jid).update(:status => status)
86
+ end
87
+ end
88
+ end
89
+
90
+ #.........................................................................................................
91
+ def update_with_version(vquery, from)
92
+ if (item = roster.filter(:jid => from.to_s))
93
+ item.update(:client_name => vquery.iname, :client_version => vquery.version, :client_os => vquery.os)
94
+ end
95
+ end
96
+
97
+ #.........................................................................................................
98
+ private :update_with_presence, :update_with_version
99
+
100
+ #### self
101
+ end
102
+
103
+ #### Roster
104
+ end
105
+
106
+ #### AgentXmpp
107
+ end
@@ -0,0 +1,91 @@
1
+ ##############################################################################################################
2
+ module AgentXmpp
3
+
4
+ #####-------------------------------------------------------------------------------------------------------
5
+ class Service
6
+
7
+ #####-------------------------------------------------------------------------------------------------------
8
+ class << self
9
+
10
+ #.........................................................................................................
11
+ def services(renew=false)
12
+ @services ||= AgentXmpp.in_memory_db[:services]
13
+ end
14
+
15
+ #.........................................................................................................
16
+ def service_items
17
+ @service_items ||= AgentXmpp.in_memory_db[:service_items]
18
+ end
19
+
20
+ #.........................................................................................................
21
+ def service_features
22
+ @service_features ||= AgentXmpp.in_memory_db[:service_features]
23
+ end
24
+
25
+ #.........................................................................................................
26
+ def update(disco_iq)
27
+ disco = disco_iq.query
28
+ case disco
29
+ when AgentXmpp::Xmpp::IqDiscoInfo then update_with_disco_info(disco_iq)
30
+ when AgentXmpp::Xmpp::IqDiscoItems then update_with_disco_items(disco_iq)
31
+ end
32
+ end
33
+
34
+ #.........................................................................................................
35
+ def has_jid?(jid)
36
+ services.filter(:jid => jid.to_s).count > 0
37
+ end
38
+
39
+ #.........................................................................................................
40
+ def has_disco_info?(jid)
41
+ services.filter(:jid => jid.to_s).count > 0
42
+ end
43
+
44
+ #.........................................................................................................
45
+ def has_disco_items?(jid)
46
+ service_items.filter(:service => jid.to_s).count > 0
47
+ end
48
+
49
+ #.........................................................................................................
50
+ # private
51
+ #.........................................................................................................
52
+ def update_with_disco_info(disco_iq)
53
+ disco, service = disco_iq.query, disco_iq.from.to_s
54
+ node = disco.node
55
+ disco.identities.each do |i|
56
+ begin
57
+ services << {:node => node, :jid => service, :category => i.category, :type => i.type, :name => i.iname}
58
+ rescue
59
+ end
60
+ end
61
+ disco.features.each do |f|
62
+ begin
63
+ service_features << {:node => node, :service => service, :var => f.var}
64
+ rescue
65
+ end
66
+ end
67
+ end
68
+
69
+ #.........................................................................................................
70
+ def update_with_disco_items(disco_iq)
71
+ disco, service = disco_iq.query, disco_iq.from.to_s
72
+ parent_node = disco.node
73
+ disco.items.each do |i|
74
+ begin
75
+ service_items << {:parent_node => parent_node, :service => service, :node => i.node, :jid => i.jid.to_s, :name => i.iname}
76
+ rescue
77
+ end
78
+ end
79
+ end
80
+
81
+ #.........................................................................................................
82
+ private :update_with_disco_info, :update_with_disco_items
83
+
84
+ #### self
85
+ end
86
+
87
+ #### Service
88
+ end
89
+
90
+ #### AgentXmpp
91
+ end