Added PHP library for Yate and example program using it.
Added several example shell scripts. git-svn-id: http://yate.null.ro/svn/yate/trunk@17 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
010b82e80a
commit
dabd6ab27d
|
@ -0,0 +1,304 @@
|
|||
<?
|
||||
|
||||
/* libyate.php
|
||||
* This file is part of the YATE Project http://YATE.null.ro
|
||||
*
|
||||
* PHP object-oriented interface library for Yate
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Yate class encapsulates the object oriented interface of PHP to Yate
|
||||
*/
|
||||
class Yate
|
||||
{
|
||||
/** String: Type of the event */
|
||||
var $type;
|
||||
/** String: Name of the message */
|
||||
var $name;
|
||||
/** String: Return value of the message */
|
||||
var $retval;
|
||||
/** Number: Time the message was generated */
|
||||
var $origin;
|
||||
/** String: Temporarily unique message ID */
|
||||
var $id;
|
||||
/** Boolean: Was the message handled or not */
|
||||
var $handled;
|
||||
/** Array: Message parameters, $obj->params["name"]="value" */
|
||||
var $params;
|
||||
|
||||
/**
|
||||
* This static function initializes globals in the PHP Yate External Module.
|
||||
* It should be called before any other method.
|
||||
*/
|
||||
function Init()
|
||||
{
|
||||
global $yate_stdin, $yate_stdout, $yate_stderr;
|
||||
$yate_stdin = fopen("php://stdin","r");
|
||||
$yate_stdout = fopen("php://stdout","w");
|
||||
$yate_stderr = fopen("php://stderr","w");
|
||||
flush();
|
||||
set_error_handler("Yate::ErrorHandler");
|
||||
ob_implicit_flush(1);
|
||||
if (function_exists("stream_set_blocking"))
|
||||
stream_set_blocking($yate_stdin,false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to output a string to Yate's stderr or logfile
|
||||
* @param $str String to output
|
||||
*/
|
||||
function Output($str)
|
||||
{
|
||||
global $yate_stderr;
|
||||
fputs($yate_stderr, $str . "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Static replacement error handler that outputs plain text to stderr
|
||||
* @param $errno Error code
|
||||
* @param $errstr Error text
|
||||
* @param $errfile Name of file that triggered the error
|
||||
* @param $errline Line number where the error occured
|
||||
*/
|
||||
function ErrorHandler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
$str = " [$errno] $errstr in $errfile line $errline\n";
|
||||
switch ($errno) {
|
||||
case E_USER_ERROR:
|
||||
Yate::Output("PHP fatal:" . $str);
|
||||
exit(1);
|
||||
break;
|
||||
case E_WARNING:
|
||||
case E_USER_WARNING:
|
||||
Yate::Output("PHP error:" . $str);
|
||||
break;
|
||||
case E_NOTICE:
|
||||
case E_USER_NOTICE:
|
||||
Yate::Output("PHP warning:" . $str);
|
||||
break;
|
||||
default:
|
||||
Yate::Output("PHP unknown error:" . $str);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to convert a Yate string representation to a boolean
|
||||
* @param $str String value to convert
|
||||
* @return True if $str is "true", false otherwise
|
||||
*/
|
||||
function Str2bool($str)
|
||||
{
|
||||
return ($str == "true") ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to convert a boolean to a Yate string representation
|
||||
* @param $bool Boolean value to convert
|
||||
* @return The string "true" if $bool was true, "false" otherwise
|
||||
*/
|
||||
function Bool2str($bool)
|
||||
{
|
||||
return $bool ? "true" : "false";
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to convert a string to its Yate escaped format
|
||||
* @param $str String to escape
|
||||
* @param $extra (optional) Character to escape in addition to required ones
|
||||
* @return Yate escaped string
|
||||
*/
|
||||
function Escape($str, $extra = "")
|
||||
{
|
||||
$s = "";
|
||||
$n = strlen($str);
|
||||
for ($i=0; $i<$n; $i++) {
|
||||
$c = $str{$i};
|
||||
if ((ord($c) < 32) || ($c == $extra)) {
|
||||
$c = chr(ord($c) + 64);
|
||||
$s .= '%';
|
||||
}
|
||||
else if ($c == '%')
|
||||
$s .= $c;
|
||||
$s .= $c;
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function to convert a Yate escaped string back to a plain string
|
||||
* @param $str Yate escaped string to unescape
|
||||
* @return Unescaped string
|
||||
*/
|
||||
function Unescape($str)
|
||||
{
|
||||
$s = "";
|
||||
$n = strlen($str);
|
||||
for ($i=0; $i<$n; $i++) {
|
||||
$c = $str{$i};
|
||||
if ($c == '%') {
|
||||
$i++;
|
||||
$c = $str{$i};
|
||||
if ($c != '%')
|
||||
$c = chr(ord($c) - 64);
|
||||
}
|
||||
$s .= $c;
|
||||
}
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a Yate message handler
|
||||
* @param $name Name of the messages to handle
|
||||
* @param $priority (optional) Priority to insert in chain, default 100
|
||||
*/
|
||||
function Install($name, $priority = 100)
|
||||
{
|
||||
$name=Yate::Escape($name);
|
||||
print "%%>install:$priority:$name\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall a Yate message handler
|
||||
* @param $name Name of the messages to stop handling
|
||||
*/
|
||||
function Uninstall($name)
|
||||
{
|
||||
$name=Yate::Escape($name);
|
||||
print "%%>uninstall:$name\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Creates a new outgoing message
|
||||
* @param $name Name of the new message
|
||||
* @param $retval (optional) Default return
|
||||
* @param $id (optional) Identifier of the new message
|
||||
*/
|
||||
function Yate($name, $retval = "", $id = "")
|
||||
{
|
||||
if ($id == "")
|
||||
$id=uniqid(rand(),1);
|
||||
$this->type="outgoing";
|
||||
$this->name=$name;
|
||||
$this->retval=$retval;
|
||||
$this->origin=time();
|
||||
$this->handled=false;
|
||||
$this->id=$id;
|
||||
$this->params=array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the parameter array from a text representation
|
||||
* @param $parts A numerically indexed array with the key=value parameters
|
||||
* @param $offs (optional) Offset in array to start processing from
|
||||
*/
|
||||
function FillParams(&$parts, $offs = 0)
|
||||
{
|
||||
$n = count($parts);
|
||||
for ($i=$offs; $i<$n; $i++) {
|
||||
$s=explode('=',$parts[$i]);
|
||||
$this->params[Yate::Unescape($s[0])]=Yate::Unescape($s[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the message to Yate for handling
|
||||
* @param $message Message object to dispatch
|
||||
*/
|
||||
function Dispatch()
|
||||
{
|
||||
if ($this->type != "outgoing") {
|
||||
Yate::Output("PHP bug: attempt to dispatch message type: " . $this->type);
|
||||
return;
|
||||
}
|
||||
$i=Yate::Escape($this->id,':');
|
||||
$t=0+$this->origin;
|
||||
$n=Yate::Escape($this->name,':');
|
||||
$r=Yate::Escape($this->retval,':');
|
||||
$p="";
|
||||
array_walk(&$this->params, "_yate_message_walk", &$p);
|
||||
print "%%>message:$i:$t:$n:$r$p\n";
|
||||
$this->type="dispatched";
|
||||
}
|
||||
|
||||
/**
|
||||
* Acknowledge the processing of a message passed from Yate
|
||||
* @param $handled (optional) True if Yate should stop processing, default false
|
||||
*/
|
||||
function Acknowledge()
|
||||
{
|
||||
if ($this->type != "incoming") {
|
||||
Yate::Output("PHP bug: attempt to acknowledge message type: " . $this->type);
|
||||
return;
|
||||
}
|
||||
$i=Yate::Escape($this->id,':');
|
||||
$k=Yate::Bool2str($this->handled);
|
||||
$n=Yate::Escape($this->name,':');
|
||||
$r=Yate::Escape($this->retval,':');
|
||||
$p="";
|
||||
array_walk(&$this->params, "_yate_message_walk", &$p);
|
||||
print "%%<message:$i:$k:$n:$r$p\n";
|
||||
$this->type="acknowledged";
|
||||
}
|
||||
|
||||
/**
|
||||
* This static function processes just one input line.
|
||||
* It must be called in a loop to keep messages running. Or else.
|
||||
* @return "EOF" if we should exit, "" if we should keep running,
|
||||
* or an Yate object instance
|
||||
*/
|
||||
function GetEvent()
|
||||
{
|
||||
global $yate_stdin;
|
||||
if (feof($yate_stdin))
|
||||
return "EOF";
|
||||
$line=fgets($yate_stdin,4096);
|
||||
if ($line == false)
|
||||
return "";
|
||||
$line=str_replace("\n", "", $line);
|
||||
if ($line == "")
|
||||
return "";
|
||||
$ev="";
|
||||
$part=explode(":", $line);
|
||||
switch ($part[0]) {
|
||||
case "%%>message":
|
||||
/* incoming message str_id:int_time:str_name:str_retval[:key=value...] */
|
||||
$ev=new Yate(Yate::Unescape($part[3]),Yate::Unescape($part[4]),Yate::Unescape($part[1]));
|
||||
$ev->type="incoming";
|
||||
$ev->origin=0+$part[2];
|
||||
$ev->FillParams(&$part,5);
|
||||
break;
|
||||
case "%%<message":
|
||||
/* message answer str_id:bool_handled:str_name:str_retval[:key=value...] */
|
||||
$ev=new Yate(Yate::Unescape($part[3]),Yate::Unescape($part[4]),Yate::Unescape($part[1]));
|
||||
$ev->type="answer";
|
||||
$ev->handled=Yate::Str2bool($part[2]);
|
||||
$ev->FillParams(&$part,5);
|
||||
break;
|
||||
case "%%<install":
|
||||
/* install answer num_priority:str_name:bool_success */
|
||||
$ev=new Yate(Yate::Unescape($part[2]),"",0+$part[1]);
|
||||
$ev->type="installed";
|
||||
$ev->handled=Yate::Str2bool($part[3]);
|
||||
break;
|
||||
case "%%<uninstall":
|
||||
/* uninstall answer num_priority:str_name:bool_success */
|
||||
$ev=new Yate(Yate::Unescape($part[2]),"",0+$part[1]);
|
||||
$ev->type="uninstalled";
|
||||
$ev->handled=Yate::Str2bool($part[3]);
|
||||
break;
|
||||
default:
|
||||
Yate::Output("PHP parse error: " . $line);
|
||||
}
|
||||
return $ev;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Internal function */
|
||||
function _yate_message_walk($item, $key, &$result)
|
||||
{
|
||||
$result .= ':' . Yate::Escape($key,':') . '=' . Yate::Escape($item,':');
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
?>
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Bourne shell test script for the Yate external module interface
|
||||
# Generates 2 seconds of white noise
|
||||
# To test add a route to: external/play/noise.sh
|
||||
|
||||
echo "=================== noise ===================" >&2
|
||||
dd if=/dev/urandom bs=320 count=100 >&4
|
||||
echo "================= noise done ================" >&2
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Bourne shell test script for the Yate external module interface
|
||||
# Plays sound using the "play" program (from the sox package)
|
||||
# To test add a route to: external/record/play.sh
|
||||
|
||||
echo "=================== play ====================" >&2
|
||||
play -t raw -c 1 -f s -r 8000 -s w - <&3
|
||||
echo "================= play done =================" >&2
|
|
@ -0,0 +1,60 @@
|
|||
#!/usr/bin/php -q
|
||||
<?
|
||||
/* Test script for the Yate PHP interface
|
||||
To test add in extmodule.conf
|
||||
|
||||
[scripts]
|
||||
test.php=
|
||||
*/
|
||||
require_once("libyate.php");
|
||||
|
||||
/* Always the first action to do */
|
||||
Yate::Init();
|
||||
|
||||
/* Install a handler for the engine generated timer message */
|
||||
Yate::Install("engine.timer",10);
|
||||
|
||||
/* Create and dispatch an initial test message */
|
||||
$m=new Yate("test");
|
||||
$m->params["param1"]="val1";
|
||||
$m->retval="ret_value";
|
||||
$m->Dispatch();
|
||||
|
||||
/* The main loop. We pick events and handle them */
|
||||
for (;;) {
|
||||
$ev=Yate::GetEvent();
|
||||
/* If Yate disconnected us then exit cleanly */
|
||||
if ($ev == "EOF")
|
||||
break;
|
||||
/* Empty events are normal in non-blocking operation.
|
||||
This is an opportunity to do idle tasks and check timers */
|
||||
if ($ev == "") {
|
||||
Yate::Output("PHP event: empty");
|
||||
continue;
|
||||
}
|
||||
/* If we reached here we should have a valid object */
|
||||
switch ($ev->type) {
|
||||
case "incoming":
|
||||
Yate::Output("PHP Message: " . $ev->name . " id: " . $ev->id);
|
||||
/* This is extremely important.
|
||||
We MUST let messages return, handled or not */
|
||||
$ev->Acknowledge();
|
||||
break;
|
||||
case "answer":
|
||||
Yate::Output("PHP Answered: " . $ev->name . " id: " . $ev->id);
|
||||
break;
|
||||
case "installed":
|
||||
Yate::Output("PHP Installed: " . $ev->name);
|
||||
break;
|
||||
case "uninstalled":
|
||||
Yate::Output("PHP Uninstalled: " . $ev->name);
|
||||
break;
|
||||
default:
|
||||
Yate::Output("PHP Event: " . $ev->type);
|
||||
}
|
||||
}
|
||||
|
||||
Yate::Output("PHP: bye!");
|
||||
|
||||
/* vi: set ts=8 sw=4 sts=4 noet: */
|
||||
?>
|
|
@ -0,0 +1,54 @@
|
|||
#!/bin/sh
|
||||
|
||||
# Bourne shell test script for the Yate external module
|
||||
# To test add in extmodule.conf
|
||||
#
|
||||
# [scripts]
|
||||
# test.sh=test param
|
||||
|
||||
gen_message()
|
||||
{
|
||||
t=`date +%s`
|
||||
echo "%%>message:$$-$RANDOM:$t:$*"
|
||||
}
|
||||
|
||||
if [ "$1" = "--generator" ]; then
|
||||
exec </dev/null
|
||||
echo "================ generator ==================" >&2
|
||||
echo "%%>install:10:engine.timer"
|
||||
# echo "%%>install:10:testmsg"
|
||||
for ((i=1; i<10; i++)); do
|
||||
sleep 1
|
||||
gen_message "testmsg:retval:val=$i:random=$RANDOM"
|
||||
done
|
||||
echo "%%>uninstall:engine.timer"
|
||||
echo "============== generator done ===============" >&2
|
||||
exit
|
||||
fi
|
||||
|
||||
echo "=============================================" >&2
|
||||
echo "\$0=$0 \$*=$*" >&2
|
||||
echo "=============================================" >&2
|
||||
|
||||
$0 --generator &
|
||||
|
||||
echo "================= reporter ==================" >&2
|
||||
while read; do
|
||||
echo "Reporter: $REPLY" >&2
|
||||
case "$REPLY" in
|
||||
%%\>message:*)
|
||||
echo "Reporter: seen incoming message" >&2
|
||||
echo "$REPLY" | sed 's/^[^:]*:\([^:]*\):.*$/%%<message:\1:false:/;'
|
||||
;;
|
||||
%%\<message:*)
|
||||
echo "Reporter: seen message answer" >&2
|
||||
;;
|
||||
%%\<install:*)
|
||||
echo "Reporter: seen install answer" >&2
|
||||
;;
|
||||
%%\<uninstall:*)
|
||||
echo "Reporter: seen uninstall answer" >&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
echo "============== reporter done ================" >&2
|
Loading…
Reference in New Issue