sprsquish-blather 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +1 -1
- data/README.rdoc +41 -12
- data/examples/echo.rb +1 -1
- data/examples/execute.rb +0 -5
- data/examples/pubsub/cli.rb +64 -0
- data/examples/pubsub/ping_pong.rb +18 -0
- data/examples/rosterprint.rb +14 -0
- data/examples/xmpp4r/echo.rb +35 -0
- data/lib/blather/client/client.rb +19 -13
- data/lib/blather/client/dsl/pubsub.rb +133 -0
- data/lib/blather/client/dsl.rb +16 -0
- data/lib/blather/client.rb +1 -1
- data/lib/blather/core_ext/active_support/inheritable_attributes.rb +117 -0
- data/lib/blather/core_ext/active_support.rb +1 -117
- data/lib/blather/core_ext/nokogiri.rb +35 -0
- data/lib/blather/errors/sasl_error.rb +3 -1
- data/lib/blather/errors/stanza_error.rb +10 -17
- data/lib/blather/errors/stream_error.rb +11 -14
- data/lib/blather/errors.rb +3 -20
- data/lib/blather/jid.rb +1 -0
- data/lib/blather/roster.rb +9 -0
- data/lib/blather/roster_item.rb +6 -1
- data/lib/blather/stanza/disco/disco_info.rb +45 -33
- data/lib/blather/stanza/disco/disco_items.rb +32 -21
- data/lib/blather/stanza/disco.rb +7 -1
- data/lib/blather/stanza/iq/query.rb +16 -8
- data/lib/blather/stanza/iq/roster.rb +33 -22
- data/lib/blather/stanza/iq.rb +13 -8
- data/lib/blather/stanza/message.rb +20 -31
- data/lib/blather/stanza/presence/status.rb +13 -21
- data/lib/blather/stanza/presence/subscription.rb +11 -16
- data/lib/blather/stanza/presence.rb +3 -5
- data/lib/blather/stanza/pubsub/affiliations.rb +50 -0
- data/lib/blather/stanza/pubsub/create.rb +43 -0
- data/lib/blather/stanza/pubsub/errors.rb +9 -0
- data/lib/blather/stanza/pubsub/event.rb +77 -0
- data/lib/blather/stanza/pubsub/items.rb +63 -0
- data/lib/blather/stanza/pubsub/publish.rb +58 -0
- data/lib/blather/stanza/pubsub/retract.rb +53 -0
- data/lib/blather/stanza/pubsub/subscribe.rb +42 -0
- data/lib/blather/stanza/pubsub/subscription.rb +66 -0
- data/lib/blather/stanza/pubsub/subscriptions.rb +55 -0
- data/lib/blather/stanza/pubsub/unsubscribe.rb +42 -0
- data/lib/blather/stanza/pubsub.rb +63 -0
- data/lib/blather/stanza/pubsub_owner/delete.rb +34 -0
- data/lib/blather/stanza/pubsub_owner/purge.rb +34 -0
- data/lib/blather/stanza/pubsub_owner.rb +41 -0
- data/lib/blather/stanza.rb +35 -18
- data/lib/blather/stream/client.rb +1 -2
- data/lib/blather/stream/component.rb +9 -5
- data/lib/blather/stream/features/resource.rb +63 -0
- data/lib/blather/stream/{sasl.rb → features/sasl.rb} +53 -52
- data/lib/blather/stream/features/session.rb +44 -0
- data/lib/blather/stream/features/tls.rb +28 -0
- data/lib/blather/stream/features.rb +53 -0
- data/lib/blather/stream/parser.rb +70 -46
- data/lib/blather/stream.rb +76 -168
- data/lib/blather/xmpp_node.rb +113 -52
- data/lib/blather.rb +35 -12
- data/spec/blather/client/client_spec.rb +44 -58
- data/spec/blather/client/dsl/pubsub_spec.rb +465 -0
- data/spec/blather/client/dsl_spec.rb +19 -6
- data/spec/blather/core_ext/nokogiri_spec.rb +83 -0
- data/spec/blather/errors/sasl_error_spec.rb +8 -8
- data/spec/blather/errors/stanza_error_spec.rb +25 -33
- data/spec/blather/errors/stream_error_spec.rb +21 -16
- data/spec/blather/errors_spec.rb +4 -11
- data/spec/blather/jid_spec.rb +31 -30
- data/spec/blather/roster_item_spec.rb +34 -23
- data/spec/blather/roster_spec.rb +27 -12
- data/spec/blather/stanza/discos/disco_info_spec.rb +61 -42
- data/spec/blather/stanza/discos/disco_items_spec.rb +47 -35
- data/spec/blather/stanza/iq/query_spec.rb +34 -11
- data/spec/blather/stanza/iq/roster_spec.rb +47 -30
- data/spec/blather/stanza/iq_spec.rb +19 -14
- data/spec/blather/stanza/message_spec.rb +30 -17
- data/spec/blather/stanza/presence/status_spec.rb +43 -20
- data/spec/blather/stanza/presence/subscription_spec.rb +41 -21
- data/spec/blather/stanza/presence_spec.rb +34 -21
- data/spec/blather/stanza/pubsub/affiliations_spec.rb +57 -0
- data/spec/blather/stanza/pubsub/create_spec.rb +56 -0
- data/spec/blather/stanza/pubsub/event_spec.rb +84 -0
- data/spec/blather/stanza/pubsub/items_spec.rb +79 -0
- data/spec/blather/stanza/pubsub/publish_spec.rb +83 -0
- data/spec/blather/stanza/pubsub/retract_spec.rb +75 -0
- data/spec/blather/stanza/pubsub/subscribe_spec.rb +61 -0
- data/spec/blather/stanza/pubsub/subscription_spec.rb +97 -0
- data/spec/blather/stanza/pubsub/subscriptions_spec.rb +59 -0
- data/spec/blather/stanza/pubsub/unsubscribe_spec.rb +61 -0
- data/spec/blather/stanza/pubsub_owner/delete_spec.rb +50 -0
- data/spec/blather/stanza/pubsub_owner/purge_spec.rb +50 -0
- data/spec/blather/stanza/pubsub_owner_spec.rb +27 -0
- data/spec/blather/stanza/pubsub_spec.rb +62 -0
- data/spec/blather/stanza_spec.rb +53 -38
- data/spec/blather/stream/client_spec.rb +231 -88
- data/spec/blather/stream/component_spec.rb +14 -5
- data/spec/blather/stream/parser_spec.rb +145 -0
- data/spec/blather/xmpp_node_spec.rb +192 -96
- data/spec/fixtures/pubsub.rb +311 -0
- data/spec/spec_helper.rb +5 -4
- metadata +53 -17
- data/Rakefile +0 -139
- data/ext/extconf.rb +0 -65
- data/ext/push_parser.c +0 -209
- data/lib/blather/core_ext/libxml.rb +0 -28
- data/lib/blather/stream/resource.rb +0 -48
- data/lib/blather/stream/session.rb +0 -36
- data/lib/blather/stream/stream_handler.rb +0 -39
- data/lib/blather/stream/tls.rb +0 -33
- data/spec/blather/core_ext/libxml_spec.rb +0 -58
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
= Blather
|
2
2
|
|
3
|
-
|
3
|
+
XMPP DSL (and more) for Ruby written on EventMachine and Nokogiri.
|
4
4
|
|
5
5
|
== Features
|
6
6
|
|
7
7
|
* evented architecture
|
8
|
-
* uses
|
8
|
+
* uses Nokogiri
|
9
9
|
* simplified starting point
|
10
10
|
|
11
11
|
== Project Pages
|
@@ -18,11 +18,7 @@ GitHub Docs:: http://docs.github.com/sprsquish/blather
|
|
18
18
|
|
19
19
|
RubyForge:: http://rubyforge.org/projects/squishtech
|
20
20
|
|
21
|
-
RDocs:: http://squishtech.rubyforge.org/blather
|
22
|
-
|
23
|
-
== Author
|
24
|
-
|
25
|
-
Jeff Smick <sprsquish@gmail.com>
|
21
|
+
RDocs:: http://squishtech.rubyforge.org/blather
|
26
22
|
|
27
23
|
= Usage
|
28
24
|
|
@@ -32,7 +28,7 @@ Jeff Smick <sprsquish@gmail.com>
|
|
32
28
|
|
33
29
|
== Example
|
34
30
|
|
35
|
-
See the
|
31
|
+
See the examples directory for more advanced examples.
|
36
32
|
|
37
33
|
This will auto-accept any subscription requests and echo back any chat messages.
|
38
34
|
|
@@ -73,7 +69,7 @@ The different types of guards are:
|
|
73
69
|
# Equivalent to stanza.chat?
|
74
70
|
message :chat?
|
75
71
|
|
76
|
-
# Hash with value (:body => 'exit')
|
72
|
+
# Hash with any value (:body => 'exit')
|
77
73
|
# Calls the key on the stanza and checks for equality
|
78
74
|
# Equivalent to stanza.body == 'exit'
|
79
75
|
message :body => 'exit'
|
@@ -99,6 +95,12 @@ The different types of guards are:
|
|
99
95
|
# Equivalent to stanza.body == 'foo' || stanza.body == 'baz'
|
100
96
|
message [{:body => 'foo'}, {:body => 'baz'}]
|
101
97
|
|
98
|
+
# XPath
|
99
|
+
# Runs the xpath query on the stanza and checks for results
|
100
|
+
# This guard type cannot be combined with other guards
|
101
|
+
# Equivalent to !stanza.find('/iq/ns:pubsub', :ns => 'pubsub:namespace').empty?
|
102
|
+
iq '/iq/ns:pubsub', :ns => 'pubsub:namespace'
|
103
|
+
|
102
104
|
== On the Command Line:
|
103
105
|
|
104
106
|
Default usage is:
|
@@ -117,11 +119,38 @@ Command line options:
|
|
117
119
|
|
118
120
|
= TODO
|
119
121
|
|
120
|
-
* Add XPath guard that passes the result to the handler
|
121
122
|
* Add Disco the the DSL
|
122
|
-
* PubSub (XEP-0060: http://xmpp.org/extensions/xep-0060.html)
|
123
123
|
* More examples (Re-write XMPP4R examples into Blather)
|
124
124
|
|
125
|
+
= Author
|
126
|
+
|
127
|
+
Jeff Smick <sprsquish@gmail.com>
|
128
|
+
|
129
|
+
= Contributors
|
130
|
+
|
131
|
+
Nolan Darilek <nolan@thewordnerd.info>
|
132
|
+
|
125
133
|
= License
|
126
134
|
|
127
|
-
|
135
|
+
Blather
|
136
|
+
|
137
|
+
Copyright (c) 2009 Jeff Smick
|
138
|
+
|
139
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
140
|
+
a copy of this software and associated documentation files (the
|
141
|
+
"Software"), to deal in the Software without restriction, including
|
142
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
143
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
144
|
+
permit persons to whom the Software is furnished to do so, subject to
|
145
|
+
the following conditions:
|
146
|
+
|
147
|
+
The above copyright notice and this permission notice shall be
|
148
|
+
included in all copies or substantial portions of the Software.
|
149
|
+
|
150
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
151
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
152
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
153
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
154
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
155
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
156
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/examples/echo.rb
CHANGED
data/examples/execute.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'blather/client'
|
4
|
+
|
5
|
+
#ls
|
6
|
+
#cd
|
7
|
+
#cat
|
8
|
+
#Blather::LOG.level = Logger::DEBUG
|
9
|
+
module CliHandler
|
10
|
+
include EM::Protocols::LineText2
|
11
|
+
|
12
|
+
def ls(node)
|
13
|
+
pubsub.node(parse_dir(node)) do |result|
|
14
|
+
cur = node.split('/')
|
15
|
+
puts
|
16
|
+
puts result.items.map { |i| (i.node.split('/') - cur).join('/') }.join("\n")
|
17
|
+
start_line
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def cd(node)
|
22
|
+
@node = parse_dir(node)
|
23
|
+
start_line
|
24
|
+
end
|
25
|
+
|
26
|
+
def cat(item)
|
27
|
+
end
|
28
|
+
|
29
|
+
def connect(who)
|
30
|
+
@who = who
|
31
|
+
puts "connected to '#{who}'"
|
32
|
+
end
|
33
|
+
|
34
|
+
def exit(_)
|
35
|
+
EM.stop
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize
|
39
|
+
$stdout.sync = true
|
40
|
+
@node = ''
|
41
|
+
@who = ''
|
42
|
+
start_line
|
43
|
+
end
|
44
|
+
|
45
|
+
def start_line
|
46
|
+
puts "\n/#{@node}> "
|
47
|
+
end
|
48
|
+
|
49
|
+
def receive_line(line)
|
50
|
+
return unless line =~ /(connect|exit|ls|cd|cat)\s?(.*)/i
|
51
|
+
__send__ $1, $2
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse_dir(list)
|
55
|
+
return '' if list == '/'
|
56
|
+
cur = @node.split('/')
|
57
|
+
list.split('/').each { |dir| dir == '..' ? cur.pop : (cur << dir) }
|
58
|
+
cur * '/'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
setup 'echo@jabber.local', 'echo'
|
63
|
+
pubsub_host 'pubsub.jabber.local'
|
64
|
+
when_ready { EM.open_keyboard CliHandler }
|
@@ -0,0 +1,18 @@
|
|
1
|
+
setup 'ping-pong@jabber.local', 'ping-pong'
|
2
|
+
|
3
|
+
pubsub.host = 'pubsub.jabber.local'
|
4
|
+
|
5
|
+
pubsub_event :node => 'ping' do |node|
|
6
|
+
pubsub.publish 'pong', node.payload
|
7
|
+
end
|
8
|
+
|
9
|
+
pubsub_event :node => 'pong' do |node|
|
10
|
+
x = node.payload.to_i
|
11
|
+
if x > 0
|
12
|
+
pubsub.publish 'ping', (x - 1)
|
13
|
+
else
|
14
|
+
shutdown
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
when_ready { pubsub.publish 'ping', 3 }
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Prints out each roster entry
|
4
|
+
|
5
|
+
require 'blather/client'
|
6
|
+
|
7
|
+
when_ready do
|
8
|
+
roster.grouped.each do |group, items|
|
9
|
+
puts "#{'*'*3} #{group || 'Ungrouped'} #{'*'*3}"
|
10
|
+
items.each { |item| puts "- #{item.name} (#{item.jid})" }
|
11
|
+
puts
|
12
|
+
end
|
13
|
+
shutdown
|
14
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# This bot will reply to every message it receives. To end the game, send 'exit'
|
4
|
+
|
5
|
+
require 'xmpp4r/client'
|
6
|
+
include Jabber
|
7
|
+
|
8
|
+
# settings
|
9
|
+
if ARGV.length != 2
|
10
|
+
puts "Run with ./echo_thread.rb user@server/resource password"
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
myJID = JID.new(ARGV[0])
|
14
|
+
myPassword = ARGV[1]
|
15
|
+
cl = Client.new(myJID)
|
16
|
+
cl.connect
|
17
|
+
cl.auth(myPassword)
|
18
|
+
cl.send(Presence.new)
|
19
|
+
puts "Connected ! send messages to #{myJID.strip.to_s}."
|
20
|
+
mainthread = Thread.current
|
21
|
+
cl.add_message_callback do |m|
|
22
|
+
if m.type != :error
|
23
|
+
m2 = Message.new(m.from, "You sent: #{m.body}")
|
24
|
+
m2.type = m.type
|
25
|
+
cl.send(m2)
|
26
|
+
if m.body == 'exit'
|
27
|
+
m2 = Message.new(m.from, "Exiting ...")
|
28
|
+
m2.type = m.type
|
29
|
+
cl.send(m2)
|
30
|
+
mainthread.wakeup
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
Thread.stop
|
35
|
+
cl.close
|
@@ -40,7 +40,8 @@ module Blather #:nodoc:
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def setup(jid, password, host = nil, port = nil)
|
43
|
-
@
|
43
|
+
@jid = JID.new(jid)
|
44
|
+
@setup = [@jid, password]
|
44
45
|
@setup << host if host
|
45
46
|
@setup << port if port
|
46
47
|
self
|
@@ -63,7 +64,6 @@ module Blather #:nodoc:
|
|
63
64
|
end
|
64
65
|
|
65
66
|
def write(stanza)
|
66
|
-
stanza.from ||= jid if stanza.respond_to?(:from)
|
67
67
|
@stream.send(stanza) if @stream
|
68
68
|
end
|
69
69
|
|
@@ -73,11 +73,7 @@ module Blather #:nodoc:
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def post_init
|
76
|
-
|
77
|
-
when Stream::Component then ready!
|
78
|
-
when Stream::Client then client_post_init
|
79
|
-
else raise "Don't know #{@stream.class} stream type. How the hell did this happen!?"
|
80
|
-
end
|
76
|
+
self.jid.node ? client_post_init : ready!
|
81
77
|
end
|
82
78
|
|
83
79
|
def close
|
@@ -93,7 +89,7 @@ module Blather #:nodoc:
|
|
93
89
|
handler.call stanza
|
94
90
|
else
|
95
91
|
stanza.handler_heirarchy.each do |type|
|
96
|
-
break if call_handler_for(type, stanza) && (stanza.is_a?(BlatherError) || stanza.type == :iq)
|
92
|
+
break if call_handler_for(type, stanza)# && (stanza.is_a?(BlatherError) || stanza.type == :iq)
|
97
93
|
end
|
98
94
|
end
|
99
95
|
end
|
@@ -132,8 +128,15 @@ module Blather #:nodoc:
|
|
132
128
|
|
133
129
|
def call_handler_for(type, stanza)
|
134
130
|
if @handlers[type]
|
135
|
-
@handlers[type].find
|
136
|
-
|
131
|
+
@handlers[type].find do |guards, handler|
|
132
|
+
if guards.first.is_a?(String)
|
133
|
+
unless (result = stanza.find(*guards)).empty?
|
134
|
+
handler.call(stanza, result)
|
135
|
+
end
|
136
|
+
elsif !guarded?(guards, stanza)
|
137
|
+
handler.call(stanza)
|
138
|
+
end
|
139
|
+
end
|
137
140
|
end
|
138
141
|
end
|
139
142
|
|
@@ -171,9 +174,12 @@ module Blather #:nodoc:
|
|
171
174
|
def check_guards(guards)
|
172
175
|
guards.each do |guard|
|
173
176
|
case guard
|
174
|
-
when Array
|
175
|
-
|
176
|
-
|
177
|
+
when Array
|
178
|
+
guard.each { |g| check_guards([g]) }
|
179
|
+
when Symbol, Proc, Hash, String
|
180
|
+
nil
|
181
|
+
else
|
182
|
+
raise "Bad guard: #{guard.inspect}"
|
177
183
|
end
|
178
184
|
end
|
179
185
|
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
module Blather
|
2
|
+
module DSL
|
3
|
+
|
4
|
+
class PubSub
|
5
|
+
attr_accessor :host
|
6
|
+
|
7
|
+
def initialize(host)
|
8
|
+
@host = host
|
9
|
+
end
|
10
|
+
|
11
|
+
##
|
12
|
+
# Retrieve Affiliations
|
13
|
+
# Yields a hash of affiliations in the form:
|
14
|
+
# {:aff_type => ['node1', 'node2']}
|
15
|
+
def affiliations(host = nil, &callback)
|
16
|
+
request Stanza::PubSub::Affiliations.new(:get, send_to(host)), :list, callback
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Retrieve Subscriptions
|
21
|
+
# Yields a hash of subscriptions in the form:
|
22
|
+
# {:sub_type => [{:node => 'node1', :jid => 'j@d'}]}
|
23
|
+
def subscriptions(host = nil, &callback)
|
24
|
+
request Stanza::PubSub::Subscriptions.new(:get, send_to(host)), :list, callback
|
25
|
+
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Discover Nodes
|
29
|
+
# Yields a list of DiscoItem::Item objects
|
30
|
+
# +path+ is the node's path. Default is '/'
|
31
|
+
def nodes(path = nil, host = nil, &callback)
|
32
|
+
path ||= '/'
|
33
|
+
stanza = Stanza::DiscoItems.new(:get, path)
|
34
|
+
stanza.to = send_to(host)
|
35
|
+
request stanza, :items, callback
|
36
|
+
end
|
37
|
+
|
38
|
+
##
|
39
|
+
# Discover node information
|
40
|
+
# Yields a DiscoInfo node
|
41
|
+
# +path+ is the node's path
|
42
|
+
def node(path, host = nil, &callback)
|
43
|
+
stanza = Stanza::DiscoInfo.new(:get, path)
|
44
|
+
stanza.to = send_to(host)
|
45
|
+
request stanza, nil, callback
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Retrieve items for a node
|
50
|
+
# +path+ is the node's path
|
51
|
+
# +list+ can be an array of items to retrieve
|
52
|
+
# +max+ can be the maximum number of items to return
|
53
|
+
def items(path, list = [], max = nil, host = nil, &callback)
|
54
|
+
request Stanza::PubSub::Items.request(send_to(host), path, list, max), :items, callback
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Subscribe to a node
|
59
|
+
# Yields the resulting Subscription object
|
60
|
+
# +node+ is the node to subscribe to
|
61
|
+
# +jid+ is the jid that should be used. Defaults to the stripped current JID
|
62
|
+
def subscribe(node, jid = nil, host = nil)
|
63
|
+
jid ||= DSL.client.jid.stripped
|
64
|
+
request(Stanza::PubSub::Subscribe.new(:set, send_to(host), node, jid)) { |n| yield n if block_given? }
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Unsubscribe from a node
|
69
|
+
# Yields the resulting Unsubscribe object
|
70
|
+
# +node+ is the node to subscribe to
|
71
|
+
# +jid+ is the jid that should be used. Defaults to the stripped current JID
|
72
|
+
def unsubscribe(node, jid = nil, host = nil)
|
73
|
+
jid ||= DSL.client.jid.stripped
|
74
|
+
request(Stanza::PubSub::Unsubscribe.new(:set, send_to(host), node, jid)) { |n| yield n if block_given? }
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Publish an item to a node
|
79
|
+
# Yields the resulting Publish node
|
80
|
+
# +node+ is the node to publish to
|
81
|
+
# +payload+ is the payload to send (see Blather::Stanza::PubSub::Publish for details)
|
82
|
+
def publish(node, payload, host = nil)
|
83
|
+
request(Stanza::PubSub::Publish.new(send_to(host), node, :set, payload)) { |n| yield n if block_given? }
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Delete items from a node
|
88
|
+
# Yields the resulting node
|
89
|
+
# +node+ is the node to retract items from
|
90
|
+
# +ids+ is a list of ids to retract. This can also be a single id
|
91
|
+
def retract(node, ids = [], host = nil)
|
92
|
+
request(Stanza::PubSub::Retract.new(send_to(host), node, :set, ids)) { |n| yield n if block_given? }
|
93
|
+
end
|
94
|
+
|
95
|
+
##
|
96
|
+
# Create a node
|
97
|
+
# Yields the resulting node
|
98
|
+
# This does not (yet) handle configuration
|
99
|
+
# +node+ is the node to create
|
100
|
+
def create(node, host = nil)
|
101
|
+
request(Stanza::PubSub::Create.new(:set, send_to(host), node)) { |n| yield n if block_given? }
|
102
|
+
end
|
103
|
+
|
104
|
+
##
|
105
|
+
# Purge all node items
|
106
|
+
# Yields the resulting node
|
107
|
+
# +node+ is the node to purge
|
108
|
+
def purge(node, host = nil)
|
109
|
+
request(Stanza::PubSubOwner::Purge.new(:set, send_to(host), node)) { |n| yield n if block_given? }
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Delete a node
|
114
|
+
# Yields the resulting node
|
115
|
+
# +node+ is the node to delete
|
116
|
+
def delete(node, host = nil)
|
117
|
+
request(Stanza::PubSubOwner::Delete.new(:set, send_to(host), node)) { |n| yield n if block_given? }
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
def request(node, method = nil, callback = nil, &block)
|
122
|
+
block = lambda { |node| callback.call(method ? node.__send__(method) : node) } unless block_given?
|
123
|
+
DSL.client.write_with_handler(node, &block)
|
124
|
+
end
|
125
|
+
|
126
|
+
def send_to(host = nil)
|
127
|
+
raise 'You must provide a host' unless (host ||= @host)
|
128
|
+
host
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
data/lib/blather/client/dsl.rb
CHANGED
@@ -2,11 +2,27 @@ require File.join(File.dirname(__FILE__), 'client')
|
|
2
2
|
|
3
3
|
module Blather
|
4
4
|
module DSL
|
5
|
+
|
6
|
+
autoload :PubSub, File.expand_path(File.join(File.dirname(__FILE__), *%w[dsl pubsub]))
|
7
|
+
|
5
8
|
def client
|
6
9
|
@client ||= Client.new
|
7
10
|
end
|
8
11
|
module_function :client
|
9
12
|
|
13
|
+
def pubsub
|
14
|
+
@pubsub ||= PubSub.new jid.domain
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Push data to the stream
|
19
|
+
# This works such that it can be chained:
|
20
|
+
# self << stanza1 << stanza2 << "raw data"
|
21
|
+
def <<(stanza)
|
22
|
+
write stanza
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
10
26
|
##
|
11
27
|
# Prepare server settings
|
12
28
|
# setup [node@domain/resource], [password], [host], [port]
|
data/lib/blather/client.rb
CHANGED
@@ -60,7 +60,7 @@ at_exit do
|
|
60
60
|
if options[:log]
|
61
61
|
log = File.new(options[:log], 'a')
|
62
62
|
log.sync = options[:debug]
|
63
|
-
Blather
|
63
|
+
Blather.logger.level = Logger::DEBUG if options[:debug]
|
64
64
|
$stdout.reopen log
|
65
65
|
$stderr.reopen $stdout
|
66
66
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
# Thanks to Rails ActiveSupport for everything in this file
|
2
|
+
|
3
|
+
# Allows attributes to be shared within an inheritance hierarchy, but where each descendant gets a copy of
|
4
|
+
# their parents' attributes, instead of just a pointer to the same. This means that the child can add elements
|
5
|
+
# to, for example, an array without those additions being shared with either their parent, siblings, or
|
6
|
+
# children, which is unlike the regular class-level attributes that are shared across the entire hierarchy.
|
7
|
+
class Class # :nodoc:
|
8
|
+
def class_inheritable_reader(*syms)
|
9
|
+
syms.each do |sym|
|
10
|
+
next if sym.is_a?(Hash)
|
11
|
+
class_eval <<-EOS
|
12
|
+
def self.#{sym}
|
13
|
+
read_inheritable_attribute(:#{sym})
|
14
|
+
end
|
15
|
+
|
16
|
+
def #{sym}
|
17
|
+
self.class.#{sym}
|
18
|
+
end
|
19
|
+
EOS
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def class_inheritable_writer(*syms)
|
24
|
+
syms.each do |sym|
|
25
|
+
class_eval <<-EOS
|
26
|
+
def self.#{sym}=(obj)
|
27
|
+
write_inheritable_attribute(:#{sym}, obj)
|
28
|
+
end
|
29
|
+
EOS
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def class_inheritable_array_writer(*syms)
|
34
|
+
syms.each do |sym|
|
35
|
+
class_eval <<-EOS
|
36
|
+
def self.#{sym}=(obj)
|
37
|
+
write_inheritable_array(:#{sym}, obj)
|
38
|
+
end
|
39
|
+
EOS
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def class_inheritable_hash_writer(*syms)
|
44
|
+
syms.each do |sym|
|
45
|
+
class_eval <<-EOS
|
46
|
+
def self.#{sym}=(obj)
|
47
|
+
write_inheritable_hash(:#{sym}, obj)
|
48
|
+
end
|
49
|
+
EOS
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def class_inheritable_accessor(*syms)
|
54
|
+
class_inheritable_reader(*syms)
|
55
|
+
class_inheritable_writer(*syms)
|
56
|
+
end
|
57
|
+
|
58
|
+
def class_inheritable_array(*syms)
|
59
|
+
class_inheritable_reader(*syms)
|
60
|
+
class_inheritable_array_writer(*syms)
|
61
|
+
end
|
62
|
+
|
63
|
+
def class_inheritable_hash(*syms)
|
64
|
+
class_inheritable_reader(*syms)
|
65
|
+
class_inheritable_hash_writer(*syms)
|
66
|
+
end
|
67
|
+
|
68
|
+
def inheritable_attributes
|
69
|
+
@inheritable_attributes ||= EMPTY_INHERITABLE_ATTRIBUTES
|
70
|
+
end
|
71
|
+
|
72
|
+
def write_inheritable_attribute(key, value)
|
73
|
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
74
|
+
@inheritable_attributes = {}
|
75
|
+
end
|
76
|
+
inheritable_attributes[key] = value
|
77
|
+
end
|
78
|
+
|
79
|
+
def write_inheritable_array(key, elements)
|
80
|
+
write_inheritable_attribute(key, []) if read_inheritable_attribute(key).nil?
|
81
|
+
write_inheritable_attribute(key, read_inheritable_attribute(key) + elements)
|
82
|
+
end
|
83
|
+
|
84
|
+
def write_inheritable_hash(key, hash)
|
85
|
+
write_inheritable_attribute(key, {}) if read_inheritable_attribute(key).nil?
|
86
|
+
write_inheritable_attribute(key, read_inheritable_attribute(key).merge(hash))
|
87
|
+
end
|
88
|
+
|
89
|
+
def read_inheritable_attribute(key)
|
90
|
+
inheritable_attributes[key]
|
91
|
+
end
|
92
|
+
|
93
|
+
def reset_inheritable_attributes
|
94
|
+
@inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
# Prevent this constant from being created multiple times
|
99
|
+
EMPTY_INHERITABLE_ATTRIBUTES = {}.freeze unless const_defined?(:EMPTY_INHERITABLE_ATTRIBUTES)
|
100
|
+
|
101
|
+
def inherited_with_inheritable_attributes(child)
|
102
|
+
inherited_without_inheritable_attributes(child) if respond_to?(:inherited_without_inheritable_attributes)
|
103
|
+
|
104
|
+
if inheritable_attributes.equal?(EMPTY_INHERITABLE_ATTRIBUTES)
|
105
|
+
new_inheritable_attributes = EMPTY_INHERITABLE_ATTRIBUTES
|
106
|
+
else
|
107
|
+
new_inheritable_attributes = inheritable_attributes.inject({}) do |memo, (key, value)|
|
108
|
+
memo.update(key => value.duplicable? ? value.dup : value)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
child.instance_variable_set('@inheritable_attributes', new_inheritable_attributes)
|
113
|
+
end
|
114
|
+
|
115
|
+
alias inherited_without_inheritable_attributes inherited
|
116
|
+
alias inherited inherited_with_inheritable_attributes
|
117
|
+
end #Class
|