Comparison

plugins/pubsub.lua @ 222:3c257afd68e7

plugins.pubsub: New, OOP-ish, PubSub interface. Beware of stubs.
author Kim Alvefur <zash@zash.se>
date Wed, 12 Oct 2011 18:11:07 +0200
parent 221:efb4f60ba36e
child 248:c4b55b0dc6ba
comparison
equal deleted inserted replaced
221:efb4f60ba36e 222:3c257afd68e7
1 local jid_bare = require "util.jid".bare; 1 local jid_bare = require "util.jid".bare;
2 local t_insert = table.insert;
2 3
3 local xmlns_pubsub = "http://jabber.org/protocol/pubsub"; 4 local xmlns_pubsub = "http://jabber.org/protocol/pubsub";
5 local xmlns_pubsub_owner = "http://jabber.org/protocol/pubsub#owner";
4 local xmlns_pubsub_event = "http://jabber.org/protocol/pubsub#event"; 6 local xmlns_pubsub_event = "http://jabber.org/protocol/pubsub#event";
5 local xmlns_pubsub_errors = "http://jabber.org/protocol/pubsub#errors"; 7 local xmlns_pubsub_errors = "http://jabber.org/protocol/pubsub#errors";
6 8
7 local pubsub = {}; 9 local pubsub = {};
8 local pubsub_mt = { __index = pubsub }; 10 local pubsub_mt = { __index = pubsub };
26 end); 28 end);
27 return true; 29 return true;
28 end 30 end
29 31
30 function pubsub:create(server, node, callback) 32 function pubsub:create(server, node, callback)
33 self.stream:warn("pubsub:create() is deprecated, "
34 .."you should use pubsub:service(%q):node(%q):create() instead\n%s", server or "", node, debug.traceback());
31 local create = verse.iq({ to = server, type = "set" }) 35 local create = verse.iq({ to = server, type = "set" })
32 :tag("pubsub", { xmlns = xmlns_pubsub }) 36 :tag("pubsub", { xmlns = xmlns_pubsub })
33 :tag("create", { node = node }):up() 37 :tag("create", { node = node }):up()
34 self.stream:send_iq(create, function (result) 38 self.stream:send_iq(create, function (result)
35 if callback then 39 if callback then
42 end 46 end
43 ); 47 );
44 end 48 end
45 49
46 function pubsub:subscribe(server, node, jid, callback) 50 function pubsub:subscribe(server, node, jid, callback)
51 self.stream:warn("pubsub:subscribe() is deprecated, "
52 .."you should use pubsub:service(%q):node(%q):subscribe(jid) instead\n%s", server or "", node, debug.traceback());
47 self.stream:send_iq(verse.iq({ to = server, type = "set" }) 53 self.stream:send_iq(verse.iq({ to = server, type = "set" })
48 :tag("pubsub", { xmlns = xmlns_pubsub }) 54 :tag("pubsub", { xmlns = xmlns_pubsub })
49 :tag("subscribe", { node = node, jid = jid or jid_bare(self.stream.jid) }) 55 :tag("subscribe", { node = node, jid = jid or jid_bare(self.stream.jid) })
50 , function (result) 56 , function (result)
51 if callback then 57 if callback then
58 end 64 end
59 ); 65 );
60 end 66 end
61 67
62 function pubsub:publish(server, node, id, item, callback) 68 function pubsub:publish(server, node, id, item, callback)
69 self.stream:warn("pubsub:publish() is deprecated, "
70 .."you should use pubsub:service(%q):node(%q):publish() instead\n%s", server or "", node, debug.traceback());
63 self.stream:send_iq(verse.iq({ to = server, type = "set" }) 71 self.stream:send_iq(verse.iq({ to = server, type = "set" })
64 :tag("pubsub", { xmlns = xmlns_pubsub }) 72 :tag("pubsub", { xmlns = xmlns_pubsub })
65 :tag("publish", { node = node }) 73 :tag("publish", { node = node })
66 :tag("item", { id = id }) 74 :tag("item", { id = id })
67 :add_child(item) 75 :add_child(item)
74 end 82 end
75 end 83 end
76 end 84 end
77 ); 85 );
78 end 86 end
87
88 --------------------------------------------------------------------------
89 ---------------------New and improved PubSub interface--------------------
90 --------------------------------------------------------------------------
91
92 local pubsub_service = {};
93 local pubsub_service_mt = { __index = pubsub_service };
94
95 -- TODO should the property be named 'jid' instead?
96 function pubsub:service(service)
97 return setmetatable({ stream = self.stream, service = service }, pubsub_service_mt)
98 end
99
100 -- Helper function for iq+pubsub tags
101
102 local function pubsub_iq(iq_type, to, ns, op, node, jid, item_id)
103 local st = verse.iq{ type = iq_type or "get", to = to }
104 :tag("pubsub", { xmlns = ns or xmlns_pubsub }) -- ns would be ..#owner
105 if op then st:tag(op, { node = node, jid = jid }); end
106 if id then st:tag("item", { id = item_id ~= true and item_id or nil }); end
107 return st;
108 end
109
110 -- http://xmpp.org/extensions/xep-0060.html#entity-subscriptions
111 function pubsub_service:subscriptions(callback)
112 self.stream:send_iq(pubsub_iq(nil, self.service, nil, "subscriptions")
113 , callback and function (result)
114 if result.attr.type == "result" then
115 local ps = result:get_child("pubsub", xmlns_pubsub);
116 local subs = ps and ps:get_child("subscriptions");
117 local nodes = {};
118 if subs then
119 for sub in subs:childtags("subscription") do
120 local node = self:node(sub.attr.node)
121 node.subscription = sub;
122 t_insert(nodes, node);
123 -- FIXME Good enough?
124 -- Or how about:
125 -- nodes[node] = sub;
126 end
127 end
128 callback(nodes);
129 else
130 callback(false, result:get_error());
131 end
132 end or nil);
133 end
134
135 -- http://xmpp.org/extensions/xep-0060.html#entity-affiliations
136 function pubsub_service:affiliations(callback)
137 self.stream:send_iq(pubsub_iq(nil, self.service, nil, "affiliations")
138 , callback and function (result)
139 if result.attr.type == "result" then
140 local ps = result:get_child("pubsub", xmlns_pubsub);
141 local affils = ps and ps:get_child("affiliations") or {};
142 local nodes = {};
143 if affils then
144 for affil in affils:childtags("affiliation") do
145 local node = self:node(affil.attr.node)
146 node.affiliation = affil;
147 t_insert(nodes, node);
148 -- nodes[node] = affil;
149 end
150 end
151 callback(nodes);
152 else
153 callback(false, result:get_error());
154 end
155 end or nil);
156 end
157
158 -- TODO Listing nodes? It's done with standard disco#items, but should
159 -- we have a wrapper here? If so, it could wrap items in pubsub_node objects
160
161 --[[
162 function pubsub_service:nodes(callback)
163 self.stream:disco_items(...)
164 end
165 --]]
166
167 local pubsub_node = {};
168 local pubsub_node_mt = { __index = pubsub_node };
169
170 function pubsub_service:node(node)
171 return setmetatable({ stream = self.stream, service = self.service, node = node }, pubsub_node_mt)
172 end
173
174 function pubsub_mt:__call(service, node)
175 local s = self:service(service);
176 return node and s:node(node) or s;
177 end
178
179 function pubsub_node:hook(callback, prio)
180 local function hook(event)
181 -- FIXME service == nil would mean anyone,
182 -- publishing would be go to your bare jid.
183 -- So if you're only interestied in your own
184 -- events, hook your own bare jid.
185 if (not event.service or event.from == self.service) and event.node == self.node then
186 return callback(event)
187 end
188 end
189 self.stream:hook("pubsub/event", hook, prio);
190 return hook;
191 end
192
193 function pubsub_node:unhook(callback)
194 self.stream:unhook("pubsub/event", callback);
195 end
196
197 function pubsub_node:create(config, callback)
198 if config ~= nil then
199 error("Not implemented yet.");
200 else
201 self.stream:send_iq(pubsub_iq("set", self.service, nil, "create", self.node), callback);
202 end
203 end
204
205 -- <configure/> and <default/> rolled into one
206 function pubsub_node:configure(config, callback)
207 if config ~= nil then
208 error("Not implemented yet.");
209 -- if config == true then
210 -- fetch form and pass it to the callback
211 -- which would process it and pass it back
212 -- and then we submit it
213 -- elseif type(config) == "table" then
214 -- it's a form or stanza that we submit
215 -- end
216 -- this would be done for everything that needs a config
217 end
218 self.stream:send_iq(pubsub_iq("set", self.service, nil, config == nil and "default" or "configure", self.node), callback);
219 end
220
221 function pubsub_node:publish(id, options, node, callback)
222 if options ~= nil then
223 error("Node configuration is not implemented yet.");
224 end
225 self.stream:send_iq(pubsub_iq("set", self.service, nil, "publish", self.node, nil, id)
226 :add_child(node)
227 , callback);
228 end
229
230 function pubsub_node:subscribe(jid, options, callback)
231 if options ~= nil then
232 error("Subscription configuration is not implemented yet.");
233 end
234 self.stream:send_iq(pubsub_iq("set", self.service, nil, "subscribe", self.node, jid, id)
235 , callback);
236 end
237
238 function pubsub_node:subscription(callback)
239 error("Not implemented yet.");
240 end
241
242 function pubsub_node:affiliation(callback)
243 error("Not implemented yet.");
244 end
245
246 function pubsub_node:unsubscribe(callback)
247 error("Not implemented yet.");
248 end
249
250 function pubsub_node:configure_subscription(options, callback)
251 error("Not implemented yet.");
252 end
253
254 function pubsub_node:items(count, callback)
255 error("Not implemented yet.");
256 end
257
258 function pubsub_node:item(id, callback)
259 error("Not implemented yet.");
260 end
261
262 function pubsub_node:retract(id, callback)
263 error("Not implemented yet.");
264 end
265
266 function pubsub_node:purge(callback)
267 error("Not implemented yet.");
268 end
269
270 function pubsub_node:delete(callback)
271 error("Not implemented yet.");
272 end
273