⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 x9991.htm

📁 Its a xmpp protocol book
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<HTML
><HEAD
><TITLE
>Headline viewer</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="Extending Messages, Groupchat, Components, and Event Models"
HREF="c7982.htm"><LINK
REL="PREVIOUS"
TITLE="RSS punter"
HREF="x9016.htm"><LINK
REL="NEXT"
TITLE="Pointers for further development"
HREF="c10187.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="x9016.htm"
>Prev</A
></TD
><TD
WIDTH="80%"
ALIGN="center"
VALIGN="bottom"
>Chapter 8. Extending Messages, Groupchat, Components, and Event Models</TD
><TD
WIDTH="10%"
ALIGN="right"
VALIGN="bottom"
><A
HREF="c10187.htm"
>Next</A
></TD
></TR
></TABLE
><HR
ALIGN="LEFT"
WIDTH="100%"></DIV
><DIV
CLASS="SECT1"
><H1
CLASS="SECT1"
><A
NAME="JABTDG-CH-8-SECT-4"
>Headline viewer</A
></H1
><P
>Wow. That was a biggie. So we're going to close this Chapter on a lighter
note, and what could be more fitting than to build a complementary 
script with which we can keep an eye on those RSS headlines that are
punted to us throughout the day. </P
><P
>In most of my workplaces, the monitor I have is 17 inches. Which means 
that every application must make a justification for 
existence on a plot of the pixel real-estate, a justification relative
to it's window size. So something that allows me to watch RSS headlines
as they scroll by ought to be small. It has no reason to be large.</P
><P
>Until now, I've droned on about the great leverage
that there is to building solutions that make use of off the shelf clients. 
<A
NAME="AEN9996"
HREF="#FTN.AEN9996"
>[1]</A
>
But it's time to buck the trend, indeed to make another point. While 
you can orientate the features of your Jabber-based applications in
the direction of standard clients, to take advantage of the installed
base of Jabber clients, if you do want to create a client that works
differently, a client that fits your needs exactly, then go ahead: it
will be surprisingly straightforward. The mantra of "server side complex,
client side simple" (with apologies to George Orwell) is there to 
help us. What's more, we can put into action an idea expressed earlier
in the book (in <A
HREF="x760.htm"
>the section called <I
>Custom Clients</I
> in Chapter 2</A
>):</P
><A
NAME="AEN9999"
></A
><BLOCKQUOTE
CLASS="BLOCKQUOTE"
><P
>A Jabber client is a piece of software that implements
as much of the Jabber protocol as required to get the job done.</P
></BLOCKQUOTE
><P
>If we're going to build a headline viewer client, and know that
the information is going to get punted to us in headline type 
<TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
> elements, why have our viewer
client understand or deal with anything else? To implement a Jabber
solution, we pick and choose the parts of the protocol that make sense
in the context of that solution. If you want to transport RPC calls
in data payloads between two endpoints, why bother with roster management
or rich-text chat facilities? If you just want to join a conference room to
talk with the other room occupants, why bother with threaded one-on-one
conversations? If you need routing and presence capabilities to have your
oven know when you've arrived home, why engineer anything else?</P
><P
>What we're going to write here is a simple headline viewer. Nothing
more. Nothing less. It will know the tiniest thing about presence&mdash;
as the headlines come in as <TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
>
elements, it will need to announce its availability to the JSM&mdash;and
the viewer we're going to build will be a Jabber client
that will have a session context with the JSM, we need to tell the JSM
that we're available when we start the client up. Otherwise the headlines
will simply be queued up by the store and forward mechanism ready for
the "next time" we're available. </P
><P
>We'll leave the registration with the RSS punter to another client
that knows about agents (services) and can interact in a
<TT
CLASS="LITERAL"
>jabber:iq:register</TT
> kind of way. I'm not a big fan 
of the "one size fits all, one client for everything" philosophy; I 
prefer to use different features of different programs to get me through
my day. So while our headline viewer will receive, understand and display
the <TT
CLASS="LITERAL"
>&#60;message type='headline'/&#62;</TT
>s, we'll
use WinJab, or even JIM (Jabber Instant Messenger) to manage our RSS
source subscriptions.
<A
HREF="x9991.htm#JABTDG-CH-8-FIG-10"
>Figure 8-8</A
> illustrates the process of registration
with our RSS punter component, using JIM. </P
><DIV
CLASS="FIGURE"
><A
NAME="JABTDG-CH-8-FIG-10"
></A
><P
><B
>Figure 8-8. Registering with the RSS punter with JIM</B
></P
><P
><IMG
SRC="CH-8-FIG-10.jpg"></P
></DIV
><P
>The suggestion of JIM as a client to complement
(cheers!) or make up for the lack of features in (boos!) our headline
viewer is deliberately ironic. JIM's remit is to provide support for
core Jabber client features, of which (as yet) headline messages are
not considered to be a part. So while JIM can interact with services and
register (and unregister&mdash;which will send the 
<TT
CLASS="LITERAL"
>&#60;remove/&#62;</TT
> tag in the query, as 
described in <A
HREF="x9016.htm#JABTDG-CH-8-SECT-3.3.5"
>the section called <I
>Handling registration requests</I
></A
>), it doesn't handle
headline type messages. Which is perfectly fine. Our headline viewer
won't handle chat or normal messages. The point is, it's not 
<I
CLASS="EMPHASIS"
>supposed</I
> to. </P
><P
>It's worth pointing out that another reason why our headline viewer
client can remain simple is because the RSS punter component will be
doing all the hard work for us. Unlike other (non-Jabber) headline
viewer programs that are available, our script depends upon the 
RSS punter. It's that component that will maintain the list of RSS
sources. It's also that component that will retrieve those sources
at regular intervals and check for new items. All we have to do is
sit back and have those new items pushed to us, at which point our
client has to make a slight effort to insert the details of those new
items into the viewer display. That's more or less it.</P
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-4.1"
>The plan</A
></H2
><P
>The viewer is visual, so let's see at what it's going to 
look like. <A
HREF="x9991.htm#JABTDG-CH-8-FIG-11"
>Figure 8-9</A
> shows the headline
viewer client in action. There's a scrollable area where the headline
titles are displayed. We can <I
CLASS="EMPHASIS"
>clear</I
> that area, or
select a headline and call up a web browser to <I
CLASS="EMPHASIS"
>fetch</I
>
the story by passing the URL to it.</P
><DIV
CLASS="FIGURE"
><A
NAME="JABTDG-CH-8-FIG-11"
></A
><P
><B
>Figure 8-9. The headline viewer client</B
></P
><P
><IMG
SRC="CH-8-FIG-11.jpg"></P
></DIV
><P
>It's also nice and small, visually and in the amount of code we're
going to have to write. We connect to our Jabber server, set up a
handler for the incoming headline messages, build our display, send
our availability, and sit back. </P
><P
>Actually, we need to say a few things about the "sitting back" bit. We
know that Jabber
programming implies an event model. We're going to use Tk&mdash;the
widget library for building GUI applications, with bindings for many
languages. Tk itself has an event model, which in many ways reflects
Jabber's. <A
HREF="x9991.htm#JABTDG-CH-8-TAB-2"
>Table 8-2</A
> shows how Jabber and 
Tk reflect in this programming model puddle.</P
><DIV
CLASS="TABLE"
><A
NAME="JABTDG-CH-8-TAB-2"
></A
><P
><B
>Table 8-2. Jabber and Tk event model reflections</B
></P
><TABLE
BORDER="1"
CLASS="CALSTABLE"
><THEAD
><TR
><TH
ALIGN="LEFT"
VALIGN="TOP"
>Jabber</TH
><TH
ALIGN="LEFT"
VALIGN="TOP"
>Tk</TH
></TR
></THEAD
><TBODY
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
>Establish connection to server</TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
>Construction of widgets</TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
>Definition of callbacks to handle incoming elements</TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
>Definition of callbacks to handle UI events</TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
>Setting of a heartbeat function 
<A
NAME="AEN10047"
HREF="#FTN.AEN10047"
>[a]</A
></TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
>Setting of a command to execute regularly with <TT
CLASS="FUNCTION"
>repeat()</TT
></TD
></TR
><TR
><TD
ALIGN="LEFT"
VALIGN="TOP"
>Launching the event loop</TD
><TD
ALIGN="LEFT"
VALIGN="TOP"
>Starting <TT
CLASS="FUNCTION"
>MainLoop()</TT
></TD
></TR
></TBODY
><TR
><TD
COLSPAN="2"
>Notes:<BR><A
NAME="FTN.AEN10047"
>a. </A
>See <A
HREF="x9016.htm#JABTDG-CH-8-SECT-3.3.3"
>the section called <I
>Preparation of the RSS event function and element handlers</I
></A
>.<BR></TD
></TR
></TABLE
></DIV
><P
>Having one program governed by two independent event loops is not 
what we want to try and achieve. We want Jabber and Tk's event models
to cooperate. This is achievable by making one of the two models the
master and the other one the slave. Using Tk's 
<TT
CLASS="FUNCTION"
>repeat()</TT
> method to invoke a function that 
calls our Jabber library's <TT
CLASS="FUNCTION"
>process()</TT
> method 
should do the trick. We can hand over control to Tk with 
<TT
CLASS="FUNCTION"
>MainLoop()</TT
>, and know that our Jabber event model
will get a look in because of the Tk event callback we've defined
with <TT
CLASS="FUNCTION"
>repeat()</TT
>. </P
></DIV
><DIV
CLASS="SECT2"
><H2
CLASS="SECT2"
><A
NAME="JABTDG-CH-8-SECT-4.2"
>The script</A
></H2
><P
>We're going to use Perl, and the <TT
CLASS="LITERAL"
>Net::Jabber</TT
> Jabber
library. Starting with the declarations of the libraries we're going
to use, along with some constants:</P
><P
><PRE
CLASS="SCREEN"
>use Tk;
use Net::Jabber qw(Client);
use strict;

use constant SERVER   =&#62; 'gnu.pipetree.com';
use constant PORT     =&#62; 5222;
use constant USER     =&#62; 'dj';
use constant PASSWORD =&#62; 'secret';
use constant RESOURCE =&#62; 'hlv';

use constant BROWSER  =&#62; '/usr/bin/konqueror';&#13;</PRE
></P
><P
>The script will connect to Jabber as a client, so we specify that
in our <TT
CLASS="LITERAL"
>use</TT
> statement to have the appropriate 
<TT
CLASS="LITERAL"
>Net::Jabber</TT
> modules loaded. We're going to be 
connecting to the Jabber server at <TT
CLASS="FILENAME"
>gnu.pipetree.com</TT
>,
although, as we said, the RSS punter might live somewhere else. It
just so happens that in our scenario, there's a reference to the component
in <TT
CLASS="FILENAME"
>gnu.pipetree.com</TT
>'s JSM 
<TT
CLASS="LITERAL"
>&#60;browse/&#62;</TT
> section, so that we can 
carry out our registration conversations with it (using JIM, for example).</P
><P
>If the <I
CLASS="EMPHASIS"
>Fetch</I
> button is pressed when an item in the
list is selected (see <A
HREF="x9991.htm#JABTDG-CH-8-FIG-11"
>Figure 8-9</A
>), we want to
jump to the story by launching a web browser. The constant 
<TT
CLASS="LITERAL"
>BROWSER</TT
> used here refers to the browser on our 
local machine.
<A
NAME="AEN10077"
HREF="#FTN.AEN10077"
>[2]</A
></P
><P
><PRE
CLASS="SCREEN"
>my @headlines;
my @list;&#13;</PRE
></P
><P
>We declare two arrays: <TT
CLASS="LITERAL"
>@headlines</TT
>, which we'll use
to hold the items as they arrive contained in the headline 
<TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
> elements on the XML stream,
and <TT
CLASS="LITERAL"
>@list</TT
>, to hold the URLs that relate to those
items in <TT
CLASS="LITERAL"
>@headlines</TT
>.</P
><P
>After connecting to and authenticating ourselves with the Jabber server
(this is very similar to the way the coffee monitor script connects 
and authenticates in <A
HREF="x8561.htm#JABTDG-CH-8-SECT-2.2.5"
>the section called <I
><TT
CLASS="FUNCTION"
>setup_Jabber()</TT
></I
></A
>):</P
><P
><PRE
CLASS="SCREEN"
>my $connection = Net::Jabber::Client-&#62;new();

$connection-&#62;Connect(
  hostname =&#62; SERVER,
  port     =&#62; PORT,
) or die "Cannot connect ($!)\n";

my @result = $connection-&#62;AuthSend(
  username =&#62; USER,
  password =&#62; PASSWORD,
  resource =&#62; RESOURCE,
);

if ($result[0] ne "ok") {
  die "Ident/Auth with server failed: $result[0] - $result[1]\n";
}&#13;</PRE
></P
><P
>we set up our callback to take care of incoming 
<TT
CLASS="LITERAL"
>&#60;message/&#62;</TT
> elements. This is the
<TT
CLASS="FUNCTION"
>handle_message()</TT
> function:</P
><P
><PRE
CLASS="SCREEN"
>$connection-&#62;SetCallBacks( message =&#62; \&#38;handle_message );&#13;</PRE
></P
><P
>Now it's time to build our GUI. We start by creating a main window, 
giving it a title and geometry, and establishing the cooperation 
between the two event models with the <TT
CLASS="FUNCTION"
>repeat()</TT
>
method:</P
><P
><PRE
CLASS="SCREEN"
>my $main = MainWindow-&#62;new( -title =&#62; "Headline Viewer" );
$main-&#62;geometry('50x5+10+10');
$main-&#62;repeat(5000, \&#38;check_headlines);&#13;</PRE
></P
><P
><TT
CLASS="FUNCTION"
>repeat()</TT
> will arrange Tk's main event loop
to hiccup every five seconds (the first argument is measured
in milliseconds) and call our <TT
CLASS="FUNCTION"
>check_headlines()</TT
>
function.</P
><P

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -