troystribling-agent_xmpp 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/README.rdoc +397 -2
  2. data/Rakefile +33 -21
  3. data/VERSION +1 -1
  4. data/agent_xmpp.gemspec +78 -33
  5. data/lib/agent_xmpp.rb +11 -7
  6. data/lib/agent_xmpp/app.rb +0 -5
  7. data/lib/agent_xmpp/app/boot.rb +47 -33
  8. data/lib/agent_xmpp/app/controller.rb +135 -19
  9. data/lib/agent_xmpp/client.rb +6 -1
  10. data/lib/agent_xmpp/client/client.rb +22 -155
  11. data/lib/agent_xmpp/client/connection.rb +41 -250
  12. data/lib/agent_xmpp/client/message_delegate.rb +706 -0
  13. data/lib/agent_xmpp/client/message_pipe.rb +176 -0
  14. data/lib/agent_xmpp/client/publish_model.rb +65 -0
  15. data/lib/agent_xmpp/{app/format.rb → client/response.rb} +19 -24
  16. data/lib/agent_xmpp/client/roster_model.rb +139 -0
  17. data/lib/agent_xmpp/client/services_model.rb +97 -0
  18. data/lib/agent_xmpp/config.rb +45 -0
  19. data/lib/agent_xmpp/main.rb +126 -0
  20. data/lib/agent_xmpp/patches.rb +6 -2
  21. data/lib/agent_xmpp/patches/{standard_library_patches/array.rb → array.rb} +14 -7
  22. data/lib/agent_xmpp/patches/{standard_library_patches/float.rb → float.rb} +0 -0
  23. data/lib/agent_xmpp/patches/{standard_library_patches/hash.rb → hash.rb} +3 -3
  24. data/lib/agent_xmpp/patches/{standard_library_patches/object.rb → object.rb} +3 -3
  25. data/lib/agent_xmpp/patches/rexml.rb +69 -0
  26. data/lib/agent_xmpp/patches/{standard_library_patches/string.rb → string.rb} +5 -0
  27. data/lib/agent_xmpp/xmpp.rb +17 -0
  28. data/lib/agent_xmpp/xmpp/element.rb +159 -0
  29. data/lib/agent_xmpp/xmpp/error_response.rb +179 -0
  30. data/lib/agent_xmpp/xmpp/iq.rb +90 -0
  31. data/lib/agent_xmpp/xmpp/iq_command.rb +47 -0
  32. data/lib/agent_xmpp/xmpp/iq_disco.rb +205 -0
  33. data/lib/agent_xmpp/xmpp/iq_pubsub.rb +268 -0
  34. data/lib/agent_xmpp/xmpp/iq_roster.rb +183 -0
  35. data/lib/agent_xmpp/xmpp/iq_version.rb +89 -0
  36. data/lib/agent_xmpp/xmpp/jid.rb +150 -0
  37. data/lib/agent_xmpp/xmpp/message.rb +82 -0
  38. data/lib/agent_xmpp/xmpp/presence.rb +127 -0
  39. data/lib/agent_xmpp/xmpp/sasl.rb +241 -0
  40. data/lib/agent_xmpp/xmpp/stanza.rb +107 -0
  41. data/lib/agent_xmpp/xmpp/x_data.rb +269 -0
  42. data/test/app/app.rb +134 -0
  43. data/test/cases/test_application_message_processing.rb +65 -0
  44. data/test/cases/test_errors.rb +24 -0
  45. data/test/cases/test_presence_management.rb +139 -0
  46. data/test/cases/test_roster_management.rb +214 -0
  47. data/test/cases/test_service_discovery.rb +168 -0
  48. data/test/cases/test_session_management.rb +120 -0
  49. data/test/cases/test_version_discovery.rb +67 -0
  50. data/test/helpers/matchers.rb +23 -0
  51. data/test/helpers/mocks.rb +82 -0
  52. data/test/helpers/test_case_extensions.rb +45 -0
  53. data/test/helpers/test_client.rb +44 -0
  54. data/test/helpers/test_delegate.rb +61 -0
  55. data/test/helpers/test_helper.rb +91 -0
  56. data/test/messages/application_messages.rb +206 -0
  57. data/test/messages/error_messages.rb +35 -0
  58. data/test/messages/presence_messages.rb +66 -0
  59. data/test/messages/roster_messages.rb +126 -0
  60. data/test/messages/service_discovery_messages.rb +201 -0
  61. data/test/messages/session_messages.rb +158 -0
  62. data/test/messages/version_discovery_messages.rb +69 -0
  63. data/test/peer/peer.rb +36 -0
  64. data/test/xml_messages.txt +197 -0
  65. metadata +82 -42
  66. data/bin/agent_xmpp +0 -56
  67. data/lib/agent_xmpp/app/chat_message_body_controller.rb +0 -16
  68. data/lib/agent_xmpp/app/map.rb +0 -45
  69. data/lib/agent_xmpp/app/routes.rb +0 -77
  70. data/lib/agent_xmpp/app/view.rb +0 -49
  71. data/lib/agent_xmpp/client/parser.rb +0 -71
  72. data/lib/agent_xmpp/patches/standard_library_patches.rb +0 -5
  73. data/lib/agent_xmpp/patches/xmpp4r_patches.rb +0 -3
  74. data/lib/agent_xmpp/patches/xmpp4r_patches/command.rb +0 -26
  75. data/lib/agent_xmpp/patches/xmpp4r_patches/iq.rb +0 -26
  76. data/lib/agent_xmpp/patches/xmpp4r_patches/x_data.rb +0 -116
  77. data/lib/agent_xmpp/utils.rb +0 -2
  78. data/lib/agent_xmpp/utils/logger.rb +0 -24
  79. data/lib/agent_xmpp/utils/roster.rb +0 -23
  80. data/lib/agent_xmpp/version.rb +0 -6
  81. data/test/agent_xmpp_test.rb +0 -7
  82. data/test/test_helper.rb +0 -10
@@ -0,0 +1,45 @@
1
+ module AgentXmpp
2
+
3
+ #.........................................................................................................
4
+ VERSION = "0.0.0"
5
+ AGENT_XMPP_NAME = 'AgentXMPP'
6
+ OS_VERSION = IO.popen('uname -sr').readlines.to_s.strip
7
+ SUBSCRIBE_RETRY_PERIOD = 60
8
+ IDENTITY = {:category => 'client', :name => AGENT_XMPP_NAME, :type => 'bot'}
9
+ FEATURES = ['http://jabber.org/protocol/disco#info',
10
+ 'http://jabber.org/protocol/disco#items',
11
+ 'jabber:iq:version',
12
+ 'jabber:x:data',
13
+ 'http://jabber.org/protocol/commands',
14
+ 'http://jabber.org/protocol/muc']
15
+ DEFAULT_PUBSUB_CONFIG = {
16
+ :title => 'event',
17
+ :access_model => 'presence',
18
+ :publish_model => 'publishers',
19
+ :max_items => 20,
20
+ :deliver_notifications => 1,
21
+ :deliver_payloads => 1,
22
+ :persist_items => 1,
23
+ :subscribe => 1,
24
+ :notify_config => 0,
25
+ :notify_delete => 0,
26
+ :notify_retract => 0,
27
+ }
28
+
29
+ #.........................................................................................................
30
+ @config_file = "agent_xmpp.yml"
31
+ @app_path = File.dirname($0)
32
+ @log_file = STDOUT
33
+
34
+ #.........................................................................................................
35
+ class << self
36
+ attr_accessor :config_file, :app_path, :log_file
37
+ def logger; @logger ||= Logger.new(STDOUT); end
38
+ def logger=(logger); @logger = logger; end
39
+ end
40
+
41
+ #.........................................................................................................
42
+ class AgentXmppError < Exception; end
43
+
44
+ end
45
+
@@ -0,0 +1,126 @@
1
+ ##############################################################################################################
2
+ OptionParser.new do |opts|
3
+ opts.banner = 'Usage: agent_xmpp.rb [options]'
4
+ opts.separator ''
5
+ opts.on('-c', '--config config.yml', 'YAML agent configuration file relative to application path') {|f| AgentXmpp.config_file = f}
6
+ opts.on('-l', '--logfile file.log', 'name of logfile') {|f| AgentXmpp.log_file = f}
7
+ opts.on_tail('-h', '--help', 'Show this message') {
8
+ puts opts
9
+ exit
10
+ }
11
+ opts.parse!(ARGV)
12
+ end
13
+
14
+ ##############################################################################################################
15
+ module AgentXmpp
16
+
17
+ #...........................................................................................................
18
+ @config = {}
19
+
20
+ #####-------------------------------------------------------------------------------------------------------
21
+ class << self
22
+
23
+ #.........................................................................................................
24
+ attr_accessor :config
25
+
26
+ #.........................................................................................................
27
+ def roster
28
+ @roster ||= RosterModel.new(jid, config['roster'])
29
+ end
30
+
31
+ #.........................................................................................................
32
+ def pubsub_root
33
+ @pubsub_root ||= "/home/#{AgentXmpp.jid.domain}"
34
+ end
35
+
36
+ #.........................................................................................................
37
+ def user_pubsub_root
38
+ @user_pubsub_root ||= "#{@pubsub_root}/#{AgentXmpp.jid.node}"
39
+ end
40
+
41
+ #.........................................................................................................
42
+ def services
43
+ @services ||= ServicesModel.new
44
+ end
45
+
46
+ #.........................................................................................................
47
+ def published
48
+ @published ||= PublishModel.new(config['publish'])
49
+ end
50
+
51
+ #.........................................................................................................
52
+ def jid
53
+ @jid ||= Xmpp::Jid.new("#{config['jid']}/#{resource}")
54
+ end
55
+
56
+ #.........................................................................................................
57
+ def jid=(jid)
58
+ @jid = jid
59
+ end
60
+
61
+ #.........................................................................................................
62
+ def resource
63
+ config['resource'] || Socket.gethostname
64
+ end
65
+
66
+ #.........................................................................................................
67
+ def port
68
+ config['port'] || 5222
69
+ end
70
+
71
+ #.........................................................................................................
72
+ def password
73
+ config['password']
74
+ end
75
+
76
+ #.........................................................................................................
77
+ def priority
78
+ @priority ||= if config['priority']
79
+ if config['priority'] < -127
80
+ -127
81
+ elsif config['priority'] > 128
82
+ 128
83
+ else
84
+ config['priority']
85
+ end
86
+ else; 1; end
87
+ end
88
+
89
+ #### self
90
+ end
91
+
92
+ #####-------------------------------------------------------------------------------------------------------
93
+ module Delegator
94
+
95
+ #####-------------------------------------------------------------------------------------------------------
96
+ class << self
97
+
98
+ #.........................................................................................................
99
+ def delegate(del, *methods)
100
+ methods.each do |method_name|
101
+ class_eval <<-RUBY
102
+ def #{method_name.to_s}(*args, &blk)
103
+ ::#{del}.send(#{method_name.inspect}, *args, &blk)
104
+ end
105
+ RUBY
106
+ end
107
+ end
108
+
109
+ #### self
110
+ end
111
+
112
+ delegate AgentXmpp::BaseController, :execute, :chat, :event
113
+ delegate AgentXmpp::Boot, :before_start, :after_connected, :restarting_client, :discovered_pubsub_node,
114
+ :discovered_command_nodes, :received_presence
115
+
116
+ #### Delegator
117
+ end
118
+
119
+ #### AgentXmpp
120
+ end
121
+
122
+ ##############################################################################################################
123
+ include AgentXmpp::Delegator
124
+
125
+ ##############################################################################################################
126
+ at_exit {AgentXmpp::Boot.boot}
@@ -1,3 +1,7 @@
1
- require 'agent_xmpp/patches/xmpp4r_patches'
2
- require 'agent_xmpp/patches/standard_library_patches'
1
+ require 'agent_xmpp/patches/object'
2
+ require 'agent_xmpp/patches/array'
3
+ require 'agent_xmpp/patches/hash'
4
+ require 'agent_xmpp/patches/string'
5
+ require 'agent_xmpp/patches/float'
6
+ require 'agent_xmpp/patches/rexml'
3
7
 
@@ -8,24 +8,31 @@ module AgentXmpp
8
8
 
9
9
  #......................................................................................................
10
10
  def to_x_data(type = 'result')
11
- data = Jabber::Dataforms::XData.new(type)
12
- reported = Jabber::Dataforms::XDataReported.new
13
- if first.instance_of?(Hash)
11
+ data = Xmpp::XData.new(type)
12
+ if first.kind_of?(Hash)
13
+ field_type = lambda{|v| v.kind_of?(Array) ? 'list-multi' : nil}
14
+ reported = Xmpp::XDataReported.new
14
15
  first.each_key {|var| reported.add_field(var.to_s)}
15
16
  data << reported
16
17
  each do |fields|
17
- item = Jabber::Dataforms::XDataItem.new
18
- fields.each {|var, value| item.add_field_with_value(var.to_s, value.to_s)}
18
+ item = Xmpp::XDataItem.new
19
+ fields.each{|var, val| item.add_field_with_value(var.to_s, [val].flatten.collect{|v| v.to_s}, field_type[val])}
19
20
  data << item
20
21
  end
21
22
  else
22
- field = Jabber::Dataforms::XDataField.new
23
- field.values = map {|v| v.to_s}
23
+ field = Xmpp::XDataField.new
24
+ field.values = map{|v| v.to_s}
25
+ field.type ='list-multi'
24
26
  data << field
25
27
  end
26
28
  data
27
29
  end
28
30
 
31
+ #......................................................................................................
32
+ def smash
33
+ self.flatten.compact
34
+ end
35
+
29
36
  #### InstanceMethods
30
37
  end
31
38
 
@@ -8,11 +8,11 @@ module AgentXmpp
8
8
 
9
9
  #.......................................................................................................
10
10
  def to_x_data(type = 'result')
11
- inject(Jabber::Dataforms::XData.new(type)) do |data, field|
12
- data.add_field_with_value(field.first.to_s, field.last.to_s)
11
+ field_type = lambda{|v| v.kind_of?(Array) ? 'list-multi' : nil}
12
+ inject(Xmpp::XData.new(type)) do |data, (var, val)|
13
+ data.add_field_with_value(var, [val].flatten.map{|v| v.to_s}, field_type[val])
13
14
  end
14
15
  end
15
-
16
16
 
17
17
  #### InstanceMethods
18
18
  end
@@ -7,15 +7,15 @@ module AgentXmpp
7
7
  module InstanceMethods
8
8
 
9
9
  #.......................................................................................................
10
- def to_x_data(type = 'result')
11
- Jabber::Dataforms::XData.new(type).add_field_with_value(nil, to_s)
10
+ def to_x_data(type='result')
11
+ Xmpp::XData.new(type).add_field_with_value(nil, to_s)
12
12
  end
13
13
 
14
14
  #.......................................................................................................
15
15
  def define_meta_class_method(name, &blk)
16
16
  (class << self; self; end).instance_eval {define_method(name, &blk)}
17
17
  end
18
-
18
+
19
19
  #### InstanceMethods
20
20
  end
21
21
 
@@ -0,0 +1,69 @@
1
+ # Original from XMPP4R - XMPP Library for Ruby Website::http://home.gna.org/xmpp4r/
2
+ ##############################################################################################################
3
+ module REXML
4
+
5
+ ####----------------------------------------------------------------------------------------------------
6
+ class Element
7
+
8
+ #.......................................................................................................
9
+ def replace_element_text(e, t)
10
+ el = first_element(e)
11
+ if el.nil?
12
+ el = REXML::Element.new(e)
13
+ add_element(el)
14
+ end
15
+ el.text = t if t
16
+ self
17
+ end
18
+
19
+ #.......................................................................................................
20
+ def first_element(e)
21
+ elements.to_a(e).first
22
+ end
23
+
24
+ #.......................................................................................................
25
+ def first_element_text(e)
26
+ el = first_element(e)
27
+ el.nil? ? nil : el.text
28
+ end
29
+
30
+ #.......................................................................................................
31
+ def typed_add(e)
32
+ add(e)
33
+ end
34
+
35
+ #.......................................................................................................
36
+ def import(xmlelement)
37
+ if @name and @name != xmlelement.name
38
+ raise "Trying to import an #{xmlelement.name} to a #{@name} !"
39
+ end
40
+ add_attributes(xmlelement.attributes.clone)
41
+ @context = xmlelement.context
42
+ xmlelement.each do |e|
43
+ if e.kind_of? REXML::Element
44
+ typed_add(e.deep_clone)
45
+ elsif e.kind_of? REXML::Text
46
+ add_text(e.value)
47
+ else
48
+ add(e.clone)
49
+ end
50
+ end
51
+ self
52
+ end
53
+
54
+ #.......................................................................................................
55
+ def self.import(xmlelement)
56
+ self.new(xmlelement.name).import(xmlelement)
57
+ end
58
+
59
+ #.......................................................................................................
60
+ def delete_elements(element)
61
+ elements.delete_all(element)
62
+ end
63
+
64
+ #### Element
65
+ end
66
+
67
+ #### REXML
68
+ end
69
+
@@ -10,6 +10,11 @@ module AgentXmpp
10
10
  def classify
11
11
  split('_').collect{|s| s.capitalize}.join
12
12
  end
13
+
14
+ #......................................................................................................
15
+ def humanize
16
+ gsub(/_/, ' ')
17
+ end
13
18
 
14
19
  #### InstanceMethods
15
20
  end
@@ -0,0 +1,17 @@
1
+ require 'agent_xmpp/xmpp/element'
2
+ require 'agent_xmpp/xmpp/stanza'
3
+ require 'agent_xmpp/xmpp/jid'
4
+ require 'agent_xmpp/xmpp/sasl'
5
+ require 'agent_xmpp/xmpp/x_data'
6
+
7
+ require 'agent_xmpp/xmpp/message'
8
+ require 'agent_xmpp/xmpp/presence'
9
+ require 'agent_xmpp/xmpp/iq'
10
+
11
+ require 'agent_xmpp/xmpp/iq_command'
12
+ require 'agent_xmpp/xmpp/iq_version'
13
+ require 'agent_xmpp/xmpp/iq_roster'
14
+ require 'agent_xmpp/xmpp/iq_disco'
15
+ require 'agent_xmpp/xmpp/iq_pubsub'
16
+
17
+ require 'agent_xmpp/xmpp/error_response'
@@ -0,0 +1,159 @@
1
+ # Original from XMPP4R - XMPP Library for Ruby Website::http://home.gna.org/xmpp4r/
2
+ ##############################################################################################################
3
+ module AgentXmpp
4
+
5
+ #####-------------------------------------------------------------------------------------------------------
6
+ module Xmpp
7
+
8
+ #####-------------------------------------------------------------------------------------------------------
9
+ class Element < REXML::Element
10
+
11
+ #.......................................................................................................
12
+ @@name_xmlns_classes = {}
13
+
14
+ #####-------------------------------------------------------------------------------------------------------
15
+ class << self
16
+
17
+ #.......................................................................................................
18
+ def name_xmlns(name, xmlns=nil)
19
+ @@name_xmlns_classes[[name, xmlns]] = self
20
+ end
21
+
22
+ #.......................................................................................................
23
+ def name_xmlns_for_class(klass)
24
+ klass.ancestors.each do |klass1|
25
+ @@name_xmlns_classes.each do |name_xmlns,k|
26
+ if klass1 == k
27
+ return name_xmlns
28
+ end
29
+ end
30
+ end
31
+ raise NoNameXmlnsRegistered.new(klass)
32
+ end
33
+
34
+ #.......................................................................................................
35
+ def class_for_name_xmlns(name, xmlns)
36
+ if @@name_xmlns_classes.has_key? [name, xmlns]
37
+ @@name_xmlns_classes[[name, xmlns]]
38
+ elsif @@name_xmlns_classes.has_key? [name, nil]
39
+ @@name_xmlns_classes[[name, nil]]
40
+ else
41
+ REXML::Element
42
+ end
43
+ end
44
+
45
+ #.......................................................................................................
46
+ def import(element)
47
+ klass = class_for_name_xmlns(element.name, element.namespace)
48
+ if klass != self and klass.ancestors.include?(self)
49
+ klass.new.import(element)
50
+ else
51
+ self.new.import(element)
52
+ end
53
+ end
54
+
55
+ #.....................................................................................................
56
+ def xmpp_attribute(*args)
57
+ sym = (args.pop[:sym] if args.last.kind_of?(Hash)).nil? ? '' : '.to_sym'
58
+ args.each do |a|
59
+ class_eval <<-DEF
60
+ def #{a.to_s}
61
+ attributes['#{a.to_s}']#{sym}
62
+ end
63
+ def #{a.to_s}=(v)
64
+ attributes['#{a.to_s}'] = v.to_s
65
+ end
66
+ DEF
67
+ end
68
+ end
69
+
70
+ #.......................................................................................................
71
+ def xmpp_child(*args)
72
+ args.each do |a|
73
+ class_eval <<-DEF
74
+ def #{a.to_s}
75
+ first_element('#{a.to_s}')
76
+ end
77
+ def #{a.to_s}=(v)
78
+ delete_elements(v.name)
79
+ add(v)
80
+ end
81
+ DEF
82
+ end
83
+ end
84
+
85
+ #### self
86
+ end
87
+
88
+ #.......................................................................................................
89
+ def initialize(*arg)
90
+ if arg.empty?
91
+ name, xmlns = self.class::name_xmlns_for_class(self.class)
92
+ super(name)
93
+ add_namespace(xmlns)
94
+ else
95
+ super
96
+ end
97
+ end
98
+
99
+ #.......................................................................................................
100
+ def typed_add(element)
101
+ if element.kind_of? REXML::Element
102
+ element_ns = (element.namespace.to_s == '') ? namespace : element.namespace
103
+ klass = Element::class_for_name_xmlns(element.name, element_ns)
104
+ if klass != element.class
105
+ element = klass.import(element)
106
+ end
107
+ end
108
+ super(element)
109
+ end
110
+
111
+ #.......................................................................................................
112
+ def parent=(new_parent)
113
+ if parent and parent.namespace('') == namespace('') and attributes['xmlns'].nil?
114
+ add_namespace parent.namespace('')
115
+ end
116
+ super
117
+ if new_parent and new_parent.namespace('') == namespace('')
118
+ delete_namespace
119
+ end
120
+ end
121
+
122
+ #.......................................................................................................
123
+ def clone
124
+ cloned = self.class.new
125
+ cloned.add_attributes self.attributes.clone
126
+ cloned.context = @context
127
+ cloned
128
+ end
129
+
130
+ #.......................................................................................................
131
+ def xml_lang
132
+ attributes['xml:lang']
133
+ end
134
+
135
+ #.......................................................................................................
136
+ def xml_lang=(l)
137
+ attributes['xml:lang'] = l
138
+ end
139
+
140
+ #.......................................................................................................
141
+ def set_xml_lang(l)
142
+ self.xml_lang = l
143
+ self
144
+ end
145
+
146
+ #.....................................................................................................
147
+ def <<(child)
148
+ add(child)
149
+ self
150
+ end
151
+
152
+ #### Element
153
+ end
154
+
155
+ #### XMPP
156
+ end
157
+
158
+ #### AgentXmpp
159
+ end