📄 x9016.htm
字号:
>, it could only be reached from the Jabber
system to which it was connected. </P
><P
>So let's say <TT
CLASS="LITERAL"
>rss.qmacro.dyndns.org</TT
> <I
CLASS="EMPHASIS"
>is</I
>
a valid and resolvable hostname.
<A
NAME="AEN9402"
HREF="#FTN.AEN9402"
>[7]</A
>
If your client is connected to a Jabber server running on, say,
<TT
CLASS="LITERAL"
>yourserver.org</TT
>, this is what would happen if
you were to send, say, a registration request—an
<TT
CLASS="LITERAL"
><iq/></TT
> element with a query qualified
by the <TT
CLASS="LITERAL"
>jabber:iq:register</TT
> namespace—addressed
to <TT
CLASS="LITERAL"
>rss.qmacro.dyndns.org</TT
>:</P
><P
></P
><DIV
CLASS="VARIABLELIST"
><DL
><DT
>Packet reaches JSM on <TT
CLASS="LITERAL"
>yourserver.org</TT
></DT
><DD
><P
>You send the IQ from your client, which is connected to your Jabber
server's JSM. So this is where the packet first arrives.</P
></DD
><DT
>Internal routing tables consulted</DT
><DD
><P
><TT
CLASS="LITERAL"
>yourserver.org</TT
>'s <B
CLASS="COMMAND"
>jabberd</B
> looks
in its list of internally registered destinations, and doesn't find
<TT
CLASS="LITERAL"
>rss.qmacro.dyndns.org</TT
> in there.</P
></DD
><DT
>Name resolved and routing established</DT
><DD
><P
><TT
CLASS="LITERAL"
>yourserver.org</TT
>'s <TT
CLASS="LITERAL"
>dnsrv</TT
>
(<I
CLASS="EMPHASIS"
>Hostname Resolution</I
>) service
is used to resolve the <TT
CLASS="LITERAL"
>rss.qmacro.dyndns.org</TT
>'s
address. Then, according to <TT
CLASS="LITERAL"
>dnsrv</TT
>'s instance
configuration (specifically the</P
><P
><PRE
CLASS="SCREEN"
><resend>s2s</resend> </PRE
></P
><P
>part—see <A
HREF="x1740.htm#JABTDG-CH-4-SECT-4.3.6"
>the section called <I
>Component Instance: <I
CLASS="EMPHASIS"
>dnsrv</I
></I
> in Chapter 4</A
>), the IQ is
then routed on to the <TT
CLASS="LITERAL"
>s2s</TT
> (<I
CLASS="EMPHASIS"
>Server to
Server)</I
> component.</P
></DD
><DT
>Server to server connection established</DT
><DD
><P
><TT
CLASS="LITERAL"
>yourserver.org</TT
> establishes a connection to
<TT
CLASS="LITERAL"
>qmacro.dyndns.org</TT
> via <TT
CLASS="LITERAL"
>s2s</TT
>
and sends the IQ across the connection.</P
></DD
><DT
>Packet arrives at RSS punter component on
<TT
CLASS="LITERAL"
>qmacro.dyndns.org</TT
></DT
><DD
><P
><B
CLASS="COMMAND"
>jabberd</B
> on <TT
CLASS="LITERAL"
>qmacro.dyndns.org</TT
>
routes the packet correctly to <TT
CLASS="LITERAL"
>rss.qmacro.dyndns.org</TT
>.</P
></DD
></DL
></DIV
><P
>So, what do we learn from this?</P
><P
>As exemplified by the reference to the JUD running at
<TT
CLASS="LITERAL"
>users.jabber.org</TT
> that comes pre-defined in
the standard <TT
CLASS="FILENAME"
>jabber.xml</TT
> with the 1.4.1. version
of the Jabber server, you can specify references to services,
components, <I
CLASS="EMPHASIS"
>on other Jabber servers</I
>. If
you take this RSS punter script (when we finally get to it!),
and run it against your own Jabber server, there's no reason
why you can't share its services with your friends who run
their own Jabber server. </P
><P
>The key is not the reference in the <TT
CLASS="LITERAL"
><browse/></TT
>
section. The key is the resolvability of component names as hostnames, and
the ability of Jabber servers to route packets to each other. The
stanza in <TT
CLASS="LITERAL"
><browse/></TT
> just makes it easier
<I
CLASS="EMPHASIS"
>for the clients</I
> to know about and automatically
be able to interact with services in general. Even if a service
offered by a public component that <I
CLASS="EMPHASIS"
>wasn't</I
> described
in the result of a <TT
CLASS="LITERAL"
>jabber:iq:agents</TT
> query,
it wouldn't stop you from reaching it. But you'd have to be good at
writing XML by hand in your browser's raw/debug mode ;-)</P
><P
>The version query in <A
HREF="x9016.htm#JABTDG-CH-8-EX-14"
>Example 8-14</A
> is a good
example of this. Regardless of whether the conference component at
<TT
CLASS="LITERAL"
>gnu.mine.nu</TT
> was listed in the
<TT
CLASS="LITERAL"
><browse/></TT
> section of the
<TT
CLASS="LITERAL"
>qmacro.dyndns.org</TT
>'s JSM, the user <I
CLASS="EMPHASIS"
>dj</I
>
was able to make a version query by specifying the component's address,
which was a valid and resolvable hostname, in the IQ-get's
<TT
CLASS="LITERAL"
>to</TT
> attribute.</P
></DIV
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-8-SECT-3.1.3"
>Polling the RSS sources</A
></H3
><P
>Now a quick word about the polling of the RSS sources. Remembering that
the programming model with Jabber is usually event-based, and that we
want to poll the RSS sources on a regular basis (although not every
second!), we need some way of "interrupting" the process of checking
for incoming elements and dispatching them to the callbacks, while we
retrieve the RSS data and check for new items. There are many ways of
achieving this; we're writing this component in Perl, so we could use
the <TT
CLASS="FUNCTION"
>alarm()</TT
> feature to set an alarm and have a
subroutine invoked, to poll the RSS sources, when that alarm went off.
This recipe uses the <TT
CLASS="LITERAL"
>Jabber::Connection</TT
> library,
which negates the needs for an external alarm, as we will see when
we come to the script.</P
><P
>Every time it's appropriate for us to poll the RSS sources, this is what
we need to do, for each one:</P
><P
></P
><OL
TYPE="1"
><LI
><P
>Try and retrieve the source from the URL we have</P
></LI
><LI
><P
>Attempt to parse the source's XML</P
></LI
><LI
><P
>Go through the items, until we come across one we've seen before.
The ones we go through until then are deemed to be new.
(We need a special case the first time around, so that we don't
flood everyone with every item of a source the first time we retrieve
it.)</P
></LI
><LI
><P
>For new items, look in our registrations database for the users that
have registered for that source, construct a headline message like the
one shown in <A
HREF="x9016.htm#JABTDG-CH-8-EX-7"
>Example 8-7</A
>, and send it to those
users.</P
></LI
><LI
><P
>Remember the first of the new items, so that we don't go beyond it
next time.</P
></LI
></OL
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-3.2"
>Other things to bear in mind</A
></H2
><P
>There are differences between programming a component and programming
a client. We're already aware of many of the major ones, described
in <A
HREF="x9016.htm#JABTDG-CH-8-SECT-3.1.1"
>the section called <I
>The script as <I
CLASS="EMPHASIS"
>component</I
></I
></A
>. There are, however, also
more subtle differences that we need to bear in mind.</P
><P
>As we know, components, unlike clients, do not connect to the JSM. They
connect as a <I
CLASS="EMPHASIS"
>peer</I
> of the JSM. Not only does this
mean, as already stated, that they cannot partake of the IM feast of
features made available by JSM's modules (see
<A
HREF="x1740.htm#JABTDG-CH-4-SECT-4.3.1.4"
>the section called <I
>Component Connection Method</I
> in Chapter 4</A
> for a list of these modules),
but also that they must
do more for themselves.
<A
NAME="AEN9494"
HREF="#FTN.AEN9494"
>[8]</A
>
When constructing an element as
a client, we should not specify a <TT
CLASS="LITERAL"
>from</TT
> attribute before
we send it; this is added "by the server"—more precisely,
<I
CLASS="EMPHASIS"
>by the JSM</I
>—as it arrives. This is to prevent
JID spoofing. Because a component does not connect through the JSM, no
"from-stamping" takes place: the component itself must stamp the element
with a <TT
CLASS="LITERAL"
>from</TT
> attribute.</P
><P
>The addressing of a component is also slightly different. Whereas client
addresses reflect the fact that they're connected to the JSM, always having
the form:</P
><P
><PRE
CLASS="SCREEN"
>[user]@[hostname]/[resource]</PRE
></P
><P
>(the resource being optional), the basic address form of a
<I
CLASS="EMPHASIS"
>component</I
> is simply:</P
><P
><PRE
CLASS="SCREEN"
>[hostname]</PRE
></P
><P
>This doesn't mean to say that the address of a component cannot have
a <TT
CLASS="LITERAL"
>[user]</TT
> or a <TT
CLASS="LITERAL"
>[resource]</TT
> part.
It's just that <I
CLASS="EMPHASIS"
>all</I
> elements addressed to:</P
><P
><PRE
CLASS="SCREEN"
><I
CLASS="EMPHASIS"
>anything</I
>@[hostname]/anything</PRE
></P
><P
>will be routed by <B
CLASS="COMMAND"
>jabberd</B
> to the component. This
means our component can play multiple roles, and have many personalities.
We'll see an example of this in the script, where we construct an
"artificial" <TT
CLASS="LITERAL"
>[user]@[hostname]</TT
> address for the
<TT
CLASS="LITERAL"
>from</TT
> attribute of a
<TT
CLASS="LITERAL"
><message/></TT
> element, to convey information.</P
><P
>The component will respond to IQ queries in the
<TT
CLASS="LITERAL"
>jabber:iq:register</TT
> namespace. It is, in fact, "customary"
for components to respond to queries in a set of common IQ namespaces,
although by no means mandatory. Taking the JUD and Conferencing
components, for example, we see that they both respond to IQ queries
in the <TT
CLASS="LITERAL"
>jabber:iq:time</TT
> and
<TT
CLASS="LITERAL"
>jabber:iq:version</TT
> namespaces.
<A
HREF="x9016.htm#JABTDG-CH-8-EX-14"
>Example 8-14</A
> shows a typical version query on a
Conferencing component. This responsiveness is simply to
provide a basic level of administrative information. We want our
component to conform to the customs, so we'll make sure it also responds
to queries in these namespaces.</P
><DIV
CLASS="EXAMPLE"
><A
NAME="JABTDG-CH-8-EX-14"
></A
><P
><B
>Example 8-14. A Conferencing component responds to a version query</B
></P
><P
><PRE
CLASS="SCREEN"
>SEND: <iq type='get' to='conf.gnu.mine.nu'>
<query xmlns='jabber:iq:version'/>
</iq>
RECV: <iq type='result' to='dj@qmacro.dyndns.org/study'
from='conf.gnu.mine.nu'>
<query xmlns='jabber:iq:version'>
<name>conference</name>
<version>0.4</version>
<os>Linux 2.2.13</os>
</query>
</iq> </PRE
></P
></DIV
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-3.3"
>The script</A
></H2
><P
>It's time to let the dog see the rabbit. The component is written
in Perl. You might want to refer to the script as a whole unit while
reading through this section—you'll find it in
<A
HREF="x9016.htm#JABTDG-CH-8-SECT-3.5"
>the section called <I
>The script in its entirety</I
></A
>. Ok. Let's go.</P
><DIV
CLASS="SECT3"
><H3
CLASS="SECT3"
><A
NAME="JABTDG-CH-8-SECT-3.3.1"
>Setup</A
></H3
><P
><PRE
CLASS="SCREEN"
>use strict;
use Jabber::Connection;
use Jabber::NodeFactory;
use Jabber::NS qw(:all);
use MLDBM 'DB_File';
use LWP::Simple;
use XML::RSS; </PRE
></P
><P
>We're going to be using the <TT
CLASS="LITERAL"
>Jabber::Connection</TT
> library,
so we declare that here; the library actually consists of three modules,
and we're going to use them all. <TT
CLASS="LITERAL"
>Jabber::Connection</TT
>
manages our connection to the server, and parses and dispatches incoming
elements. <TT
CLASS="LITERAL"
>Jabber::NodeFactory</TT
> allows us to manipulate
elements (generically called "nodes" by the module), and
<TT
CLASS="LITERAL"
>Jabber::NS</TT
> provides us with a raft of constants that
reflect namespaces and other common strings used in Jabber server, client
and component programming. </P
><P
>We need a way of storing the registration information between invocations
of the component script, and we'll use <TT
CLASS="LITERAL"
>MLDBM</TT
> for that.
<TT
CLASS="LITERAL"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -