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:
mathieui
2015-02-24 18:58:40 +01:00
parent e112e86475
commit c66a4d4097
36 changed files with 498 additions and 401 deletions

View File

@@ -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")

View File

@@ -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()

View File

@@ -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:

View File

@@ -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()

View File

@@ -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",

View File

@@ -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))

View File

@@ -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" %

View File

@@ -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()

View File

@@ -20,7 +20,7 @@ class Boomerang(Endpoint):
@remote
def throw(self):
print "Duck!"
print("Duck!")

View File

@@ -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...')