agent_xmpp 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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