NAME
Volity::Jabber - a base class for Jabber-speaking Volity objects
SYNOPSIS
package My::Volity::Object;
use base qw(Volity::Jabber);
use fields qw(wubba_wubba);
# Override the parent's initialize method to set values on construction.
sub initialize {
my $self = shift;
$self->SUPER::initialize(@_); # Don't forget to call the parent's init!
# Initialization goes here
$self->wubba_wubba('grink gronk');
}
# An example chat handler, defined by the base class
sub handle_groupchat_message {
my $self = shift;
my ($message) = @_; # A hashref with info about the incoming message.
# Send a debug message.
$self->logger->debug(sprintf("%s says, '%s'\n", $$message{from}, $$message{body}));
# More use message-handling code goes here.
}
DESCRIPTION
This package provides a base class for Volity objects that speak Jabber. These objects will automatically connect to (and authenticate with ) a Jabber server on construction, and then provide some methods for doing some common jabbery things, as well as access the POE kernel.
USAGE
For game authors
You don't need to know much of anything at this level. Here be dragons.
Stick to the modules listed in "Modules of interest to game developers" in Volity, especially Volity::Game
.
For deep-voodoo wizards
To use this module, write an object class that subclasses Volity::Jabber
, then override any event-handling methods which should perform some action other than the default (which is usually a no-op). See "CALLBACK METHODS" for a list of these handlers.
Commonly, you'll want to respond to incoming Jabber stanzas by firing off some stanzas of your own, and the methods listed under "JABBER ACTION METHODS" can help you here.
Keep in mind that every instance of your class will represent a separate connection to a Jabber server. So, a single object can represent a game server, a client connection, or a "bot", among other things.
Object construction and initialization
The module inherits from Class::Accessor::Fields, so using it means using the base
and fields
pragmas, respectively. If you don't like this behavior, you can just overload the new() method. Otherwise, you don't need to define new() at all.
If you want to initialize your object, override the initialize
method. however, you must call SUPER::initilialize
, otherwise the connection won't open.
Localization
This module supports language localization compliant with the core Jabber protocol. All stanzas automatically get an xml:lang
attribute set on their top-level element (such as <message>
or <presence>
) whose value is the object's current default_language
value (en
being the default's default, and you can change this through the default_language
accessor method).
Some methods, such as send_message
(described under "JABBER ACTION METHODS"), allow you to specify either plain text strings in the default language, or localized text strings in several languages. To provide localized strings, pass the method a hash reference where'd you'd normally pass in a plain string. The hash's keys should be ISO 639-compliant two-letter language codes, with their corresponding localized text as values. For example:
{
'en' => "This is some localized text.",
'es' => "Éste es un poco de texto localizado.",
'fr' => "C'est un certain texte localisé.",
'ru' => "Это будет некоторый локализованный текст.",
}
Do make sure that you "use utf8" and enter UTF-8 only text if you're using anything other then ASCII. Remember, Latin-1 is NOT compatible with UTF-8.
If you aren't concerned at all with localization, you can simply ignore all these methods and techniques, and nothing will break. So, in the same place as you'd use the above hashref, you could instead simply use a string like this:
"This string is available in English only. C'est la vie."
METHODS
Accessors
All these accessor methods take the same form, as defined by Class::Accessor: all return a scalar value (or undef
) representing a current value set on the object, and will set this value first if called with an argument (which can be a scalar or a list, if appropriate).
Also in Class::Accessor style, you can set any of these values during construction by passing them in a hashref to the new
method.
- kernel
-
The current POE kernel. You shouldn't need to access this much, but it's there if you need it.
- alias
-
The 'nickname' under which this object's own POE session will be known to the kernel. You should set this to something meaningful, and unique to the application.
- host
-
The Jabber server's hostname (or IP address).
- jid_host
-
The connection's concept of the hostname part of its Jabber ID. This is almost always identical to the value of the
host
key, but if there's some proxy-connection magic afoot, these may be different. - port
-
The Jabber server's TCP port.
- user
-
The username to use when connecting to the Jabber server.
- password
-
The password to use when connecting to the Jabber server.
- resource
-
The resource identifier to use when connecting to the Jabber server. (This is the part that gets stuck on the end of the JID, after the slash. So, setting this to "foo" will result in a JID like "bob@somejabberserver.com/foo")
- default_language
-
The two-letter language code that the object will attach to all outgoing Jabber stanzas to identify their default language. Defaults to
en
. (See "Localization" more more information about how this module handles different langauges.) - jid (read-only)
-
After connection, this will return the connection's JID.
- basic_jid (read-only)
-
Like
jid
, except it returns the non-resource part of the JID. (e.g.foo@bar.com
versusfoo@bar.com/bazzle
.)
CALLBACK METHODS
Element-handling methods
All these object methods are called with a single argument: the XML node that triggered them. See POE::Filter::XML::Node for more about this node object's API.
- jabber_presence
-
Called when a presence element is received.
- jabber_iq
-
Called when a an IQ element is received.
If you override this, you should call SUPER::jabber_iq within the method, since the base class already does a lot of work with incoming IQ elements, such as handling RPC requests and responses.
The following related methods handle specific applications of the <<iq>> element. As with
jabber_iq
, the single argument in every case is a POE::Filter::XML::Node object representing the triggering XMPP <<iq>> element. - handle_disco_items
- handle_disco_info
- handle_disco_items_request
- handle_disco_info_request
-
Define these methods in your subclass to let it respond to Jabber service discovery (JEP-0030) requests and responses. The first two methods handle other entities' response to requests that this one sent; the latter two handle entities seeking disco information on this object.
RPC handler methods
These methods are called by RPC events.
- handle_rpc_response({id=>$id, response=>$response, from=>$from, rpc_object=>$obj})
-
Called upon receipt of an RPC response. The argument is a hashref containing the response's ID attribute and response value, as well as an RPC::XML object representing the response.
- handle_rpc_request({id=>$id, method=>$method, args=>[@args], from=>$from, rpc_object=>$obj})
-
Called upon receipt of an RPC request. The argument is a hashref containing the request's ID attribute, method, argument list (as an arrayref), and originating JID, as well as an RPC::XML object representing the request.
- handle_rpc_fault({id=>$id, rpc_object=>$obj, from=>$from, fault_code=>$code, fault_string=>$string})
-
Called upon receipt of an RPC fault response.
- handle_rpc_transmission_error($iq_node, $error_code, $error_message);
-
Called upon receipt of a Jabber IQ packet that's of type
error
, but that seems to contain a Jabber-RPC element. This usually means that the RPC message failed to reach its destination for some reason. If this reason is known, it will show up as a code and (maybe) a text message in the callback's arguments.Note that this is distinct from an RPC fault, which is something returned from a network entity after successfully receiving an RPC request.
Message handler methods
All of the following methods are called with a single hashref as an argument, containing message information under the following keys: from
, to
, subject
, body
, thread
handle_normal_message
handle_groupchat_message
handle_chat_message
handle_headline_message
handle_error_message
JABBER ACTION METHODS
These methods will send messages and other data to the Jabber server.
send_rpc_request($args_hashref)
Send an RPC request. The single argument is a hashref with the following keys:
- to
-
The JID to which this request should be sent.
- id
-
The ID of this request. (The RPC result will have the same ID.)
- methodname
-
The name of the remote method to call.
- args
-
The method's arguments, as a list reference. If there's only one argument, and it's not itself an array reference, you can optionally pass it in by itself. If there are no arguments, you can pass
undef
or just skip this key.Each argument must be either a simple scalar, a hashref, or an arrayref. In the latter cases, the argument will turn into an RPC struct or array, respectively. All the datatyping magic is handled by the RPC::XML module (q.v.).
- handler
-
This is the response handler. It's executed when we get an answer back. If it isn't passed then the default handler is used (which does nothing unless overridden). It can either be a CODE ref or the name of a premade response handler. CODE refs are passed only the response. Premade response handler are not provided here but may be available in subclasses. The method name of the handler is in the form "rpc_response_$handler". So if $handler was "start_game" then the method containing the response handler would be "rpc_response_start_game". Premade response handlers are called as methods with the response as their argument.
send_rpc_response ($receiver_jid, $response_id, $response_value)
Send an RPC response. The value can be any scalar.
send_rpc_fault ($receiver_jid, $response_id, $fault_code, $fault_string)
Send an RPC fault.
send_message($args_hashref)
Send a Jabber message. The single argument is a hashref with the following keys:
- to
-
The JID to which this message is to be sent.
- type
-
The type of Jabber message this is. Should be one of:
chat
,groupchat
,normal
,headline
orerror
. (See the Jabber protocol for explanation on what these mean.) - thread
-
Optional A string identifying the thread that this message belongs to.
- subject
-
Optional The message's subject. Can be either a string, or a hashref of the sort described in "Localization".
- body
-
Optional The message's body. Can be either a string, or a hashref of the sort described in "Localization".
- invitation
-
Optional A hashref describing a Volity message-based invitation. Keys include
referee
,name
,player
,parlor
,ruleset
andtable
.
send_query($args_hashref)
Send a Jabber <<query>> element, wrapped in an <<iq>> packet. The single argument is a hashref describing the query to send, and can take the following keys:
- to
-
The JID that this query will be sent to.
- id
-
The ID attribute attached to the enfolding <<iq>> envelope.
- type
-
The sort of <<iq>> this will be, e.g.
set
orresult
. - query_ns
-
The XML namespace to attach to the query. It's usually important to set this to some value, since it lets the receiver know which Jabber application the query applies to. For instance, a MUC configuration form query would set this to "http://jabber.org/protocol/muc#owner", as per JEP-0045.
- content
-
An anonymous array containing POE::Filter::XML::Node objects (or objects made from a subclass thereof), to be added as children to the outgoing query.
join_muc($args_hashref)
Join a multi-user conference (MUC). The single argument is a hashref with the following keys:
- jid
-
The JID of the conference to join. You can specify the MUC either through this key, or the
room
andserver
keys. - nick
-
The nickname to use in the conference. If you don't specify this, the nick used will default to the object's username.
- server
-
The server on which this MUC is located.
- room
-
The name of the MUC.
The return value is the JID of the MUC that presence was sent to.
leave_muc ($muc_jid)
Leave the multi-user conference whose JID matches the provided argument.
send_presence ($info_hashref)
Send a presence packet. Its optional argument is a hashref containing any of the following keys:
- to
-
The destination of this presence packet (if it's a directed packet and not just a 'ping' to one's Jabber server).
- type
-
Sets the type attribute. See the XMPP-IM protocol for more information as to their use and legal values.
- show
- status
- priority
-
These all set sub-elements on the outgoing presence element. See the XMPP-IM protocol for more information as to their use. You may set these to localized values by setting their values to hashrefs instead of strings, as described in "Localization".
- caps
-
This optional key has a value of another hashref containing entity capabilities (JEP-0115) information. Its keys are
node
,ver
andext
. - namespace
-
If you define this optional key, then the presence packet will include an empty <<x/>> element with the given
xmlns
attribute value.
You can leave out the hashref entirely to send a blank <<presence/>> element.
request_roster
Requests the user's roster from its Jabber server. Takes no arguments.
This will result in a new roster object becoming available under the roster
accessor method. See "Volity::Jabber::Roster" for this object's API.
request_disco_info ($args_hashref)
Request service-discovery info from a JID/node combination. The server's answer will trigger your module's receive_disco_info
callback method (see "CALLBACK METHODS").
The argument hashref can contain the following keys:
- to
-
A JID that the request will be sent to.
- node
-
An optional string, specifying the node of the given JID.
- id
-
The ID of this request.
request_disco_items ($args_hashref)
Request service-discovery items from a JID/node combination. The server's answer will trigger your module's receive_disco_items
callback method (see "CALLBACK METHODS").
The argument hashref can contain the following keys:
- to
-
A JID that the request will be sent to.
- node
-
An optional string, specifying the node of the given JID.
- id
-
The ID of this request.
disconnect
Disconnects this entity from the Jabber server.
It sends out an 'unavailable' presence packet before doing so, just to be nice.
post_node($node)
Post the given XML node object to the POE kernel, which will then send it off to the Jabber server.
This is the method that is ultimately called by all the other action methods. You can use it too, if you find yourself knitting up raw nodes for some reason.
SUPPLEMENTARY PACKAGES
This module also include a handful of supplementary packages which define some helper objects. You'll usually use them in conjunction with the methods described above.
Volity::Jabber::Roster
Objects of this class represent a Jabber roster, and its creation is usually the result of a call to the request_roster
method of a Volity::Jabber
object. Roster objects have methods appropriate for storing and grouping Jabber IDs (JIDs), as follows:
- add_item ($item_hash)
-
Adds to the roster the JID described by the given hash reference. The hash must include a
jid
key, whose value is the JID to add to the roster. It can optionally contain aname
, whose value is a nickname to associate with this roster JID, and agroup
key, whose value is an anonymous list of all the roster group names that this JID should be filed under. - remove_item ($jid)
-
Removes the given JID from the roster.
- jids
-
Returns a list of all the JIDs on the roster.
- ungrouped_jids
-
Returns a list of all the JIDs which do not belong to any group.
- jids_in_group ($group)
-
Returns a list of all the JIDs which belong to the given group.
- jid_for_name ($name)
-
Returns the JID corresponding to the given nickname, if any.
- name_for_jid ($jid)
-
Returns the nickname associated with the given JID, if any.
- groups_for_jid ($jid)
-
Returns a list of the groups that the given JID belongs to, if any.
- has_jid ($jid)
-
Returns
1
if the given jid is on the roster, and 0 if it isn't. - presence ($jid, {type=>$presence_type)
-
Gets or sets a hash of information about the given JID's presence. Note that the roster object doesn't listen to presence and do this all by itself; this method has to be called from outside.
The JID in the required first argument may include a resource string. If so, the method will set and return presence information only for that one JID / resource combination.
At this time, only a single key,
type
, is supported in the optional second argument. If present, it sets the presence of the given JID (and resource, if provided) to that key's value, e.g. "unavailable".The return value is a list of anonymous hashes describing all known presence information about this JID. Each hash has two keys,
resource
andtype
.
Volity::Jabber::Disco::Item
This object represents a Jabber Service Discovery item. A subclass of POE::XML::Node, it may be inserted directly into disco responses you are building, just as <<item>> elements in disco responses you receive may be re-blessed into this class.
It contains the following simple accessor methods, whose ultimate function is described in JEP-0030:
- jid
- node
- name
Volity::Jabber::Disco::Identity
Just like Volity::Jabber::Disco::Item, except for disco <<identity>> elements.
It contains the following simple accessor methods:
- category
- type
- name
Volity::Jabber::Disco::Feature
Just like Volity::Jabber::Disco::Item, except for disco <<feature>> elements.
It contains the following simple accessor methods (er, method):
- var
Volity::Jabber::Form
Caution: incomplete implementation.
A class for Jabber data forms, as defined by JEP-0004. An object of this class is useful to stick under the content
key of of the send_query
argument (see "ACTION METHODS".
Simple accessors:
- type
- title
- instructions
Other accessors:
- fields
-
Returns, as a list of Volity::Jabber::Form::Field objects, the form's fields, with any values they may contain.
Optionally call with an array of Volity::Jabber::Form::Field objects to first set the form's fields.
- clear_fields
-
Erases all the form's fields.
Other methods:
- invalid_fields
-
Returns a list of Volity::Jabber::Form::Field objects set as
required
but which have no values set.
Volity::Jabber::Form::Field
Just like Volity::Jabber::Disco::Item, except for JEP-0004 form-field elements.
It contains the following simple accessor methods:
- label
- var
- type
- desc
- required
And the slightly less-simple accessors:
- values (@values)
-
If a list of arguments is provided, it becomes the values for this form field.
Returns a list of this field's current values.
- clear_values
-
Clears this field's list of values.
- options (@options)
-
If a list of arguments is provided, it becomes the options for this form field. Each argument should be an anonymous hash, with a
values
key set to an anonymous list of the values this option allows, and an optionallabel
key.Returns a list of this field's current options, using the anonymous hash format described above.
- clear_options
-
Clears the options from this form element.
Other methods:
- is_required ($is_required)
-
Set to a true value to define this field as
required
. Call with a false (but defined) value to set the field to not-required
(which is the initial state of all new objects of this class).Returns the current required-state of this object, expressed as 0 or 1.
- is_valid
-
Returns 0 if this field is set
required
and contains no values; 1 otherwise.
NOTES
This class was originally written with the Volity internet game system in mind, but it doesn't really have much Volity-specific code in it. It might end up leaving the Volity namespace, if it stays as such for a long time.
BUGS AND SUCH
JEP-0004 (data forms) is not yet fully implemented, especially where handling incoming forms is concerned.
The module is only patchily object-oriented. Some things that really ought to have object classes lack them, such as Jabber iq/message/presence packets. Future versions of this module. Backwards compatibility will be attempted but is not guaranteed. (Therefore, modules which subclass from Volity::Jabber should really be specific about which version they require.)
SEE ALSO
AUTHOR
Jason McIntosh <jmac@jmac.org>
COPYRIGHT
Copyright (c) 2003-2006 by Jason McIntosh.