Honestly, this is mainly just a demo/proof of concept that we
can handle dependencies and ordering issues with stream features.
DON'T use XEP-0078 if you are able to use the normal SASL method,
which should be the case unless you are dealing with a very old
XMPP server implementation.
The error bubbles through the event processing loop, breaking it and
hanging the application.
Instead, there is now a .exception(e) method on XMLStream which may
be overridden or reassigned that will receive all unhandled exceptions
(read: not XMPPError) from event and stream handlers.
If a stanza handler raised an exception, the exception was processed
and replied by the modified stanza, not a stanza with the original
content.
A copy is now made before handler processing, and if an exception occurs
it is the copy that processes the exception using the original content.
Since camelcase names are aliased to the underscored name at startup,
if the underscored version is replaced later, the camelCase name does
not reflect the change.
Instead of the actual callback object, return just the name of
the callback object created when using iq.send(callback=..).
This will help prevent memory leaks by not keeping an additional
reference to the object, but still allows for the callback to be
canceled by using self.remove_handler("handler_name").
This allows exceptions to include the original
content of a stanza in the error response by including
the parameter clear=False when raising the exception.
Stream features now use stanza objects!
Features are given a ranking that expresses the dependency
relationships (since only one feature is negotiated at a time, the
dependency graph can be replaced by a line).
>>> xmpp.register_feature('my_feature', _my_handler,
>>> restart=True, # Requires stream restart
>>> order=600) # Ranking (out of ~ 10,000,
>>> # lower #'s executed first)
SASL mechanisms may now be added or disabled as needed. Each mechanism
is given a priority value indicating the order in which the client
wishes for mechanisms to be tried. Higher priority numbers are executed
first.
>>> xmpp.register_sasl_mechanism('SASL-MECH', _mech_handler,
>>> priority=0)
Disabling a SASL mechanism:
>>> xmpp.remove_sasl_mechanism('ANONYMOUS')
We now raise the unexpected exceptions instead of sending
them on the network.
- avoids flood (sending a traceback on a MUC, for example…) and
maybe some security issues.
- lets you handle the traceback (catch it to handle
it properly, or with except_hook, etc)
- an exception cannot be raised without you knowing
The callback will be a stream level handler, and will not
execute in its own thread. If you must have a thread, have the
callback function raise a custom event, which can be processed
by another event handler, which may run in an individual thread,
like so:
def handle_reply(self, iq):
self.event('custom_event', iq)
def do_long_operation_in_thread(self, iq):
...
self.add_event_handler('custom_event', self.do_long_operation_in_thread)
...take out already prepared iq stanza...
iq.send(callback=self.handle_reply)