Today I've maked the second PHPurple release and changed it's status to alpha. The changes, came into it, are:
* fixed zts compatibility
* implemented the loopHeartBeat method
* the runLoop method was changed to set the heartbeat interval
* fixed memory leak on empty alias
* purple.debug_enabled is now boolean
The most interesting on this release is the PurpleClient::loopHeartBeat() story, which is of course implemented with g_timeout_add. Take a look at the new example script to see how it works.
PHP:
#!/usr/bin/env php
<?php
/**
* PHPurple test script
* @package phpurple
*/
/**
* Loading the extension
*/
if(!extension_loaded('purple')) {
dl('purple.' . PHP_SHLIB_SUFFIX);
}
/**
* @class CustomPurpleClient
* @author Anatoliy Belsky
*
* The method names are firmly and must be overloaded to work
* For php <= 5.3 the class name is firmly too
*/
class CustomPurpleClient extends PurpleClient
{
/**
* @access private
* @var array
*/
private $dictionary;
/**
* @access private
* @var boolean
*/
private $newYearMessageSent = false;
/**
* @access private
* @var boolean
*/
private $newYearAccountCreated = false;
/**
* Initalize internal class stuff
* Since we have protected final __construct, the initInternal() is called within the construct instead
* @access protected
* @return void
*/
protected function initInternal()
{
$this->dictionary = array( "/.*(hello|hi).*/i" => "hi there!",
"/\/date/i" => date("d.m.Y"),
"/\/version/i" => "0.2.0 alpha"
);
}
/**
* Analyse the message and try to get the answer
* @access private
* @param string $message
* @return string answer
*/
private function getAnswer($message)
{
foreach($this->dictionary as $match => $answer) {
if(preg_match($match, strtolower($message))) {
return $answer;
}
}
return "sorry, i don't understand you!";
}
/**
* @access protected
* @param object $conversation
* @param object|string $buddy object if the user exists in our blist
* @param string $message
* @param int $flags
* @param int $time
* @return void
*
*/
protected function writeIM($conversation, $buddy, $message, $flags, $time)
{
if(PurpleClient::MESSAGE_RECV == $flags) {
printf( "(%s) %s %s: %s\n",
$conversation->getName() ? $conversation->getName() : $buddy->getName(),
date("H:i:s", $time),
!$buddy || is_string($buddy) ? $buddy : $buddy->getAlias(),
$message
);
$conversation->sendIM($this->getAnswer($message));
}
}
/**
* This method is called when an account gets signed on
* @access protected
* @param object $conversation
* @return void
*/
protected function onSignedOn($connection)
{
$account = $connection->getAccount();
$buddy = "somenick";
$conversation = new PurpleConversation(PurpleClient::CONV_TYPE_IM, $account, $buddy);
$conversation->sendIM("hi there");
}
/**
* This method is called with the interval, given at the loop start
* @access protected
* @return void
*/
protected function loopHeartBeat()
{
/**
* Send the new year congratulation
*/
if(time() > mktime(00, 00, 00, 1, 1, 2008) && (!$this->newYearAccountCreated || !$this->newYearMessageSent)) {
/**
* Create an account
*/
static $account;
if(!$this->newYearAccountCreated) {
$account = new PurpleAccount("nickname@hotmail.com", "msn");
$account->setPassword("password");
$account->setEnabled(true);
$this->newYearAccountCreated = true;
}
/**
* Start the conversation if the account got connected
*/
if($account->isConnected()) {
$conversation = new PurpleConversation(PurpleClient::CONV_TYPE_IM, $account, "othernick@hotmail.com");
$conversation->sendIM("Happy New Year!!!");
$this->newYearMessageSent = true;
}
}
}
}
try {
/**
* Set the user dir
*/
$user_dir = "/tmp/phpurple-test";
if(!file_exists($user_dir) || !is_dir($user_dir)) {
mkdir($user_dir);
}
PurpleClient::setUserDir($user_dir);
/**
* Load the existing buddy list
*/
PurpleBuddyList::load();
/**
* Instantiate the client
*/
$client = CustomPurpleClient::getInstance();
/**
* Add new aim account
*/
$client->addAccount("aim://nickname:password");
/**
* Sign on
*/
$client->connectToSignal("signed-on");
/**
* Set the interval for the heartbeat to 5 seconds and start the loop
*/
$client->runLoop(5000);
} catch (Exception $e) {
echo "[Purple]: " . $e->getMessage() . "\n";
die();
}
As you can see, invoking the runLoop() with an integer parameter causes the loopHeartBeat() start with the interval in milliseconds as given. The mechanism built completely on the glib, because it's turned out, that the tick functions have a conflict with it.
Concerning the zts compatibility - for now it isn't neseccary to build with zts. The extension will only work correctly as cli (or may be cgi), but will bring unforseeable results within threaded servers. But if the ZTS API ever changes to become relevant for the cli builds too, the extension will be ready.
So, have more fun with the new version.