mojodna-switchboard 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +31 -0
- data/bin/switchboard +35 -0
- data/examples/election_results.rb +61 -0
- data/lib/switchboard/colors.rb +10 -0
- data/lib/switchboard/commands/command.rb +85 -0
- data/lib/switchboard/commands/config/config.rb +20 -0
- data/lib/switchboard/commands/config.rb +1 -0
- data/lib/switchboard/commands/default.rb +47 -0
- data/lib/switchboard/commands/help/help.rb +15 -0
- data/lib/switchboard/commands/help.rb +1 -0
- data/lib/switchboard/commands/pubsub/pubsub.rb +16 -0
- data/lib/switchboard/commands/pubsub/subscribe.rb +35 -0
- data/lib/switchboard/commands/pubsub/subscriptions.rb +32 -0
- data/lib/switchboard/commands/pubsub/unsubscribe.rb +31 -0
- data/lib/switchboard/commands/pubsub.rb +4 -0
- data/lib/switchboard/commands/roster/add.rb +26 -0
- data/lib/switchboard/commands/roster/list.rb +24 -0
- data/lib/switchboard/commands/roster/remove.rb +29 -0
- data/lib/switchboard/commands/roster/roster.rb +7 -0
- data/lib/switchboard/commands/roster.rb +4 -0
- data/lib/switchboard/commands.rb +6 -0
- data/lib/switchboard/core.rb +324 -0
- data/lib/switchboard/instance_exec.rb +16 -0
- data/lib/switchboard/jacks/auto_accept.rb +16 -0
- data/lib/switchboard/jacks/debug.rb +17 -0
- data/lib/switchboard/jacks/notify.rb +15 -0
- data/lib/switchboard/jacks/oauth_pubsub.rb +50 -0
- data/lib/switchboard/jacks/roster_debug.rb +23 -0
- data/lib/switchboard/jacks.rb +5 -0
- data/lib/switchboard/oauth/request_proxy/mock_request.rb +21 -0
- data/lib/switchboard/settings.rb +32 -0
- data/lib/switchboard/switchboard.rb +5 -0
- data/lib/switchboard/version.rb +3 -0
- data/lib/switchboard/xmpp4r/pubsub/helper/oauth_service_helper.rb +107 -0
- data/lib/switchboard.rb +1 -0
- data/switchboard.gemspec +14 -0
- metadata +113 -0
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
begin
|
3
|
+
require 'xmpp4r'
|
4
|
+
rescue LoadError => e
|
5
|
+
gem = e.message.split("--").last.strip
|
6
|
+
puts "The #{gem} gem is required."
|
7
|
+
end
|
8
|
+
|
9
|
+
# allow local library modifications/additions to be loaded
|
10
|
+
$: << File.join(File.dirname(__FILE__))
|
11
|
+
|
12
|
+
require 'switchboard/instance_exec'
|
13
|
+
require 'xmpp4r/roster'
|
14
|
+
|
15
|
+
|
16
|
+
module Switchboard
|
17
|
+
class Core
|
18
|
+
include Timeout
|
19
|
+
|
20
|
+
attr_reader :client, :jacks, :roster, :settings
|
21
|
+
|
22
|
+
def initialize(settings = Switchboard::Settings.new, spin = true, &block)
|
23
|
+
# register a handler for SIGINTs
|
24
|
+
trap(:INT) do
|
25
|
+
# exit on a second ^C
|
26
|
+
trap(:INT) do
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
@deferreds.each do |name, deferred|
|
31
|
+
puts "Killing #{name}" if debug?
|
32
|
+
deferred.kill
|
33
|
+
end
|
34
|
+
|
35
|
+
shutdown!
|
36
|
+
end
|
37
|
+
|
38
|
+
@settings = settings
|
39
|
+
@loop = spin
|
40
|
+
@shutdown = false
|
41
|
+
@deferreds = {}
|
42
|
+
@main = block if block_given?
|
43
|
+
|
44
|
+
# TODO jid may already have a resource, so account for that
|
45
|
+
@client = Jabber::Client.new([settings["jid"], settings["resource"]] * "/")
|
46
|
+
end
|
47
|
+
|
48
|
+
# Turn the hydrant on.
|
49
|
+
def run!
|
50
|
+
startup
|
51
|
+
|
52
|
+
if @main
|
53
|
+
instance_eval(&@main)
|
54
|
+
elsif loop?
|
55
|
+
sleep 5 while !shutdown?
|
56
|
+
end
|
57
|
+
|
58
|
+
shutdown
|
59
|
+
end
|
60
|
+
|
61
|
+
# TODO don't start threads yet; wait until all startup hooks have been run
|
62
|
+
def defer(callback_name, timeout = 30, &block)
|
63
|
+
puts "Deferring to #{callback_name}..." if debug?
|
64
|
+
@deferreds[callback_name.to_sym] = Thread.new do
|
65
|
+
|
66
|
+
begin
|
67
|
+
|
68
|
+
timeout(timeout) do
|
69
|
+
results = instance_eval(&block)
|
70
|
+
send(callback_name.to_sym, results)
|
71
|
+
end
|
72
|
+
|
73
|
+
puts "Done with #{callback_name}." if debug?
|
74
|
+
# TODO make this thread-safe
|
75
|
+
@deferreds.delete(callback_name.to_sym)
|
76
|
+
|
77
|
+
rescue Timeout::Error
|
78
|
+
puts "Deferred method timed out."
|
79
|
+
rescue
|
80
|
+
puts "An error occurred while running a deferred: #{$!}"
|
81
|
+
puts $!.backtrace * "\n"
|
82
|
+
puts "Initiating shutdown..."
|
83
|
+
@shutdown = true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Connect a jack to the switchboard
|
89
|
+
def plug!(*jacks)
|
90
|
+
@jacks ||= []
|
91
|
+
jacks.each do |jack|
|
92
|
+
puts "Connecting jack: #{jack}" if debug?
|
93
|
+
@jacks << jack
|
94
|
+
jack.connect(self)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Register a hook to run when the Jabber::Client encounters an exception.
|
99
|
+
def on_exception(&block)
|
100
|
+
register_hook(:exception, &block)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Register a hook to run when iq stanzas are received.
|
104
|
+
def on_iq(&block)
|
105
|
+
register_hook(:iq, &block)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Register a hook to run when message stanzas are received.
|
109
|
+
def on_message(&block)
|
110
|
+
register_hook(:message, &block)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Register a hook to run when presence stanzas are received.
|
114
|
+
def on_presence(&block)
|
115
|
+
register_hook(:presence, &block)
|
116
|
+
end
|
117
|
+
|
118
|
+
def on_roster_presence(&block)
|
119
|
+
register_hook(:roster_presence, &block)
|
120
|
+
end
|
121
|
+
|
122
|
+
def on_roster_query(&block)
|
123
|
+
register_hook(:roster_query, &block)
|
124
|
+
end
|
125
|
+
|
126
|
+
def on_roster_subscription(&block)
|
127
|
+
register_hook(:roster_subscription, &block)
|
128
|
+
end
|
129
|
+
|
130
|
+
def on_roster_subscription_request(&block)
|
131
|
+
register_hook(:roster_subscription_request, &block)
|
132
|
+
end
|
133
|
+
|
134
|
+
def on_roster_loaded(&block)
|
135
|
+
register_hook(:roster_loaded, &block)
|
136
|
+
end
|
137
|
+
|
138
|
+
def on_roster_update(&block)
|
139
|
+
register_hook(:roster_update, &block)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Register a startup hook.
|
143
|
+
# Hooks will be given 5 seconds to complete before moving on.
|
144
|
+
def on_startup(&block)
|
145
|
+
register_hook(:startup, &block)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Register a shutdown hook.
|
149
|
+
# Hooks will be given 5 seconds to complete before moving on.
|
150
|
+
def on_shutdown(&block)
|
151
|
+
register_hook(:shutdown, &block)
|
152
|
+
end
|
153
|
+
|
154
|
+
protected
|
155
|
+
|
156
|
+
def connect!
|
157
|
+
client.connect
|
158
|
+
client.auth(settings["password"])
|
159
|
+
@roster = Jabber::Roster::Helper.new(client)
|
160
|
+
end
|
161
|
+
|
162
|
+
def connected?
|
163
|
+
@connected
|
164
|
+
end
|
165
|
+
|
166
|
+
def debug?
|
167
|
+
settings["debug"]
|
168
|
+
end
|
169
|
+
|
170
|
+
def disconnect
|
171
|
+
presence(:unavailable)
|
172
|
+
client.close
|
173
|
+
end
|
174
|
+
|
175
|
+
def register_hook(name, &block)
|
176
|
+
@hooks ||= {}
|
177
|
+
@hooks[name.to_sym] ||= []
|
178
|
+
|
179
|
+
puts "Registering #{name} hook" if debug?
|
180
|
+
@hooks[name.to_sym] << block
|
181
|
+
end
|
182
|
+
|
183
|
+
def on(name, *args)
|
184
|
+
@hooks ||= {}
|
185
|
+
@hooks[name.to_sym] ||= []
|
186
|
+
@hooks[name.to_sym].each do |hook|
|
187
|
+
execute_hook(hook, *args)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def execute_hook(hook, *args)
|
192
|
+
timeout(1) do
|
193
|
+
instance_exec(*args, &hook)
|
194
|
+
end
|
195
|
+
rescue Timeout::Error
|
196
|
+
puts "Hook timed out, consider deferring it."
|
197
|
+
rescue
|
198
|
+
puts "An error occurred while running the hook; shutting down..."
|
199
|
+
puts $!
|
200
|
+
puts $!.backtrace * "\n"
|
201
|
+
shutdown
|
202
|
+
raise
|
203
|
+
end
|
204
|
+
|
205
|
+
def loop?
|
206
|
+
@loop
|
207
|
+
end
|
208
|
+
|
209
|
+
def presence(status = nil, to = nil)
|
210
|
+
presence = Jabber::Presence.new(nil, status)
|
211
|
+
presence.to = to
|
212
|
+
client.send(presence)
|
213
|
+
end
|
214
|
+
|
215
|
+
def register_default_callbacks
|
216
|
+
client.on_exception do |e, stream, where|
|
217
|
+
on(:exception, e, stream, where)
|
218
|
+
|
219
|
+
case where
|
220
|
+
when :something
|
221
|
+
else
|
222
|
+
puts "Caught #{e.inspect} on #{stream} at #{where}. You might want to consider handling this."
|
223
|
+
raise e
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
client.add_presence_callback do |presence|
|
228
|
+
on(:presence, presence)
|
229
|
+
end
|
230
|
+
|
231
|
+
client.add_message_callback do |message|
|
232
|
+
on(:message, message)
|
233
|
+
end
|
234
|
+
|
235
|
+
client.add_iq_callback do |iq|
|
236
|
+
on(:iq, iq)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def register_roster_callbacks
|
241
|
+
# presence from someone on my roster
|
242
|
+
roster.add_presence_callback do |item, old_presence, new_presence|
|
243
|
+
on(:roster_presence, item, old_presence, new_presence)
|
244
|
+
end
|
245
|
+
|
246
|
+
# roster query completed (rarely used)
|
247
|
+
roster.add_query_callback do |query|
|
248
|
+
on(:roster_query, query)
|
249
|
+
end
|
250
|
+
|
251
|
+
# roster subscription
|
252
|
+
roster.add_subscription_callback do |item, presence|
|
253
|
+
# confirmation that we were able to subscribe to someone else
|
254
|
+
on(:roster_subscription, item, presence)
|
255
|
+
end
|
256
|
+
|
257
|
+
roster.add_subscription_request_callback do |item, presence|
|
258
|
+
# someone wants to subscribe to me!
|
259
|
+
on(:roster_subscription_request, item, presence)
|
260
|
+
end
|
261
|
+
|
262
|
+
# roster was updated (rarely used)
|
263
|
+
roster.add_update_callback do |old_item, new_item|
|
264
|
+
# roster has been updated; don't care
|
265
|
+
# puts "update: #{old_item.inspect}, #{new_item.inspect}"
|
266
|
+
on(:roster_update, old_item, new_item)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def startup
|
271
|
+
begin
|
272
|
+
timeout(30) do
|
273
|
+
connect!
|
274
|
+
@connected = true
|
275
|
+
|
276
|
+
register_default_callbacks
|
277
|
+
register_roster_callbacks
|
278
|
+
|
279
|
+
# tell others that we're online
|
280
|
+
presence
|
281
|
+
|
282
|
+
# wait for the roster to load
|
283
|
+
roster.wait_for_roster
|
284
|
+
end
|
285
|
+
rescue Timeout::Error
|
286
|
+
puts "Startup took too long. Shutting down."
|
287
|
+
shutdown(false)
|
288
|
+
exit 1
|
289
|
+
end
|
290
|
+
|
291
|
+
# roster has now been loaded
|
292
|
+
on(:roster_loaded)
|
293
|
+
|
294
|
+
puts "Core startup completed." if debug?
|
295
|
+
|
296
|
+
# run startup hooks
|
297
|
+
on(:startup)
|
298
|
+
|
299
|
+
puts "=> Switchboard started."
|
300
|
+
end
|
301
|
+
|
302
|
+
def shutdown!
|
303
|
+
puts "Shutdown initiated."
|
304
|
+
@shutdown = true
|
305
|
+
end
|
306
|
+
|
307
|
+
def shutdown(run_hooks = true)
|
308
|
+
while (pending = @deferreds.select { |k,d| d.alive? }.length) > 0
|
309
|
+
puts "Waiting for #{pending} thread(s) to finish" if debug?
|
310
|
+
sleep 1
|
311
|
+
end
|
312
|
+
|
313
|
+
# run shutdown hooks
|
314
|
+
on(:shutdown) if run_hooks
|
315
|
+
|
316
|
+
puts "Shutting down..." if debug?
|
317
|
+
disconnect if connected?
|
318
|
+
end
|
319
|
+
|
320
|
+
def shutdown?
|
321
|
+
@shutdown
|
322
|
+
end
|
323
|
+
end
|
324
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Kernel
|
2
|
+
|
3
|
+
# Like instance_eval but allows parameters to be passed.
|
4
|
+
|
5
|
+
def instance_exec(*args, &block)
|
6
|
+
mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
|
7
|
+
Object.class_eval{ define_method(mname, &block) }
|
8
|
+
begin
|
9
|
+
ret = send(mname, *args)
|
10
|
+
ensure
|
11
|
+
Object.class_eval{ undef_method(mname) } rescue nil
|
12
|
+
end
|
13
|
+
ret
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class AutoAcceptJack
|
2
|
+
def self.connect(switchboard)
|
3
|
+
# complain if subscription requests were denied
|
4
|
+
switchboard.on_roster_subscription do |item, subscription|
|
5
|
+
unless subscription.type == :subscribed
|
6
|
+
puts "My subscription request was denied!"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# auto-accept subscription requests
|
11
|
+
switchboard.on_roster_subscription_request do |item, subscription|
|
12
|
+
puts "Accepting subscription from #{subscription.from}"
|
13
|
+
roster.accept_subscription(subscription.from)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'switchboard/colors'
|
2
|
+
|
3
|
+
class DebugJack
|
4
|
+
def self.connect(switchboard)
|
5
|
+
switchboard.on_presence do |presence|
|
6
|
+
puts "<< #{presence.to_s}".green
|
7
|
+
end
|
8
|
+
|
9
|
+
switchboard.on_message do |message|
|
10
|
+
puts "<< #{message.to_s}".blue
|
11
|
+
end
|
12
|
+
|
13
|
+
switchboard.on_iq do |iq|
|
14
|
+
puts "<< #{iq.to_s}".yellow
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class NotifyJack
|
2
|
+
def self.connect(switchboard)
|
3
|
+
switchboard.on_roster_loaded do
|
4
|
+
roster.items.each do |jid, item|
|
5
|
+
presence(nil, jid)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
switchboard.on_shutdown do
|
10
|
+
roster.items.each do |jid, item|
|
11
|
+
presence(:unavailable, jid)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
begin
|
3
|
+
require 'oauth'
|
4
|
+
rescue LoadError => e
|
5
|
+
gem = e.message.split("--").last.strip
|
6
|
+
puts "The #{gem} gem is required."
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'oauth/consumer'
|
10
|
+
require 'oauth/request_proxy/mock_request'
|
11
|
+
require 'xmpp4r/pubsub'
|
12
|
+
require 'xmpp4r/pubsub/helper/oauth_service_helper'
|
13
|
+
|
14
|
+
class OAuthPubSubJack
|
15
|
+
def self.connect(switchboard)
|
16
|
+
switchboard.on_startup do
|
17
|
+
@pubsub = Jabber::PubSub::OAuthServiceHelper.new(client, settings["pubsub.server"])
|
18
|
+
|
19
|
+
@oauth_consumer = OAuth::Consumer.new(settings["oauth.consumer_key"], settings["oauth.consumer_secret"])
|
20
|
+
@oauth_token = OAuth::Token.new(settings["oauth.token"], settings["oauth.token_secret"])
|
21
|
+
# this is Fire Eagle-specific
|
22
|
+
@general_token = OAuth::Token.new(settings["oauth.general_token"], settings["oauth.general_token_secret"])
|
23
|
+
|
24
|
+
@pubsub.add_event_callback do |event|
|
25
|
+
on(:pubsub_event, event)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# TODO add the ability to define accessors
|
30
|
+
def switchboard.general_token
|
31
|
+
@general_token
|
32
|
+
end
|
33
|
+
|
34
|
+
def switchboard.oauth_consumer
|
35
|
+
@oauth_consumer
|
36
|
+
end
|
37
|
+
|
38
|
+
def switchboard.oauth_token
|
39
|
+
@oauth_token
|
40
|
+
end
|
41
|
+
|
42
|
+
def switchboard.pubsub
|
43
|
+
@pubsub
|
44
|
+
end
|
45
|
+
|
46
|
+
def switchboard.on_pubsub_event(&block)
|
47
|
+
register_hook(:pubsub_event, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class RosterDebugJack
|
2
|
+
def self.connect(switchboard)
|
3
|
+
switchboard.on_roster_presence do |item, old_presence, new_presence|
|
4
|
+
puts "[presence] << #{item.inspect}: #{old_presence.to_s}, #{new_presence.to_s}"
|
5
|
+
end
|
6
|
+
|
7
|
+
switchboard.on_roster_query do |query|
|
8
|
+
puts "[roster query] << #{query.to_s}"
|
9
|
+
end
|
10
|
+
|
11
|
+
switchboard.on_roster_subscription do |item, subscription|
|
12
|
+
puts "[subscription] << #{item.inspect}: #{subscription.to_s}"
|
13
|
+
end
|
14
|
+
|
15
|
+
switchboard.on_roster_subscription_request do |item, subscription|
|
16
|
+
puts "[subscription request] << #{item.inspect}: #{subscription.to_s}"
|
17
|
+
end
|
18
|
+
|
19
|
+
switchboard.on_roster_update do |old_item, new_item|
|
20
|
+
puts "[update] #{old_item.inspect}, #{new_item.inspect}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'oauth/request_proxy/base'
|
2
|
+
|
3
|
+
module OAuth
|
4
|
+
module RequestProxy
|
5
|
+
class MockRequest < OAuth::RequestProxy::Base
|
6
|
+
proxies Hash
|
7
|
+
|
8
|
+
def parameters
|
9
|
+
@request["parameters"]
|
10
|
+
end
|
11
|
+
|
12
|
+
def method
|
13
|
+
@request["method"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def uri
|
17
|
+
@request["uri"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Switchboard
|
2
|
+
class Settings
|
3
|
+
DEFAULT_PATH = File.join(ENV["HOME"], ".switchboardrc")
|
4
|
+
|
5
|
+
def initialize(path = DEFAULT_PATH)
|
6
|
+
@path = path
|
7
|
+
|
8
|
+
if File.exists?(path)
|
9
|
+
@config = YAML.load(File.read(path))
|
10
|
+
end
|
11
|
+
|
12
|
+
@config ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(key)
|
16
|
+
Switchboard::Command::OPTIONS[key] || @config[key] || Switchboard::Command::DEFAULT_OPTIONS[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
alias_method :[], :get
|
20
|
+
|
21
|
+
def set!(key, value)
|
22
|
+
@config[key] = value
|
23
|
+
write
|
24
|
+
end
|
25
|
+
|
26
|
+
def write
|
27
|
+
open(@path, "w") do |f|
|
28
|
+
f << @config.to_yaml
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Jabber
|
2
|
+
module PubSub
|
3
|
+
# PubSub service helper for use with OAuth-authenticated nodes
|
4
|
+
class OAuthServiceHelper < ServiceHelper
|
5
|
+
def initialize(stream, pubsubjid)
|
6
|
+
super(stream, pubsubjid)
|
7
|
+
end
|
8
|
+
|
9
|
+
# override #get_subscriptions_from_all_nodes to add an oauth element
|
10
|
+
def get_subscriptions_from_all_nodes(oauth_consumer, oauth_token)
|
11
|
+
iq = basic_pubsub_query(:get)
|
12
|
+
|
13
|
+
iq.pubsub.add(create_oauth_node(oauth_consumer, oauth_token))
|
14
|
+
|
15
|
+
entities = iq.pubsub.add(REXML::Element.new('subscriptions'))
|
16
|
+
res = nil
|
17
|
+
@stream.send_with_id(iq) { |reply|
|
18
|
+
if reply.pubsub.first_element('subscriptions')
|
19
|
+
res = []
|
20
|
+
reply.pubsub.first_element('subscriptions').each_element('subscription') { |subscription|
|
21
|
+
res << Jabber::PubSub::Subscription.import(subscription)
|
22
|
+
}
|
23
|
+
end
|
24
|
+
}
|
25
|
+
|
26
|
+
res
|
27
|
+
end
|
28
|
+
|
29
|
+
# override #subscribe_to to add an oauth element
|
30
|
+
def subscribe_to(node, oauth_consumer, oauth_token)
|
31
|
+
iq = basic_pubsub_query(:set)
|
32
|
+
sub = REXML::Element.new('subscribe')
|
33
|
+
sub.attributes['node'] = node
|
34
|
+
sub.attributes['jid'] = @stream.jid.strip.to_s
|
35
|
+
|
36
|
+
sub.add(create_oauth_node(oauth_consumer, oauth_token))
|
37
|
+
|
38
|
+
iq.pubsub.add(sub)
|
39
|
+
res = nil
|
40
|
+
@stream.send_with_id(iq) do |reply|
|
41
|
+
pubsubanswer = reply.pubsub
|
42
|
+
if pubsubanswer.first_element('subscription')
|
43
|
+
res = PubSub::Subscription.import(pubsubanswer.first_element('subscription'))
|
44
|
+
end
|
45
|
+
end # @stream.send_with_id(iq)
|
46
|
+
res
|
47
|
+
end
|
48
|
+
|
49
|
+
# override #unsubscribe_from to add an oauth element
|
50
|
+
def unsubscribe_from(node, oauth_consumer, oauth_token, subid=nil)
|
51
|
+
iq = basic_pubsub_query(:set)
|
52
|
+
unsub = PubSub::Unsubscribe.new
|
53
|
+
unsub.node = node
|
54
|
+
unsub.jid = @stream.jid.strip
|
55
|
+
|
56
|
+
unsub.add(create_oauth_node(oauth_consumer, oauth_token))
|
57
|
+
|
58
|
+
iq.pubsub.add(unsub)
|
59
|
+
ret = false
|
60
|
+
@stream.send_with_id(iq) { |reply|
|
61
|
+
ret = reply.kind_of?(Jabber::Iq) and reply.type == :result
|
62
|
+
} # @stream.send_with_id(iq)
|
63
|
+
ret
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
# add the OAuth sauce (XEP-235)
|
69
|
+
def create_oauth_node(oauth_consumer, oauth_token)
|
70
|
+
require 'oauth/signature/hmac/sha1'
|
71
|
+
require 'cgi'
|
72
|
+
|
73
|
+
request = OAuth::RequestProxy.proxy \
|
74
|
+
"method" => "iq",
|
75
|
+
"uri" => [@stream.jid.strip.to_s, @pubsubjid.strip.to_s] * "&",
|
76
|
+
"parameters" => {
|
77
|
+
"oauth_consumer_key" => oauth_consumer.key,
|
78
|
+
"oauth_token" => oauth_token.token,
|
79
|
+
"oauth_signature_method" => "HMAC-SHA1"
|
80
|
+
}
|
81
|
+
|
82
|
+
signature = OAuth::Signature.sign(request, :consumer => oauth_consumer, :token => oauth_token)
|
83
|
+
|
84
|
+
oauth = REXML::Element.new("oauth")
|
85
|
+
oauth.attributes['xmlns'] = 'urn:xmpp:oauth'
|
86
|
+
|
87
|
+
oauth_consumer_key = REXML::Element.new("oauth_consumer_key")
|
88
|
+
oauth_consumer_key.text = oauth_consumer.key
|
89
|
+
oauth.add(oauth_consumer_key)
|
90
|
+
|
91
|
+
oauth_token_node = REXML::Element.new("oauth_token")
|
92
|
+
oauth_token_node.text = oauth_token.token
|
93
|
+
oauth.add(oauth_token_node)
|
94
|
+
|
95
|
+
oauth_signature_method = REXML::Element.new("oauth_signature_method")
|
96
|
+
oauth_signature_method.text = "HMAC-SHA1"
|
97
|
+
oauth.add(oauth_signature_method)
|
98
|
+
|
99
|
+
oauth_signature = REXML::Element.new("oauth_signature")
|
100
|
+
oauth_signature.text = signature
|
101
|
+
oauth.add(oauth_signature)
|
102
|
+
|
103
|
+
oauth
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/lib/switchboard.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'switchboard/switchboard'
|
data/switchboard.gemspec
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "switchboard"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.summary = "XMPP toolkit"
|
5
|
+
s.description = "A toolkit for assembling XMPP clients and interacting with XMPP servers."
|
6
|
+
s.authors = ["Seth Fitzsimmons"]
|
7
|
+
s.email = ["seth@mojodna.net"]
|
8
|
+
|
9
|
+
s.files = ["bin", "bin/switchboard", "examples/election_results.rb", "github-test.rb", "lib", "lib/switchboard", "lib/switchboard/colors.rb", "lib/switchboard/commands", "lib/switchboard/commands/command.rb", "lib/switchboard/commands/config", "lib/switchboard/commands/config/config.rb", "lib/switchboard/commands/config.rb", "lib/switchboard/commands/default.rb", "lib/switchboard/commands/help", "lib/switchboard/commands/help/help.rb", "lib/switchboard/commands/help.rb", "lib/switchboard/commands/pubsub", "lib/switchboard/commands/pubsub/pubsub.rb", "lib/switchboard/commands/pubsub/subscribe.rb", "lib/switchboard/commands/pubsub/subscriptions.rb", "lib/switchboard/commands/pubsub/unsubscribe.rb", "lib/switchboard/commands/pubsub.rb", "lib/switchboard/commands/roster", "lib/switchboard/commands/roster/add.rb", "lib/switchboard/commands/roster/list.rb", "lib/switchboard/commands/roster/remove.rb", "lib/switchboard/commands/roster/roster.rb", "lib/switchboard/commands/roster.rb", "lib/switchboard/commands.rb", "lib/switchboard/core.rb", "lib/switchboard/instance_exec.rb", "lib/switchboard/jacks", "lib/switchboard/jacks/auto_accept.rb", "lib/switchboard/jacks/debug.rb", "lib/switchboard/jacks/notify.rb", "lib/switchboard/jacks/oauth_pubsub.rb", "lib/switchboard/jacks/roster_debug.rb", "lib/switchboard/jacks.rb", "lib/switchboard/oauth", "lib/switchboard/oauth/request_proxy", "lib/switchboard/oauth/request_proxy/mock_request.rb", "lib/switchboard/settings.rb", "lib/switchboard/switchboard.rb", "lib/switchboard/version.rb", "lib/switchboard/xmpp4r", "lib/switchboard/xmpp4r/pubsub", "lib/switchboard/xmpp4r/pubsub/helper", "lib/switchboard/xmpp4r/pubsub/helper/oauth_service_helper.rb", "lib/switchboard.rb", "README.markdown", "switchboard-0.0.1.gem", "switchboard.gemspec"]
|
10
|
+
s.executables = ["switchboard"]
|
11
|
+
s.require_paths = ["lib"]
|
12
|
+
|
13
|
+
s.add_dependency("xmpp4r")
|
14
|
+
end
|