Update the documentation and examples
- update most of the examples with slixmpp - change the help channels pointed out in the doc - add a page listing differences from slixmpp and how to use asyncio nicely with slixmpp - fix some in-code rst documentation
This commit is contained in:
@@ -11,20 +11,12 @@
|
||||
See the file LICENSE for copying permission.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
# This can be used when you are in a test environment and need to make paths right
|
||||
sys.path=['/Users/jocke/Dropbox/06_dev/Slixmpp']+sys.path
|
||||
|
||||
import logging
|
||||
import unittest
|
||||
import distutils.core
|
||||
import datetime
|
||||
|
||||
from glob import glob
|
||||
from os.path import splitext, basename, join as pjoin
|
||||
from os.path import basename, join as pjoin
|
||||
from argparse import ArgumentParser
|
||||
from urllib import urlopen
|
||||
from getpass import getpass
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.plugins.xep_0323.device import Device
|
||||
@@ -186,5 +178,5 @@ if __name__ == '__main__':
|
||||
logging.debug("ready ending")
|
||||
|
||||
else:
|
||||
print "noopp didn't happen"
|
||||
print("noopp didn't happen")
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
from slixmpp.xmlstream.asyncio import asyncio
|
||||
|
||||
|
||||
class Disco(slixmpp.ClientXMPP):
|
||||
@@ -53,6 +54,7 @@ class Disco(slixmpp.ClientXMPP):
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -79,17 +81,17 @@ class Disco(slixmpp.ClientXMPP):
|
||||
# received. Non-blocking options would be to listen
|
||||
# for the disco_info event, or passing a handler
|
||||
# function using the callback parameter.
|
||||
info = self['xep_0030'].get_info(jid=self.target_jid,
|
||||
node=self.target_node,
|
||||
block=True)
|
||||
elif self.get in self.items_types:
|
||||
info = yield from self['xep_0030'].get_info(jid=self.target_jid,
|
||||
node=self.target_node,
|
||||
coroutine=True)
|
||||
if self.get in self.items_types:
|
||||
# The same applies from above. Listen for the
|
||||
# disco_items event or pass a callback function
|
||||
# if you need to process a non-blocking request.
|
||||
items = self['xep_0030'].get_items(jid=self.target_jid,
|
||||
node=self.target_node,
|
||||
block=True)
|
||||
else:
|
||||
items = yield from self['xep_0030'].get_items(jid=self.target_jid,
|
||||
node=self.target_node,
|
||||
coroutine=True)
|
||||
if self.get not in self.info_types and self.get not in self.items_types:
|
||||
logging.error("Invalid disco request type.")
|
||||
return
|
||||
except IqError as e:
|
||||
@@ -143,7 +145,7 @@ if __name__ == '__main__':
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
parser.add_argument("query", choices=["all", "info", "items", "identities", "features"])
|
||||
parser.add_argument("target-jid")
|
||||
parser.add_argument("target_jid")
|
||||
parser.add_argument("node", nargs='?')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
import logging
|
||||
from getpass import getpass
|
||||
import threading
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import XMPPError
|
||||
from slixmpp import asyncio
|
||||
|
||||
|
||||
FILE_TYPES = {
|
||||
@@ -40,8 +40,14 @@ class AvatarDownloader(slixmpp.ClientXMPP):
|
||||
self.add_event_handler('avatar_metadata_publish', self.on_avatar)
|
||||
|
||||
self.received = set()
|
||||
self.presences_received = threading.Event()
|
||||
self.presences_received = asyncio.Event()
|
||||
self.roster_received = asyncio.Event()
|
||||
|
||||
def roster_received_cb(self, event):
|
||||
self.roster_received.set()
|
||||
self.presences_received.clear()
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -56,16 +62,20 @@ class AvatarDownloader(slixmpp.ClientXMPP):
|
||||
data.
|
||||
"""
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
self.get_roster(callback=self.roster_received_cb)
|
||||
|
||||
print('Waiting for presence updates...\n')
|
||||
self.presences_received.wait(15)
|
||||
yield from self.roster_received.wait()
|
||||
print('Roster received')
|
||||
yield from self.presences_received.wait()
|
||||
self.disconnect()
|
||||
|
||||
@asyncio.coroutine
|
||||
def on_vcard_avatar(self, pres):
|
||||
print("Received vCard avatar update from %s" % pres['from'].bare)
|
||||
try:
|
||||
result = self['xep_0054'].get_vcard(pres['from'], cached=True)
|
||||
result = yield from self['xep_0054'].get_vcard(pres['from'].bare, cached=True,
|
||||
coroutine=True, timeout=5)
|
||||
except XMPPError:
|
||||
print("Error retrieving avatar for %s" % pres['from'])
|
||||
return
|
||||
@@ -76,16 +86,18 @@ class AvatarDownloader(slixmpp.ClientXMPP):
|
||||
pres['from'].bare,
|
||||
pres['vcard_temp_update']['photo'],
|
||||
filetype)
|
||||
with open(filename, 'w+') as img:
|
||||
with open(filename, 'wb+') as img:
|
||||
img.write(avatar['BINVAL'])
|
||||
|
||||
@asyncio.coroutine
|
||||
def on_avatar(self, msg):
|
||||
print("Received avatar update from %s" % msg['from'])
|
||||
metadata = msg['pubsub_event']['items']['item']['avatar_metadata']
|
||||
for info in metadata['items']:
|
||||
if not info['url']:
|
||||
try:
|
||||
result = self['xep_0084'].retrieve_avatar(msg['from'], info['id'])
|
||||
result = yield from self['xep_0084'].retrieve_avatar(msg['from'].bare, info['id'],
|
||||
coroutine=True, timeout=5)
|
||||
except XMPPError:
|
||||
print("Error retrieving avatar for %s" % msg['from'])
|
||||
return
|
||||
@@ -94,7 +106,7 @@ class AvatarDownloader(slixmpp.ClientXMPP):
|
||||
|
||||
filetype = FILE_TYPES.get(metadata['type'], 'png')
|
||||
filename = 'avatar_%s_%s.%s' % (msg['from'].bare, info['id'], filetype)
|
||||
with open(filename, 'w+') as img:
|
||||
with open(filename, 'wb+') as img:
|
||||
img.write(avatar['value'])
|
||||
else:
|
||||
# We could retrieve the avatar via HTTP, etc here instead.
|
||||
@@ -105,6 +117,7 @@ class AvatarDownloader(slixmpp.ClientXMPP):
|
||||
Wait to receive updates from all roster contacts.
|
||||
"""
|
||||
self.received.add(pres['from'].bare)
|
||||
print((len(self.received), len(self.client_roster.keys())))
|
||||
if len(self.received) >= len(self.client_roster.keys()):
|
||||
self.presences_received.set()
|
||||
else:
|
||||
|
||||
@@ -103,5 +103,5 @@ def on_session2(event):
|
||||
new_xmpp.disconnect()
|
||||
new_xmpp.add_event_handler('session_start', on_session2)
|
||||
|
||||
if new_xmpp.connect():
|
||||
new_xmpp.process(block=True)
|
||||
new_xmpp.connect()
|
||||
new_xmpp.process()
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
import logging
|
||||
from getpass import getpass
|
||||
from argparse import ArgumentParser
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
from slixmpp import asyncio
|
||||
|
||||
import slixmpp
|
||||
|
||||
@@ -36,6 +38,7 @@ class PingTest(slixmpp.ClientXMPP):
|
||||
# our roster.
|
||||
self.add_event_handler("session_start", self.start)
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -53,8 +56,8 @@ class PingTest(slixmpp.ClientXMPP):
|
||||
self.get_roster()
|
||||
|
||||
try:
|
||||
rtt = self['xep_0199'].ping(self.pingjid,
|
||||
timeout=10)
|
||||
rtt = yield from self['xep_0199'].ping(self.pingjid,
|
||||
timeout=10)
|
||||
logging.info("Success! RTT: %s", rtt)
|
||||
except IqError as e:
|
||||
logging.info("Error pinging %s: %s",
|
||||
@@ -78,8 +81,7 @@ if __name__ == '__main__':
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
parser.add_argument("-t", "--pingto", help="set jid to ping",
|
||||
action="store", type="string", dest="pingjid",
|
||||
default=None)
|
||||
dest="pingjid", default=None)
|
||||
|
||||
# JID and password options.
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
|
||||
@@ -7,7 +7,13 @@ from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.xmlstream import ET, tostring
|
||||
from slixmpp.xmlstream.asyncio import asyncio
|
||||
|
||||
def make_callback():
|
||||
future = asyncio.Future()
|
||||
def callback(result):
|
||||
future.set_result(result)
|
||||
return future, callback
|
||||
|
||||
class PubsubClient(slixmpp.ClientXMPP):
|
||||
|
||||
@@ -41,8 +47,10 @@ class PubsubClient(slixmpp.ClientXMPP):
|
||||
self.disconnect()
|
||||
|
||||
def nodes(self):
|
||||
future, callback = make_callback()
|
||||
try:
|
||||
result = self['xep_0060'].get_nodes(self.pubsub_server, self.node)
|
||||
self['xep_0060'].get_nodes(self.pubsub_server, self.node, callback=callback)
|
||||
result = yield from future
|
||||
for item in result['disco_items']['items']:
|
||||
print(' - %s' % str(item))
|
||||
except:
|
||||
@@ -63,16 +71,20 @@ class PubsubClient(slixmpp.ClientXMPP):
|
||||
|
||||
def publish(self):
|
||||
payload = ET.fromstring("<test xmlns='test'>%s</test>" % self.data)
|
||||
future, callback = make_callback()
|
||||
try:
|
||||
result = self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload)
|
||||
self['xep_0060'].publish(self.pubsub_server, self.node, payload=payload, callback=callback)
|
||||
result = yield from future
|
||||
id = result['pubsub']['publish']['item']['id']
|
||||
print('Published at item id: %s' % id)
|
||||
except:
|
||||
logging.error('Could not publish to: %s' % self.node)
|
||||
|
||||
def get(self):
|
||||
future, callback = make_callback()
|
||||
try:
|
||||
result = self['xep_0060'].get_item(self.pubsub_server, self.node, self.data)
|
||||
self['xep_0060'].get_item(self.pubsub_server, self.node, self.data, callback=callback)
|
||||
result = yield from future
|
||||
for item in result['pubsub']['items']['substanzas']:
|
||||
print('Retrieved item %s: %s' % (item['id'], tostring(item['payload'])))
|
||||
except:
|
||||
@@ -80,28 +92,28 @@ class PubsubClient(slixmpp.ClientXMPP):
|
||||
|
||||
def retract(self):
|
||||
try:
|
||||
result = self['xep_0060'].retract(self.pubsub_server, self.node, self.data)
|
||||
self['xep_0060'].retract(self.pubsub_server, self.node, self.data)
|
||||
print('Retracted item %s from node %s' % (self.data, self.node))
|
||||
except:
|
||||
logging.error('Could not retract item %s from node %s' % (self.data, self.node))
|
||||
|
||||
def purge(self):
|
||||
try:
|
||||
result = self['xep_0060'].purge(self.pubsub_server, self.node)
|
||||
self['xep_0060'].purge(self.pubsub_server, self.node)
|
||||
print('Purged all items from node %s' % self.node)
|
||||
except:
|
||||
logging.error('Could not purge items from node %s' % self.node)
|
||||
|
||||
def subscribe(self):
|
||||
try:
|
||||
result = self['xep_0060'].subscribe(self.pubsub_server, self.node)
|
||||
self['xep_0060'].subscribe(self.pubsub_server, self.node)
|
||||
print('Subscribed %s to node %s' % (self.boundjid.bare, self.node))
|
||||
except:
|
||||
logging.error('Could not subscribe %s to node %s' % (self.boundjid.bare, self.node))
|
||||
|
||||
def unsubscribe(self):
|
||||
try:
|
||||
result = self['xep_0060'].unsubscribe(self.pubsub_server, self.node)
|
||||
self['xep_0060'].unsubscribe(self.pubsub_server, self.node)
|
||||
print('Unsubscribed %s from node %s' % (self.boundjid.bare, self.node))
|
||||
except:
|
||||
logging.error('Could not unsubscribe %s from node %s' % (self.boundjid.bare, self.node))
|
||||
|
||||
@@ -90,7 +90,7 @@ class RegisterBot(slixmpp.ClientXMPP):
|
||||
resp['register']['password'] = self.password
|
||||
|
||||
try:
|
||||
resp.send()
|
||||
yield from resp.send_coroutine()
|
||||
logging.info("Account created for %s!" % self.boundjid)
|
||||
except IqError as e:
|
||||
logging.error("Could not register account: %s" %
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
|
||||
import logging
|
||||
from getpass import getpass
|
||||
import threading
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import IqError, IqTimeout
|
||||
from slixmpp.xmlstream.asyncio import asyncio
|
||||
|
||||
|
||||
class RosterBrowser(slixmpp.ClientXMPP):
|
||||
@@ -36,8 +36,9 @@ class RosterBrowser(slixmpp.ClientXMPP):
|
||||
self.add_event_handler("changed_status", self.wait_for_presences)
|
||||
|
||||
self.received = set()
|
||||
self.presences_received = threading.Event()
|
||||
self.presences_received = asyncio.Event()
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -51,8 +52,12 @@ class RosterBrowser(slixmpp.ClientXMPP):
|
||||
event does not provide any additional
|
||||
data.
|
||||
"""
|
||||
future = asyncio.Future()
|
||||
def callback(result):
|
||||
future.set_result(None)
|
||||
try:
|
||||
self.get_roster()
|
||||
self.get_roster(callback=callback)
|
||||
yield from future
|
||||
except IqError as err:
|
||||
print('Error: %' % err.iq['error']['condition'])
|
||||
except IqTimeout:
|
||||
@@ -61,7 +66,7 @@ class RosterBrowser(slixmpp.ClientXMPP):
|
||||
|
||||
|
||||
print('Waiting for presence updates...\n')
|
||||
self.presences_received.wait(5)
|
||||
yield from asyncio.sleep(10)
|
||||
|
||||
print('Roster for %s' % self.boundjid.bare)
|
||||
groups = self.client_roster.groups()
|
||||
|
||||
@@ -20,7 +20,7 @@ class Boomerang(Endpoint):
|
||||
|
||||
@remote
|
||||
def throw(self):
|
||||
print "Duck!"
|
||||
print("Duck!")
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
from slixmpp.exceptions import XMPPError
|
||||
|
||||
from slixmpp import asyncio
|
||||
|
||||
class AvatarSetter(slixmpp.ClientXMPP):
|
||||
|
||||
@@ -33,6 +33,7 @@ class AvatarSetter(slixmpp.ClientXMPP):
|
||||
|
||||
self.filepath = filepath
|
||||
|
||||
@asyncio.coroutine
|
||||
def start(self, event):
|
||||
"""
|
||||
Process the session_start event.
|
||||
@@ -51,7 +52,7 @@ class AvatarSetter(slixmpp.ClientXMPP):
|
||||
|
||||
avatar_file = None
|
||||
try:
|
||||
avatar_file = open(os.path.expanduser(self.filepath))
|
||||
avatar_file = open(os.path.expanduser(self.filepath), 'rb')
|
||||
except IOError:
|
||||
print('Could not find file: %s' % self.filepath)
|
||||
return self.disconnect()
|
||||
@@ -65,32 +66,31 @@ class AvatarSetter(slixmpp.ClientXMPP):
|
||||
avatar_file.close()
|
||||
|
||||
used_xep84 = False
|
||||
try:
|
||||
print('Publish XEP-0084 avatar data')
|
||||
self['xep_0084'].publish_avatar(avatar)
|
||||
used_xep84 = True
|
||||
except XMPPError:
|
||||
print('Could not publish XEP-0084 avatar')
|
||||
|
||||
try:
|
||||
print('Update vCard with avatar')
|
||||
self['xep_0153'].set_avatar(avatar=avatar, mtype=avatar_type)
|
||||
except XMPPError:
|
||||
print('Publish XEP-0084 avatar data')
|
||||
result = yield from self['xep_0084'].publish_avatar(avatar, coroutine=True)
|
||||
if isinstance(result, XMPPError):
|
||||
print('Could not publish XEP-0084 avatar')
|
||||
else:
|
||||
used_xep84 = True
|
||||
|
||||
print('Update vCard with avatar')
|
||||
result = yield from self['xep_0153'].set_avatar(avatar=avatar, mtype=avatar_type, coroutine=True)
|
||||
if isinstance(result, XMPPError):
|
||||
print('Could not set vCard avatar')
|
||||
|
||||
if used_xep84:
|
||||
try:
|
||||
print('Advertise XEP-0084 avatar metadata')
|
||||
self['xep_0084'].publish_avatar_metadata([
|
||||
{'id': avatar_id,
|
||||
'type': avatar_type,
|
||||
'bytes': avatar_bytes}
|
||||
# We could advertise multiple avatars to provide
|
||||
# options in image type, source (HTTP vs pubsub),
|
||||
# size, etc.
|
||||
# {'id': ....}
|
||||
])
|
||||
except XMPPError:
|
||||
print('Advertise XEP-0084 avatar metadata')
|
||||
result = yield from self['xep_0084'].publish_avatar_metadata([
|
||||
{'id': avatar_id,
|
||||
'type': avatar_type,
|
||||
'bytes': avatar_bytes}
|
||||
# We could advertise multiple avatars to provide
|
||||
# options in image type, source (HTTP vs pubsub),
|
||||
# size, etc.
|
||||
# {'id': ....}
|
||||
], coroutine=True)
|
||||
if isinstance(result, XMPPError):
|
||||
print('Could not publish XEP-0084 metadata')
|
||||
|
||||
print('Wait for presence updates to propagate...')
|
||||
|
||||
Reference in New Issue
Block a user