sintonia/application/models/TransportRecord.php

420 lines
11 KiB
PHP

<?php
define('TR_LEAVE_CLOSED', TRUE);
/**
* Auxiliary class for transport records
*
* @package Airtime
* @subpackage StorageServer
* @copyright 2010 Sourcefabric O.P.S.
* @license http://www.gnu.org/licenses/gpl.txt
*/
class TransportRecord
{
/**
* @var DB
*/
//public $dbc;
/**
* @var GreenBox
*/
private $gb;
/**
* @var array
*/
//private $config;
/**
* @var Transport
*/
private $tr;
/**
* @var boolean
*/
private $recalled = FALSE;
/**
* @var boolean
*/
private $dropped = FALSE;
/**
* @param Transport $tr
* @return TransportRecord
*/
public function __construct(&$tr)
{
$this->tr =& $tr;
$this->gb =& $tr->gb;
}
/**
* Factory method
*
* @param Transport $tr
* @param string $trtype
* transport type (see Transport::install)
* @param string $direction
* 'up' | 'down'
* @param array $defaults
* default parameters (optional, internal use)
* @return TransportRecord
*/
function create(&$tr, $trtype, $direction='up', $defaults=array())
{
global $CC_DBC, $CC_CONFIG;
$trec = new TransportRecord($tr);
$trec->trtok = $trtok = $tr->_createTransportToken();
$trec->row = array_merge($defaults,
array('trtype'=>$trtype, 'direction'=>$direction));
$trec->recalled = TRUE;
if (!isset($defaults['title'])) {
$defaults['title'] = $trec->getTitle();
if (PEAR::isError($defaults['title'])) {
return $defaults['title'];
}
}
$id = $CC_DBC->nextId($CC_CONFIG['transSequence']);
$names = "id, trtok, direction, state, trtype, start, ts";
$values = "$id, '$trtok', '$direction', 'init', '$trtype', now(), now()";
foreach ($defaults as $k => $v) {
$sqlVal = $trec->_getSqlVal($k, $v);
$names .= ", $k";
$values .= ", $sqlVal";
}
$query = "
INSERT INTO ".$CC_CONFIG['transTable']."
($names)
VALUES
($values)
";
$res = $CC_DBC->query($query);
if (PEAR::isError($res)) {
return $res;
}
return $trec;
}
/**
* Recall transport record from DB
*
* @param Transport $tr
* @param string $trtok
* transport token
* @return TransportRecord
*/
function recall(&$tr, $trtok)
{
global $CC_DBC, $CC_CONFIG;
$trec = new TransportRecord($tr);
$trec->trtok = $trtok;
$row = $CC_DBC->getRow("
SELECT
id, trtok, state, trtype, direction,
to_hex(gunid)as gunid, to_hex(pdtoken)as pdtoken,
fname, localfile, url, rtrtok, mdtrtok, uid,
expectedsize, realsize, expectedsum, realsum,
errmsg, title, jobpid
FROM ".$CC_CONFIG['transTable']."
WHERE trtok='$trtok'
");
if (PEAR::isError($row)) {
return $row;
}
if (is_null($row)) {
return PEAR::raiseError("TransportRecord::recall:".
" invalid transport token ($trtok)", TRERR_TOK
);
}
$row['pdtoken'] = StoredFile::NormalizeGunid($row['pdtoken']);
$row['gunid'] = StoredFile::NormalizeGunid($row['gunid']);
$trec->row = $row;
$trec->recalled = TRUE;
return $trec;
}
/**
* Set state of transport record
*
* @param string $newState
* @param array $data
* other data fields to set
* @param string $oldState
* check old state and do nothing if differ
* @param boolean $lock
* check lock and do nothing if differ
* @return boolean success
*/
function setState($newState, $data=array(), $oldState=NULL, $lock=NULL)
{
global $CC_CONFIG, $CC_DBC;
$set = " state='$newState', ts=now()";
if (!is_null($lock)) {
$slock = ($lock ? 'Y' : 'N');
$nlock = (!$lock);
$snlock = ($nlock ? 'Y' : 'N');
$set .= ", lock='$snlock'";
}
foreach ($data as $k => $v) {
$set .= ", $k=".$this->_getSqlVal($k, $v);
}
$r = $CC_DBC->query("
UPDATE ".$CC_CONFIG['transTable']."
SET $set
WHERE trtok='{$this->trtok}'".
(is_null($oldState) ? '' : " AND state='$oldState'").
(is_null($lock) ? '' : " AND lock = '$slock'")
);
if (PEAR::isError($r)) {
return $r;
}
// return TRUE;
$affRows = $CC_DBC->affectedRows();
if (PEAR::isError($affRows)) {
return $affRows;
}
return ($affRows == 1);
}
/**
* Return state of transport record
*
* @return string
* state
*/
function getState()
{
if (!$this->recalled) {
return PEAR::raiseError("TransportRecord::getState:".
" not recalled ({$this->trtok})", TRERR_TOK
);
}
return $this->row['state'];
}
/**
* Set lock on transport record and save/clear process id
*
* @param boolean $lock
* lock if true, release lock if false
* @param int $pid
* process id
* @return mixed
* true or error
*/
function setLock($lock, $pid=NULL)
{
global $CC_CONFIG, $CC_DBC;
$pidsql = (is_null($pid) ? "NULL" : "$pid" );
if ($this->dropped) {
return TRUE;
}
$slock = ($lock ? 'Y' : 'N');
$nlock = (!$lock);
$snlock = ($nlock ? 'Y' : 'N');
$r = $CC_DBC->query("
UPDATE ".$CC_CONFIG['transTable']."
SET lock='$slock', jobpid=$pidsql, ts=now()
WHERE trtok='{$this->trtok}' AND lock = '$snlock'"
);
if (PEAR::isError($r)) {
return $r;
}
$affRows = $CC_DBC->affectedRows();
if (PEAR::isError($affRows)) {
return $affRows;
}
if ($affRows === 0) {
$ltxt = ($lock ? 'lock' : 'unlock' );
return PEAR::raiseError(
"TransportRecord::setLock: can't $ltxt ({$this->trtok})"
);
}
return TRUE;
}
/**
* Return type of transport
*
* @return string
* Transport type
*/
function getTransportType()
{
if (!$this->recalled) {
return PEAR::raiseError("TransportRecord::getTransportType:".
" not recalled ({$this->trtok})", TRERR_TOK
);
}
return $this->row['trtype'];
}
/**
* Kill transport job (on pause or cancel)
*
* @return string
* Transport type
*/
function killJob()
{
if (!$this->recalled) {
return PEAR::raiseError("TransportRecord::getTransportType:".
" not recalled ({$this->trtok})", TRERR_TOK
);
}
$jobpid = $this->row['jobpid'];
$res = system("pkill -P $jobpid", $status);
}
/**
* Set state to failed and set error message in transport record
*
* @param string $txt
* base part of error message
* @param PEAR_Error $eo
* (opt.) error msg can be construct from it
* @return mixed
* boolean true or error
*/
function fail($txt='', $eo=NULL)
{
if (!$this->recalled) {
return PEAR::raiseError("TransportRecord::fail:".
" not recalled ({$this->trtok})", TRERR_TOK
);
}
$msg = $txt;
if (!is_null($eo)) {
$msg .= $eo->getMessage()." ".$eo->getUserInfo().
" [".$eo->getCode()."]";
}
$r = $this->setState('failed', array('errmsg'=>$msg));
if (PEAR::isError($r)) {
return $r;
}
return TRUE;
}
/**
* Close transport record
*
* @return mixed
* boolean true or error
*/
function close()
{
global $CC_CONFIG, $CC_DBC;
if (!$this->recalled) {
return PEAR::raiseError("TransportRecord::close:".
" not recalled ({$this->trtok})", TRERR_TOK
);
}
if (TR_LEAVE_CLOSED) {
$r = $this->setState('closed');
if (PEAR::isError($r)) {
return $r;
}
} else {
$r = $CC_DBC->query("
DELETE FROM ".$CC_CONFIG['transTable']."
WHERE trtok='{$this->trtok}'
");
if (PEAR::isError($r)) {
return $r;
}
$this->recalled = FALSE;
$this->dropped = TRUE;
}
return TRUE;
}
/**
* Add field specific envelopes to values (e.g. ' around strings)
*
* @param string $fldName
* field name
* @param mixed $fldVal
* field value
* @return string
*/
function _getSqlVal($fldName, $fldVal)
{
switch ($fldName) {
case 'realsize':
case 'expectedsize':
case 'uid':
return ("$fldVal"!='' ? "$fldVal" : "NULL");
break;
case 'gunid':
case 'pdtoken':
return "x'$fldVal'::bigint";
break;
default:
$fldVal = pg_escape_string($fldVal);
return "'$fldVal'";
break;
}
}
/**
* Get title from transported object's metadata (if exists)
*
* @return string
* the title or descriptive string
*/
function getTitle()
{
$defStr = 'unknown';
$trtype = $this->getTransportType(); //contains recall check
if (PEAR::isError($trtype)) {
return $trtype;
}
switch ($trtype) {
case "audioclip":
case "playlist":
case "playlistPkg":
case "metadata":
$title = $this->gb->bsGetTitle(NULL, $this->row['gunid']);
if (is_null($title)) {
$title = $defStr;
}
if (PEAR::isError($title)) {
if ($title->getCode() == GBERR_FOBJNEX) {
$title = $defStr;
} else {
return $title;
}
}
break;
case "searchjob":
$title = 'searchjob';
break;
case "file":
$title = ( isset($this->row['localfile']) ?
basename($this->row['localfile']) : 'regular file');
break;
default:
$title = $defStr;
}
return $title;
}
} // class TransportRecord
?>