diff --git a/livesupport/modules/storageServer/var/BasicStor.php b/livesupport/modules/storageServer/var/BasicStor.php
index 3fa06ac60..275de9844 100644
--- a/livesupport/modules/storageServer/var/BasicStor.php
+++ b/livesupport/modules/storageServer/var/BasicStor.php
@@ -23,7 +23,7 @@
Author : $Author: tomas $
- Version : $Revision: 1.20 $
+ Version : $Revision: 1.21 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/BasicStor.php,v $
------------------------------------------------------------------------------*/
@@ -37,12 +37,14 @@ define('GBERR_AOBJNEX', 46);
define('GBERR_NOTF', 47);
define('GBERR_SESS', 48);
define('GBERR_PREF', 49);
+define('GBERR_TOKEN', 50);
+define('GBERR_PUT', 51);
-define('GBERR_NOTIMPL', 50);
+define('GBERR_NOTIMPL', 69);
require_once "../../../alib/var/alib.php";
require_once "StoredFile.php";
-#require_once "Transport.php";
+require_once "Transport.php";
/**
* BasicStor class
@@ -50,7 +52,7 @@ require_once "StoredFile.php";
* Core of LiveSupport file storage module
*
* @author $Author: tomas $
- * @version $Revision: 1.20 $
+ * @version $Revision: 1.21 $
* @see Alib
*/
class BasicStor extends Alib{
@@ -111,16 +113,17 @@ class BasicStor extends Alib{
* @param mdataFileLP string, local path of metadata file
* @param gunid string, global unique id OPTIONAL
* @param ftype string, internal file type
+ * @param mdataLoc string 'file'|'string' (optional)
* @return int
* @exception PEAR::error
*/
- function bsPutFile($parid, $fileName,
- $mediaFileLP, $mdataFileLP, $gunid=NULL, $ftype='unKnown')
+ function bsPutFile($parid, $fileName, $mediaFileLP, $mdataFileLP,
+ $gunid=NULL, $ftype='unKnown', $mdataLoc='file')
{
$name = "$fileName";
$id = $this->addObj($name , 'File', $parid);
$ac =& StoredFile::insert(
- &$this, $id, $name, $mediaFileLP, $mdataFileLP, 'file',
+ &$this, $id, $name, $mediaFileLP, $mdataFileLP, $mdataLoc,
$gunid, $ftype
);
if(PEAR::isError($ac)){
@@ -236,11 +239,12 @@ class BasicStor extends Alib{
* Delete file
*
* @param id int, virt.file's local id
+ * @param forced boolean, unconditional delete
* @return true or PEAR::error
*/
- function bsDeleteFile($id)
+ function bsDeleteFile($id, $forced=FALSE)
{
- $res = $this->removeObj($id);
+ $res = $this->removeObj($id, $forced);
return $res;
}
@@ -353,7 +357,8 @@ class BasicStor extends Alib{
*
* @param id int, virt.file's local id
* @param part string, 'media'|'metadata'
- * @return array with: downloadable URL, download token
+ * @return array with strings:
+ * downloadable URL, download token, chsum, size, filename
*/
function bsOpenDownload($id, $part='media')
{
@@ -361,18 +366,31 @@ class BasicStor extends Alib{
if(PEAR::isError($ac)) return $ac;
$gunid = $ac->gunid;
switch($part){
- case"media":
- $fname = $ac->_getRealRADFname();
- $ext = $ac->_getExt();
- break;
- case"metadata":
- $fname = $ac->_getRealMDFname();
- $ext = "xml";
- break;
+ case"media":
+ $realfile = $ac->_getRealRADFname();
+ $ext = $ac->_getExt();
+ $filename = $ac->_getFileName();
+ break;
+ case"metadata":
+ $realfile = $ac->_getRealMDFname();
+ $ext = "xml";
+ $filename = $ac->_getFileName();
+ break;
+ default:
+ return PEAR::raiseError(
+ "BasicStor::bsOpenDownload: unknown part ($part)"
+ );
}
- $acc = $this->bsAccess($fname, $ext, $gunid, 'download');
+ $acc = $this->bsAccess($realfile, $ext, $gunid, 'download');
+ if(PEAR::isError($acc)){ return $acc; }
$url = $this->getUrlPart()."access/".basename($acc['fname']);
- return array('url'=>$url, 'token'=>$acc['token']);
+ $chsum = md5_file($realfile);
+ $size = filesize($realfile);
+ return array(
+ 'url'=>$url, 'token'=>$acc['token'],
+ 'chsum'=>$chsum, 'size'=>$size,
+ 'filename'=>$filename
+ );
}
/**
@@ -403,6 +421,10 @@ class BasicStor extends Alib{
{
$ext = '';
$token = StoredFile::_createGunid();
+ $res = $this->dbc->query("
+ DELETE FROM {$this->accessTable} WHERE token=x'$token'::bigint
+ ");
+ if(PEAR::isError($res)){ return $res; }
$res = $this->dbc->query("
INSERT INTO {$this->accessTable}
(gunid, token, ext, chsum, type, ts)
@@ -426,9 +448,11 @@ class BasicStor extends Alib{
*/
function bsClosePut($token)
{
+ $token = StoredFile::_normalizeGunid($token);
if(!$this->bsCheckToken($token, 'put')){
return PEAR::raiseError(
- "BasicStor::bsClosePut: invalid token ($token)"
+ "BasicStor::bsClosePut: invalid token ($token)",
+ GBERR_TOKEN
);
}
$chsum = $this->dbc->getOne("
@@ -444,12 +468,47 @@ class BasicStor extends Alib{
if($chsum != $md5sum){
if(file_exists($fname)) @unlink($fname);
return PEAR::raiseError(
- "BasicStor::bsClosePut: md5sum does not match (token=$token)"
+ "BasicStor::bsClosePut: md5sum does not match (token=$token)",
+ GBERR_PUT
);
}
return $fname;
}
+ /**
+ * Check uploaded file
+ *
+ * @param token string, put token
+ * @return hash, (
+ * status: boolean,
+ * size: int - filesize
+ * expectedsum: string - expected checksum
+ * realsum: string - checksum of uploaded file
+ * )
+ */
+ function bsCheckPut($token)
+ {
+ if(!$this->bsCheckToken($token, 'put')){
+ return PEAR::raiseError(
+ "BasicStor::bsClosePut: invalid token ($token)"
+ );
+ }
+ $chsum = $this->dbc->getOne("
+ SELECT chsum FROM {$this->accessTable}
+ WHERE token=x'{$token}'::bigint
+ ");
+ if(PEAR::isError($chsum)){ return $chsum; }
+ $fname = "{$this->accessDir}/$token";
+ $md5sum = md5_file($fname);
+ $size = filesize($fname);
+ $status = ($chsum == $md5sum);
+ return array(
+ 'status'=>$status, 'size'=>$size,
+ 'expectedsum'=>$chsum,
+ 'realsum'=>$md5sum,
+ );
+ }
+
/**
* Return starting part of storageServer URL
*
@@ -644,7 +703,7 @@ class BasicStor extends Alib{
if($v['type'] == 'File'){
$gunid = $this->_gunidFromId($v['id']);
$listArr[$i]['type'] =
- StoredFile::_getType($gunid);
+ $this->_getType($gunid);
$listArr[$i]['gunid'] = $gunid;
if(StoredFIle::_getState($gunid) == 'incomplete')
unset($listArr[$i]);
@@ -725,12 +784,47 @@ class BasicStor extends Alib{
$type = $this->getObjName($oid, 'type');
if($type == 'File'){
$ftype =
- StoredFile::_getType($this->_gunidFromId($oid));
+ $this->_getType($this->_gunidFromId($oid));
if(!is_null($ftype)) $type=$ftype;
}
return $type;
}
+ /**
+ * Add new user with home folder
+ *
+ * @param login string
+ * @param pass string OPT
+ * @return int/err
+ */
+ function addSubj($login, $pass=NULL)
+ {
+ $uid = parent::addSubj($login, $pass);
+ if(PEAR::isError($uid)) return $uid;
+ $fid = $this->bsCreateFolder($this->storId, $login);
+ if(PEAR::isError($fid)) return $fid;
+ $res = $this->addPerm($uid, '_all', $fid, 'A');
+ if(PEAR::isError($res)) return $res;
+ return $uid;
+ }
+ /**
+ * Remove user and his home folder
+ *
+ * @param login string
+ * @param uid int OPT
+ * @return boolean/err
+ */
+ function removeSubj($login, $uid=NULL)
+ {
+ $res = parent::removeSubj($login, $pass);
+ if(PEAR::isError($res)) return $res;
+ $id = $this->getObjId($login, $this->storId);
+ if(PEAR::isError($id)) return $id;
+ $res = $this->bsDeleteFile($id);
+ if(PEAR::isError($res)) return $res;
+ return TRUE;
+ }
+
/* ==================================================== "private" methods */
/**
* Check authorization - auxiliary method
@@ -767,6 +861,10 @@ class BasicStor extends Alib{
$parid = $this->getObjId(
$this->getSessLogin($sessid), $this->storId
);
+ if(is_null($parid)){
+ return PEAR::raiseError("BasicStor::_getHomeDirId: ".
+ "homedir not found", GBERR_NOTF);
+ }
return $parid;
}
@@ -801,6 +899,21 @@ class BasicStor extends Alib{
return StoredFile::_normalizeGunid($gunid);
}
+ /**
+ * Get storage-internal file type
+ *
+ * @param gunid string, global unique id of file
+ * @return string, see install()
+ */
+ function _getType($gunid)
+ {
+ $ftype = $this->dbc->getOne("
+ SELECT ftype FROM {$this->filesTable}
+ WHERE gunid=x'$gunid'::bigint
+ ");
+ return $ftype;
+ }
+
/* ------------------------------------------ redefined "private" methods */
/**
* Copy virtual file.
@@ -845,21 +958,22 @@ class BasicStor extends Alib{
* Redefined from parent class.
*
* @param id int, local id of removed object
+ * @param forced boolean, unconditional delete
* @return true or PEAR::error
*/
- function removeObj($id)
+ function removeObj($id, $forced=FALSE)
{
switch($ot = $this->getObjType($id)){
case"audioclip":
case"playlist":
$ac =& StoredFile::recall(&$this, $id);
if(PEAR::isError($ac)) return $ac;
- if($ac->isEdited()){
+ if($ac->isEdited() && !$forced){
return PEAR::raiseError(
'BasicStor.php: removeObj: is edited'
);
}
- if($ac->isAccessed()){
+ if($ac->isAccessed() && !$forced){
return PEAR::raiseError(
'BasicStor.php: removeObj: is accessed'
);
@@ -923,7 +1037,7 @@ class BasicStor extends Alib{
// $this->dbc->query("DELETE FROM {$this->filesTable}");
$ids = $this->dbc->getAll("SELECT id FROM {$this->filesTable}");
if(is_array($ids)) foreach($ids as $i=>$item){
- $this->bsDeleteFile($item['id']);
+ $this->bsDeleteFile($item['id'], TRUE);
}
parent::deleteData();
$this->initData();
diff --git a/livesupport/modules/storageServer/var/GreenBox.php b/livesupport/modules/storageServer/var/GreenBox.php
index 93391bd19..6ebcb1ae6 100644
--- a/livesupport/modules/storageServer/var/GreenBox.php
+++ b/livesupport/modules/storageServer/var/GreenBox.php
@@ -23,7 +23,7 @@
Author : $Author: tomas $
- Version : $Revision: 1.23 $
+ Version : $Revision: 1.24 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/GreenBox.php,v $
------------------------------------------------------------------------------*/
@@ -35,7 +35,7 @@ require_once "BasicStor.php";
* LiveSupport file storage module
*
* @author $Author: tomas $
- * @version $Revision: 1.23 $
+ * @version $Revision: 1.24 $
* @see BasicStor
*/
class GreenBox extends BasicStor{
@@ -278,41 +278,6 @@ class GreenBox extends BasicStor{
/* ---------------------------------------------------- redefined methods */
- /**
- * Add new user with home folder
- *
- * @param login string
- * @param pass string OPT
- * @return int/err
- */
- function addSubj($login, $pass=NULL)
- {
- $uid = parent::addSubj($login, $pass);
- if(PEAR::isError($uid)) return $uid;
- $fid = $this->bsCreateFolder($this->storId, $login);
- if(PEAR::isError($fid)) return $fid;
- $res = $this->addPerm($uid, '_all', $fid, 'A');
- if(PEAR::isError($res)) return $res;
- return $uid;
- }
- /**
- * Remove user and his home folder
- *
- * @param login string
- * @param uid int OPT
- * @return boolean/err
- */
- function removeSubj($login, $uid=NULL)
- {
- $res = parent::removeSubj($login, $pass);
- if(PEAR::isError($res)) return $res;
- $id = $this->getObjId($login, $this->storId);
- if(PEAR::isError($id)) return $id;
- $res = $this->bsDeleteFile($id);
- if(PEAR::isError($res)) return $res;
- return TRUE;
- }
-
/**
* Get file's path in virtual filesystem
*
diff --git a/livesupport/modules/storageServer/var/LocStor.php b/livesupport/modules/storageServer/var/LocStor.php
index 2641f363b..754596618 100644
--- a/livesupport/modules/storageServer/var/LocStor.php
+++ b/livesupport/modules/storageServer/var/LocStor.php
@@ -23,7 +23,7 @@
Author : $Author: tomas $
- Version : $Revision: 1.22 $
+ Version : $Revision: 1.23 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/LocStor.php,v $
------------------------------------------------------------------------------*/
@@ -48,7 +48,9 @@ class LocStor extends BasicStor{
* @param chsum string, md5 checksum of media file
* @return struct {url:writable URL for HTTP PUT, token:access token
*/
- function storeAudioClipOpen($sessid, $gunid, $metadata, $fname, $chsum)
+ function storeAudioClipOpen(
+ $sessid, $gunid, $metadata, $fname, $chsum, $ftype='audioclip'
+ )
{
// test if specified gunid exists:
if(!preg_match("|^([0-9a-fA-F]{16})?$|", $gunid)){
@@ -59,8 +61,9 @@ class LocStor extends BasicStor{
$ac =& StoredFile::recallByGunid(&$this, $gunid);
if(!PEAR::isError($ac)){
// gunid exists - do replace
+ $oid = $ac->getId();
if(($res = $this->_authorize(
- 'write', $ac->getId(), $sessid
+ 'write', $oid, $sessid
)) !== TRUE) return $res;
if($ac->isAccessed()){
return PEAR::raiseError(
@@ -68,7 +71,7 @@ class LocStor extends BasicStor{
);
}
$res = $ac->replace(
- $ac->getId(), $ac->name, '', $metadata, 'string'
+ $oid, $ac->name, '', $metadata, 'string'
);
if(PEAR::isError($res)) return $res;
}else{
@@ -82,7 +85,7 @@ class LocStor extends BasicStor{
if(PEAR::isError($oid)) return $oid;
$ac =& StoredFile::insert(
&$this, $oid, '', '', $metadata, 'string',
- $gunid, 'audioclip'
+ $gunid, $ftype
);
if(PEAR::isError($ac)){
$res = $this->removeObj($oid);
@@ -121,6 +124,17 @@ class LocStor extends BasicStor{
return $ac->gunid;
}
+ /**
+ * Check uploaded file
+ *
+ * @param token string, put token
+ * @return hash, (status: boolean, size: int - filesize)
+ */
+ function uploadCheck($token)
+ {
+ return $this->bsCheckPut($token);
+ }
+
/* --------------------------------------------------------------- access */
/**
* Make access to audio clip
@@ -158,16 +172,18 @@ class LocStor extends BasicStor{
*
* @param sessid string, session id
* @param gunid string, global unique id
- * @return array with: downloadable URL, download token
+ * @return array with strings:
+ * downloadable URL, download token, chsum, size, filename
*/
function downloadRawAudioDataOpen($sessid, $gunid)
{
- $res = $this->existsAudioClip($sessid, $gunid);
- if(PEAR::isError($res)) return $res;
+ $ex = $this->existsAudioClip($sessid, $gunid);
+ if(PEAR::isError($ex)) return $ex;
$id = $this->_idFromGunid($gunid);
- if(is_null($id)){
+ if(is_null($id) || !$ex){
return PEAR::raiseError(
- "LocStor::downloadRawAudioDataOpen: gunid not found ($gunid)"
+ "LocStor::downloadRawAudioDataOpen: gunid not found ($gunid)",
+ GBERR_NOTF
);
}
if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE)
@@ -191,12 +207,13 @@ class LocStor extends BasicStor{
*
* @param sessid string, session id
* @param gunid string, global unique id
- * @return array with: downloadable URL, download token
+ * @return array with strings:
+ * downloadable URL, download token, chsum, filename
*/
function downloadMetadataOpen($sessid, $gunid)
{
- $res = $this->existsAudioClip($sessid, $gunid);
- if(PEAR::isError($res)) return $res;
+# $res = $this->existsAudioClip($sessid, $gunid);
+# if(PEAR::isError($res)) return $res;
$id = $this->_idFromGunid($gunid);
if(is_null($id)){
return PEAR::raiseError(
@@ -205,7 +222,9 @@ class LocStor extends BasicStor{
}
if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE)
return $res;
- return $this->bsOpenDownload($id, 'metadata');
+ $res = $this->bsOpenDownload($id, 'metadata');
+ #unset($res['filename']);
+ return $res;
}
/**
@@ -350,7 +369,7 @@ class LocStor extends BasicStor{
default: return $ac;
}
}
- if(!is_null($ftype) && ($ac->_getType() != $ftype)) return FALSE;
+ if(!is_null($ftype) && ($this->_getType($gunid) != $ftype)) return FALSE;
if(($res = $this->_authorize('read', $ac->getId(), $sessid)) !== TRUE)
return $res;
return TRUE;
@@ -399,6 +418,10 @@ class LocStor extends BasicStor{
function resetStorage($input='')
{
$this->deleteData();
+ if(!$this->config['isArchive']){
+ $tr =& new Transport($this->dbc, $this, $this->config);
+ $tr->resetData();
+ }
$rootHD = $this->getObjId('root', $this->storId);
include"../tests/sampleData.php";
$res = array('audioclips'=>array(), 'playlists'=>array());
@@ -483,7 +506,8 @@ class LocStor extends BasicStor{
*
* @param sessid string, session ID
* @param playlistId string, playlist global unique ID
- * @return struct {url:readable URL for HTTP GET, token:access token}
+ * @return struct
+ * {url:readable URL for HTTP GET, token:access token, chsum:checksum}
*/
function editPlaylist($sessid, $playlistId)
{
@@ -505,6 +529,7 @@ class LocStor extends BasicStor{
$res = $this->bsOpenDownload($id, 'metadata');
if(PEAR::isError($res)){ return $res; }
$this->_setEditFlag($playlistId, TRUE);
+ unset($res['filename']);
return $res;
}
@@ -557,7 +582,8 @@ class LocStor extends BasicStor{
*
* @param sessid string, session ID
* @param playlistId string, playlist global unique ID
- * @return struct {url:readable URL for HTTP GET, token:access token
+ * @return struct
+ * {url:readable URL for HTTP GET, token:access token, chsum:checksum}
*/
function accessPlaylist($sessid, $playlistId)
{
@@ -565,13 +591,16 @@ class LocStor extends BasicStor{
if(PEAR::isError($ex)){ return $ex; }
if(!$ex){
return PEAR::raiseError(
- 'LocStor.php: accessPlaylist: playlist not found'
+ "LocStor.php: accessPlaylist: playlist not found ($playlistId)",
+ GBERR_NOTF
);
}
$id = $this->_idFromGunid($playlistId);
if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE)
return $res;
- return $this->bsOpenDownload($id, 'metadata');
+ $res = $this->bsOpenDownload($id, 'metadata');
+ unset($res['filename']);
+ return $res;
}
/**
diff --git a/livesupport/modules/storageServer/var/StoredFile.php b/livesupport/modules/storageServer/var/StoredFile.php
index 9884116ff..1b49b1e1c 100644
--- a/livesupport/modules/storageServer/var/StoredFile.php
+++ b/livesupport/modules/storageServer/var/StoredFile.php
@@ -23,7 +23,7 @@
Author : $Author: tomas $
- Version : $Revision: 1.16 $
+ Version : $Revision: 1.17 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/StoredFile.php,v $
------------------------------------------------------------------------------*/
@@ -93,7 +93,7 @@ class StoredFile{
$ac->mime = "unKnown";
$emptyState = TRUE;
if($ac->name=='') $ac->name=$ac->gunid;
- $this->dbc->query("BEGIN");
+ $ac->dbc->query("BEGIN");
$res = $ac->dbc->query("
INSERT INTO {$ac->filesTable}
(id, name, gunid, mime, state, ftype)
@@ -101,7 +101,7 @@ class StoredFile{
('$oid', '{$ac->name}', x'{$ac->gunid}'::bigint,
'{$ac->mime}', 'incomplete', '$ftype')
");
- if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; }
+ if(PEAR::isError($res)){ $ac->dbc->query("ROLLBACK"); return $res; }
// --- metadata insert:
if($metadata != ''){
if($mdataLoc=='file' && !file_exists($metadata))
@@ -111,7 +111,7 @@ class StoredFile{
}
$res = $ac->md->insert($metadata, $mdataLoc);
if(PEAR::isError($res)){
- $this->dbc->query("ROLLBACK"); return $res;
+ $ac->dbc->query("ROLLBACK"); return $res;
}
$emptyState = FALSE;
}
@@ -124,7 +124,7 @@ class StoredFile{
}
$res = $ac->rmd->insert($mediaFileLP);
if(PEAR::isError($res)){
- $this->dbc->query("ROLLBACK"); return $res;
+ $ac->dbc->query("ROLLBACK"); return $res;
}
$mime = $ac->rmd->getMime();
//$gb->debugLog("gunid={$ac->gunid}, mime=$mime");
@@ -140,8 +140,8 @@ class StoredFile{
$res = $ac->setState('ready');
if(PEAR::isError($res)){ $ac->dbc->query("ROLLBACK"); return $res; }
}
- $res = $this->dbc->query("COMMIT");
- if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; }
+ $res = $ac->dbc->query("COMMIT");
+ if(PEAR::isError($res)){ $ac->dbc->query("ROLLBACK"); return $res; }
return $ac;
}
@@ -224,7 +224,7 @@ class StoredFile{
{
$ac =& StoredFile::insert(
&$src->gb, $nid, $src->name, $src->_getRealRADFname(),
- '', '', NULL, $src->_getType()
+ '', '', NULL, $src->gb->_getType($src->gunid)
);
if(PEAR::isError($ac)) return $ac;
$ac->md->replace($src->md->getMetaData(), 'string');
@@ -256,7 +256,7 @@ class StoredFile{
$this->dbc->query("ROLLBACK"); return $res;
}
if($metadata != ''){ // metadata
- $res = $this->md->replace($metadata, $mdataLoc);
+ $res = $this->replaceMetaData($metadata, $mdataLoc);
}else{
$res = $this->md->delete();
}
@@ -495,6 +495,7 @@ class StoredFile{
SELECT to_hex(gunid) FROM {$this->filesTable}
WHERE gunid=x'{$this->gunid}'::bigint
");
+ if(PEAR::isError($indb)) return $indb;
return (!is_null($indb) && $this->rmd->exists());
}
@@ -585,22 +586,6 @@ class StoredFile{
");
}
- /**
- * Get storage-internal file type
- *
- * @param gunid string, optional, global unique id of file
- * @return string, see install()
- */
- function _getType($gunid=NULL)
- {
- if(is_null($gunid)) $gunid = $this->gunid;
- $ftype = $this->dbc->getOne("
- SELECT ftype FROM {$this->filesTable}
- WHERE gunid=x'$gunid'::bigint
- ");
- return $ftype;
- }
-
/**
* Get storage-internal file state
*
@@ -639,8 +624,9 @@ class StoredFile{
function _getResDir()
{
$resDir="{$this->gb->storageDir}/".substr($this->gunid, 0, 3);
+ #$this->gb->debugLog("$resDir");
// see Transport::_getResDir too for resDir name create code
- if(!file_exists($resDir)){ mkdir($resDir, 02775); chmod($resDir, 02775); }
+ if(!is_dir($resDir)){ mkdir($resDir, 02775); chmod($resDir, 02775); }
return $resDir;
}
@@ -671,6 +657,7 @@ class StoredFile{
*/
function _getAccessFname($token, $ext='EXT')
{
+ $token = StoredFile::_normalizeGunid($token);
return "{$this->accessDir}/$token.$ext";
}
}
diff --git a/livesupport/modules/storageServer/var/Transport.php b/livesupport/modules/storageServer/var/Transport.php
index 4ee7b402a..96c91e3fd 100644
--- a/livesupport/modules/storageServer/var/Transport.php
+++ b/livesupport/modules/storageServer/var/Transport.php
@@ -23,11 +23,15 @@
Author : $Author: tomas $
- Version : $Revision: 1.3 $
+ Version : $Revision: 1.4 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/Transport.php,v $
------------------------------------------------------------------------------*/
-include_once "xmlrpc/XML/RPC.php";
+define('TRERR_', 70);
+define('TRERR_MD', 71);
+define('TRERR_TOK', 72);
+
+include_once "XML/RPC.php";
/**
* Class for handling file tranport between StorageServer and ArchiveServer
@@ -43,29 +47,703 @@ class Transport{
* Constructor
*
* @param dbc PEAR DB object reference
+ * @param gb LocStor object reference
* @param config config array
*/
- function Transport(&$dbc, $config)
+ function Transport(&$dbc, &$gb, $config)
{
$this->dbc =& $dbc;
$this->config = $config;
$this->transTable = $config['tblNamePrefix'].'trans';
$this->transDir = $config['transDir'];
+ $this->gb =& $gb;
}
+ /* ================================================== status info methods */
/**
* Return state of transport job
*
+ * @param trtok string, transport token
+ * @return string, transport state
*/
- function getTransportStatus($trid)
+ function getState($trtok)
{
$row = $this->dbc->getRow(
- "SELECT state FROM {$this->transTable} WHERE trid='$trid'"
+ "SELECT state FROM {$this->transTable} WHERE trtok='$trtok'"
);
- if(PEAR::isError($res)) return $res;
+ if(PEAR::isError($row)) return $row;
+ if(is_null($row)){
+ return PEAR::raiseError("Transport::getState:".
+ " invalid transport token ($trtok)", TRERR_TOK
+ );
+ }
return $row['state'];
}
+ /**
+ * Return hash with useful information about transport
+ *
+ * @param trtok string, transport token
+ * @return hash:
+ * trtype,
+ * direction,
+ * status,
+ * expectedsize,
+ * realsize,
+ * expectedsum,
+ * realsum
+ */
+ function getTransportInfo($trtok)
+ {
+ $row = $this->dbc->getRow("
+ SELECT
+ trtype, direction, state,
+ expectedsize, realsize,
+ expectedsum, realsum
+ FROM {$this->transTable}
+ WHERE trtok='$trtok'
+ ");
+ if(PEAR::isError($row)){ return $row; }
+ if(is_null($row)){
+ return PEAR::raiseError("Transport::getTransportInfo:".
+ " invalid transport token ($trtok)", TRERR_TOK
+ );
+ }
+ $row['status'] == ($row['state'] == 'closed');
+# unset($row['state']);
+ return $row;
+ }
+
+ /* ======================================================= upload methods */
+
+ /**
+ *
+ */
+ function uploadToArchive($gunid, $sessid='')
+ {
+ $trtype = $this->gb->_getType($gunid);
+ switch($trtype){
+ case"audioclip":
+ $ex = $this->gb->existsAudioClip($sessid, $gunid);
+ break;
+ case"playlist":
+ $ex = $this->gb->existsPlaylist($sessid, $gunid);
+ break;
+ default:
+ return PEAR::raiseError("Transport::uploadToArchive:".
+ " unknown trtype ($trtype)"
+ );
+ }
+ if(PEAR::isError($ex)) return $ex;
+ if(!$ex){
+ return PEAR::raiseError("Transport::uploadToArchive:".
+ " $trtype not found ($gunid)"
+ );
+ }
+ $trtok = $this->_createTrtok();
+ $id = $this->dbc->nextId("{$this->transTable}_id_seq");
+ $res = $this->dbc->query("
+ INSERT INTO {$this->transTable}
+ (id, trtok, direction, state, trtype,
+ gunid,
+ expectedsum, realsum, expectedsize, realsize
+ )
+ VALUES
+ ($id, '$trtok', 'up', 'init', '$trtype',
+ x'$gunid'::bigint,
+ '?e', '?r', '0', '0'
+ )
+ ");
+ if(PEAR::isError($res)) return $res;
+#?? $this->uploadCron();
+ return $trtok;
+ }
+
+ /**
+ *
+ */
+ function uploadCron()
+ {
+ // fetch all opened uploads
+ $rows = $this->dbc->getAll("
+ SELECT
+ id, trtok, state, trtype,
+ to_hex(gunid)as gunid, to_hex(pdtoken)as pdtoken,
+ fname, localfile, expectedsum, expectedsize, url
+ FROM {$this->transTable}
+ WHERE direction='up' AND state<>'closed'
+ ");
+ if(PEAR::isError($rows)){ $this->trLogPear($rows); return FALSE; }
+ if(count($rows)==0) return TRUE;
+ // login to archive server
+ $r = $this->loginToArchive();
+ if(PEAR::isError($r)){ $this->trLog("Login error"); return FALSE; }
+ $asessid = $r['sessid'];
+ chdir($this->config['transDir']);
+ // for all opened uploads:
+ foreach($rows as $i=>$row){
+ $row['pdtoken'] = StoredFile::_normalizeGunid($row['pdtoken']);
+ $row['gunid'] = StoredFile::_normalizeGunid($row['gunid']);
+ #var_dump($row);
+ switch($row['state']){
+ case"init": // ------ new uploads
+ $ret = $this->uploadCronInit($row, $asessid);
+ if(PEAR::isError($ret)){
+ $this->trLogPear($ret, $row); break;
+ }
+ $row = array_merge($row, $ret);
+ // break;
+ case"pending": // ------ pending uploads
+ $ret = $this->uploadCronPending($row, $asessid);
+ if(PEAR::isError($ret)){ $this->trLogPear($ret, $row); }
+ break;
+ case"finished": // ------ finished uploads
+ $ret = $this->uploadCronFinished($row, $asessid);
+ if(PEAR::isError($ret)){ $this->trLogPear($ret, $row); }
+ break;
+ case"failed": // ------ failed uploads
+ $ret = $this->uploadCronFailed($row, $asessid);
+ if(PEAR::isError($ret)){ $this->trLogPear($ret, $row); }
+ break;
+ default:
+ $this->trLog("uploadCron: unknown state ".
+ "({$row['state']}, id={$row['id']})");
+ } // switch state
+ } // foreach opened
+ $r = $this->logoutFromArchive($asessid);
+ if(PEAR::isError($r)) $this->trLog("Logout error");
+ return TRUE;
+ }
+
+ /**
+ *
+ */
+ function uploadCronInit($row, $asessid)
+ {
+ $this->trLog("INIT UP id={$row['id']}, trtok={$row['trtok']}");
+ switch($row['trtype']){
+ case"audioclip":
+ $ac =& StoredFile::recallByGunid(&$this->gb, $row['gunid']);
+ if(PEAR::isError($ac)) return $ac;
+ $fpath = $ac->_getRealRADFname();
+ $fname = $ac->_getFileName();
+ $chsum = $this->_chsum($fpath);
+ $size = filesize($fpath);
+ $metadata = file_get_contents($ac->_getRealMDFname());
+ $ret = $this->xmlrpcCall( 'archive.storeAudioClipOpen',
+ array(
+ 'sessid' => $asessid,
+ 'gunid' => $row['gunid'],
+ 'metadata' => $metadata,
+ 'fname' => $fname,
+ 'chsum' => $chsum,
+ )
+ );
+ if(PEAR::isError($ret)) return $ret;
+ $r = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET
+ state = 'pending',
+ fname = '$fname',
+ localfile = '$fpath',
+ expectedsum = '$chsum',
+ expectedsize= $size,
+ url = '{$ret['url']}',
+ pdtoken = x'{$ret['token']}'::bigint
+ WHERE id={$row['id']}
+ ");
+ if(PEAR::isError($r)) return $r;
+ return array(
+ 'state'=>'pending',
+ 'url'=>$ret['url'], 'pdtoken'=>$ret['token'],
+ 'localfile'=>$fpath, 'fname'=>$fname,
+ 'expectedsum'=>$chsum, 'expectedsize'=>$size,
+ );
+ break;
+ case"playlist":
+ $ac =& StoredFile::recallByGunid(&$this->gb, $row['gunid']);
+ if(PEAR::isError($ac)) return $ac;
+ $fname = $ac->_getFileName();
+ $size = filesize($fpath);
+ $metadata = file_get_contents($ac->_getRealMDFname());
+ $ret = $this->xmlrpcCall( 'archive.createPlaylist',
+ array(
+ 'sessid' => $asessid,
+ 'plid' => $row['gunid'],
+ 'fname' => $fname,
+ )
+ );
+ if(PEAR::isError($ret)) return $ret;
+ $ret = $this->xmlrpcCall( 'archive.editPlaylist',
+ array(
+ 'sessid' => $asessid,
+ 'plid' => $row['gunid'],
+ 'metadata' => $metadata,
+ )
+ );
+ if(PEAR::isError($ret)) return $ret;
+# $this->trLog("INIT UP after edit {$ret['token']}");
+ $r = $this->xmlrpcCall( 'archive.savePlaylist',
+ array(
+ 'sessid' => $asessid,
+ 'token' => $ret['token'],
+ 'newPlaylist' => $metadata,
+ )
+ );
+ if(PEAR::isError($r)) return $r;
+# $this->trLog("INIT UP after save {$r['plid']}");
+ $r = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET
+ state = 'closed',
+ fname = '$fname',
+ url = '{$ret['url']}'
+ WHERE id={$row['id']}
+ ");
+ if(PEAR::isError($r)) return $r;
+ return array(
+ 'state'=>'closed',
+ 'url'=>$ret['url'], 'pdtoken'=>$ret['token'],
+ 'fname'=>$fname,
+ );
+ break;
+ case"searchjob":
+ return array();
+ default:
+ return PEAR::raiseError("Transport::uploadCronInit:".
+ " unknown trtype ({$row['trtype']})"
+ );
+ } // switch $row['trtype']
+ }
+
+ /**
+ *
+ */
+ function uploadCronPending($row, $asessid)
+ {
+ if($row['trtype'] != 'audioclip') return;
+ $check = $this->uploadCheck($row['pdtoken']);
+ if(PEAR::isError($check)) return $check;
+ #var_dump($row);
+ #var_dump($check);
+ // test filesize
+ if(intval($check['size']) < $row['expectedsize']){
+ // not finished - upload next part
+ $command =
+ "curl -s -C {$check['size']} --max-time 600".
+ " --speed-time 20 --speed-limit 500".
+ " --connect-timeout 20".
+ " -T {$row['localfile']} {$row['url']}";
+# echo "$command\n";
+ $res = system($command, $status);
+ }else{
+ // hmmm - we are finished? OK - continue
+ $status = 0;
+ }
+ // status 18 - Partial file. Only a part of the file was transported.
+ if($status == 0 || $status == 18){
+ $check = $this->uploadCheck($row['pdtoken']);
+ if(PEAR::isError($check)) return $check;
+ #var_dump($check);
+ // test checksum
+ if($check['status'] == TRUE){
+ // finished
+ $res = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET state ='finished',
+ realsum ='{$check['realsum']}',
+ realsize={$check['size']}
+ WHERE id='{$row['id']}'
+ ");
+ if(PEAR::isError($res)) return $res;
+ }else{
+ if(intval($check['size']) < $row['expectedsize']){
+ $res = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET
+ realsum ='{$check['realsum']}',
+ realsize={$check['realsize']}
+ WHERE id='{$row['id']}'
+ ");
+ if(PEAR::isError($res)) return $res;
+ }else{
+ // wrong md5 at finish - TODO: start again
+ // $this->xmlrpcCall('archive.uploadReset', array());
+ return PEAR::raiseError("Transport::uploadCron:".
+ " file uploaded with bad md5 ".
+ "({$check['realsum']}/{$check['expectedsum']})"
+ );
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ function uploadCronFinished($row, $asessid)
+ {
+ if($row['trtype'] != 'audioclip') return;
+ $res = $this->xmlrpcCall(
+ 'archive.storeAudioClipClose',
+ array('sessid'=>$asessid, 'token'=>$row['pdtoken'])
+ );
+# if(PEAR::isError($res)) return $res;
+ if(PEAR::isError($res)){
+ switch($res->getCode()){
+ case GBERR_PUT:
+ // mark as failed
+ $this->dbc->query("
+ UPDATE {$this->transTable} SET state='failed'
+ WHERE id='{$row['id']}'
+ ");
+ break;
+ return FALSE;
+ default:
+# echo $res->getCode()."\n"; exit;
+ return $res;
+ }
+ }
+ // close upload in db
+ $r = $this->dbc->query("
+ UPDATE {$this->transTable} SET state='closed'
+ WHERE id='{$row['id']}'
+ ");
+ /*
+ $r = $this->dbc->query("
+ DELETE FROM {$this->transTable}
+ WHERE id='{$row['id']}'
+ ");
+ */
+ if(PEAR::isError($r)) return $r;
+ $this->trLog("FIN UP id={$row['id']}, trtok={$row['trtok']}".
+ "\n ".serialize($row));
+ }
+
+ /**
+ *
+ */
+ function uploadCronFailed($row, $asessid)
+ {
+ /*
+ $r = $this->dbc->query("
+ DELETE FROM {$this->transTable}
+ WHERE id='{$row['id']}'
+ ");
+ if(PEAR::isError($r)) return $r;
+ */
+ }
+
+ /**
+ * Check state of uploaded file
+ *
+ * @param pdtoken string, put token
+ * @return hash: chsum, size, url
+ */
+ function uploadCheck($pdtoken)
+ {
+ $ret = $this->xmlrpcCall(
+ 'archive.uploadCheck',
+ array('token'=>$pdtoken)
+ );
+ return $ret;
+ }
+
+ /* ===================================================== download methods */
+ /**
+ *
+ */
+ function downloadFromArchive($gunid, $sessid='')
+ {
+ // insert transport record to db
+ $uid = $this->gb->getSessUserId($sessid);
+ if(PEAR::isError($uid)) return $uid;
+ if(is_null($uid)){
+ return PEAR::raiseError("Transport::downloadFromArchive: ".
+ "invalid session id",GBERR_SESS);
+ }
+ $parid = $this->gb->_getHomeDirId($sessid);
+ if(PEAR::isError($parid)) return $parid;
+ $trtok = $this->_createTrtok();
+ $id = $this->dbc->nextId("{$this->transTable}_id_seq");
+ if(PEAR::isError($id)) return $id;
+ $res = $this->dbc->query("
+ INSERT INTO {$this->transTable}
+ (id, trtok, direction, state, trtype,
+ gunid,
+ expectedsum, realsum, expectedsize, realsize,
+ uid, parid
+ )
+ VALUES
+ ($id, '$trtok', 'down', 'init', '?',
+ x'$gunid'::bigint,
+ '?e', '?r', '0', '0',
+ $uid, $parid
+ )
+ ");
+ if(PEAR::isError($res)) return $res;
+#?? $this->downloadCron();
+ return $trtok;
+ }
+
+ /**
+ *
+ */
+ function downloadCron()
+ {
+ // fetch all opened downloads
+ $rows = $this->dbc->getAll("
+ SELECT
+ id, trtok, state, trtype,
+ to_hex(gunid)as gunid, to_hex(pdtoken)as pdtoken,
+ fname, localfile, expectedsum, expectedsize, url,
+ uid, parid
+ FROM {$this->transTable}
+ WHERE direction='down' AND state<>'closed'
+ ");
+ if(PEAR::isError($rows)){ $this->trLogPear($rows); return FALSE; }
+ if(count($rows)==0) return TRUE;
+ // login to archive server
+ $r = $this->loginToArchive();
+ if(PEAR::isError($r)){ $this->trLog("Login error"); return FALSE; }
+ $asessid = $r['sessid'];
+ chdir($this->config['transDir']);
+ // for all opened downloads:
+ foreach($rows as $i=>$row){
+ $row['pdtoken'] = StoredFile::_normalizeGunid($row['pdtoken']);
+ $row['gunid'] = StoredFile::_normalizeGunid($row['gunid']);
+ switch($row['state']){
+ case"init": // ------ new downloads
+ $ret = $this->downloadCronInit($row, $asessid);
+ if(PEAR::isError($ret)){
+ $this->trLogPear($ret, $row); break;
+ }
+ $row = array_merge($row, $ret);
+ #break;
+ case"pending": // ------ pending downloads
+ $ret = $this->downloadCronPending($row, $asessid);
+ if(PEAR::isError($ret)){ $this->trLogPear($ret, $row); }
+ break;
+ case"finished": // ------ finished downloads
+ $ret = $this->downloadCronFinished($row, $asessid);
+ if(PEAR::isError($ret)){ $this->trLogPear($ret, $row); }
+ break;
+ case"failed": // ------ failed downloads
+ $ret = $this->downloadCronFailed($row, $asessid);
+ if(PEAR::isError($ret)){ $this->trLogPear($ret, $row); }
+ break;
+ default:
+ $this->trLog("downloadCron: unknown state ".
+ "({$row['state']}, id={$row['id']})");
+ } // switch state
+ } // foreach opened
+ $r = $this->logoutFromArchive($asessid);
+ if(PEAR::isError($r)) $this->trLog("Logout error");
+ return TRUE;
+ }
+
+ /**
+ *
+ */
+ function downloadCronInit($row, $asessid)
+ {
+ $ret = $this->xmlrpcCall('archive.downloadRawAudioDataOpen',
+ array('sessid'=>$asessid, 'gunid'=>$row['gunid'])
+ );
+ if(PEAR::isError($ret)){
+ // catch 'not found' exception:
+ if($ret->getCode() != 847) return $ret;
+ else $trtype = '?';
+ }else $trtype = 'audioclip';
+ if($trtype == '?'){
+ $ret = $this->xmlrpcCall('archive.existsPlaylist',
+ array('sessid'=>$asessid, 'plid'=>$row['gunid'])
+ );
+ if(PEAR::isError($ret)){
+ // catch 'not found' exception:
+ if($ret->getCode() != 847) return $ret;
+ else $trtype = '?';
+ }else{
+ $trtype = 'playlist';
+ $r1 = $this->downloadMetadata($row['gunid'], $asessid);
+ if(PEAR::isError($r1)) return $r1;
+ $r2 = $this->gb->bsPutFile($row['parid'], $r1['filename'],
+ '', $r1['mdata'], $row['gunid'], $trtype, 'string');
+ if(PEAR::isError($r2)) return $r2;
+ $res = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET state='closed',
+ trtype='$trtype'
+ WHERE id='{$row['id']}'
+ ");
+ if(PEAR::isError($res)) return $res;
+ return array(
+ 'state'=>'closed', 'trtype'=>$trtype,
+ 'fname'=>$r1['filename'],
+ );
+ }
+ }
+ if($trtype == '?'){
+ return PEAR::raiseError("Transport::downloadCronInit:".
+ " unknown trtype ({$row['trtype']})"
+ );
+ }
+ $fpath = $this->transDir."/".basename($ret['url']); // ***
+ touch($fpath);
+ $res = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET
+ state = 'pending',
+ trtype = '$trtype',
+ fname = '{$ret['filename']}',
+ localfile = '$fpath',
+ expectedsum = '{$ret['chsum']}',
+ expectedsize= '{$ret['size']}',
+ url = '{$ret['url']}',
+ pdtoken = x'{$ret['token']}'::bigint
+ WHERE id='{$row['id']}'
+ ");
+ if(PEAR::isError($res)) return $res;
+ $this->trLog("INIT DOWN id={$row['id']}, trtok={$row['trtok']}");
+ return array(
+ 'state'=>'pending', 'trtype'=>$trtype,
+ 'url'=>$ret['url'], 'pdtoken'=>$ret['token'],
+ 'localfile'=>$fpath, 'fname'=>$ret['filename'],
+ 'expectedsum'=>$ret['chsum'], 'expectedsize'=>$ret['size'],
+ );
+ }
+
+ /**
+ *
+ */
+ function downloadCronPending($row, $asessid)
+ {
+ if($row['trtype'] != 'audioclip') return;
+ // wget the file
+ $command =
+ "wget -q -c --timeout={$this->timeout}".
+ " --waitretry={$this->waitretry}".
+ " -t {$this->retries} {$row['url']}";
+# echo "$command\n";
+ $res = system($command, $status);
+ // check consistency
+ $chsum = $this->_chsum($row['localfile']);
+ $size = filesize($row['localfile']);
+ if($status == 0){
+ if($chsum == $row['expectedsum']){
+ // mark download as finished
+ $res = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET state='finished',
+ realsum ='{$chsum}',
+ realsize={$size}
+ WHERE id='{$row['id']}'
+ ");
+ if(PEAR::isError($res)) return $res;
+ }else{
+ @unlink($row['localfile']);
+ $res = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET
+ realsum ='{$chsum}',
+ realsize={$size}
+ WHERE id='{$row['id']}'
+ ");
+ if(PEAR::isError($res)) return $res;
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ function downloadCronFinished($row, $asessid)
+ {
+ if($row['trtype'] != 'audioclip') return;
+ // call archive that downloads have been finished OK
+ $res = $this->xmlrpcCall(
+ 'archive.downloadRawAudioDataClose',
+ array('sessid'=>$asessid, 'token'=>$row['pdtoken'])
+ );
+ if(PEAR::isError($res)) return $res;
+ $res2 = $this->downloadMetadata($row['gunid'], $asessid);
+ if(PEAR::isError($res2)) return $res2;
+ $mdata = $res2['mdata'];
+ $name = $row['fname'];
+ $this->trLog("FIN1 DOWN id={$row['id']}, trtok={$row['trtok']}".
+ "\n ".serialize($row));
+ $ac =& StoredFile::recallByGunid(&$this->gb, $row['gunid']);
+ if(!PEAR::isError($ac)){
+ // gunid exists - do replace
+ $id = $ac->getId();
+ $ac->replace(
+ $id, $name, $row['localfile'], $mdata, 'string'
+ );
+ if(PEAR::isError($ac)) return $ac;
+ }else{
+ // gunid doesn't exists - do insert
+ $id = $this->gb->addObj($name , 'File', $row['parid']);
+ if(PEAR::isError($id)) return $id;
+ $ac =& StoredFile::insert(
+ &$this->gb, $id, $name, $row['localfile'], $mdata, 'string',
+ $row['gunid'], 'audioclip'
+ );
+ if(PEAR::isError($ac)) return $ac;
+ }
+ // close download in db
+ $res = $this->dbc->query("
+ UPDATE {$this->transTable}
+ SET state='closed'
+ WHERE id='{$row['id']}'
+ ");
+ /*
+ $res = $this->dbc->query("
+ DELETE FROM {$this->transTable}
+ WHERE id='{$row['id']}'
+ ");
+ */
+ if(PEAR::isError($res)) return $res;
+ $this->trLog("FIN DOWN id={$row['id']}, trtok={$row['trtok']}".
+ "\n ".serialize($row));
+ }
+
+ /**
+ *
+ */
+ function downloadCronFailed($row, $asessid)
+ {
+ /*
+ $r = $this->dbc->query("
+ DELETE FROM {$this->transTable}
+ WHERE id='{$row['id']}'
+ ");
+ if(PEAR::isError($r)) return $r;
+ */
+ }
+
+ /**
+ *
+ */
+ function downloadMetadata($gunid, $asessid)
+ {
+ $ret = $this->xmlrpcCall('archive.downloadMetadataOpen',
+ array('sessid'=>$asessid, 'gunid'=>$gunid)
+ );
+ if(PEAR::isError($ret)) return $ret;
+ #echo "{$ret['url']}\n";
+ if(($mdata = file_get_contents($ret['url'])) === FALSE){
+ return PEAR::raiseError("Transport::downloadCronInit: ".
+ "metadata download failed ({$gunid})", TRERR_MD
+ );
+ }
+ $filename = $ret['filename'];
+ $ret = $this->xmlrpcCall('archive.downloadMetadataClose',
+ array('token'=>$ret['token'])
+ );
+ if(PEAR::isError($ret)) return $ret;
+ return array('mdata'=>$mdata, 'filename'=>$filename);
+ }
+
/* ======================================================= search methods */
/**
* Start search in archive
@@ -87,259 +765,6 @@ class Transport{
// not implemented yet
}
- /* ======================================= general file transport methods */
-
- /**
- *
- */
- function uploadOpen($file, $type, $sessid='', $gunid='X')
- {
- $trid = $this->_createTrId();
- $md5h = $this->_md5sum($this->transDir."/$file");
- $id = $this->dbc->nextId("{$this->transTable}_id_seq");
- $res = $this->dbc->query("
- INSERT INTO {$this->transTable}
- (id, trid, direction, state, type,
- md5h, url, fname, gunid
- )
- VALUES
- ($id, '$trid', 'up', 'init', '$type',
- '$md5h', '', '$file', '$gunid'
- )
- ");
- if(PEAR::isError($res)) return $res;
-#?? $this->uploadCron();
- return $trid;
- }
-
- /**
- *
- */
- function uploadCron()
- {
- // fetch all opened uploads
- $rows = $this->dbc->getAll("
- SELECT * FROM {$this->transTable}
- WHERE direction='up' AND state<>'closed'
- ");
- if(count($rows)==0) return TRUE;
- $asessid = $this->loginToArchive();
- chdir($this->config['transDir']);
- // for all opened uploads:
- foreach($rows as $i=>$row){
- switch($row['state']){
- case"init": // ------ new uploads
- $finf = $this->xmlrpcCall( 'archive.uploadOpen',
- array('sessid'=>$asessid, 'trid'=>$row['trid'],
- 'type'=>$row['type']
- )
- );
- if(PEAR::isError($finf)) return $finf;
- $res = $this->dbc->query("
- UPDATE {$this->transTable}
- SET state='pending', url='{$finf['url']}'
- WHERE id='{$row['id']}'
- ");
- if(PEAR::isError($res)) return $res;
- $row['url'] = $finf['url'];
-#break;
- case"pending": // ------ pending uploads
- $finf = $this->uploadCheck($asessid, $row['url']);
- if(PEAR::isError($finf)) return $finf;
- // test filesize
- if(intval($finf['size']) < filesize($row['fname'])){
- // not finished - upload next part
- $res = system(
- "curl -s -C {$finf['size']} --max-time 600".
- " --speed-time 20 --speed-limit 500".
- " --connect-timeout 20".
- " -T {$row['fname']} {$row['url']}",
- $status
- );
- }else{
- // hmmm - we are finished? OK - continue
- $status = 0;
- }
- if($status == 0 || $status == 18){
- $finf = $this->uploadCheck($asessid, $row['url']);
- if(PEAR::isError($finf)) return $finf;
- // test checksum
- if($finf['md5h'] == $row['md5h']){
- // finished
- $res = $this->dbc->query("
- UPDATE {$this->transTable} SET state='finished'
- WHERE id='{$row['id']}'
- ");
- if(PEAR::isError($res)) return $res;
- }else{
- if(intval($finf['size']) >= filesize($row['fname']))
- {
- // wrong md5 at finish - TODO: start again
- // $this->xmlrpcCall('archive.uploadReset', array());
- return PEAR::raiseError("Transport::uploadCron:".
- " file uploaded with bad md5"
- );
- }
- }
- }
-#break;
- case"finished": // ------ finished uploads
- $res = $this->xmlrpcCall(
- 'archive.uploadClose',
- array('sessid'=>$asessid,
- 'url'=>$row['url'], 'type'=>$row['type'],
- 'gunid'=>$row['gunid'],
- )
- );
- if(PEAR::isError($res)) return $res;
- @unlink($this->transDir."/".$row['fname']);
- // close upload in db TODO: or delete record?
- $this->dbc->query("
- UPDATE {$this->transTable} SET state='closed'
- WHERE id='{$row['id']}'
- ");
- break;
- default:
- echo "Transport::uploadCron: unknown state".
- " '{$row['state']}' (id={$row['id']})\n";
- } // switch state
- } // foreach opened
- $this->logoutFromArchive($asessid);
- return TRUE;
- }
-
- /**
- * Check state of uploaded file
- *
- * @param sessid
- * @param url
- * @return hash: md5h, size, url
- */
- function uploadCheck($sessid, $url)
- {
- $finf = $this->xmlrpcCall(
- 'archive.uploadCheck',
- array('sessid'=>$sessid, 'url'=>$url)
- );
- return $finf;
- }
-
- /**
- *
- */
- function downloadOpen($sessid, $type, $gunid, $uid)
- {
- // insert transport record to db
- $trid = $this->_createTrId();
- $id = $this->dbc->nextId("{$this->transTable}_id_seq");
- $res = $this->dbc->query("
- INSERT INTO {$this->transTable}
- (id, trid, direction, state, type,
- gunid, sessid, uid
- )
- VALUES
- ($id, '$trid', 'down', 'init', '$type',
- '$gunid', '$sessid', $uid
- )
- ");
- if(PEAR::isError($res)) return $res;
-#?? $this->downloadCron();
- return $trid;
- }
-
- /**
- *
- */
- function downloadCron(&$gb)
- {
- // fetch all opened downloads
- $rows = $this->dbc->getAll("
- SELECT * FROM {$this->transTable}
- WHERE direction='down' AND state<>'closed'
- ");
- if(count($rows)==0) return TRUE;
- $asessid = $this->loginToArchive();
- chdir($this->config['transDir']);
- // for all opened downloads:
- foreach($rows as $i=>$row){
- switch($row['state']){
- case"init": // ------ new downloads
- // call archive.downloadOpen
- $finf = $this->xmlrpcCall(
- 'archive.downloadOpen',
- array('sessid'=>$asessid, 'type'=>$row['type'],
- 'par'=>$row['gunid']
- )
- );
- if(PEAR::isError($finf)) return $finf;
- $res = $this->dbc->query("
- UPDATE {$this->transTable}
- SET state='pending', url='{$finf['url']}',
- md5h='{$finf['md5h']}', fname='{$finf['fname']}'
- WHERE id='{$row['id']}'
- ");
- if(PEAR::isError($res)) return $res;
- $row = array_merge($row, $finf);
-#break;
- case"pending": // ------ pending downloads
- // wget the file
- $res = system(
- "wget -q -c --timeout={$this->timeout}".
- " --waitretry={$this->waitretry}".
- " -t {$this->retries} {$row['url']}",
- $status
- );
- // check consistency
- $md5h = $this->_md5sum($row['fname']);
- if($status == 0){
- if($md5h == $row['md5h']){
- // mark download as finished
- $res = $this->dbc->query("
- UPDATE {$this->transTable}
- SET state='finished'
- WHERE id='{$row['id']}'
- ");
- if(PEAR::isError($res)) return $res;
- }else{
- @unlink($row['fname']);
- }
- }
-#break;
- case"finished": // ------ finished downloads
- // call archive that downloads have been finished OK
- $res = $this->xmlrpcCall(
- 'archive.downloadClose',
- array('sessid'=>$asessid, 'url'=>$row['url'])
- );
- if(PEAR::isError($res)) return $res;
- // process file in fake session
- $lsessid = $gb->_fakeSession($row['uid']);
- if(PEAR::isError($lsessid)) return $lsessid;
- $res = $gb->processTransported(
- $lsessid, $row['fname'], $row['type'], $row['gunid']
- );
- if(PEAR::isError($res)) return $res;
- $res = $gb->logout($lsessid);
- if(PEAR::isError($res)) return $res;
-
- // close download in db TODO: or delete record?
- $res = $this->dbc->query("
- UPDATE {$this->transTable}
- SET state='closed'
- WHERE id='{$row['id']}'
- ");
- if(PEAR::isError($res)) return $res;
- break;
- default:
- echo "Transport::downloadCron: unknown state".
- " '{$row['state']}' (id={$row['id']})\n";
- } // switch state
- } // foreach opened
- $this->logoutFromArchive($asessid);
- return TRUE;
- }
-
-
/* =============================================== authentication methods */
/**
@@ -380,10 +805,13 @@ class Transport{
/**
*
*/
- function _createTrId()
+ function _createTrtok()
{
- return md5(microtime().$_SERVER['SERVER_ADDR'].rand().
- "org.mdlf.livesupport");
+ $initString =
+ microtime().$_SERVER['SERVER_ADDR'].rand()."org.mdlf.livesupport";
+ $hash = md5($initString);
+ $res = substr($hash, 0, 16);
+ return $res;
}
/**
@@ -396,64 +824,120 @@ class Transport{
return $resDir;
}
+ /**
+ * Ping to archive server
+ *
+ * @return string sessid or error
+ */
+ function pingToArchive()
+ {
+ $res = $this->xmlrpcCall(
+ 'archive.ping',
+ array(
+ 'par'=>'testString_'.date('H:i:s')
+ )
+ );
+ return $res;
+ }
/**
* XMLRPC call to archive
*/
function xmlrpcCall($method, $pars=array())
{
- $xrp = xmlrpc_encoder($pars);
- $c = new xmlrpc_client(
+ $xrp = XML_RPC_encode($pars);
+ $c = new XML_RPC_Client(
"{$this->config['archiveUrlPath']}/".
"{$this->config['archiveXMLRPC']}",
$this->config['archiveUrlHost'], $this->config['archiveUrlPort']
);
- $f=new xmlrpcmsg($method, array($xrp));
+ $f=new XML_RPC_Message($method, array($xrp));
+ #echo "\n--\n".$f->serialize()."\n--\n";
$r = $c->send($f);
if ($r->faultCode()>0) {
return PEAR::raiseError($r->faultString(), $r->faultCode());
}else{
$v = $r->value();
- return xmlrpc_decoder($v);
+ return XML_RPC_decode($v);
}
}
/**
* md5 checksum of local file
*/
- function _md5sum($fpath)
+ function _chsum($fpath)
{
- $md5h = `md5sum $fpath`;
- $arr = split(' ', $md5h);
- return $arr[0];
+ return md5_file($fpath);
}
+ /**
+ * logging wrapper for PEAR error object
+ *
+ * @param eo PEAR error object
+ */
+ function trLogPear($eo, $row=NULL)
+ {
+ $msg = $eo->getMessage()." ".$eo->getUserInfo();
+ if(!is_null($row)) $msg .= "\n ".serialize($row);
+ $this->trLog($msg);
+ }
+
+ /**
+ * logging for debug transports
+ *
+ * @param msg string - log message
+ */
+ function trLog($msg)
+ {
+ $fp=fopen("{$this->transDir}/log", "a") or die("Can't write to log\n");
+ fputs($fp, "---".date("H:i:s")."---\n $msg\n");
+ fclose($fp);
+ }
+
/* ====================================================== install methods */
+ /**
+ * Delete all transports
+ */
+ function resetData()
+ {
+ return $this->dbc->query("DELETE FROM {$this->transTable}");
+ }
+
/**
* Install method
- * state: pending, finished, closed
+ *
+ * direction: up | down
+ * state: init | pending | finished | closed | failed
+ * trtype: audioclip | playlist | searchjob
+ *
*/
function install()
{
$this->dbc->query("CREATE TABLE {$this->transTable} (
id int not null,
- trid char(32) not null,
- direction varchar(128) not null, -- down | up
+ trtok char(16) not null, -- transport token
+ direction varchar(128) not null,
state varchar(128) not null,
- type varchar(128) not null, -- file | searchJob
- md5h char(32),
+ trtype varchar(128) not null,
+ gunid bigint, -- global unique id
+ pdtoken bigint, -- put/download token from archive
url varchar(255),
- fname varchar(255),
- gunid char(32),
- sessid char(32),
- uid int,
- parid int,
+ fname varchar(255), -- mnemonic filename
+ localfile varchar(255), -- pathname of local part
+ expectedsum char(32), -- expected file checksum
+ realsum char(32), -- checksum of transported part
+ expectedsize int, -- expected filesize in bytes
+ realsize int, -- filesize of transported part
+ uid int, -- local user id of transport owner
+ parid int, -- local id of download destination folder
ts timestamp
)");
$this->dbc->createSequence("{$this->transTable}_id_seq");
$this->dbc->query("CREATE UNIQUE INDEX {$this->transTable}_id_idx
ON {$this->transTable} (id)");
- $this->dbc->query("CREATE INDEX {$this->transTable}_trid_idx
- ON {$this->transTable} (trid)");
+ $this->dbc->query("CREATE UNIQUE INDEX {$this->transTable}_trtok_idx
+ ON {$this->transTable} (trtok)");
+ $this->dbc->query("CREATE UNIQUE INDEX {$this->transTable}_token_idx
+ ON {$this->transTable} (token)");
$this->dbc->query("CREATE INDEX {$this->transTable}_gunid_idx
ON {$this->transTable} (gunid)");
}
diff --git a/livesupport/modules/storageServer/var/cron/transportCron.php b/livesupport/modules/storageServer/var/cron/transportCron.php
index 2cfab1ed5..57679657a 100755
--- a/livesupport/modules/storageServer/var/cron/transportCron.php
+++ b/livesupport/modules/storageServer/var/cron/transportCron.php
@@ -1,5 +1,6 @@
#!/usr/bin/php -q
setFetchMode(DB_FETCHMODE_ASSOC);
$gb = &new LocStor(&$dbc, $config);
+$tr =& new Transport(&$dbc, &$gb, $config);
+$cnt = 1;
-$res = $gb->cronJob();
+#$res = $gb->cronJob();
+#var_dump($res);
-var_dump($res);
+for($i=0; $i<$cnt; $i++){
+ $r = $tr->uploadCron();
+ if(!$r) exit(1);
+}
+
+for($i=0; $i<$cnt; $i++){
+ $r = $tr->downloadCron();
+ if(!$r) exit(1);
+}
+
+exit(0);
?>
\ No newline at end of file
diff --git a/livesupport/modules/storageServer/var/xmlrpc/XR_LocStor.php b/livesupport/modules/storageServer/var/xmlrpc/XR_LocStor.php
index e93047dff..84e11e766 100644
--- a/livesupport/modules/storageServer/var/xmlrpc/XR_LocStor.php
+++ b/livesupport/modules/storageServer/var/xmlrpc/XR_LocStor.php
@@ -23,7 +23,7 @@
Author : $Author: tomas $
- Version : $Revision: 1.8 $
+ Version : $Revision: 1.9 $
Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/xmlrpc/XR_LocStor.php,v $
------------------------------------------------------------------------------*/
@@ -188,7 +188,7 @@ class XR_LocStor extends LocStor{
*