Package spade :: Module pubsub
[hide private]
[frames] | no frames]

Source Code for Module spade.pubsub

  1  from Behaviour import MessageTemplate, OneShotBehaviour 
  2   
  3  from xmpp.protocol import * 
  4  from xmpp.simplexml import Node 
  5  import uuid 
  6   
7 -def gen_id():
8 return str(uuid.uuid4())
9 10 #def PubSubMessageTemplate(): 11 # msgs = [] 12 # for ns in (NS_PUBSUB, NS_PUBSUB_OWNER): 13 # msg = Iq() 14 # msg.addChild(name='pubsub', namespace=ns) 15 # msgs.append(msg) 16 # return reduce(lambda a,b: a | b, map(lambda msg: MessageTemplate(msg), msgs)) 17 18 19 #class XMPPIdTemplate(MessageTemplate): 20 21 # def __init__(self, id): 22 # iq = Iq() 23 # iq.setID(id) 24 # MessageTemplate.__init__(self, iq) 25 26 #TODO: Implementar retrieve nodes y discovery 27
28 -class PubSub(object):
29
30 - def __init__(self, agent): #, msgrecv):
31 self._client = agent.getAID().getName() 32 #self.msgrecv = msgrecv 33 self.myAgent = agent 34 self._server = agent.server
35
36 - def _sendAndReceive(self, iq, getContents):
37 id = gen_id() 38 t = MessageTemplate(Iq(attrs={'id':id})) 39 iq.setID(id) 40 b = self._sendAndReceiveBehav(iq,getContents) 41 42 if self.myAgent._running: 43 self.myAgent.addBehaviour(b,t) 44 b.join() 45 else: 46 self.myAgent.runBehaviourOnce(b,t) 47 48 return b.result
49
50 - class _sendAndReceiveBehav(OneShotBehaviour):
51 - def __init__(self,iq,getContents):
52 OneShotBehaviour.__init__(self) 53 self.iq = iq 54 self.getContents = getContents 55 self.timeout = 15 56 self.result = (None,None)
57
58 - def _process(self):
59 #print 'Sending ', str(self.iq) 60 self.myAgent.send(self.iq) 61 62 #Wait for the answer 63 msg = self._receive(block=True,timeout=self.timeout) 64 #print 'Received ', str(msg) 65 if msg is None: 66 #Timeout 67 self.result = ('error',['timeout']) 68 return 69 if msg['type'] == 'error': 70 errors = [] 71 for error in msg.getTag('error').getChildren(): 72 if error.getName() == 'text': continue 73 errors.append(error.getName()) 74 self.result = ('error',errors) 75 return 76 if msg['type'] == 'result': 77 self.result = ('ok',self.getContents(msg)) 78 return 79 80 self.result = ('error',['unknown']) 81 return
82 83 84 85
86 - def publish(self, node, event=None):
87 """ 88 Publishes an item to a given node. 89 90 XXX: 'node' here is not an XML node, but the attribute for <publish> 91 92 @type node: string 93 @param node: The ID of the pubsub node to publish 94 @type event: Event 95 @param event: Content to publish 96 @rtype: (string , list[string]) 97 @return: A tuple with the type of answer ('ok','error') and information 98 about the answer. In case of 'error', a list with the errors. In case of 99 'ok' the name of the created node. 100 """ 101 iq = Iq( 102 typ='set', 103 queryNS=None, 104 attrs={}, 105 frm=self._client 106 ) 107 108 pubsub_node = Node(tag='pubsub', attrs={'xmlns':NS_PUBSUB}) 109 publish_node = Node(tag='publish', attrs={'node':node}) 110 item_node = Node(tag='item') 111 if event is not None: 112 item_node.addChild(node=event) 113 publish_node.addChild(node=item_node) 114 pubsub_node.addChild(node=publish_node) 115 iq.addChild(node=pubsub_node) 116 117 def getContents(msg): 118 node_publish = msg.getTag('pubsub').getTag('publish') 119 #XXX: Server implementation always returns the item id, but XEP-60 does 120 # vim snot require it 121 return [node_publish['node'],node_publish.getTag('item')['id']]
122 123 return self._sendAndReceive(iq, getContents) 124 125 126 127
128 - def subscribe(self, node, server=None, jid=None):
129 """ 130 Subscribes to the selected node 131 132 @type node: string 133 @param node: id of the node to delete 134 @type server: string 135 @param server: PubSub server 136 @rtype: (string , list[string]) 137 @return: A tuple with the type of answer ('ok','error') and information 138 about the answer. In case of 'error', a list with the errors. In case of 139 'ok', an empty list. 140 141 """ 142 143 if server is None: 144 server = self._server 145 146 if jid is None: 147 jid = self._client 148 149 iq = Iq( 150 typ='set', 151 queryNS=None, 152 attrs={}, 153 frm=self._client, 154 to=server 155 ) 156 157 pubsub_node = Node(tag='pubsub', attrs={'xmlns':NS_PUBSUB}) 158 subscribe_node = Node(tag='subscribe', attrs={'node':node, 'jid':jid}) 159 pubsub_node.addChild(node=subscribe_node) 160 iq.addChild(node=pubsub_node) 161 162 return self._sendAndReceive(iq, lambda msg: [])
163
164 - def unsubscribe(self, node, server=None, jid=None):
165 """ 166 Unsubscribe from the selected node 167 168 @type node: string 169 @param node: id of the node to unsubscribe 170 @type server: string 171 @param server: PubSub server 172 @rtype: (string , list[string]) 173 @return: A tuple with the type of answer ('ok','error') and information 174 about the answer. In case of 'error', a list with the errors. In case of 175 'ok' an empty list. 176 177 """ 178 179 if server is None: 180 server = self._server 181 182 if jid is None: 183 jid = self._client 184 185 iq = Iq( 186 typ='set', 187 queryNS=None, 188 attrs={}, 189 frm=self._client, 190 to=server 191 ) 192 193 pubsub_node = Node(tag='pubsub', attrs={'xmlns':NS_PUBSUB_OWNER}) 194 unsubscribe_node = Node(tag='unsubscribe', attrs={'node':node, 'jid':jid}) 195 pubsub_node.addChild(node=unsubscribe_node) 196 iq.addChild(node=pubsub_node) 197 return self._sendAndReceive(iq, lambda msg: [])
198
199 - def createNode(self, node, server=None, type='leaf', parent=None, access=None):
200 """ 201 Creates a node with the specified parameters. 202 203 @type node: string 204 @param node: The ID of the node to create 205 @type server: string 206 @param server: PubSub server 207 @type type: string 208 @param type: Type of the node: 'leaf' or 'collection' 209 @type parent: string 210 @param parent: id of the parent node. None if parent is root 211 @type access: string 212 @param acccess: Access model of the node 213 @rtype: (string , list[string]) 214 @return: A tuple with the type of answer ('ok','error') and information 215 about the answer. In case of 'error', a list with the errors. In case of 216 'ok' the name of the created node. 217 """ 218 #TODO: Add suport for node configuration (RECOMMENDED in XEP-60) 219 if server is None: 220 server = self._server 221 222 iq = Iq( 223 typ='set', 224 queryNS=None, 225 attrs={}, 226 frm=self._client, 227 to=server 228 ) 229 230 231 pubsub_node = Node(tag='pubsub', attrs={'xmlns':NS_PUBSUB}) 232 create_node = Node(tag='create', attrs={} if node is None else {'node':node}) 233 234 pubsub_node.addChild(node=create_node) 235 iq.addChild(node=pubsub_node) 236 if parent is not None or type=='collection' or access is not None: 237 field_nodes=[] 238 configure_node = Node(tag='configure') 239 field_nodes.append(DataField('FORM_TYPE', NS_PUBSUB+'#node_config','hidden')) 240 if parent is not None: 241 field_nodes.append(DataField('pubsub#collection',parent)) 242 # <field var='pubsub#collection'><value>announcements</value></field> 243 if type == 'collection': 244 field_nodes.append(DataField('pubsub#node_type','collection')) 245 if access is not None: 246 field_nodes.append(DataField('pubsub#access_model',access)) 247 x_node = DataForm(typ='submit',data=field_nodes) 248 configure_node.addChild(x_node) 249 pubsub_node.addChild(configure_node) 250 251 return self._sendAndReceive(iq, lambda msg:[msg.getTag('pubsub').getTag('create')['node']])
252 253 254
255 - def createInstantNode(self, server=None, type='leaf', parent=None, access=None):
256 """ 257 Creates an instant node without a name. The server will generate id. 258 """ 259 260 if server is None: 261 server = self._server 262 263 return createNode(self, None, server, type, parent, access)
264 265
266 - def deleteNode(self, node, server=None):
267 """ 268 Deletes the selected node. 269 270 @type node: string 271 @param node: id of the node to delete 272 @type server: string 273 @param server: PubSub server 274 @rtype: (string , list[string]) 275 @return: A tuple with the type of answer ('ok','error') and information 276 about the answer. In case of 'error', a list with the errors. In case of 277 'ok' an empty list. 278 279 280 """ 281 282 #TODO: A method to redirect the subscriptions to the node to another one COULD be implemented 283 284 if server is None: 285 server = self._server 286 287 iq = Iq( 288 typ='set', 289 queryNS=None, 290 attrs={}, 291 frm=self._client, 292 to=server, 293 ) 294 295 pubsub_node = Node(tag='pubsub', attrs={'xmlns':NS_PUBSUB_OWNER}) 296 pubsub_node.addChild(name='delete', attrs={'node':node}) 297 iq.addChild(node=pubsub_node) 298 299 return self._sendAndReceive(iq, lambda msg: [])
300