Merge branch 'docs' into develop
Conflicts: docs/_static/haiku.css docs/_static/header.png docs/conf.py docs/getting_started/muc.rst docs/index.rst examples/muc.py
This commit is contained in:
commit
72e1ab47fc
9 changed files with 450 additions and 7 deletions
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
_build/*
|
35
docs/_static/haiku.css
vendored
35
docs/_static/haiku.css
vendored
|
@ -59,9 +59,10 @@ body {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
font-family: "Helvetica Neueu", Helvetica, sans-serif;
|
font-family: "Helvetica Neueu", Helvetica, sans-serif;
|
||||||
min-width: 59em;
|
min-width: 30em;
|
||||||
max-width: 70em;
|
max-width: 70em;
|
||||||
color: #444;
|
color: #444;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.footer {
|
div.footer {
|
||||||
|
@ -124,21 +125,25 @@ a.headerlink:hover {
|
||||||
/* basic text elements */
|
/* basic text elements */
|
||||||
|
|
||||||
div.content {
|
div.content {
|
||||||
|
margin: auto;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
margin-left: 40px;
|
|
||||||
margin-right: 40px;
|
|
||||||
margin-bottom: 50px;
|
margin-bottom: 50px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
|
width: 700px;
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* heading and navigation */
|
/* heading and navigation */
|
||||||
|
|
||||||
div.header {
|
div.header {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
margin: auto;
|
||||||
margin-top: 125px;
|
margin-top: 125px;
|
||||||
height: 85px;
|
height: 85px;
|
||||||
padding: 0 40px;
|
padding: 0 40px;
|
||||||
font-family: "Yanone Kaffeesatz";
|
font-family: "Yanone Kaffeesatz";
|
||||||
|
text-align: left;
|
||||||
|
width: 750px;
|
||||||
}
|
}
|
||||||
div.header h1 {
|
div.header h1 {
|
||||||
font-size: 2.6em;
|
font-size: 2.6em;
|
||||||
|
@ -185,12 +190,12 @@ div.topnav {
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
div.topnav p {
|
div.topnav p {
|
||||||
|
margin: auto;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-left: 40px;
|
|
||||||
margin-right: 40px;
|
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
|
width: 750px;
|
||||||
}
|
}
|
||||||
div.bottomnav {
|
div.bottomnav {
|
||||||
background: #eeeeee;
|
background: #eeeeee;
|
||||||
|
@ -404,3 +409,23 @@ div.viewcode-block:target {
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#from_andyet {
|
||||||
|
-webkit-box-shadow: #CCC 0px 0px 3px;
|
||||||
|
background: rgba(255, 255, 255, 1);
|
||||||
|
bottom: 0px;
|
||||||
|
right: 17px;
|
||||||
|
padding: 3px 10px;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#from_andyet h2 {
|
||||||
|
background-image: url("images/from_&yet.png");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
height: 29px;
|
||||||
|
line-height: 0;
|
||||||
|
text-indent: -9999em;
|
||||||
|
width: 79px;
|
||||||
|
margin-top: 0;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
BIN
docs/_static/images/from_&yet.png
vendored
Normal file
BIN
docs/_static/images/from_&yet.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
70
docs/_static/pygments.css
vendored
Normal file
70
docs/_static/pygments.css
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
.highlight .hll { background-color: #ffffcc }
|
||||||
|
.highlight { background: #000000; color: #f6f3e8; }
|
||||||
|
.highlight .c { color: #7C7C7C; } /* Comment */
|
||||||
|
.highlight .err { color: #f6f3e8; } /* Error */
|
||||||
|
.highlight .g { color: #f6f3e8; } /* Generic */
|
||||||
|
.highlight .k { color: #00ADEE; } /* Keyword */
|
||||||
|
.highlight .l { color: #f6f3e8; } /* Literal */
|
||||||
|
.highlight .n { color: #f6f3e8; } /* Name */
|
||||||
|
.highlight .o { color: #f6f3e8; } /* Operator */
|
||||||
|
.highlight .x { color: #f6f3e8; } /* Other */
|
||||||
|
.highlight .p { color: #f6f3e8; } /* Punctuation */
|
||||||
|
.highlight .cm { color: #7C7C7C; } /* Comment.Multiline */
|
||||||
|
.highlight .cp { color: #96CBFE; } /* Comment.Preproc */
|
||||||
|
.highlight .c1 { color: #7C7C7C; } /* Comment.Single */
|
||||||
|
.highlight .cs { color: #7C7C7C; } /* Comment.Special */
|
||||||
|
.highlight .gd { color: #f6f3e8; } /* Generic.Deleted */
|
||||||
|
.highlight .ge { color: #f6f3e8; } /* Generic.Emph */
|
||||||
|
.highlight .gr { color: #ffffff; background-color: #ff0000 } /* Generic.Error */
|
||||||
|
.highlight .gh { color: #f6f3e8; font-weight: bold; } /* Generic.Heading */
|
||||||
|
.highlight .gi { color: #f6f3e8; } /* Generic.Inserted */
|
||||||
|
.highlight .go { color: #070707; } /* Generic.Output */
|
||||||
|
.highlight .gp { color: #f6f3e8; } /* Generic.Prompt */
|
||||||
|
.highlight .gs { color: #f6f3e8; } /* Generic.Strong */
|
||||||
|
.highlight .gu { color: #f6f3e8; font-weight: bold; } /* Generic.Subheading */
|
||||||
|
.highlight .gt { color: #ffffff; font-weight: bold; background-color: #FF6C60 } /* Generic.Traceback */
|
||||||
|
.highlight .kc { color: #6699CC; } /* Keyword.Constant */
|
||||||
|
.highlight .kd { color: #6699CC; } /* Keyword.Declaration */
|
||||||
|
.highlight .kn { color: #6699CC; } /* Keyword.Namespace */
|
||||||
|
.highlight .kp { color: #6699CC; } /* Keyword.Pseudo */
|
||||||
|
.highlight .kr { color: #6699CC; } /* Keyword.Reserved */
|
||||||
|
.highlight .kt { color: #FFFFB6; } /* Keyword.Type */
|
||||||
|
.highlight .ld { color: #f6f3e8; } /* Literal.Date */
|
||||||
|
.highlight .m { color: #FF73FD; } /* Literal.Number */
|
||||||
|
.highlight .s { color: #F46DBA;/*#A8FF60;*/ } /* Literal.String */
|
||||||
|
.highlight .na { color: #f6f3e8; } /* Name.Attribute */
|
||||||
|
.highlight .nb { color: #f6f3e8; } /* Name.Builtin */
|
||||||
|
.highlight .nc { color: #f6f3e8; } /* Name.Class */
|
||||||
|
.highlight .no { color: #99CC99; } /* Name.Constant */
|
||||||
|
.highlight .nd { color: #f6f3e8; } /* Name.Decorator */
|
||||||
|
.highlight .ni { color: #E18964; } /* Name.Entity */
|
||||||
|
.highlight .ne { color: #f6f3e8; } /* Name.Exception */
|
||||||
|
.highlight .nf { color: #F64DBA; } /* Name.Function */
|
||||||
|
.highlight .nl { color: #f6f3e8; } /* Name.Label */
|
||||||
|
.highlight .nn { color: #f6f3e8; } /* Name.Namespace */
|
||||||
|
.highlight .nx { color: #f6f3e8; } /* Name.Other */
|
||||||
|
.highlight .py { color: #f6f3e8; } /* Name.Property */
|
||||||
|
.highlight .nt { color: #00ADEE; } /* Name.Tag */
|
||||||
|
.highlight .nv { color: #C6C5FE; } /* Name.Variable */
|
||||||
|
.highlight .ow { color: #ffffff; } /* Operator.Word */
|
||||||
|
.highlight .w { color: #f6f3e8; } /* Text.Whitespace */
|
||||||
|
.highlight .mf { color: #FF73FD; } /* Literal.Number.Float */
|
||||||
|
.highlight .mh { color: #FF73FD; } /* Literal.Number.Hex */
|
||||||
|
.highlight .mi { color: #FF73FD; } /* Literal.Number.Integer */
|
||||||
|
.highlight .mo { color: #FF73FD; } /* Literal.Number.Oct */
|
||||||
|
.highlight .sb { color: #A8FF60; } /* Literal.String.Backtick */
|
||||||
|
.highlight .sc { color: #A8FF60; } /* Literal.String.Char */
|
||||||
|
.highlight .sd { color: #A8FF60; } /* Literal.String.Doc */
|
||||||
|
.highlight .s2 { color: #A8FF60; } /* Literal.String.Double */
|
||||||
|
.highlight .se { color: #A8FF60; } /* Literal.String.Escape */
|
||||||
|
.highlight .sh { color: #A8FF60; } /* Literal.String.Heredoc */
|
||||||
|
.highlight .si { color: #A8FF60; } /* Literal.String.Interpol */
|
||||||
|
.highlight .sx { color: #A8FF60; } /* Literal.String.Other */
|
||||||
|
.highlight .sr { color: #A8FF60; } /* Literal.String.Regex */
|
||||||
|
.highlight .s1 { color: #A8FF60; } /* Literal.String.Single */
|
||||||
|
.highlight .ss { color: #A8FF60; } /* Literal.String.Symbol */
|
||||||
|
.highlight .bp { color: #f6f3e8; } /* Name.Builtin.Pseudo */
|
||||||
|
.highlight .vc { color: #C6C5FE; } /* Name.Variable.Class */
|
||||||
|
.highlight .vg { color: #C6C5FE; } /* Name.Variable.Global */
|
||||||
|
.highlight .vi { color: #C6C5FE; } /* Name.Variable.Instance */
|
||||||
|
.highlight .il { color: #FF73FD; } /* Literal.Number.Integer.Long */
|
70
docs/_templates/layout.html
vendored
Normal file
70
docs/_templates/layout.html
vendored
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
{#
|
||||||
|
haiku/layout.html
|
||||||
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Sphinx layout template for the haiku theme.
|
||||||
|
|
||||||
|
:copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
#}
|
||||||
|
{% extends "basic/layout.html" %}
|
||||||
|
{% set script_files = script_files + ['_static/theme_extras.js'] %}
|
||||||
|
{% set css_files = css_files + ['_static/print.css'] %}
|
||||||
|
|
||||||
|
{# do not display relbars #}
|
||||||
|
{% block relbar1 %}{% endblock %}
|
||||||
|
{% block relbar2 %}{% endblock %}
|
||||||
|
|
||||||
|
{% macro nav() %}
|
||||||
|
<p>
|
||||||
|
{%- block haikurel1 %}
|
||||||
|
{%- endblock %}
|
||||||
|
{%- if prev %}
|
||||||
|
«  <a href="{{ prev.link|e }}">{{ prev.title }}</a>
|
||||||
|
  ::  
|
||||||
|
{%- endif %}
|
||||||
|
<a class="uplink" href="{{ pathto(master_doc) }}">{{ _('Contents') }}</a>
|
||||||
|
{%- if next %}
|
||||||
|
  ::  
|
||||||
|
<a href="{{ next.link|e }}">{{ next.title }}</a>  »
|
||||||
|
{%- endif %}
|
||||||
|
{%- block haikurel2 %}
|
||||||
|
{%- endblock %}
|
||||||
|
</p>
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="header">
|
||||||
|
{%- block haikuheader %}
|
||||||
|
{%- if theme_full_logo != "false" %}
|
||||||
|
<a href="{{ pathto('index') }}">
|
||||||
|
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||||
|
</a>
|
||||||
|
{%- else %}
|
||||||
|
{%- if logo -%}
|
||||||
|
<img class="rightlogo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||||
|
{%- endif -%}
|
||||||
|
<h1 class="heading"><a href="{{ pathto('index') }}">
|
||||||
|
<span>{{ title|striptags }}</span></a></h1>
|
||||||
|
<h2 class="heading"><span>{{ shorttitle|e }}</span></h2>
|
||||||
|
{%- endif %}
|
||||||
|
{%- endblock %}
|
||||||
|
</div>
|
||||||
|
<div class="topnav">
|
||||||
|
{{ nav() }}
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
{#{%- if display_toc %}
|
||||||
|
<div id="toc">
|
||||||
|
<h3>Table Of Contents</h3>
|
||||||
|
{{ toc }}
|
||||||
|
</div>
|
||||||
|
{%- endif %}#}
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
<div class="bottomnav">
|
||||||
|
{{ nav() }}
|
||||||
|
</div>
|
||||||
|
<a id="from_andyet" href="http://andyet.net"><h2>From &yet</h2></a>
|
||||||
|
{% endblock %}
|
||||||
|
|
|
@ -50,7 +50,7 @@ copyright = u'2011, Nathan Fritz, Lance Stout'
|
||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '1.0'
|
version = '1.0'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '1.0RC3'
|
release = '1.0'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@ -91,7 +91,7 @@ pygments_style = 'tango'
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
# a list of builtin themes.
|
# a list of builtin themes.
|
||||||
html_theme = 'nature'
|
html_theme = 'haiku'
|
||||||
|
|
||||||
# Theme options are theme-specific and customize the look and feel of a theme
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
# further. For a list of options available for each theme, see the
|
# further. For a list of options available for each theme, see the
|
||||||
|
|
|
@ -1,2 +1,208 @@
|
||||||
|
.. _mucbot:
|
||||||
|
|
||||||
|
=========================
|
||||||
Mulit-User Chat (MUC) Bot
|
Mulit-User Chat (MUC) Bot
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
.. 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>`_.
|
||||||
|
|
||||||
|
If you have not yet installed SleekXMPP, do so now by either checking out a version
|
||||||
|
from `Github <http://github.com/fritzy/SleekXMPP>`_, or installing it using ``pip``
|
||||||
|
or ``easy_install``.
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
pip install sleekxmpp # Or: easy_install sleekxmpp
|
||||||
|
|
||||||
|
|
||||||
|
Now that you've got the basic gist of using SleekXMPP by following the
|
||||||
|
echobot example (:ref:`echobot`), we can use one of the bundled plugins
|
||||||
|
to create a very popular XMPP starter project: a `Multi-User Chat`_
|
||||||
|
(MUC) bot. Our bot will login to an XMPP server, join an MUC chat room
|
||||||
|
and "lurk" indefinitely, responding with a generic message to anyone
|
||||||
|
that mentions its nickname. It will also greet members as they join the
|
||||||
|
chat room.
|
||||||
|
|
||||||
|
.. _`multi-user chat`: http://xmpp.org/extensions/xep-0045.html
|
||||||
|
|
||||||
|
Joining The Room
|
||||||
|
----------------
|
||||||
|
|
||||||
|
As usual, our code will be based on the pattern explained in :ref:`echobot`.
|
||||||
|
To start, we create an ``MUCBot`` class based on
|
||||||
|
:class:`ClientXMPP <sleekxmpp.clientxmpp.ClientXMPP>` and which accepts
|
||||||
|
parameters for the JID of the MUC room to join, and the nick that the
|
||||||
|
bot will use inside the chat room. We also register an
|
||||||
|
:term:`event handler` for the :term:`session_start` event.
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import sleekxmpp
|
||||||
|
|
||||||
|
class MUCBot(sleekxmpp.ClientXMPP):
|
||||||
|
|
||||||
|
def __init__(self, jid, password, room, nick):
|
||||||
|
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||||
|
|
||||||
|
self.room = room
|
||||||
|
self.nick = nick
|
||||||
|
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
|
||||||
|
After initialization, we also need to register the MUC (XEP-0045) plugin
|
||||||
|
so that we can make use of the group chat plugin's methods and events.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
xmpp.register_plugin('xep_0045')
|
||||||
|
|
||||||
|
Finally, we can make our bot join the chat room once an XMPP session
|
||||||
|
has been established:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def start(self, event):
|
||||||
|
self.get_roster()
|
||||||
|
self.send_presence()
|
||||||
|
self.plugin['xep_0045'].joinMUC(self.room,
|
||||||
|
self.nick,
|
||||||
|
wait=True)
|
||||||
|
|
||||||
|
Note that as in :ref:`echobot`, we need to include send an initial presence and request
|
||||||
|
the roster. Next, we want to join the group chat, so we call the
|
||||||
|
``joinMUC`` method of the MUC plugin.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The :attr:`plugin <sleekxmpp.basexmpp.BaseXMPP.plugin>` attribute is
|
||||||
|
dictionary that maps to instances of plugins that we have previously
|
||||||
|
registered, by their names.
|
||||||
|
|
||||||
|
|
||||||
|
Adding Functionality
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Currently, our bot just sits dormantly inside the chat room, but we
|
||||||
|
would like it to respond to two distinct events by issuing a generic
|
||||||
|
message in each case to the chat room. In particular, when a member
|
||||||
|
mentions the bot's nickname inside the chat room, and when a member
|
||||||
|
joins the chat room.
|
||||||
|
|
||||||
|
Responding to Mentions
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Whenever a user mentions our bot's nickname in chat, our bot will
|
||||||
|
respond with a generic message resembling *"I heard that, user."* We do
|
||||||
|
this by examining all of the messages sent inside the chat and looking
|
||||||
|
for the ones which contain the nickname string.
|
||||||
|
|
||||||
|
First, we register an event handler for the :term:`groupchat_message`
|
||||||
|
event inside the bot's ``__init__`` function.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
We do not register a handler for the :term:`message` event in this
|
||||||
|
bot, but if we did, the group chat message would have been sent to
|
||||||
|
both handlers.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def __init__(self, jid, password, room, nick):
|
||||||
|
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||||
|
|
||||||
|
self.room = room
|
||||||
|
self.nick = nick
|
||||||
|
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
self.add_event_handler("groupchat_message", self.muc_message)
|
||||||
|
|
||||||
|
Then, we can send our generic message whenever the bot's nickname gets
|
||||||
|
mentioned.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Always check that a message is not from yourself,
|
||||||
|
otherwise you will create an infinite loop responding
|
||||||
|
to your own messages.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def muc_message(self, msg):
|
||||||
|
if msg['mucnick'] != self.nick and self.nick in msg['body']:
|
||||||
|
self.send_message(mto=msg['from'].bare,
|
||||||
|
mbody="I heard that, %s." % msg['mucnick'],
|
||||||
|
mtype='groupchat')
|
||||||
|
|
||||||
|
|
||||||
|
Greeting Members
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Now we want to greet member whenever they join the group chat. To
|
||||||
|
do this we will use the dynamic ``muc::room@server::got_online`` [1]_
|
||||||
|
event so it's a good idea to register an event handler for it.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The groupchat_presence event is triggered whenever a
|
||||||
|
presence stanza is received from any chat room, including
|
||||||
|
any presences you send yourself. To limit event handling
|
||||||
|
to a single room, use the events ``muc::room@server::presence``,
|
||||||
|
``muc::room@server::got_online``, or ``muc::room@server::got_offline``.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def __init__(self, jid, password, room, nick):
|
||||||
|
sleekxmpp.ClientXMPP.__init__(self, jid, password)
|
||||||
|
|
||||||
|
self.room = room
|
||||||
|
self.nick = nick
|
||||||
|
|
||||||
|
self.add_event_handler("session_start", self.start)
|
||||||
|
self.add_event_handler("groupchat_message", self.muc_message)
|
||||||
|
self.add_event_handler("muc::%s::got_online" % self.room,
|
||||||
|
self.muc_online)
|
||||||
|
|
||||||
|
Now all that's left to do is to greet them:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
def muc_online(self, presence):
|
||||||
|
if presence['muc']['nick'] != self.nick:
|
||||||
|
self.send_message(mto=presence['from'].bare,
|
||||||
|
mbody="Hello, %s %s" % (presence['muc']['role'],
|
||||||
|
presence['muc']['nick']),
|
||||||
|
mtype='groupchat')
|
||||||
|
|
||||||
|
.. [1] this is similar to the :term:`got_online` event and is sent by
|
||||||
|
the xep_0045 plugin whenever a member joins the referenced
|
||||||
|
MUC chat room.
|
||||||
|
|
||||||
|
|
||||||
|
Final Product
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. compound::
|
||||||
|
|
||||||
|
The final step is to create a small runner script for initialising our ``MUCBot`` 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 muc.py -d -j jid@example.com -r room@muc.example.net -n lurkbot
|
||||||
|
|
||||||
|
which will prompt for the password, log in, and join the group chat. To test, open
|
||||||
|
your regular IM client and join the same group chat that you sent the bot to. You
|
||||||
|
will see ``lurkbot`` as one of the members in the group chat, and that it greeted
|
||||||
|
you upon entry. Send a message with the string "lurkbot" inside the body text, and you
|
||||||
|
will also see that it responds with our pre-programmed customized message.
|
||||||
|
|
||||||
|
.. include:: ../../examples/muc.py
|
||||||
|
:literal:
|
||||||
|
|
|
@ -59,6 +59,72 @@ SleekXMPP's design goals and philosphy are:
|
||||||
sensible defaults and appropriate abstractions. XML can be ugly to work
|
sensible defaults and appropriate abstractions. XML can be ugly to work
|
||||||
with, but it doesn't have to be that way.
|
with, but it doesn't have to be that way.
|
||||||
|
|
||||||
|
Here's your first SleekXMPP Bot:
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from sleekxmpp import ClientXMPP
|
||||||
|
from sleekxmpp.exceptions import IqError, IqTimeout
|
||||||
|
|
||||||
|
|
||||||
|
class EchoBot(ClientXMPP):
|
||||||
|
|
||||||
|
def __init__(self, jid, password):
|
||||||
|
ClientXMPP.__init__(self, jid, password)
|
||||||
|
|
||||||
|
self.add_event_handler("session_start", self.session_start)
|
||||||
|
self.add_event_handler("message", self.message)
|
||||||
|
|
||||||
|
self.register_plugin('xep_0030') # Service Discovery
|
||||||
|
self.register_plugin('xep_0199') # XMPP Ping
|
||||||
|
|
||||||
|
# Here's how to access plugins once you've registered them:
|
||||||
|
# self['xep_0030'].add_feature('echodemo')
|
||||||
|
# You can also use self.plugin['xep_0030']
|
||||||
|
|
||||||
|
# If you are working with an OpenFire server, you will
|
||||||
|
# need to use a different SSL version:
|
||||||
|
# import ssl
|
||||||
|
# self.ssl_version = ssl.PROTOCOL_SSLv3
|
||||||
|
|
||||||
|
def session_start(self, event):
|
||||||
|
self.send_presence()
|
||||||
|
self.get_roster()
|
||||||
|
|
||||||
|
# Most get_*/set_* methods from plugins use Iq stanzas, which
|
||||||
|
# can generate IqError and IqTimeout exceptions
|
||||||
|
#
|
||||||
|
# try:
|
||||||
|
# self.get_roster()
|
||||||
|
# except IqError as err:
|
||||||
|
# logging.error('There was an error getting the roster')
|
||||||
|
# logging.error(err.iq['error']['condition'])
|
||||||
|
# self.disconnect()
|
||||||
|
# except IqTimeout:
|
||||||
|
# logging.error('Server is taking too long to respond')
|
||||||
|
# self.disconnect()
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
if msg['type'] in ('chat', 'normal'):
|
||||||
|
msg.reply("Thanks for sending\n%(body)s" % msg).send()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Ideally use optparse or argparse to get JID,
|
||||||
|
# password, and log level.
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.DEBUG,
|
||||||
|
format='%(levelname)-8s %(message)s')
|
||||||
|
|
||||||
|
xmpp = EchoBot('somejid@example.com', 'use_getpass')
|
||||||
|
xmpp.connect()
|
||||||
|
xmpp.process(block=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Getting Started (with Examples)
|
Getting Started (with Examples)
|
||||||
-------------------------------
|
-------------------------------
|
||||||
.. toctree::
|
.. toctree::
|
||||||
|
|
|
@ -76,8 +76,13 @@ class MUCBot(sleekxmpp.ClientXMPP):
|
||||||
event does not provide any additional
|
event does not provide any additional
|
||||||
data.
|
data.
|
||||||
"""
|
"""
|
||||||
|
<<<<<<< HEAD
|
||||||
self.getRoster()
|
self.getRoster()
|
||||||
self.sendPresence()
|
self.sendPresence()
|
||||||
|
=======
|
||||||
|
self.get_roster()
|
||||||
|
self.send_presence()
|
||||||
|
>>>>>>> docs
|
||||||
self.plugin['xep_0045'].joinMUC(self.room,
|
self.plugin['xep_0045'].joinMUC(self.room,
|
||||||
self.nick,
|
self.nick,
|
||||||
# If a room password is needed, use:
|
# If a room password is needed, use:
|
||||||
|
|
Loading…
Reference in a new issue