Merge branch 'block-threaded-examples-docs' into 'master'
Remove the remaining block and threaded from examples See merge request poezio/slixmpp!105
This commit is contained in:
commit
370abb1d98
5 changed files with 68 additions and 72 deletions
|
@ -18,7 +18,7 @@ messages sent to it. We will also go through adding some basic command line conf
|
|||
for enabling or disabling debug log outputs and setting the username and password
|
||||
for the bot.
|
||||
|
||||
For the command line options processing, we will use the built-in ``optparse``
|
||||
For the command line options processing, we will use the built-in ``argparse``
|
||||
module and the ``getpass`` module for reading in passwords.
|
||||
|
||||
TL;DR Just Give Me the Code
|
||||
|
@ -39,7 +39,8 @@ To get started, here is a brief outline of the structure that the final project
|
|||
import asyncio
|
||||
import logging
|
||||
import getpass
|
||||
from optparse import OptionParser
|
||||
|
||||
from argparse import ArgumentParser
|
||||
|
||||
import slixmpp
|
||||
|
||||
|
@ -93,9 +94,9 @@ we also need to define the ``self.start`` handler.
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
def start(self, event):
|
||||
async def start(self, event):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
await self.get_roster()
|
||||
|
||||
.. warning::
|
||||
|
||||
|
@ -144,6 +145,11 @@ The XMPP stanzas from the roster retrieval process could look like this:
|
|||
</query>
|
||||
</iq>
|
||||
|
||||
Additionally, since :meth:`get_roster <slixmpp.clientxmpp.ClientXMPP.get_roster>` is using
|
||||
``<iq/>`` stanzas, which will always receive an answer, it should be awaited on, to keep
|
||||
a synchronous flow.
|
||||
|
||||
|
||||
Responding to Messages
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
Now that an ``EchoBot`` instance handles :term:`session_start`, we can begin receiving and
|
||||
|
@ -212,8 +218,7 @@ Command Line Arguments and Logging
|
|||
|
||||
While this isn't part of Slixmpp itself, we do want our echo bot program to be able
|
||||
to accept a JID and password from the command line instead of hard coding them. We will
|
||||
use the ``optparse`` module for this, though there are several alternative methods, including
|
||||
the newer ``argparse`` module.
|
||||
use the ``argparse`` module for this.
|
||||
|
||||
We want to accept three parameters: the JID for the echo bot, its password, and a flag for
|
||||
displaying the debugging logs. We also want these to be optional parameters, since passing
|
||||
|
@ -222,22 +227,29 @@ a password directly through the command line can be a security risk.
|
|||
.. code-block:: python
|
||||
|
||||
if __name__ == '__main__':
|
||||
optp = OptionParser()
|
||||
# Setup the command line arguments.
|
||||
parser = ArgumentParser(description=EchoBot.__doc__)
|
||||
|
||||
optp.add_option('-d', '--debug', help='set logging to DEBUG',
|
||||
action='store_const', dest='loglevel',
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
optp.add_option("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
optp.add_option("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
# Output verbosity options.
|
||||
parser.add_argument("-q", "--quiet", help="set logging to ERROR",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.ERROR, default=logging.INFO)
|
||||
parser.add_argument("-d", "--debug", help="set logging to DEBUG",
|
||||
action="store_const", dest="loglevel",
|
||||
const=logging.DEBUG, default=logging.INFO)
|
||||
|
||||
opts, args = optp.parse_args()
|
||||
# JID and password options.
|
||||
parser.add_argument("-j", "--jid", dest="jid",
|
||||
help="JID to use")
|
||||
parser.add_argument("-p", "--password", dest="password",
|
||||
help="password to use")
|
||||
|
||||
if opts.jid is None:
|
||||
opts.jid = raw_input("Username: ")
|
||||
if opts.password is None:
|
||||
opts.password = getpass.getpass("Password: ")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.jid is None:
|
||||
args.jid = input("Username: ")
|
||||
if args.password is None:
|
||||
args.password = getpass("Password: ")
|
||||
|
||||
Since we included a flag for enabling debugging logs, we need to configure the
|
||||
``logging`` module to behave accordingly.
|
||||
|
@ -248,7 +260,7 @@ Since we included a flag for enabling debugging logs, we need to configure the
|
|||
|
||||
# .. option parsing from above ..
|
||||
|
||||
logging.basicConfig(level=opts.loglevel,
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
|
||||
|
@ -276,52 +288,36 @@ at this stage. For example, let's say we want our bot to support `service discov
|
|||
If the ``EchoBot`` class had a hard dependency on a plugin, we could register that plugin in
|
||||
the ``EchoBot.__init__`` method instead.
|
||||
|
||||
.. note::
|
||||
|
||||
If you are using the OpenFire server, you will need to include an additional
|
||||
configuration step. OpenFire supports a different version of SSL than what
|
||||
most servers and Slixmpp support.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import ssl
|
||||
xmpp.ssl_version = ssl.PROTOCOL_SSLv3
|
||||
|
||||
Now we're ready to connect and begin echoing messages. If you have the package
|
||||
``aiodns`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP` method
|
||||
``aiodns`` installed, then the :meth:`slixmpp.clientxmpp.ClientXMPP.connect` method
|
||||
will perform a DNS query to find the appropriate server to connect to for the
|
||||
given JID. If you do not have ``aiodns``, then Slixmpp will attempt to
|
||||
connect to the hostname used by the JID, unless an address tuple is supplied
|
||||
to :meth:`slixmpp.clientxmpp.ClientXMPP`.
|
||||
to :meth:`slixmpp.clientxmpp.ClientXMPP.connect`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
# .. option parsing & echo bot configuration
|
||||
xmpp.connect():
|
||||
xmpp.process(forever=True)
|
||||
|
||||
if xmpp.connect():
|
||||
xmpp.process(block=True)
|
||||
else:
|
||||
print('Unable to connect')
|
||||
|
||||
To begin responding to messages, you'll see we called :meth:`slixmpp.basexmpp.BaseXMPP.process`
|
||||
which will start the event handling, send queue, and XML reader threads. It will also call
|
||||
the :meth:`slixmpp.plugins.base.BasePlugin.post_init` method on all registered plugins. By
|
||||
passing ``block=True`` to :meth:`slixmpp.basexmpp.BaseXMPP.process` we are running the
|
||||
main processing loop in the main thread of execution. The :meth:`slixmpp.basexmpp.BaseXMPP.process`
|
||||
call will not return until after Slixmpp disconnects. If you need to run the client in the background
|
||||
for another program, use ``block=False`` to spawn the processing loop in its own thread.
|
||||
The :meth:`slixmpp.basexmpp.BaseXMPP.connect` will only schedule a connection
|
||||
asynchronously. To actually connect, you need to let the event loop take over.
|
||||
This is done with the :meth:`slixmpp.basexmpp.BaseXMPP.process` method,
|
||||
which can either run forever (``forever=True``, the default), run for a (maximum)
|
||||
duration of time (``timeout=n``), and/or run until it gets disconnected (``forever=False``).
|
||||
|
||||
However, calling ``process()`` is not required if you already have an event loop
|
||||
running, so you can handle the logic around it however you like.
|
||||
|
||||
.. note::
|
||||
|
||||
Before 1.0, controlling the blocking behaviour of :meth:`slixmpp.basexmpp.BaseXMPP.process` was
|
||||
done via the ``threaded`` argument. This arrangement was a source of confusion because some users
|
||||
interpreted that as controlling whether or not Slixmpp used threads at all, instead of how
|
||||
the processing loop itself was spawned.
|
||||
|
||||
The statements ``xmpp.process(threaded=False)`` and ``xmpp.process(block=True)`` are equivalent.
|
||||
|
||||
Before slixmpp, :meth:slixmpp.basexmpp.BaseXMPP.process` took ``block`` and ``threaded``
|
||||
arguments. These do not make sense anymore and have been removed. Slixmpp does not use
|
||||
threads at all.
|
||||
|
||||
.. _echobot_complete:
|
||||
|
||||
|
|
|
@ -31,23 +31,23 @@ for the JID that will receive our message, and the string content of the message
|
|||
|
||||
self.add_event_handler('session_start', self.start)
|
||||
|
||||
def start(self, event):
|
||||
async def start(self, event):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
await self.get_roster()
|
||||
|
||||
Note that as in :ref:`echobot`, we need to include send an initial presence and request
|
||||
the roster. Next, we want to send our message, and to do that we will use :meth:`send_message <slixmpp.basexmpp.BaseXMPP.send_message>`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def start(self, event):
|
||||
async def start(self, event):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
await self.get_roster()
|
||||
|
||||
self.send_message(mto=self.recipient, mbody=self.msg)
|
||||
|
||||
Finally, we need to disconnect the client using :meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>`.
|
||||
Now, sent stanzas are placed in a queue to pass them to the send thread.
|
||||
Now, sent stanzas are placed in a queue to pass them to the send routine.
|
||||
:meth:`disconnect <slixmpp.xmlstream.XMLStream.disconnect>` by default will wait for an
|
||||
acknowledgement from the server for at least `2.0` seconds. This time is configurable with
|
||||
the `wait` parameter. If `0.0` is passed for `wait`, :meth:`disconnect
|
||||
|
@ -55,9 +55,9 @@ the `wait` parameter. If `0.0` is passed for `wait`, :meth:`disconnect
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
def start(self, event):
|
||||
async def start(self, event):
|
||||
self.send_presence()
|
||||
self.get_roster()
|
||||
await self.get_roster()
|
||||
|
||||
self.send_message(mto=self.recipient, mbody=self.msg)
|
||||
|
||||
|
|
|
@ -9,10 +9,8 @@ Glossary
|
|||
stream handler
|
||||
A callback function that accepts stanza objects pulled directly
|
||||
from the XML stream. A stream handler is encapsulated in a
|
||||
object that includes a :class:`Matcher <.MatcherBase>` object, and
|
||||
which provides additional semantics. For example, the
|
||||
:class:`.Waiter` handler wrapper blocks thread execution until a
|
||||
matching stanza is received.
|
||||
object that includes a :class:`Matcher <.MatcherBase>` object
|
||||
which provides additional semantics.
|
||||
|
||||
event handler
|
||||
A callback function that responds to events raised by
|
||||
|
|
|
@ -168,13 +168,13 @@ if __name__ == '__main__':
|
|||
xmpp.beClientOrServer(server=True)
|
||||
while not(xmpp.testForRelease()):
|
||||
xmpp.connect()
|
||||
xmpp.process(block=True)
|
||||
xmpp.process(forever=False)
|
||||
logging.debug("lost connection")
|
||||
if args.sensorjid:
|
||||
logging.debug("will try to call another device for data")
|
||||
xmpp.beClientOrServer(server=False,clientJID=args.sensorjid)
|
||||
xmpp.connect()
|
||||
xmpp.process(block=True)
|
||||
xmpp.process(forever=False)
|
||||
logging.debug("ready ending")
|
||||
|
||||
else:
|
||||
|
|
|
@ -73,21 +73,21 @@ old_xmpp = slixmpp.ClientXMPP(args.old_jid, args.old_password)
|
|||
|
||||
roster = []
|
||||
|
||||
def on_session(event):
|
||||
roster.append(old_xmpp.get_roster())
|
||||
async def on_session(event):
|
||||
roster.append(await old_xmpp.get_roster())
|
||||
old_xmpp.disconnect()
|
||||
old_xmpp.add_event_handler('session_start', on_session)
|
||||
|
||||
if old_xmpp.connect():
|
||||
old_xmpp.process(block=True)
|
||||
old_xmpp.process(forever=False)
|
||||
|
||||
if not roster:
|
||||
print('No roster to migrate')
|
||||
sys.exit()
|
||||
|
||||
new_xmpp = slixmpp.ClientXMPP(args.new_jid, args.new_password)
|
||||
def on_session2(event):
|
||||
new_xmpp.get_roster()
|
||||
async def on_session2(event):
|
||||
await new_xmpp.get_roster()
|
||||
new_xmpp.send_presence()
|
||||
|
||||
logging.info(roster[0])
|
||||
|
@ -97,9 +97,11 @@ def on_session2(event):
|
|||
for jid, item in data.items():
|
||||
if item['subscription'] != 'none':
|
||||
new_xmpp.send_presence(ptype='subscribe', pto=jid)
|
||||
new_xmpp.update_roster(jid,
|
||||
name = item['name'],
|
||||
groups = item['groups'])
|
||||
await new_xmpp.update_roster(
|
||||
jid,
|
||||
name=item['name'],
|
||||
groups=item['groups']
|
||||
)
|
||||
new_xmpp.disconnect()
|
||||
new_xmpp.add_event_handler('session_start', on_session2)
|
||||
|
||||
|
|
Loading…
Reference in a new issue