xmpp-agent 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: cc18c3e39574543fd3941ec362455ad1de84f879
4
- data.tar.gz: 0814d2fd8695a4b085495ea7423a1f3f97e7d4f6
2
+ SHA256:
3
+ metadata.gz: 577bb2cc12f813639ee3d0b732b0809f26a0acb38fe23d4bcfc7a3b56966adbb
4
+ data.tar.gz: 8a35a77d8e4d593d1cda6b7d7d881011bfffef1a323f57a52afb0300c692e06f
5
5
  SHA512:
6
- metadata.gz: 8cc44846f6d4fe645e779602a6ec18ecc31d68d3dfe8b09e4eb20ee81504063696c33b68ddbd96168d92363f5584c7b17566f162eb9211d8e76256b36fad2bee
7
- data.tar.gz: 00819f6dc86d2739d5c787cf471787e8c2b82f0ec3766af63ab766f96354b3f836dbd12cd15d9e5fe3c64b0fd9d652586c0d41e05b8f69d418aaca29ab01da72
6
+ metadata.gz: 7db481786756250f1dc7b60bb6be95c73d337860db32dc27f120d6b38504b681e68650c77547905df7482b7ce964936a896b9f98a29b354f92f5fe189fc3dfbf
7
+ data.tar.gz: 5a25264b3e434b5c30b73f7e1331f0041dfe107d5058e62153f9c5dd319f84b10fc86d6f6439c05608b524a2874e7b33aecd2d3f0df74538749541bd35ac0ef6
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/lib/xmpp-agent.rb CHANGED
@@ -2,62 +2,98 @@
2
2
 
3
3
  # file: xmpp-agent.rb
4
4
 
5
- require 'em-xmpp'
5
+ require "xrc"
6
6
  require 'app-routes'
7
7
 
8
+
8
9
  class XMPPAgent
9
10
  include AppRoutes
10
11
 
11
- def initialize()
12
- @routes = {}; @params = {}; @conn = nil; @ctx = nil
13
- super()
14
- end
12
+ attr_reader :client
15
13
 
16
- def received(conn,ctx)
14
+ def initialize(jid: '', password: '', port: 5222, host: nil, debug: false, callback: nil)
15
+
16
+ @routes = {}; @params = {}; msg = nil
17
+ @debug = debug
18
+
19
+ super()
20
+
21
+ h = {
22
+ jid: @jid = jid,
23
+ password: password,
24
+ port: port
25
+ }
26
+
27
+ h.merge!({hosts: [ host ]}) if host
17
28
 
18
- @conn = conn
19
- @ctx = ctx
20
- messages(@params, @conn, @ctx)
21
- run_route ctx.body.strip
22
- end
29
+ @client = client = Xrc::Client.new(h)
30
+
31
+ @client.on_private_message do |message|
32
+
33
+ messages(@params, client, message)
34
+ run_route message.body.strip
35
+
36
+ end
37
+
38
+ @client.on_connection_established do
39
+
40
+ on_connected()
23
41
 
24
- def messages(params, conn, ctx)
42
+ end
43
+
44
+ @client.on_event do |e|
45
+
46
+ if e.name.to_s == 'presence' then
47
+ on_presence_update(show=e.text('show'), status=e.text('status'), user=e.attributes['from'] )
48
+ end
49
+
50
+ end
51
+
52
+
53
+ end
54
+
55
+ def connect()
56
+ @client.connect
57
+ end
58
+
59
+ protected
60
+
61
+ def on_connected()
62
+ end
63
+
64
+ def on_presence_update(show, status, user)
65
+ end
66
+
67
+ private
68
+
69
+ def messages(params, client, msg)
25
70
 
26
71
  message %r{(send_to|send2)\s+([^\s]+)\s+(.*)} do
27
72
 
28
- user, message = params[:captures].values_at 1,2
29
- data = conn.message_stanza('to' => user) {|xml| xml.body(message) }
30
- conn.send_stanza data
73
+ user, msgout = params[:captures].values_at 1,2
74
+
75
+ client.say(body: msgout, from: @jid, to: user, type: "chat")
31
76
  end
32
77
 
33
78
  message 'help' do
34
- data = conn.message_stanza('to' => ctx.from) do |xml|
35
- xml.body('available commands: help, send_to')
36
- end
37
- conn.send_stanza data
79
+ msgout = 'available commands: help, send_to'
80
+ client.reply(body: msgout, to: msg)
38
81
  end
39
82
 
40
83
  message '.*' do
41
84
 
42
- data = conn.message_stanza('to' => ctx.from) do |xml|
43
- xml.body('need some help? type help')
44
- end
45
- conn.send_stanza data
85
+ msgout = 'need some help? type help'
86
+ client.reply(body: msgout, to: msg)
46
87
  end
47
88
 
48
89
  end
49
90
 
50
91
  def add_route(arg)
51
- get(arg) {yield(@params, @conn, @ctx)}
92
+ get(arg) {yield(@params, @client, @msg)}
52
93
  end
53
94
 
54
95
  def message(route, &blk)
55
96
  get(route, &blk)
56
- end
57
-
58
- def conn() @conn end
59
-
60
- def presence_update(ctx)
61
- end
97
+ end
62
98
 
63
99
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xmpp-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -10,65 +10,80 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDljCCAn6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBIMRIwEAYDVQQDDAlnZW1t
14
- YXN0ZXIxHjAcBgoJkiaJk/IsZAEZFg5qYW1lc3JvYmVydHNvbjESMBAGCgmSJomT
15
- 8ixkARkWAmV1MB4XDTE0MDQwNTE5MjM1OVoXDTE1MDQwNTE5MjM1OVowSDESMBAG
16
- A1UEAwwJZ2VtbWFzdGVyMR4wHAYKCZImiZPyLGQBGRYOamFtZXNyb2JlcnRzb24x
17
- EjAQBgoJkiaJk/IsZAEZFgJldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
18
- ggEBAL0Uq28c4pfHfHXtX03cuOL4svrytTcBVcAT0CMrQLWkp9exVzFEic6sK6w1
19
- Gjfycf39ij1yFLEvR5rhZSL8qB+U+C7mjM5O2d1O4RB1sTQzs2bsEHx5Xvt9gY6b
20
- 4icqnJNfDpWdN4dCchhinYVet+MSOfwTrk6cSdeupKkLAJqzn7ckOLS6YGjvChGd
21
- slsFgEO3Di50HGpYbky9AwfSrRtps6MjsOl/uedr+FPLT/nP894HAXJt5HHwj79j
22
- tLHHM8FrWQokPBf2cVgWC2Rn5LghEo3IHD3En4nZKqJRJkd2zGkK03L2KSj1e2jN
23
- aVQYzv8ARVXkg6NhmIIbkXjYKO8CAwEAAaOBijCBhzAJBgNVHRMEAjAAMAsGA1Ud
24
- DwQEAwIEsDAdBgNVHQ4EFgQUHNdoeObmaJOyyCZrjWBargjqkiowJgYDVR0RBB8w
25
- HYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0c29uLmV1MCYGA1UdEgQfMB2BG2dlbW1h
26
- c3RlckBqYW1lc3JvYmVydHNvbi5ldTANBgkqhkiG9w0BAQUFAAOCAQEARN5IbndL
27
- vLnc2DlGh2kB9tcTSamlUM4bGke+GmItqk1IHfHFIvnCQU6WasCvi5sz2IifrBJ0
28
- gAQGclMgasc/5YiRVRbLxTk8Cf9iJ39YpCk6xwVc2py/0g+B9k7ahk/Y0/QBYJug
29
- VhnqZ064ebat8mLAHP+dL44SoMFsKGScYR5/RnjhQnONvg5xPuOg7wpXv9dz9TzL
30
- Xq/YKsl9GmhmsDj/Wy9ugRxGupRi4CaUo2ZWz6YAjE7u3Y4x2AuYPFSmKPFg4WpJ
31
- dK8nOI/ggrVJPOIbhAfE35/0QJ5Jec4k2Z1lGL+tzA//Tl8XlGDhTqcfVqnPwPxM
32
- GiPYMZ7fiR8BAw==
13
+ MIIEXjCCAsagAwIBAgIBATANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDDCFnZW1t
14
+ YXN0ZXIvREM9amFtZXNyb2JlcnRzb24vREM9ZXUwHhcNMTkwOTIxMjMxNzMxWhcN
15
+ MjAwOTIwMjMxNzMxWjAsMSowKAYDVQQDDCFnZW1tYXN0ZXIvREM9amFtZXNyb2Jl
16
+ cnRzb24vREM9ZXUwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDtgFiq
17
+ +G7z+lIkbabWI1SzgWk9rBl8iI85tELX3YFvz4ayg7DX+NuHC/X720NBXTEppcf8
18
+ NWNtopq2XXCHlPerLKQFa4InW2O+AvOyTtitCR+Sza3zKxk3gUw2ToddLvwWk6cD
19
+ ZP+FCorucGhDhGCGABM9BEGMSkJG9Lod3MvHXVS/oLHhPvqaYAaZECH1khWL7RWM
20
+ jAqBvU/A00xN7jOJVBkH+UA9EyVL2lk7830P8D+5jhERAc/XLX2q+I2sdsFn6Wor
21
+ wxkfCTU/rL+eDS/gOPeigMlYg1Mt4vjmEwK+8QNKqmONa2AYB3o15ejP0TrsZR72
22
+ 3W1XFw2OIQG/01l89BgtaFRb4ylMGbHFpYNpNqEJumwksKgsTSZC5JeJyS9BnCeV
23
+ gcjV+DxwN+smzXrEeV8d3vr0u6tgVQPjF+qvy4rRvJ9lqZUAiml69Izd2oFEHXKo
24
+ kgwxCMzMFOW3xa9J6g0j7rkhz9GJxKeEaM2eL33cE/LhUcAC/ifbkQxzBQECAwEA
25
+ AaOBijCBhzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU/0itzTBw
26
+ 3QvdhrAlvTjNB+5tAVkwJgYDVR0RBB8wHYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0
27
+ c29uLmV1MCYGA1UdEgQfMB2BG2dlbW1hc3RlckBqYW1lc3JvYmVydHNvbi5ldTAN
28
+ BgkqhkiG9w0BAQsFAAOCAYEAAxdl3NXLewgOSwPtfdtQqhRDMoFlziIB0es/atjt
29
+ Hn7M7sV0rXG46qNiAuS33aoSI3lxf+ylHFonhwnyO8I0wfAq46pRxyEA4Xswmhzz
30
+ Nk4lRCJym7DGrPuciNZKJt8EEMLny9UBZUQGPlAnayqcLYWhTWCLU9G/xbka2chI
31
+ wM5OZO2ubW1HN1kqvLzh8zAxJKAxxuwkGAlQczmbnatp+ZpTLJ2jRMCK/d+G0yos
32
+ j8lmbAVbxD+f1fB1+P4/DvpKlN2h8HxdDirdbWjE+6QvgSE9cymnhz5Qgc1EwbR+
33
+ HrlBlt200+/DSQvjwXFY3+T+NPT4ESPe1cHPtkce8xNPbNLgKu7Qr9GZP/XqUGJn
34
+ 71RBgFbe7Wp4fFf1dj6v8xgG+uqxCVtK4LbHgCYqnmWvCfD9x3jhBTfwzPUJHQSR
35
+ 9Eg9Gbw3IF8iMcIPwTT7WTzb3vLw4+o6hP8oRi2CD1KB4KMDSxn4li5v8VuGdZ1o
36
+ ZPG6kphiEV/Pdc0QAh4qYhIN
33
37
  -----END CERTIFICATE-----
34
- date: 2014-04-05 00:00:00.000000000 Z
38
+ date: 2019-09-21 00:00:00.000000000 Z
35
39
  dependencies:
36
40
  - !ruby/object:Gem::Dependency
37
- name: em-xmpp
41
+ name: xrc
38
42
  requirement: !ruby/object:Gem::Requirement
39
43
  requirements:
40
- - - '='
44
+ - - "~>"
41
45
  - !ruby/object:Gem::Version
42
- version: 0.0.11
46
+ version: '0.1'
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 0.1.8
43
50
  type: :runtime
44
51
  prerelease: false
45
52
  version_requirements: !ruby/object:Gem::Requirement
46
53
  requirements:
47
- - - '='
54
+ - - "~>"
55
+ - !ruby/object:Gem::Version
56
+ version: '0.1'
57
+ - - ">="
48
58
  - !ruby/object:Gem::Version
49
- version: 0.0.11
59
+ version: 0.1.8
50
60
  - !ruby/object:Gem::Dependency
51
61
  name: app-routes
52
62
  requirement: !ruby/object:Gem::Requirement
53
63
  requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '0.1'
54
67
  - - ">="
55
68
  - !ruby/object:Gem::Version
56
- version: '0'
69
+ version: 0.1.19
57
70
  type: :runtime
58
71
  prerelease: false
59
72
  version_requirements: !ruby/object:Gem::Requirement
60
73
  requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '0.1'
61
77
  - - ">="
62
78
  - !ruby/object:Gem::Version
63
- version: '0'
79
+ version: 0.1.19
64
80
  description:
65
- email: james@r0bertson.co.uk
81
+ email: james@jamesrobertson.eu
66
82
  executables: []
67
83
  extensions: []
68
84
  extra_rdoc_files: []
69
85
  files:
70
86
  - lib/xmpp-agent.rb
71
- - lib/xmpp4r-simple.rb
72
87
  homepage: https://github.com/jrobertson/xmpp-agent
73
88
  licenses:
74
89
  - MIT
@@ -81,16 +96,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
96
  requirements:
82
97
  - - ">="
83
98
  - !ruby/object:Gem::Version
84
- version: '0'
99
+ version: 2.1.2
85
100
  required_rubygems_version: !ruby/object:Gem::Requirement
86
101
  requirements:
87
102
  - - ">="
88
103
  - !ruby/object:Gem::Version
89
104
  version: '0'
90
105
  requirements: []
91
- rubyforge_project:
92
- rubygems_version: 2.0.14
106
+ rubygems_version: 3.0.3
93
107
  signing_key:
94
108
  specification_version: 4
95
- summary: xmpp-agent
109
+ summary: Uses the Xrc gem to build a simple XMPP client.
96
110
  test_files: []
metadata.gz.sig CHANGED
Binary file
data/lib/xmpp4r-simple.rb DELETED
@@ -1,494 +0,0 @@
1
- # Jabber::Simple - An extremely easy-to-use Jabber client library.
2
- # Copyright 2006 Blaine Cook <blaine@obvious.com>, Obvious Corp.
3
- #
4
- # Jabber::Simple is free software; you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation; either version 2 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # Jabber::Simple is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with Jabber::Simple; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
-
18
- require 'rubygems'
19
- require 'xmpp4r'
20
- require 'xmpp4r/roster'
21
- require 'xmpp4r/vcard'
22
-
23
- module Jabber
24
-
25
- class ConnectionError < StandardError #:nodoc:
26
- end
27
-
28
- class Contact #:nodoc:
29
-
30
- include DRb::DRbUndumped if defined?(DRb::DRbUndumped)
31
-
32
- def initialize(client, jid)
33
- @jid = jid.respond_to?(:resource) ? jid : JID.new(jid)
34
- @client = client
35
- end
36
-
37
- def inspect
38
- "Jabber::Contact #{jid.to_s}"
39
- end
40
-
41
- def subscribed?
42
- [:to, :both].include?(subscription)
43
- end
44
-
45
- def subscription
46
- roster_item && roster_item.subscription
47
- end
48
-
49
- def ask_for_authorization!
50
- subscription_request = Presence.new.set_type(:subscribe)
51
- subscription_request.to = jid
52
- client.send!(subscription_request)
53
- end
54
-
55
- def unsubscribe!
56
- unsubscription_request = Presence.new.set_type(:unsubscribe)
57
- unsubscription_request.to = jid
58
- client.send!(unsubscription_request)
59
- client.send!(unsubscription_request.set_type(:unsubscribed))
60
- end
61
-
62
- def jid(bare=true)
63
- bare ? @jid.strip : @jid
64
- end
65
-
66
- private
67
-
68
- def roster_item
69
- client.roster.items[jid]
70
- end
71
-
72
- def client
73
- @client
74
- end
75
- end
76
-
77
- class Simple
78
-
79
- include DRb::DRbUndumped if defined?(DRb::DRbUndumped)
80
-
81
- # Create a new Jabber::Simple client. You will be automatically connected
82
- # to the Jabber server and your status message will be set to the string
83
- # passed in as the status_message argument.
84
- #
85
- # jabber = Jabber::Simple.new("me@example.com", "password", "Chat with me - Please!")
86
- def initialize(jid, password, status = nil, status_message = "Available")
87
- @jid = jid
88
- @password = password
89
- @disconnected = false
90
- status(status, status_message)
91
- start_deferred_delivery_thread
92
- end
93
-
94
- def inspect #:nodoc:
95
- "Jabber::Simple #{@jid}"
96
- end
97
-
98
- # Send a message to jabber user jid.
99
- #
100
- # Valid message types are:
101
- #
102
- # * :normal (default): a normal message.
103
- # * :chat: a one-to-one chat message.
104
- # * :groupchat: a group-chat message.
105
- # * :headline: a "headline" message.
106
- # * :error: an error message.
107
- #
108
- # If the recipient is not in your contacts list, the message will be queued
109
- # for later delivery, and the Contact will be automatically asked for
110
- # authorization (see Jabber::Simple#add).
111
- #
112
- # message should be a string or a valid Jabber::Message object. In either case,
113
- # the message recipient will be set to jid.
114
- def deliver(jid, message, type=:chat)
115
- contacts(jid) do |friend|
116
- unless subscribed_to? friend
117
- add(friend.jid)
118
- return deliver_deferred(friend.jid, message, type)
119
- end
120
- if message.kind_of?(Jabber::Message)
121
- msg = message
122
- msg.to = friend.jid
123
- else
124
- msg = Message.new(friend.jid)
125
- msg.type = type
126
- msg.body = message
127
- end
128
- send!(msg)
129
- end
130
- end
131
-
132
- # Set your presence, with a message.
133
- #
134
- # Available values for presence are:
135
- #
136
- # * nil: online.
137
- # * :chat: free for chat.
138
- # * :away: away from the computer.
139
- # * :dnd: do not disturb.
140
- # * :xa: extended away.
141
- #
142
- # It's not possible to set an offline status - to do that, disconnect! :-)
143
- def status(presence, message)
144
- @presence = presence
145
- @status_message = message
146
- stat_msg = Presence.new(@presence, @status_message)
147
- send!(stat_msg)
148
- end
149
-
150
- # Ask the users specified by jids for authorization (i.e., ask them to add
151
- # you to their contact list). If you are already in the user's contact list,
152
- # add() will not attempt to re-request authorization. In order to force
153
- # re-authorization, first remove() the user, then re-add them.
154
- #
155
- # Example usage:
156
- #
157
- # jabber_simple.add("friend@friendosaurus.com")
158
- #
159
- # Because the authorization process might take a few seconds, or might
160
- # never happen depending on when (and if) the user accepts your
161
- # request, results are placed in the Jabber::Simple#new_subscriptions queue.
162
- def add(*jids)
163
- contacts(*jids) do |friend|
164
- next if subscribed_to? friend
165
- friend.ask_for_authorization!
166
- end
167
- end
168
-
169
- # Remove the jabber users specified by jids from the contact list.
170
- def remove(*jids)
171
- contacts(*jids) do |unfriend|
172
- unfriend.unsubscribe!
173
- end
174
- end
175
-
176
- # Returns true if this Jabber account is subscribed to status updates for
177
- # the jabber user jid, false otherwise.
178
- def subscribed_to?(jid)
179
- contacts(jid) do |contact|
180
- return contact.subscribed?
181
- end
182
- end
183
-
184
- # If contacts is a single contact, returns a Jabber::Contact object
185
- # representing that user; if contacts is an array, returns an array of
186
- # Jabber::Contact objects.
187
- #
188
- # When called with a block, contacts will yield each Jabber::Contact object
189
- # in turn. This is mainly used internally, but exposed as an utility
190
- # function.
191
- def contacts(*contacts, &block)
192
- @contacts ||= {}
193
- contakts = []
194
- contacts.each do |contact|
195
- jid = contact.to_s
196
- unless @contacts[jid]
197
- @contacts[jid] = contact.respond_to?(:ask_for_authorization!) ? contact : Contact.new(self, contact)
198
- end
199
- yield @contacts[jid] if block_given?
200
- contakts << @contacts[jid]
201
- end
202
- contakts.size > 1 ? contakts : contakts.first
203
- end
204
-
205
- # Returns true if the Jabber client is connected to the Jabber server,
206
- # false otherwise.
207
- def connected?
208
- @client ||= nil
209
- connected = @client.respond_to?(:is_connected?) && @client.is_connected?
210
- return connected
211
- end
212
-
213
- # Returns an array of messages received since the last time
214
- # received_messages was called. Passing a block will yield each message in
215
- # turn, allowing you to break part-way through processing (especially
216
- # useful when your message handling code is not thread-safe (e.g.,
217
- # ActiveRecord).
218
- #
219
- # e.g.:
220
- #
221
- # jabber.received_messages do |message|
222
- # puts "Received message from #{message.from}: #{message.body}"
223
- # end
224
- def received_messages(&block)
225
- dequeue(:received_messages, &block)
226
- end
227
-
228
- # Returns true if there are unprocessed received messages waiting in the
229
- # queue, false otherwise.
230
- def received_messages?
231
- !queue(:received_messages).empty?
232
- end
233
-
234
- # Returns an array of presence updates received since the last time
235
- # presence_updates was called. Passing a block will yield each update in
236
- # turn, allowing you to break part-way through processing (especially
237
- # useful when your presence handling code is not thread-safe (e.g.,
238
- # ActiveRecord).
239
- #
240
- # e.g.:
241
- #
242
- # jabber.presence_updates do |friend, new_presence|
243
- # puts "Received presence update from #{friend}: #{new_presence}"
244
- # end
245
- def presence_updates(&block)
246
- updates = []
247
- @presence_mutex.synchronize do
248
- dequeue(:presence_updates) do |friend|
249
- presence = @presence_updates[friend]
250
- next unless presence
251
- new_update = [friend, presence[0], presence[1]]
252
- yield new_update if block_given?
253
- updates << new_update
254
- @presence_updates.delete(friend)
255
- end
256
- end
257
- return updates
258
- end
259
-
260
- # Returns true if there are unprocessed presence updates waiting in the
261
- # queue, false otherwise.
262
- def presence_updates?
263
- !queue(:presence_updates).empty?
264
- end
265
-
266
- # Returns an array of subscription notifications received since the last
267
- # time new_subscriptions was called. Passing a block will yield each update
268
- # in turn, allowing you to break part-way through processing (especially
269
- # useful when your subscription handling code is not thread-safe (e.g.,
270
- # ActiveRecord).
271
- #
272
- # e.g.:
273
- #
274
- # jabber.new_subscriptions do |friend, presence|
275
- # puts "Received presence update from #{friend.to_s}: #{presence}"
276
- # end
277
- def new_subscriptions(&block)
278
- dequeue(:new_subscriptions, &block)
279
- end
280
-
281
- # Returns true if there are unprocessed presence updates waiting in the
282
- # queue, false otherwise.
283
- def new_subscriptions?
284
- !queue(:new_subscriptions).empty?
285
- end
286
-
287
- # Returns an array of subscription notifications received since the last
288
- # time subscription_requests was called. Passing a block will yield each update
289
- # in turn, allowing you to break part-way through processing (especially
290
- # useful when your subscription handling code is not thread-safe (e.g.,
291
- # ActiveRecord).
292
- #
293
- # e.g.:
294
- #
295
- # jabber.subscription_requests do |friend, presence|
296
- # puts "Received presence update from #{friend.to_s}: #{presence}"
297
- # end
298
- def subscription_requests(&block)
299
- dequeue(:subscription_requests, &block)
300
- end
301
-
302
- # Returns true if auto-accept subscriptions (friend requests) is enabled
303
- # (default), false otherwise.
304
- def accept_subscriptions?
305
- @accept_subscriptions = true if @accept_subscriptions.nil?
306
- @accept_subscriptions
307
- end
308
-
309
- # Change whether or not subscriptions (friend requests) are automatically accepted.
310
- def accept_subscriptions=(accept_status)
311
- @accept_subscriptions = accept_status
312
- end
313
-
314
- # Direct access to the underlying Roster helper.
315
- def roster
316
- return @roster if @roster
317
- self.roster = Roster::Helper.new(client)
318
- end
319
-
320
- # Direct access to the underlying Jabber client.
321
- def client
322
- connect!() unless connected?
323
- @client
324
- end
325
-
326
- # Send a Jabber stanza over-the-wire.
327
- def send!(msg)
328
- attempts = 0
329
- begin
330
- attempts += 1
331
- client.send(msg)
332
- rescue Errno::EPIPE, IOError => e
333
- sleep 1
334
- disconnect
335
- reconnect
336
- retry unless attempts > 3
337
- raise e
338
- rescue Errno::ECONNRESET => e
339
- sleep (attempts^2) * 60 + 60
340
- disconnect
341
- reconnect
342
- retry unless attempts > 3
343
- raise e
344
- end
345
- end
346
-
347
- # Use this to force the client to reconnect after a force_disconnect.
348
- def reconnect
349
- @disconnected = false
350
- connect!
351
- end
352
-
353
- # Use this to force the client to disconnect and not automatically
354
- # reconnect.
355
- def disconnect
356
- disconnect!
357
- end
358
-
359
- # Queue messages for delivery once a user has accepted our authorization
360
- # request. Works in conjunction with the deferred delivery thread.
361
- #
362
- # You can use this method if you want to manually add friends and still
363
- # have the message queued for later delivery.
364
- def deliver_deferred(jid, message, type)
365
- msg = {:to => jid, :message => message, :type => type}
366
- queue(:pending_messages) << [msg]
367
- end
368
-
369
- private
370
-
371
- def client=(client)
372
- self.roster = nil # ensure we clear the roster, since that's now associated with a different client.
373
- @client = client
374
- end
375
-
376
- def roster=(new_roster)
377
- @roster = new_roster
378
- end
379
-
380
- def connect!
381
- raise ConnectionError, "Connections are disabled - use Jabber::Simple::force_connect() to reconnect." if @disconnected
382
- # Pre-connect
383
- @connect_mutex ||= Mutex.new
384
-
385
- # don't try to connect if another thread is already connecting.
386
- return if @connect_mutex.locked?
387
-
388
- @connect_mutex.lock
389
- disconnect!(false) if connected?
390
-
391
- # Connect
392
- jid = JID.new(@jid)
393
- my_client = Client.new(@jid)
394
- my_client.connect
395
- my_client.auth(@password)
396
- self.client = my_client
397
-
398
- # Post-connect
399
- register_default_callbacks
400
- status(@presence, @status_message)
401
- @connect_mutex.unlock
402
- end
403
-
404
- def disconnect!(auto_reconnect = true)
405
- if client.respond_to?(:is_connected?) && client.is_connected?
406
- begin
407
- client.close
408
- rescue Errno::EPIPE, IOError => e
409
- # probably should log this.
410
- nil
411
- end
412
- end
413
- client = nil
414
- @disconnected = auto_reconnect
415
- end
416
-
417
- def register_default_callbacks
418
- client.add_message_callback do |message|
419
- queue(:received_messages) << message unless message.body.nil?
420
- end
421
-
422
- roster.add_subscription_callback do |roster_item, presence|
423
- if presence.type == :subscribed
424
- queue(:new_subscriptions) << [roster_item, presence]
425
- end
426
- end
427
-
428
- roster.add_subscription_request_callback do |roster_item, presence|
429
- if accept_subscriptions?
430
- roster.accept_subscription(presence.from)
431
- else
432
- queue(:subscription_requests) << [roster_item, presence]
433
- end
434
- end
435
-
436
- @presence_updates = {}
437
- @presence_mutex = Mutex.new
438
- roster.add_presence_callback do |roster_item, old_presence, new_presence|
439
- simple_jid = roster_item.jid.strip.to_s
440
- presence = case new_presence.type
441
- when nil
442
- new_presence.show || :online
443
- when :unavailable
444
- :unavailable
445
- else
446
- nil
447
- end
448
-
449
- if presence && @presence_updates[simple_jid] != presence
450
- queue(:presence_updates) << simple_jid
451
- @presence_mutex.synchronize { @presence_updates[simple_jid] = [presence, new_presence.status] }
452
- end
453
- end
454
- end
455
-
456
- # This thread facilitates the delivery of messages to users who haven't yet
457
- # accepted an invitation from us. When we attempt to deliver a message, if
458
- # the user hasn't subscribed, we place the message in a queue for later
459
- # delivery. Once a user has accepted our authorization request, we deliver
460
- # any messages that have been queued up in the meantime.
461
- def start_deferred_delivery_thread #:nodoc:
462
- Thread.new {
463
- loop {
464
- messages = [queue(:pending_messages).pop].flatten
465
- messages.each do |message|
466
- if subscribed_to?(message[:to])
467
- deliver(message[:to], message[:message], message[:type])
468
- else
469
- queue(:pending_messages) << message
470
- end
471
- end
472
- }
473
- }
474
- end
475
-
476
- def queue(queue)
477
- @queues ||= Hash.new { |h,k| h[k] = Queue.new }
478
- @queues[queue]
479
- end
480
-
481
- def dequeue(queue, non_blocking = true, max_items = 100, &block)
482
- queue_items = []
483
- max_items.times do
484
- queue_item = queue(queue).pop(non_blocking) rescue nil
485
- break if queue_item.nil?
486
- queue_items << queue_item
487
- yield queue_item if block_given?
488
- end
489
- queue_items
490
- end
491
- end
492
- end
493
-
494
- true