ONLamp.com
oreilly.comSafari Books Online.Conferences.

advertisement


LAMP and the Spread Toolkit
Pages: 1, 2, 3

Programmatic Access

Now that you have the Spread daemon running, you can try to access it from code. The latest version of the Spread module for Python (1.5) is available from Zope, and older versions from the original Python Spread page. Download and extract the contents of the distribution (see Resources), then from the created directory, run:



python setup.py build
sudo python setup.py install

Test that the installation was successful by following the same steps as you did with spuser (join a group, send a message to the group):

Python 2.4.3 (#2, Apr 27 2006, 14:43:58) 
[GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import spread
>>> c = spread.connect('4804')
>>> c.join('test')
>>> c.receive()
<MembershipMsg object at 0xb7d342c0>
>>> c.multicast(spread.RELIABLE_MESS, 'test', 'test message from python')
24
>>> msg = c.receive()
>>> msg.message
'test message from python'
>>> c.disconnect()

Note that you may get an error message when importing the spread module:

Traceback (most recent call last):
  File "<stdin>", line 1, in ?
ImportError: libtspread.so: cannot open shared object file: No such file or directory

If so, try setting your LD_LIBRARY_PATH to the location of the Spread library files. For example:

export LD_LIBRARY_PATH=/usr/local/lib

PHP is a tad more challenging, given that I was completely unsuccessful in getting the PHP Spread extension package (available from PECL) to compile, build, run, or even look at me slightly askance. If you're a PHP extension expert, you'll probably immediately see the problem and have the package installed in a few moments. For others, unable to find 15 sacrificial PHP virgins to dance the Rites of Extension Installation with, I've included a reworked version of the module in the Resources section of this article. Given that the last time I had to touch C code in anger (and it was in anger, I recall) was slightly more than a decade ago, please either ignore the rather embarrassing attempt at a Makefile or just snicker quietly from behind a small pot-plant somewhere. In addition, I've only tested it with PHP 5, so I'm keen to hear if anyone has any success on earlier versions of PHP (and what changes it needs to work).

To build and install this extension, you need to know the directory of the Spread include and library files, the location of includes for PHP, and the directory in which PHP expects its extensions. In the case of my Kubuntu machine, the Makefile variables look like:

INSTALL_TO              = /usr/lib/PHP5/20051025

SPREAD_INCLUDE          = /usr/local/include
SPREAD_LIB              = /usr/local/lib
PHP_INCLUDE             = /usr/include/PHP5

Compile and install the extension by running:

make
sudo make install

PHP also needs to know about the shared object, so find the PHP.ini for your distribution (mine is in /etc/PHP5/apache2, or /etc/PHP5/cli if you want to add the extension for command-line execution of PHP scripts). Add the line extension=spread.so. (Look for other references to extension if you can't find the extension directory.) Assuming a successful build and install, you can now try an integration test--sending a message from PHP to Python. Restart Apache httpd and try a PHP page:

<html>
<body>
<?PHP
$id = spread_connect('4804', 'PHPtest');

if ($id != null) {
        spread_join($id, 'test');
        $msg = spread_receive($id, 120000);
        echo "<p>received message " . $msg['message'] . "</p>";
        spread_leave($id, 'test');
        spread_disconnect($id);
}
else {
        echo "<p>Failed to connect</p>";
}
?> 
</body>
</html>

While the browser hangs, waiting for a message, open another console, and try:

Python 2.4.3 (#2, Apr 27 2006, 14:43:58) 
>>> import spread
>>> c = spread.connect('4804', 'mytest', 0, 0)
>>> c.multicast(spread.RELIABLE_MESS, 'test', 'hello there from python')

With any luck, the browser should display your message.

Free of Restriction

It should hopefully be obvious from the previous examples that Spread is refreshingly free of any restrictions, which means you can choose your own strategies for its use. Joining a group and sending a message corresponds with the publish/subscribe cycle of messaging, and point-to-point is available using the private name of a connection. For example, in one Python console type:

Python 2.4.3 (#2, Apr 27 2006, 14:43:58) 
>>> import spread
>>> c = spread.connect('4804', 'testname1', 0, 0)
>>> print c.receive().message

In another console:

Python 2.4.3 (#2, Apr 27 2006, 14:43:58) 
>>> import spread
>>> c = spread.connect('4804', 'testname2', 0, 0)
>>> c.multicast(spread.RELIABLE_MESS, '#testname1#machine1', 'this is a point-to-point message')

Where "#testname1#machine1" is the unique private name given to the first connection.

Defining a Basic Protocol

Where something like JMS specifies the format of a transmitted message, with Spread you are free to choose your own protocol. Because HTTP is such a well-known protocol, it makes sense, to me at least, to use a similar format for messaging. Thus I've decided to include headers at the beginning of a message, with the body containing whatever content I need to transmit. The first steps, then, are to define the libraries for creating and consuming messages in this format. You can then use these libraries to send an uploaded file from a PHP app to a Python app, which, for the simple purposes of this article, will just document the receipt.

For my Python applications, I use a custom Message class, defined in spreadutils.py, that is capable of both creating and parsing messages sent via Spread (once again, see the Resources section for the source to this and other code mentioned in this article). My test code is:

import spread
from spreadutils import *
c = spread.connect('4804', 'mytest', 0, 0)
msg = Message({ 'header1' : 'val1', 'header2' : 'val2' }, \
    'this is a test message with headers')
c.multicast(spread.RELIABLE_MESS, '#mytest#machine1', str(msg))

smsg = c.receive()
recmsg = Message(parse_msg=smsg.message)
print 'sent == received == %s' % (recmsg == msg)

This script sends a message back to the same connection (point-to-point) using the Message class both to create and then consume--and then to check the equality of sent and received messages. The PHP version of the class is only capable of message creation, as I'm not convinced it makes sense to receive messages in my PHP applications (despite the fact that the Spread extension for PHP allows for this behavior). The concept of sending an asynchronous message only to hang while awaiting a response doesn't sit well in my personal view of the world. For the moment, you can test sending a message from a PHP page, and receipt to a Python app using two scripts.

For Python (test2.py):

import spread
from spreadutils import *

c = spread.connect('4804', 'mytest', 0, 0)
c.join('testgroup')
smsg = c.receive()
recmsg = Message(parse_msg = smsg.message)
print str(recmsg)

For PHP (spreadtest.php.txt):

<?PHP
require_once('spreadutils.php');

$id = spread_connect('4804', 'PHPtest');

if ($id != null) {
    $msg = new Message();
    $msg->set_header('test1', 'test2');
    $msg->set_header('test2', 'test3');
    $msg->set_content('this is a test PHP message');

    spread_multicast('testgroup', $msg->str());
    spread_disconnect($id);
}
else {
    echo "<p>Failed to connect</p>";
}
?>

Run the Python script first--python test2.py--and then run the PHP script--php spreadtest.php. (Don't forget to start the Spread daemon first, if it's not already running.) The output from the Python script should be something like:

test1: test2
test2: test3

this is a test PHP message

Pages: 1, 2, 3

Next Pagearrow





Sponsored by: