NAME
E2::Interface - A client interface to the everything2.com collaborative database
SYNOPSIS
use E2::Interface;
use E2::Message;
# Login
my $e2 = new E2::Interface;
$e2->login( "username", "password" );
# Print client information
print "Info about " . $e2->client_name . "/" . $e2->version . ":";
print "\n domain: " . $e2->domain";
print "\n cookie: " . $e2->cookie";
print "\n parse links:" . ($e2->parse_links ? "yes" : "no");
print "\n username: " . $e2->this_username;
print "\n user_id: " . $e2->this_userid;
# Load a page from e2
my $page = $e2->process_request(
node_id => 124,
displaytype => "xmltrue"
);
# Now send a chatterbox message using the current
# settings of $e2
my $msg = new E2::Message;
$msg->clone( $e2 );
$msg->send( "This is a message" ); # See E2::Message
# Logout
$e2->logout;
DESCRIPTION
Introduction
This module is the base class for e2interface, a set of modules that interface with everything2.com. It maintains an agent that connects to E2 via HTTP and that holds a persistent state (a cookie) that can be clone
d to allow multiple descendants of E2::Interface
to act a single, consistent client. It also contains a few convenience methods.
e2interface
The modules that compose e2interface are listed below and indented to show their inheritance structure.
E2::Interface - The base module
E2::Node - Loads regular (non-ticker) nodes
E2::E2Node - Loads and manipulates e2nodes
E2::Writeup - Loads and manipulates writeups
E2::User - Loads user information
E2::Superdoc - Loads superdocs
E2::Room - Loads room information
E2::Usergroup - Loads usergroup information
E2::Ticker - Modules for loading ticker nodes
E2::Message - Loads, stores, and posts msgs
E2::Search - Title-based searches
E2::Usersearch - Search for writeups by user
E2::Session - Session information
E2::ClientVersion - Client version information
E2::Scratchpad - Load and update scratchpads
See the manpages of each module for information on how to use that particular module.
Error handling
e2interface uses Perl's exception-handling system, Carp::croak
and eval
. An example:
my $e2 = new E2::Interface;
print "Enter username:";
my $name = <>; chomp $name;
print "Enter password:";
my $pass = <>; chomp $pass;
eval {
if( $e2->login( $name, $pass ) ) {
print "$name successfully logged in.";
} else {
print "Unable to login.";
}
};
if( $@ ) {
if $@ =~ /Unable to process request/ {
print "Network exception: $@\n";
} else {
print "Unknown exception: $@\n";
}
}
In this case, login
may generate an "Unable to process request" exception if it's unable to communicate with or receives a server error from everything2.com. This exception may be raised by any method in any package in e2interface that attempts to communicate with the everything2.com server.
Common exceptions include the following (those ending in ':' contain more specific data after that ':'):
'Unable to process request' - HTTP communication error.
'Invalid document' - Invalid document received.
'Parse error:' - Exception raised while parsing
document (the error output of
XML::Twig::parse is placed after
the ':'
'Usage:' - Usage error (method called with
improper parameters)
I'd suggest not trying to catch 'Usage:' exceptions: they can be raised by any method in e2interface and if they are triggered it is almost certainly due to a bug in the calling code.
All methods list which exceptions (besides 'Usage:') that they may potentially throw.
Threading
Network access is slow. Methods that rely upon network access may hold control of your program for a number of seconds, perhaps even minutes. In an interactive program, this sort of wait may be unacceptable.
e2interface supports a limited form of multithreading (in versions of perl that support ithreads--i.e. 5.8.0 and later) that allows network-dependant members to be called in the background and their return values to be retrieved later on. This is enabled by calling use_threads
on an instance of any class derived from E2::Interface (threading is clone
d, so use_threads
affects all instances of e2interface classes that have been clone
d from one-another). After enabling threading, any method that relies on network access will return (-1, job_id) and be executed in the background.
This job_id can then be passed to finish
to retrieve the return value of the method. If, in the call to finish
, the method has not yet completed, it returns (-1, job_id). If the method has completed, finish
returns a list consisting of the job_id followed by the return value of the method.
A code reference can be also be attached to a background method. See thread_then
.
A simple example of threading in e2interface:
use E2::Message;
my $catbox = new E2::Message;
$catbox->use_threads; # Turn on threading
my @r = $catbox->list_public; # This will run in the background
while( $r[0] eq "-1" ) { # While method deferred (use a string
# comparison--if $r[0] happens to be
# a string, you'll get a warning when
# using a numeric comparison)
# Do stuff here........
@r = $catbox->finish( $r[1] ); # $r[1] == job_id
}
# Once we're here, @r contains: ( job_id, return value )
shift @r; # Discard the job_id
foreach( @r ) {
print $_->{text}; # Print out each message
}
Or, the same thing could be done using thread_then
:
use E2::Message;
my $catbox = new E2::Message;
$catbox->use_threads;
# Execute $catbox->list_public in the background
$catbox->thread_then( [\&E2::Message::list_public, $self],
# This subroutine will be called when list_public
# finishes, and will be passed its return value in @_
sub {
foreach( @_ ) {
print $_->{text};
}
# If we were to return something here, it could
# be retrieved in the call to finish() below.
}
);
# Do stuff here.....
# Discard the return value of the deferred method (this will be
# the point where the above anonymous subroutine actually
# gets executed, during a call to finish())
while( $node->finish ) {} # Finish will not return a false
# value until all deferred methods
# have completed
CONSTRUCTOR
- new
-
new
creates anE2::Interface
object. It defaults to using 'Guest User' until eitherlogin
orcookie
is used to log in a user.
METHODS
- $e2->login USERNAME, PASSWORD
-
This method attempts to login to Everything2.com with the specified USERNAME and PASSWORD.
This method returns true on success and
undef
on failure.Exceptions: 'Unable to process request', 'Invalid document'
- $e2->verify_login
-
This method can be called after setting
cookie
to verify the login.It (1) verifies that the everything2 server accepted the cookie as valid, and (2) determines the user_id of the logged-in user, which would otherwise be unavailable.
- $e2->logout
-
logout
attempts to log the user out of Everything2.com.Returns true on success and
undef
on failure. - $e2->process_request HASH
-
process_request
requests the specified page via HTTP and returns its text.It assembles a URL based upon the key/value pairs in HASH (example:
process_request( node_id => 124 )
would translate to "http://everything2.com/?node_id=124" (well, technically, a POST is used rather than a GET, but you get the idea)).The returned text is stripped of HTTP headers and smart quotes and other MS weirdness prior te the return.
For those pages that may be retrieved with or without link parsing (conversion of "[link]" to a markup tag), this method uses this object's
parse_links
setting.All necessary character escaping is handled by
process_request
.Exceptions: 'Unable to process request'
- $e2->clone OBJECT
-
clone
copies various members from theE2::Interface
-derived object OBJECT to this object so that both objects will use the same agent to process requests to Everything2.com.This is useful if, for example, one wants to use both an E2::Node and an E2::Message object to communicate with Everything2.com as the same user. This would work as follows:
$msg = new E2::Message; $msg->login( $username, $password ); $node = new E2::Node; $node->clone( $msg )
clone
copies the cookie, domain, parse_links value, and agentstring, and it does so in such a way that if any of the clones (or the original) change any of these values, the changes will be propogated to all the others. It also clones background threads, so these threads are shared among cloned objects.clone
returns$self
if successful, otherwise returnsundef
. - E2::Interface::debug [ LEVEL ]
-
debug
sets the debug level of e2interface.The default debug level is zero. This value is shared by all instances of e2interface classes.
Debug levels (each displays all messages from levels lower than it):
0 : No debug information displayed 1 : E2::Interface info displayed once; vital debug messages displayed (example: trying to perform an operation that requires being logged in will cause a debug message if you're not logged in) 2 : Each non-trivial subroutine displays its name when called 3 : Important data structures are displayed as processed
Debug messages are output on STDERR.
- E2::Interface::client_name
-
client_name
return the name of this client, "e2interface-perl". - E2::Interface::version
-
version
returns the version number of this client. - $e2->this_username
-
this_username
returns the username currently being used by this agent. - $e2->this_user_id
-
this_user_id
returns the user_id of the current user.This is only available after
login
orverify_login
has been called (in this instance or anotherclone
d instance). - $e2->domain [ DOMAIN ]
-
This method returns, and (if DOMAIN is specified) sets the domain used to fetch pages from e2.
By default, this is "everything2.com".
DOMAIN should contain neither an "http://" or a trailing "/".
-
cookie
returns the current everything2.com cookie (used to maintain login).If COOKIE is specified,
cookie
sets everything2.com's cookie to "COOKIE" and returns that value."COOKIE" is a string value of the "userpass" cookie at everything2.com. Example: an account with the username "willie" and password "S3KRet" would have a cookie of "willie%257CwirQfxAfmq8I6". This is generated by the everything2 servers.
This is how
cookie
would normally be used:# Store the cookie so we can save it to a file if( $e2->login( $user, $pass ) ) { $cookies{$user} = $e2->cookie; } ... print CONFIG_FILE "[cookies]\n"; foreach( keys %cookies ) { print CONFIG_FILE "$_ = $cookies{$_}\n"; }
Or:
# Load the appropriate cookie while( $_ = <CONFIG_FILE> ) { chomp; if( /^$username = (.*)$/ ) { $e2->cookie( $1 ); last; } }
If COOKIE is not valid, this function returns
undef
and the login cookie remains unchanged. - $e2->agentstring [ AGENTSTRING ]
-
agentstring
returns and optionally sets the value prependend to e2interface's agentstring, which is then used in HTTP requests. - $e2->document
-
document
returns the text of the last document retrieved by this instance in a call toprocess_request
.Note: if threading is turned on, this is updated by a call to
finish
, and will refer to the document from the most recent methodfinish
ed. - $e2->logged_in
-
logged_in
returns a boolean value, true if the user is logged in andundef
if not.Exceptions: 'Unable to process request', 'Parse error:'
- $e2->use_threads [ NUMBER ]
-
use_threads
creates a background thread (or NUMBER background threads) to be used to execute network-dependant methods.This method can only be called once for any instance (or set of
clone
d instances), and must be disabled again (by a call tojoin_threads
ordetach_threads
) before it can be re-enabled (this would be useful if you wanted to change the NUMBER of threads).use_threads
returns true on success andundef
on failure. - $e2->join_threads
- $e2->detach_threads
-
These methods disable e2interface's threading for an instance or a set of
clone
d instances.join_threads
waits for the background threads to run through the remainder of their queues before destroying them.detach_threads
detaches the threads immediately, discarding any incomplete jobs on the queue.Both methods process any finished jobs that have not yet been
finish
ed and return a list of these jobs. i.e.:my @r; my @i; while( @i = $e2->finish ) { push @r, \@i if $i[0] ne "-1" } return @r;
- $e2->finish [ JOB_ID ]
-
finish
handles all post-processing of deferred methods, and returns the final return value of the deferred method.(See
thread_then
for information on adding post-processing to a method.)If JOB_ID is specified, it attempts to return the return value of that job, otherwise it attempts to return the return value of the first completed job on its queue.
It returns a list consisting of the job_id of the deferred method followed by the return value of the method in list context. If JOB_ID is specified and the corresponding method is not yet completed, this method returns -1. If JOB_ID is not specified, and there are methods left on the deferred queue but none of them are completed, it returns (-1, -1). If the deferred queue is empty, it returns an empty list.
If exceptions have been raised by a deferred method, or by post-processing code, they will be raised in the call to
finish
. - $e2->thread_then METHOD, CODE [, FINAL ]
-
thread_then
executes METHOD (which is a reference to an array that consists of a method and its parameters, e.g.: [ \&E2::Node::load, $e2, $title, $type ]), and sets up CODE (a code reference) to be passed the return value of METHOD when METHOD completes.thread_then
is named as a sort of mnemonic device: "thread this method, then do this..."thread_then
returns (-1, job_id) if METHOD is deferred; if METHOD is not deferred, thread_then immediately passes its return value to CODE and then returns the return value of CODE. This allows code to be written that can be run as either threaded or unthreaded; indeed this is how e2interface is implemented internally.If METHOD throws an exception (threaded exceptions are thrown during the call to
finish
), CODE will not be executed. If CODE throws an exception, any post-processing chained after CODE will not be executed. For this reason, a third code reference, FINAL, can be specified. This code will be passed no parameters, and its return value will be discarded, but it is guaranteed to be executed after all post-processing is complete, or, in the case of an exception thrown by METHOD or CODE, to be executed beforefinish
throws that exception.
SEE ALSO
E2::Node, E2::E2Node, E2::Writeup, E2::User, E2::Superdoc, E2::Usergroup, E2::Room, E2::Ticker, E2::Message, E2::Search, E2::UserSearch, E2::ClientVersion, E2::Session, E2::Scratchpad, http://everything2.com, http://everything2.com/?node=clientdev
AUTHOR
Jose M. Weeks <jose@joseweeks.com> (Simpleton on E2)
COPYRIGHT
This software is public domain.