Many implementors tend to make socket-oriented APIs for networking protocols, as for example in perl's Net::IRC. This would be disastrous as it defeats the principle of letting the PSYC backend think about the routing. It's not your application's job to do that.

That's why we strongly encourage an API where the actual socket management is to be done by your PSYC backend handler. The API only knows about packets coming from somewhere going somewhere.

There are two design schools for a PSYC API - either you do heavy object orientation and have all aspects of a message as attributes of a message object. In that case the API probably looks something like message.send(). In case you have a more imperative approach to doing your API, it is probably a good idea to keep it compatible to the psyced one that follows.

Contents

PSYC API

The typical Application Programming Interface for PSYC libraries currently looks like this:

Protocol Elements

The Protocol is packet-oriented. Each packet has a method that we like to call mc as in method code or message code.

Looking at PSYC only from an object-oriented perspective doesn't take into full account the power of its syntax, so we prefer mc over method.

Also it comes with a message body we typically call data and a set of headers which we keep in a hash/mapping called vars, that's because in PSYC headers have state and can be modified, making them more like variables rather than headers.

In this API we tend to pass the _source and _target routing variables as extra parameters, which is a bit illogical since _context and even _source_relay might deserve that treatment, too. Other variants of this API leave all of them in vars, so you can think of source and target parameters simply not being there.

Receiving a Message

When receiving packets (see parser) from PSYC, the PSYC library figures out which _target is the intended recipient of a message (by looking at the logical target and using context slaves, but that's not so important here), then calls this method in your object class:

msg(source, mc, data, vars)

When writing a client, that entire part however may not be of relevance, as the only target is you, so your implementation may be skipping the targeting logic of PSYC.

When processing PSYC input, first you have to make sure you can trust the physical source of the packet. As a client your physical source will be your own identification most of the time, so you have all reasons to trust it. The physical source of the packet is defined as

psource = vars["_source"] || vars["_context"];

If you can't trust the physical source, then you shouldn't use the _source_relay in the following calculations, as it may be a lie. _source and _context cannot lie, routing-wise, but _source_relay is a forward operation that requires your trust.

When implementing a client, you typically need to sort the messages by context, as to make them appear in the right tabs, windows or screens. The popular approach to do that is to look at the logical context which is defined as

lcontext = vars["_context"] || vars["_source_relay"] || vars["_source"];

Leave out the _source_relay if you don't trust it.

So you have the logical context where to put the message, now look at the logical source to figure out who the original author of it is.

lsource = vars["_source_relay"] || vars["_source"] || vars["_context"];

Again, leave out the _source_relay if you can't trust it.

Just in case you didn't know: The double-pipe operator || mentioned here is C-syntax for or and essentially means, if the first isn't available, use the second. It works as used here in most computer languages.

Once you have figured out where to put the message, you probably need to figure out what the method you received is wanting you to do. Please read inheritance for a handbook on implementing method inheritance easily and correctly.

Sending a Message

sendmsg(target, mc, data, vars)

this generates a unicast message to the given _target. vars should only contain PSYC variables, not MMP variables, but should you need to put some in, the current sendmsg API sorts them out and puts them in the right places of the transmission, as it needs to do that anyhow (we don't permit PSYC vars with the same name as MMP vars).

Casting a Message

castmsg(source, mc, data, vars)

where source is actually the _source_relay since in our current multicast paradigm the sender is always the _context. castmsg only needs to be implemented by multicasting entities like UNIs that cast presence or public chatroom talk. a client would not implement this function, at least as long as we're not heading for multipeer multicast.

Comparing Variables and Methods

Since the principles of inheritance apply for Method Naming vars and mcs are typically compared with an abbrev() function rather than a comparison, like this:

if (abbrev("_notice_authentication", mc)) {
        ... feel authenticated ...
}

so in case a newer server sends you a _notice_authentication_submarine you will still be able to do the right thing that is to do, even though you don't know jack about submarines.

here's a javascript implementation of abbrev(). the function originally stems from rexx however.

function abbrev(short, long) {
        if (short == long) return true;
        if (short.length > long.length) return false;
        return short == long.substr( 0, short.length );
}

then again in javascript you could use something like long.startsWith(short) so you don't need an abbrev function. the method call notation has the advantage of being semantically obvious, you don't get confused which parameter comes first.

Another classic is trail() to compare if an mc ended with a certain keyword, like this:

unless (trail("_quiet", mc)) {
        ... be verbose ...
}

There is also the idea of a more generic psycmatch() function, but not in use as yet.

psyctext()

See psyctext.

Try & Slice

Don't forget about the Try & Slice paradigm!

Applications

psyced

A rough hitchhiker's guide to the psyced source code is given in http://www.psyced.org/DEVELOP

perlpsyc

Obviously perlpsyc comes with a similar API. Look at it on http://search.cpan.org/dist/Net-PSYC/PSYC.pm

PsycZilla

PsycZilla implements an API in JavaScript and a front-end application based on the Mozilla platform.

The PsycZilla framework is making progress on some API-related features that might be of interest for other PSYC implementations. One such feature is Modular Packet Handlers which allow callback functions to be registered in a manner similar to typical Javascript Event Handlers.

ppp

ppp uses an object oriented API, where all parameters are attributes of a PSYC packet class:

class Packet {
   mapping (string:mixed) vars;
   string mc;
   string data;
   ...
}

Lower layer APIs

http://secushare.org/pubsub describes a lower-level API for PSYC2's pubsub capabilities. The upper level API as described here-in does not exist for PSYC2 yet. We are working on it.

See also