Add guide for sending a message and then disconnecting.

This commit is contained in:
Lance Stout 2011-08-17 21:21:37 -07:00
parent 01061a0355
commit 961668d420
8 changed files with 146 additions and 162 deletions

8
docs/api/basexmpp.rst Normal file
View file

@ -0,0 +1,8 @@
========
basexmpp
========
.. module:: sleekxmpp.basexmpp
.. autoclass:: BaseXMPP
:members:

8
docs/api/xmlstream.rst Normal file
View file

@ -0,0 +1,8 @@
=========
xmlstream
=========
.. module:: sleekxmpp.xmlstream
.. autoclass:: XMLStream
:members:

2
docs/features.rst Normal file
View file

@ -0,0 +1,2 @@
How to Use Stream Features
==========================

View file

@ -1,3 +1,5 @@
.. _echobot:
=============================== ===============================
SleekXMPP Quickstart - Echo Bot SleekXMPP Quickstart - Echo Bot
=============================== ===============================
@ -386,127 +388,3 @@ can also be found in the SleekXMPP `examples directory <http://github.com/fritzy
.. include:: ../../examples/echo_client.py .. include:: ../../examples/echo_client.py
:literal: :literal:
..
.. #!/usr/bin/env python
.. # -*- coding: utf-8 -*-
.. import sys
.. import logging
.. import time
.. import getpass
.. from optparse import OptionParser
..
.. import sleekxmpp
..
..
.. class EchoBot(sleekxmpp.ClientXMPP):
..
.. """
.. A simple SleekXMPP bot that will echo messages it
.. receives, along with a short thank you message.
.. """
..
.. def __init__(self, jid, password):
.. sleekxmpp.ClientXMPP.__init__(self, jid, password)
..
.. # The session_start event will be triggered when
.. # the bot establishes its connection with the server
.. # and the XML streams are ready for use. We want to
.. # listen for this event so that we we can intialize
.. # our roster.
.. self.add_event_handler("session_start", self.start)
..
.. # The message event is triggered whenever a message
.. # stanza is received. Be aware that that includes
.. # MUC messages and error messages.
.. self.add_event_handler("message", self.message)
..
.. def start(self, event):
.. """
.. Process the session_start event.
..
.. Typical actions for the session_start event are
.. requesting the roster and broadcasting an intial
.. presence stanza.
..
.. Arguments:
.. event -- An empty dictionary. The session_start
.. event does not provide any additional
.. data.
.. """
.. self.send_presence()
.. self.get_roster()
..
.. def message(self, msg):
.. """
.. Process incoming message stanzas. Be aware that this also
.. includes MUC messages and error messages. It is usually
.. a good idea to check the messages's type before processing
.. or sending replies.
..
.. Arguments:
.. msg -- The received message stanza. See the documentation
.. for stanza objects and the Message stanza to see
.. how it may be used.
.. """
.. if msg['type'] in ('normal', 'chat'):
.. msg.reply("Thanks for sending\n%(body)s" % msg).send()
..
..
.. if __name__ == '__main__':
.. # Setup the command line arguments.
.. optp = OptionParser()
..
.. # Output verbosity options.
.. optp.add_option('-q', '--quiet', help='set logging to ERROR',
.. action='store_const', dest='loglevel',
.. const=logging.ERROR, default=logging.INFO)
.. optp.add_option('-d', '--debug', help='set logging to DEBUG',
.. action='store_const', dest='loglevel',
.. const=logging.DEBUG, default=logging.INFO)
.. optp.add_option('-v', '--verbose', help='set logging to COMM',
.. action='store_const', dest='loglevel',
.. const=5, default=logging.INFO)
..
.. # JID and password options.
.. optp.add_option("-j", "--jid", dest="jid",
.. help="JID to use")
.. optp.add_option("-p", "--password", dest="password",
.. help="password to use")
..
.. opts, args = optp.parse_args()
..
.. # Setup logging.
.. logging.basicConfig(level=opts.loglevel,
.. format='%(levelname)-8s %(message)s')
..
.. if opts.jid is None:
.. opts.jid = raw_input("Username: ")
.. if opts.password is None:
.. opts.password = getpass.getpass("Password: ")
..
.. # Setup the EchoBot and register plugins. Note that while plugins may
.. # have interdependencies, the order in which you register them does
.. # not matter.
.. xmpp = EchoBot(opts.jid, opts.password)
.. xmpp.register_plugin('xep_0030') # Service Discovery
.. xmpp.register_plugin('xep_0199') # XMPP Ping
..
.. # If you are working with an OpenFire server, you may need
.. # to adjust the SSL version used:
.. # xmpp.ssl_version = ssl.PROTOCOL_SSLv3
..
.. # Connect to the XMPP server and start processing XMPP stanzas.
.. if xmpp.connect():
.. # If you do not have the pydns library installed, you will need
.. # to manually specify the name of the server if it does not match
.. # the one in the JID. For example, to use Google Talk you would
.. # need to use:
.. #
.. # if xmpp.connect(('talk.google.com', 5222)):
.. # ...
.. xmpp.process(threaded=False)
.. print("Done")
.. else:
.. print("Unable to connect.")

View file

@ -1,5 +1,94 @@
Login, Send a Message, and Disconnect Sign in, Send a Message, and Disconnect
===================================== =======================================
.. note::
If you have any issues working through this quickstart guide
or the other tutorials here, please either send a message to the
`mailing list <http://groups.google.com/group/sleekxmpp-discussion>`_
or join the chat room at `sleek@conference.jabber.org
<xmpp:sleek@conference.jabber.org?join>`_.
A common use case for SleekXMPP is to send one-off messages from A common use case for SleekXMPP is to send one-off messages from
time to time. time to time. For example, one use case could be sending out a notice when
a shell script finishes a task.
We will create our one-shot bot based on the pattern explained in :ref:`echobot`. To
start, we create a client class based on :class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` and
register a handler for the :term:`session_start` event. We will also accept parameters
for the JID that will receive our message, and the string content of the message.
.. code-block:: python
import sleekxmpp
class SendMsgBot(sleekxmpp.ClientXMPP):
def __init__(self, jid, password, recipient, msg):
super(SendMsgBot, self).__init__(jid, password)
self.recipient = recipient
self.msg = msg
self.add_event_handler('session_start', self.start)
def start(self, event):
self.send_presence()
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 <sleekxmpp.basexmpp.BaseXMPP.send_message>`.
.. code-block:: python
def start(self, event):
self.send_presence()
self.get_roster()
self.send_message(mto=self.recipient, mbody=self.msg)
Finally, we need to disconnect the client using :meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>`.
Now, sent stanzas are placed in a queue to pass them to the send thread. If we were to call
:meth:`disconnect <sleekxmpp.xmlstream.XMLStream.disconnect>` without any parameters, then it is possible
for the client to disconnect before the send queue is processed and the message is actually
sent on the wire. To ensure that our message is processed, we use
:meth:`disconnect(wait=True) <sleekxmpp.xmlstream.XMLStream.disconnect>`.
.. code-block:: python
def start(self, event):
self.send_presence()
self.get_roster()
self.send_message(mto=self.recipient, mbody=self.msg)
self.disconnect(wait=True)
.. warning::
If you happen to be adding stanzas to the send queue faster than the send thread
can process them, then :meth:`disconnect(wait=True) <sleekxmpp.xmlstream.XMLStream.disconnect>`
will block and not disconnect.
Final Product
-------------
.. compound::
The final step is to create a small runner script for initialising our ``SendMsgBot`` class and adding some
basic configuration options. By following the basic boilerplate pattern in :ref:`echobot`, we arrive
at the code below. To experiment with this example, you can use:
.. code-block:: sh
python send_client.py -d -j oneshot@example.com -t someone@example.net -m "This is a message"
which will prompt for the password and then log in, send your message, and then disconnect. To test, open
your regular IM client with the account you wish to send messages to. When you run the ``send_client.py``
example and instruct it to send your IM client account a message, you should receive the message you
gave. If the two JIDs you use also have a mutual presence subscription (they're on each other's buddy lists)
then you will also see the ``SendMsgBot`` client come online and then go offline.
.. include:: ../../examples/send_client.py
:literal:

View file

@ -67,7 +67,7 @@ SleekXMPP's design goals and philosphy are:
Getting Started (with Examples) Getting Started (with Examples)
------------------------------- -------------------------------
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 1
getting_started/echobot getting_started/echobot
getting_started/sendlogout getting_started/sendlogout
@ -82,27 +82,29 @@ Getting Started (with Examples)
Tutorials, FAQs, and How To Guides Tutorials, FAQs, and How To Guides
---------------------------------- ----------------------------------
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 1
xeps xeps
xmpp_tdg xmpp_tdg
create_plugin create_plugin
features
sasl sasl
handlersmatchers handlersmatchers
Plugin Guides Plugin Guides
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 1
guide_xep_0030 guide_xep_0030
SleekXMPP Architecture and Design SleekXMPP Architecture and Design
--------------------------------- ---------------------------------
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 3
architecture.rst architecture
plugin_arch
API Reference API Reference
------------- -------------
@ -111,6 +113,8 @@ API Reference
event_index event_index
api/clientxmpp api/clientxmpp
api/basexmpp
api/xmlstream
Additional Info Additional Info
--------------- ---------------

2
docs/plugin_arch.rst Normal file
View file

@ -0,0 +1,2 @@
Plugin Architecture
===================

View file

@ -29,13 +29,18 @@ if sys.version_info < (3, 0):
class SendMsgBot(sleekxmpp.ClientXMPP): class SendMsgBot(sleekxmpp.ClientXMPP):
""" """
A simple SleekXMPP bot that will echo messages it A basic SleekXMPP bot that will log in, send a message,
receives, along with a short thank you message. and then log out.
""" """
def __init__(self, jid, password): def __init__(self, jid, password, recipient, message):
sleekxmpp.ClientXMPP.__init__(self, jid, password) sleekxmpp.ClientXMPP.__init__(self, jid, password)
# The message we wish to send, and the JID that
# will receive it.
self.recipient = recipient
self.msg = message
# The session_start event will be triggered when # The session_start event will be triggered when
# the bot establishes its connection with the server # the bot establishes its connection with the server
# and the XML streams are ready for use. We want to # and the XML streams are ready for use. We want to
@ -43,11 +48,6 @@ class SendMsgBot(sleekxmpp.ClientXMPP):
# our roster. # our roster.
self.add_event_handler("session_start", self.start) self.add_event_handler("session_start", self.start)
# The message event is triggered whenever a message
# stanza is received. Be aware that that includes
# MUC messages and error messages.
self.add_event_handler("message", self.message)
def start(self, event): def start(self, event):
""" """
Process the session_start event. Process the session_start event.
@ -63,27 +63,14 @@ class SendMsgBot(sleekxmpp.ClientXMPP):
""" """
self.send_presence() self.send_presence()
self.get_roster() self.get_roster()
msg = self.Message()
msg['to'] = 'user@example.com'
msg['type'] = 'chat'
msg['body'] = "Hello there!"
msg.send()
self.disconnect()
def message(self, msg): self.send_message(mto=self.recipient,
""" mbody=self.msg,
Process incoming message stanzas. Be aware that this also mtype='chat')
includes MUC messages and error messages. It is usually
a good idea to check the messages's type before processing
or sending replies.
Arguments: # Using wait=True ensures that the send queue will be
msg -- The received message stanza. See the documentation # emptied before ending the session.
for stanza objects and the Message stanza to see self.disconnect(wait=True)
how it may be used.
"""
#msg.reply("Thanks for sending\n%(body)s" % msg).send()
print "Msg rceived from %(body)s: %(jid)s" % msg
if __name__ == '__main__': if __name__ == '__main__':
@ -106,6 +93,10 @@ if __name__ == '__main__':
help="JID to use") help="JID to use")
optp.add_option("-p", "--password", dest="password", optp.add_option("-p", "--password", dest="password",
help="password to use") help="password to use")
optp.add_option("-t", "--to", dest="to",
help="JID to send the message to")
optp.add_option("-m", "--message", dest="message",
help="message to send")
opts, args = optp.parse_args() opts, args = optp.parse_args()
@ -117,14 +108,16 @@ if __name__ == '__main__':
opts.jid = raw_input("Username: ") opts.jid = raw_input("Username: ")
if opts.password is None: if opts.password is None:
opts.password = getpass.getpass("Password: ") opts.password = getpass.getpass("Password: ")
if opts.to is None:
opts.to = raw_input("Send To: ")
if opts.message is None:
opts.message = raw_input("Message: ")
# Setup the EchoBot and register plugins. Note that while plugins may # Setup the EchoBot and register plugins. Note that while plugins may
# have interdependencies, the order in which you register them does # have interdependencies, the order in which you register them does
# not matter. # not matter.
xmpp = SendMsgBot(opts.jid, opts.password) xmpp = SendMsgBot(opts.jid, opts.password, opts.to, opts.message)
xmpp.register_plugin('xep_0030') # Service Discovery xmpp.register_plugin('xep_0030') # Service Discovery
xmpp.register_plugin('xep_0004') # Data Forms
xmpp.register_plugin('xep_0060') # PubSub
xmpp.register_plugin('xep_0199') # XMPP Ping xmpp.register_plugin('xep_0199') # XMPP Ping
# If you are working with an OpenFire server, you may need # If you are working with an OpenFire server, you may need