📄 x7499.htm
字号:
<HTML
><HEAD
><TITLE
>Presence-sensitive CVS notification</TITLE
><META
NAME="GENERATOR"
CONTENT="Modular DocBook HTML Stylesheet Version 1.64
"><LINK
REL="HOME"
TITLE="Programming Jabber"
HREF="book1.htm"><LINK
REL="UP"
TITLE="Messages, Presence, and Presence Subscription"
HREF="c6941.htm"><LINK
REL="PREVIOUS"
TITLE="Dialup system watch"
HREF="x7229.htm"><LINK
REL="NEXT"
TITLE="Extending Messages, Groupchat, Components, and Event Models"
HREF="c7982.htm"></HEAD
><BODY
CLASS="SECT1"
BGCOLOR="#FFFFFF"
TEXT="#000000"
LINK="#0000FF"
VLINK="#840084"
ALINK="#0000FF"
><DIV
CLASS="NAVHEADER"
><TABLE
WIDTH="100%"
BORDER="0"
CELLPADDING="0"
CELLSPACING="0"
><TR
><TH
COLSPAN="3"
ALIGN="center"
>Programming Jabber</TH
></TR
><TR
><TD
WIDTH="10%"
ALIGN="left"
VALIGN="bottom"
><A
HREF="x7229.htm"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 7. Messages, Presence, and Presence Subscription</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c7982.htm"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="JABTDG-CH-7-SECT-3"
>Presence-sensitive CVS notification</A
></H1
><P
>In <A
HREF="x6950.htm"
>the section called <I
>CVS notification</I
></A
> earlier in this chapter we
replaced the email-based CVS notification mechanism with a Jabber-based
one. The script used was extremely simple—it connected to the Jabber
server specified, authenticated, and sent off the notification message to the
recipient JID. </P
><P
>What if we wanted to make the script "sensitive"? Jabber's presence concept
could help us here; if we extended the mechanism to allow for the building
of presence-based relationships between the notification script and the
notification recipients, we can make the sending of the notification message
dependent on the recipient's availability. "Presence-based relationships"
refers to the <I
CLASS="EMPHASIS"
>presence subscription</I
> mechanism described
in the sidebar in <A
HREF="x4089.htm#JABTDG-CH-5-SECT-5.4.2.1"
>the section called <I
>Presence Attributes</I
> in Chapter 5</A
>. </P
><P
>Here's how it would work:</P
><P
></P
><UL
><LI
><P
>Each potential recipient adds the JID used by the CVS notification script
to their roster, and sends a subscription request to it.
<A
NAME="AEN7510"
HREF="#FTN.AEN7510"
>[1]</A
></P
></LI
><LI
><P
>The notification script, on receipt of the presence subscription from
a recipient,
accepts the request and reciprocates by sending a subscription request
back to that recipient.</P
></LI
><LI
><P
>On receipt of the presence subscription from the
notification script, the recipient accepts the request. </P
></LI
><LI
><P
>When the notification script starts up to send a message, it announces
its own availability with a <TT
CLASS="LITERAL"
><presence/></TT
>
element, which causes the availability of the JIDs to which it has a
presence subscription to be sent to it. Based on these
<TT
CLASS="LITERAL"
><presence/></TT
> packets received, it can
make a decision as to whether to send the notification message or not.</P
><P
>The decision we're going to use here is an arbitrary one:
If the recipient is online, we'll send the message, unless they've
specified that they don't want to be disturbed, with the
<TT
CLASS="LITERAL"
><show>dnd</show></TT
> element.</P
></LI
></UL
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-7-SECT-3.1"
>Subscription relationships</A
></H2
><P
>This method will result in "balanced" subscription relationships between
script and recipients. In other words, the script is subscribed to a
recipient's presence, and vice versa.</P
><P
>Of the two presence subscription "directions", the one where the
<I
CLASS="EMPHASIS"
>notification script</I
>
subscribes to the
<I
CLASS="EMPHASIS"
>recipient's</I
> presence (as opposed to the one
where the <I
CLASS="EMPHASIS"
>recipient</I
> subscribes to the
<I
CLASS="EMPHASIS"
>notification script's</I
> presence) is by far the most
important. While it's not critical that the recipients know when the
notification script is connected and active, it's essential that the
notification script know about a recipient's availability at the time it
wants to send a message. </P
><P
>So would it be more appropriate to create "unbalanced" subscription
relationships?</P
><P
>An unbalanced relationship is one where one party knows
about the other party's availability, but <I
CLASS="EMPHASIS"
>not</I
>
vice versa. The idea for sensitizing our notification script will work
as long as the script can know about the availability of the recipients.
Whether or not the opposite is true is largely irrelevant. </P
><P
>Nevertheless, it's worth basing the interaction on balanced, or reciprocal,
presence subscriptions, primarily for simplicity's sake, and also for the
fact that
most Jabber clients (and most <I
CLASS="EMPHASIS"
>users</I
> of these clients)
tend to cope well and consistently with "balanced" subscriptions,
whereby the representation and interpretation of unbalanced relationships
is dealt with and understood in different manners. Some clients use a
"<I
CLASS="EMPHASIS"
>Lurker</I
>" group to classify one-way presence
subscriptions from other JIDs: a "lurker" being one that can see you
while you can't see it.</P
><P
>Far from being nebulous concepts, balanced and unbalanced subscription
relationships are characterized technically by values of a certain
attribute specified
in each item—each JID—in a roster: the
<TT
CLASS="LITERAL"
>subscription</TT
> attribute of the
<TT
CLASS="LITERAL"
><item/></TT
> tags within the roster. As we
progress through the extensions to our CVS notification script, we'll
pause at various stages to examine these values.</P
><DIV
CLASS="NOTE"
><BLOCKQUOTE
CLASS="NOTE"
><P
><B
>Anthropomorphism: </B
>It's worth pointing out at this stage that adding a JID that's used by a
<I
CLASS="EMPHASIS"
>script</I
> to connect to Jabber is slightly symbolic of
the extension of the instant messaging world into the wider arena of A2P
messaging. Adding a <I
CLASS="EMPHASIS"
>service</I
> JID to your roster and
sharing presence information with that service is such a powerful concept
and one which can be used to base A2P solutions upon.</P
></BLOCKQUOTE
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-7-SECT-3.2"
>Extending the script</A
></H2
><P
>The script, as it stands in <A
HREF="x6950.htm#JABTDG-CH-7-SECT-1.3.2"
>the section called <I
>The script in its entirety</I
></A
>, is
what we want to extend and make sensitive to presence. We'll walk through
the additions, and then present the extended script at the end of this
section.</P
><P
>We bring in a string function that we'll be needing later in the script
to chop up JIDs into their component parts (<I
CLASS="EMPHASIS"
>username</I
>,
<I
CLASS="EMPHASIS"
>hostname</I
>, and <I
CLASS="EMPHASIS"
>resource</I
>):</P
><P
><PRE
CLASS="SCREEN"
>import Jabber, XMLStream
import sys
<TT
CLASS="USERINPUT"
><B
>from string import split</B
></TT
>
cvsuser = sys.argv[1]
message = '' </PRE
></P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-7-SECT-3.2.1"
>Callbacks and handlers</A
></H3
><P
>The next addition to the script is a callback to handle
<TT
CLASS="LITERAL"
><presence/></TT
> elements. The callback in
this script takes the form of a subroutine called
<TT
CLASS="FUNCTION"
>presenceCB()</TT
> ("presence CallBack").</P
><TABLE
CLASS="SIDEBAR"
BORDER="1"
CELLPADDING="5"
><TR
><TD
><DIV
CLASS="SIDEBAR"
><A
NAME="AEN7560"
></A
><P
><B
>Jabber programming and <I
CLASS="EMPHASIS"
>callbacks</I
></B
></P
><P
>When programming all but the simplest Jabber scripts, you're going
to be using <I
CLASS="EMPHASIS"
>callbacks</I
>. Callbacks are also known
as <I
CLASS="EMPHASIS"
>handlers</I
>.</P
><P
>Rather than purely procedural programming ("do this, then do that,
then do the other"), we need a different model to cope with the
<I
CLASS="EMPHASIS"
>event-based</I
> nature of Jabber, or more precisely,
the event-based nature of how we converse using the Jabber protocol
over an XML stream. Although we control what we
<I
CLASS="EMPHASIS"
>send</I
> over the XML stream connection that we've
established with the Jabber server, we can't control what we
<I
CLASS="EMPHASIS"
>receive</I
>, and more importantly, we can't
control <I
CLASS="EMPHASIS"
>when</I
> we receive it. We need an
event-based programming model to be able to <I
CLASS="EMPHASIS"
>handle</I
>
the protocol elements as they arrive. </P
><P
>The libraries available for programming with Jabber offer
<I
CLASS="EMPHASIS"
>callback</I
> mechanisms. With these callback mechanisms
we can register subroutines with the mechanism that's
handling the reception of XML stream fragments, so that when an
element appears on the incoming stream (a fragment in the stream
document that the Jabber server is sending to us—see
<A
HREF="x3837.htm"
>the section called <I
>XML Streams</I
> in Chapter 5</A
>), the Jabber library can pass
it to the appropriate subroutine in our script for us to act upon.</P
><P
><A
HREF="x7499.htm#JABTDG-CH-7-FIG-5"
>Figure 7-5</A
> shows the relationship between the
library and script, and the sequence of events surrounding registering
a handler and having it called. Here are the steps shown:</P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>[1] Register handler</DT
><DD
><P
>The script uses a library function to register a subroutine —in
this case it's <TT
CLASS="FUNCTION"
>presenceCB()</TT
>—as
a handler with the library. In the registration, the subroutine
is assigned as a handler for <TT
CLASS="LITERAL"
><presence/></TT
>
elements.</P
></DD
><DT
>[2] <TT
CLASS="LITERAL"
><presence/> element arrives</TT
></DT
><DD
><P
>An XML fragment arrives on the stream, sent by the Jabber server.</P
></DD
><DT
>[3] Parse, and create node</DT
><DD
><P
>The fragment is parsed into its component parts by an XML parser, and
a node is created. A "node" is simply a term used to describe a succinct
XML fragment—containing attributes, data, and child tags—
that usually is in the form of an object that is programmatically
accessible. The node creation step is theoretically optional; we could
have the library pass on the fragment in a simple string representation
form, but that would put the onus on the script to parse the string
before being able to manipulate the fragment that the string represented.</P
></DD
><DT
>[4] Determine handler</DT
><DD
><P
>Once parsed, the library looks at what sort of element, or node, the
fragment is, and determines what (if any) handler has been registered.
In this case, it's a <TT
CLASS="LITERAL"
><presence/></TT
> element,
and finds that the subroutine <TT
CLASS="FUNCTION"
>presenceCB()</TT
> has
been registered as a handler for <TT
CLASS="LITERAL"
><presence/></TT
>
elements.</P
></DD
><DT
>[5] Call handler</DT
><DD
><P
>The library calls the handler <TT
CLASS="FUNCTION"
>presenceCB()</TT
> in the
script, passing in the node. It may pass in other information too (for
example, the Python library <TT
CLASS="LITERAL"
>Jabber</TT
> also passes in the
stream connection object, as we'll see in a moment), and the Perl library
<TT
CLASS="LITERAL"
>Net::Jabber</TT
> also passes in a session ID relating to the
stream.
<A
NAME="AEN7607"
HREF="#FTN.AEN7607"
>[2]</A
></P
></DD
></DL
></DIV
></DIV
></TD
></TR
></TABLE
><DIV
CLASS="FIGURE"
><A
NAME="JABTDG-CH-7-FIG-5"
></A
><P
><B
>Figure 7-5. Handlers and the relationship between the Jabber library and
your script</B
></P
><PRE
CLASS="SCREEN"
> +---------------------------+ +---------------------+
| Jabber library | | Your script |
|---------------------------| |---------------------|
| | | |
| | | [1] |
| +----------------------- register handler |
| | | | |
| +-V-------+ | | |
| |presence ........................ |
| +---------+ | | : |
| |message | | | +------------+ |
XML | +---------+ | | +->|presenceCB()| |
stream | |iq | | | | |------------| |
| | +---------+ | | | | | |
V | ^ | | | | | |
============== | | | | +------------+ |
[2] <presence/> +-------+ | | | |
element arrives | | | | |
----------------> [3] parse, and | | | | |
============== create node | | | | |
| [4] determine handler | | | |
| [5] call handler ---------------+ |
| | | |
| | | |
+---------------------------+ +---------------------+ </PRE
></DIV
><P
>This is what the callback for handling
<TT
CLASS="LITERAL"
><presence/></TT
> elements looks like:</P
><P
><PRE
CLASS="SCREEN"
>def presenceCB(con, prs):
type = prs.getType()
parts = split(prs.getFrom(), '/')
who = parts[0]
if type == None: type = 'available'
# subscription request:
# - accept their subscription
# - send request for subscription to their presence
if type == 'subscribe':
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -