diff --git a/livesupport/modules/storageServer/var/BasicStor.php b/livesupport/modules/storageServer/var/BasicStor.php new file mode 100644 index 000000000..5d887b80c --- /dev/null +++ b/livesupport/modules/storageServer/var/BasicStor.php @@ -0,0 +1,1050 @@ +config = $config; + $this->filesTable = $config['tblNamePrefix'].'files'; + $this->mdataTable = $config['tblNamePrefix'].'mdata'; + $this->accessTable= $config['tblNamePrefix'].'access'; + $this->storageDir = $config['storageDir']; + $this->bufferDir = $config['bufferDir']; + $this->transDir = $config['transDir']; + $this->accessDir = $config['accessDir']; + $this->dbc->setErrorHandling(PEAR_ERROR_RETURN); + $this->rootId = $this->getRootNode(); + $this->storId = $this->wd = + $this->getObjId('StorageRoot', $this->rootId); + $this->dbc->setErrorHandling(); + } + + /** + * Create new folder + * + * @param parid int, parent id + * @param folderName string, name for new folder + * @return id of new folder + * @exception PEAR::error + */ + function bsCreateFolder($parid, $folderName) + { + return $this->addObj($folderName , 'Folder', $parid); + } + + /** + * Store new file in the storage + * + * @param parid int, parent id + * @param fileName string, name for new file + * @param mediaFileLP string, local path of media file + * @param mdataFileLP string, local path of metadata file + * @param gunid string, global unique id OPTIONAL + * @return int + * @exception PEAR::error + */ + function bsPutFile($parid, $fileName, + $mediaFileLP, $mdataFileLP, $gunid=NULL) + { + $name = "$fileName"; + $id = $this->addObj($name , 'File', $parid); + $ac =& StoredFile::insert( + &$this, $id, $name, $mediaFileLP, $mdataFileLP, 'file', $gunid + ); + if(PEAR::isError($ac)) return $ac; + return $id; + } + + /** + * Analyze media file for internal metadata information + * + * @param id int, virt.file's local id + * @return array + */ + function bsAnalyzeFile($id) + { + $ac =& StoredFile::recall(&$this, $id); + if(PEAR::isError($ac)) return $ac; + $ia = $ac->analyzeMediaFile(); + return $ia; + } + + /** + * Rename file + * + * @param id int, virt.file's local id + * @param newName string + * @return boolean or PEAR::error + */ + function bsRenameFile($id, $newName) + { + $parid = $this->getParent($id); + $ac =& StoredFile::recall(&$this, $id); + if(PEAR::isError($ac)){ + // catch nonerror exception: + if($ac->getCode() != GBERR_FOBJNEX) return $ac; + } + $res = $ac->rename($newName); + if(PEAR::isError($res)) return $res; + return $this->renameObj($id, $newName); + } + + /** + * Move file + * + * @param id int, virt.file's local id + * @param did int, destination folder local id + * @return boolean or PEAR::error + */ + function bsMoveFile($id, $did) + { + if($this->getObjType($did) !== 'Folder') + return PEAR::raiseError( + 'BasicStor::moveFile: destination is not folder', GBERR_WRTYPE + ); + $this->_relocateSubtree($id, $did); + } + + /** + * Copy file + * + * @param id int, virt.file's local id + * @param did int, destination folder local id + * @return boolean or PEAR::error + */ + function bsCopyFile($id, $did) + { + if($this->getObjType($did)!=='Folder') + return PEAR::raiseError( + 'GreenBox::copyFile: destination is not folder', GBERR_WRTYPE + ); + return $this->_copySubtree($id, $did); + } + + /** + * Delete file + * + * @param id int, virt.file's local id + * @return true or PEAR::error + */ + function bsDeleteFile($id) + { + $parid = $this->getParent($id); + $res = $this->removeObj($id); + if(PEAR::isError($res)) return $res; + return TRUE; + } + + /* ----------------------------------------------------- put, access etc. */ + /** + * Check validity of asscess/put token + * + * @param token string, access/put token + * @param type string 'put'|'access'|'download' + * @return boolean + */ + function bsCheckToken($token, $type='put') + { + $cnt = $this->dbc->getOne(" + SELECT count(token) FROM {$this->accessTable} + WHERE token='{$token}' AND type='$type' + "); + if(PEAR::isError($cnt)){ return FALSE; } + return ($cnt == 1); + } + + /** + * Create and return access link to media file + * + * @param realFname string, local filepath to accessed file + * @param ext string, useful filename extension for accessed file + * @param gunid int, global unique id + * @param sessid string, session id + * @param type string 'access'|'download' + * @return array with: seekable filehandle, access token + */ + function bsAccess($realFname, $ext, $gunid, $sessid='', $type='access') + { + $token = StoredFile::_createGunid(); + $res = $this->dbc->query(" + INSERT INTO {$this->accessTable} + (gunid, sessid, token, ext, type, ts) + VALUES + ('{$gunid}', '$sessid', '$token', '$ext', '$type', now()) + "); + if(PEAR::isError($res)){ return $res; } + $linkFname = "{$this->accessDir}/$token.$ext"; + + if(!file_exists($realFname)){ + return PEAR::raiseError( + "BasicStor::bsAccess: symlink create failed ($accLinkName)", + GBERR_FILEIO); + } + if(! @symlink($realFname, $linkFname)){ + return PEAR::raiseError( + "BasicStor::bsAccess: symlink create failed ($linkFname)", + GBERR_FILEIO); + } + return array('fname'=>$linkFname, 'token'=>$token); + } + + /** + * Release access link to media file + * + * @param token string, access token + * @param type string 'access'|'download' + * @return boolean + */ + function bsRelease($token, $type='access') + { + if(!$this->bsCheckToken($token, $type)){ + return PEAR::raiseError( + "BasicStor::bsRelease: invalid token ($token)" + ); + } + $ext = $this->dbc->getOne(" + SELECT ext FROM {$this->accessTable} + WHERE token='{$token}' AND type='$type' + "); + if(PEAR::isError($ext)){ return $ext; } + $linkFname = "{$this->accessDir}/$token.$ext"; + $res = $this->dbc->query(" + DELETE FROM {$this->accessTable} WHERE token='$token' + "); + if(PEAR::isError($res)){ return $res; } + if(! @unlink($linkFname)){ + return PEAR::raiseError( + "BasicStor::bsRelease: unlink failed ($linkFname)", + GBERR_FILEIO); + } + return TRUE; + } + + /** + * Create and return downloadable URL for file + * + * @param id int, virt.file's local id + * @param part string, 'media'|'metadata' + * @return array with: downloadable URL, download token + */ + function bsOpenDownload($id, $part='media') + { + $ac =& StoredFile::recall(&$this, $id); + if(PEAR::isError($ac)) return $ac; + $gunid = $ac->gunid; + switch($part){ + case"media": + $fname = $ac->_getRealRADFname(); + $ext = $ac->_getExt(); + break; + case"metadata": + $md = $this->bsGetMdata($id); + $fname = "{$this->bufferDir}/$gunid"; + $e = FALSE; + if(!$fh = fopen($fname, "w")){ $e = TRUE; } + elseif(fwrite($fh, $md) === FALSE){ $e = TRUE; } + if($e){ + return PEAR::raiseError( + "BasicStor::bsOpenDownload: can't write ($fname)", + GBERR_FILEIO); + } + fclose($fh); + $ext = "xml"; + break; + } + $sessid = ''; + $acc = $this->bsAccess($fname, $ext, $gunid, $sessid, 'download'); + $url = $this->getUrlPart()."access/".basename($acc['fname']); + return array('url'=>$url, 'token'=>$acc['token']); + } + + /** + * Discard downloadable URL + * + * @param token string, download token + * @param part string, 'media'|'metadata' + * @return boolean + */ + function bsCloseDownload($token, $part='media') + { + if($part == 'metadata'){ + $gunid = $this->dbc->getOne(" + SELECT gunid FROM {$this->accessTable} + WHERE token='{$token}' AND type='download' + "); + if(PEAR::isError($gunid)){ return $gunid; } + $fname = "{$this->bufferDir}/$gunid"; + @unlink($fname); + } + return $this->bsRelease($token, 'download'); + } + + /** + * Create writable URL for HTTP PUT method file insert + * + * @param chsum string, md5sum of the file having been put + * @param gunid string, global unique id + * @return array with: writable URL, PUT token + */ + function bsOpenPut($chsum, $gunid) + { + $sessid = ''; + $ext = ''; + $token = StoredFile::_createGunid(); + $res = $this->dbc->query(" + INSERT INTO {$this->accessTable} + (gunid, sessid, token, ext, chsum, type, ts) + VALUES + ('{$gunid}', '$sessid', '$token', + '$ext', '$chsum', 'put', now()) + "); + if(PEAR::isError($res)){ return $res; } + $fname = "{$this->accessDir}/$token"; + touch($fname); // is it needed? + $url = $this->getUrlPart()."xmlrpc/put.php?token=$token"; + return array('url'=>$url, 'token'=>$token); + } + + /** + * Get file from writable URL and insert it to the storage + * + * @param token string, PUT token + * @return string, local path of the file having been put + */ + function bsClosePut($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='{$token}' + "); + $fname = "{$this->accessDir}/$token"; + $md5sum = md5_file($fname); + if($chsum != $md5sum){ + return PEAR::raiseError( + 'BasicStor::bsClosePut: md5sum does not match (token=$token)' + ); + } + $res = $this->dbc->query(" + DELETE FROM {$this->accessTable} WHERE token='$token' + "); + if(PEAR::isError($res)){ return $res; } + return $fname; + } + + /** + * Return starting part of storageServer URL + * + * @return string, url + */ + function getUrlPart() + { + $host = $this->config['storageUrlHost']; + $port = $this->config['storageUrlPort']; + $path = $this->config['storageUrlPath']; + return "http://$host:$port$path/"; + } + + /* ---------------------------------------------- replicas, versions etc. */ + /** + * Create replica.
+ * TODO: NOT FINISHED + * + * @param id int, virt.file's local id + * @param did int, destination folder local id + * @param replicaName string, name of new replica + * @return int, local id of new object + */ + function bsCreateReplica($id, $did, $replicaName) + { + return PEAR::raiseError( + 'GreenBox::createVersion: not implemented', GBERR_NOTIMPL + ); + // --- + if($this->getObjType($did)!=='Folder') + return PEAR::raiseError( + 'GreenBox::createReplica: dest is not folder', GBERR_WRTYPE + ); + if($replicaName=='') $replicaName = $this->getObjName($id); + while(($exid = $this->getObjId($replicaName, $did))<>'') + { $replicaName.='_R'; } + $rid = $this->addObj($replicaName , 'Replica', $did, 0, $id); + if(PEAR::isError($rid)) return $rid; +# $this->addMdata($this->_pathFromId($rid), 'isReplOf', $id, $sessid); + return $rid; + } + + /** + * Create version.
+ * TODO: NOT FINISHED + * + * @param id int, virt.file's local id + * @param did int, destination folder local id + * @param versionLabel string, name of new version + * @return int, local id of new object + */ + function bsCreateVersion($id, $did, $versionLabel) + { + return PEAR::raiseError( + 'GreenBox::createVersion: not implemented', GBERR_NOTIMPL + ); + } + + /* ------------------------------------------------------------- metadata */ + + /** + * Update metadata tree + * + * @param id int, virt.file's local id + * @param mdataFile string, local path of metadata XML file + * @return boolean or PEAR::error + */ + function bsUpdateMetadata($id, $mdataFile) + { + $ac =& StoredFile::recall(&$this, $id); + if(PEAR::isError($ac)) return $ac; + return $ac->updateMetaData($mdataFile); + } + + /** + * Update object namespace and value of one metadata record + * + * @param id int, virt.file's local id + * @param mdid int, metadata record id + * @param object string, object value, e.g. title string + * @param objns string, object namespace prefix, have to be defined + * in file's metadata (or reserved prefix) + * @return boolean or PEAR::error + * @see MetaData + */ + function bsUpdateMetadataRecord($id, $mdid, $object, $objns='_L') + { + $ac =& StoredFile::recall(&$this, $id); + if(PEAR::isError($ac)) return $ac; + return $ac->updateMetaDataRecord($mdid, $object, $objns); + } + + /** + * Add single metadata record.
+ * TODO: NOT FINISHED
+ * Params could be changed! + * + * @param id int, virt.file's local id + * @param propertyName string + * @param propertyValue string + * @return boolean or PEAR::error + * @see MetaData + */ + function bsAddMetaDataRecord($id, $propertyName, $propertyValue) + { + return PEAR::raiseError( + 'GreenBox::addMetaDataRecord: not implemented', GBERR_NOTIMPL + ); + } + + /** + * Get metadata XML tree as string + * + * @param id int, virt.file's local id + * @return string or PEAR::error + */ + function bsGetMdata($id) + { + $ac =& StoredFile::recall(&$this, $id); + if(PEAR::isError($ac)) return $ac; + return $ac->getMetaData(); + } + + /** + * Search in local metadata database.
+ * TODO: NOT FINISHED
+ * It will support structured queries - array of mode and query parts. + * Mode is "match all" or "match any". + * Query parts is array of [fieldname, operator, value] entities. + * + * @param searchData string, search query - + * only one SQL LIKE term supported now. + * It will be searched in all literal object values + * in metadata database + * @return array of gunid strings + */ + function bsLocalSearch($searchData) + { + $ftsrch = $searchData; + $res = $this->dbc->getCol("SELECT md.gunid as gunid + FROM {$this->filesTable} f, {$this->mdataTable} md + WHERE f.gunid=md.gunid AND md.objns='_L' AND + md.object like '%$ftsrch%' + GROUP BY md.gunid + "); + if(!is_array($res)) $res = array(); + return $res; + } + + /* --------------------------------------------------------- info methods */ + + /** + * List files in folder + * + * @param id int, local id of folder + * @return array + */ + function bsListFolder($id) + { + if($this->getObjType($id)!=='Folder') + return PEAR::raiseError( + 'GreenBox::listFolder: not a folder', GBERR_NOTF + ); + $a = $this->getDir($id, 'id, name, type, param as target', 'name'); + return $a; + } + + /** + * List files in folder + * + * @param id int, local id of object + * @param relPath string, relative path + * @return array + */ + function getObjIdFromRelPath($id, $relPath='.') + { + $a = split('/', $relPath); + if($this->getObjType($id)!=='Folder') $nid = $this->getparent($id); + else $nid = $id; + foreach($a as $i=>$item){ + switch($item){ + case".": + break; + case"..": + $nid = $this->getparent($nid); + break; + case"": + break; + default: + $nid = $this->getObjId($item, $nid); + } + } + return $nid; + } + + + + + /* -------------------------------------------- remote repository methods */ + + /** + * Upload file to remote repository + * + * @param id int, virt.file's local id + * @param gunid string, global id + * @param sessid string, session id + * @return string - transfer id or PEAR::error + */ + function uploadFile($id, $gunid, $sessid='') + { + $res = $this->prepareForTransport($id, $gunid, $sessid); + if(PEAR::isError($res)) return $res; + list($mediaFile, $mdataFile, $gunid) = $res; + $tr =& new Transport(&$this->dbc, $this->config); + $res = $tr->uploadOpen($mediaFile, 'media', $sessid, $gunid); + if(PEAR::isError($res)) return $res; + $res2 = $tr->uploadOpen($mdataFile, 'metadata', $sessid, $gunid); + if(PEAR::isError($res2)) return $res2; + $res3 = $tr->getTransportStatus($res); + $res4 = $tr->getTransportStatus($res2); +# return $res; + return array($res, $res2, $res3, $res4); + } + + /** + * Download file from remote repository + * + * @param gunid int, global unique id + * @param sessid string, session id + * @return string - transfer id or PEAR::error + */ + function downloadFile($gunid, $sessid='') + { + $tr =& new Transport(&$this->dbc, $this->config); + // get home dir if needed + $res = $tr->downloadOpen($sessid, 'media', $gunid, + $this->getSessUserId($sessid) + ); + if(PEAR::isError($res)) return $res; + $res2 = $tr->downloadOpen($sessid, 'metadata', $gunid, + $this->getSessUserId($sessid) + ); + if(PEAR::isError($res)) return $res; + $res3 = $tr->getTransportStatus($res); + $res4 = $tr->getTransportStatus($res2); +# return $res; + return array($res, $res2, $res3, $res4); + } + + + + /** + * Method for handling interupted transports via cron + * + */ + function cronJob() + { + $tr =& new Transport(&$this->dbc, $this->config); + $ru = $tr->uploadCron(); + $rd = $tr->downloadCron(&$this); + return array($ru, $rd); + } + + /** + * Get status of asynchronous transfer + * + * @param transferId int, id of asynchronous transfer + * returned by uploadFile or downloadFile methods + * @param sessid string, session id + * @return string or PEAR::error + */ + function getTransferStatus($transferId, $sessid='') + { + return PEAR::raiseError( + 'GreenBox::getTransferStatus: not implemented', GBERR_NOTIMPL + ); + } + + /** + * Prepare symlink to media file and create metadata file for transport + * + * @param id + * @param gunid + * @param sessid + * @return array + */ + function prepareForTransport($id, $gunid, $sessid='') + { + if(!$gunid) $gunid = $this->_gunidFromId($id); + else $id = $this->_idFromGunid($gunid); + $ac =& StoredFile::recallByGunid(&$this, $gunid); + if(PEAR::isError($ac)) return $ac; + $mediaTarget = $ac->_getRealRADFname(); + $mediaFile = "$gunid"; + $mdataFile = "$gunid.xml"; + @symlink($mediaTarget, $this->transDir."/$mediaFile"); + $mdata = $this->getMdata($id, $sessid); + if(PEAR::isError($mdata)) return $mdata; + if(!($fh = fopen($this->transDir."/$mdataFile", 'w'))) $res=FALSE; + else{ + $res = fwrite($fh, $mdata); + fclose($fh); + } + if($res === FALSE) return PEAR::raiseError( + "GreenBox::prepareForTransport:". + " can't write metadata tmp file ($mdataFile)" + ); + return array($mediaFile, $mdataFile, $gunid); + } + + /** + * Insert transported file and metadata into storage.
+ * TODO: cals methods from LocStor - it's not good + * + * @param sessid string - session id + * @param file string - local path to filr + * @param type string - media|metadata|search + * @param gunid string - global unique id + */ + function processTransported($sessid, $file, $type, $gunid='X') + { + switch($type){ + case 'media': + if(!file_exists($file)) break; + $res = $this->storeAudioClip($sessid, $gunid, + $file, ''); + if(PEAR::isError($res)) return $res; + @unlink($file); + break; + case 'metadata': + case 'mdata': + if(!file_exists($file)) break; + $res = $this->updateAudioClipMetadata($sessid, $gunid, + $file); + if(PEAR::isError($res)){ + // catch valid exception + if($res->getCode() == GBERR_FOBJNEX){ + $res2 = $this->storeAudioClip($sessid, $gunid, + '', $file); + if(PEAR::isError($res2)) return $res2; + }else return $res; + } + @unlink($file); + break; + case 'search': + //$this->localSearch($criteria); + return PEAR::raiseError("processTranferred: search not implemented"); + break; + default: + return PEAR::raiseError("processTranferred: unknown type ($type)"); + break; + } + } + + /** + * Search in central metadata database + * + * @param searchData string, search query - see localSearch method + * @param sessid string, session id + * @return string - job id or PEAR::error + */ + function globalSearch($searchData, $sessid='') + { + return PEAR::raiseError( + 'GreenBox::globalSearch: not implemented', GBERR_NOTIMPL + ); + /* + $srchid = md5($sessid.mtime()); + $fh = fopen($this->transDir."/$srchid", "w"); + fwrite($fh, serialize($searchData)); + fclose($fh); + $res = $tr->uploadOpen($srchid, 'search', $sessid, $gunid); + if(PEAR::isError($res)) return $res; + return $res; + */ + } + + /** + * Get results from asynchronous search + * + * @param transferId int, transfer id returned by + * @param sessid string, session id + * @return array with results or PEAR::error + */ + function getSearchResults($transferId, $sessid='') + { + return PEAR::raiseError( + 'GreenBox::getSearchResults: not implemented', GBERR_NOTIMPL + ); + } + + /* =============================================== test and debug methods */ + /** + * dump + * + */ + function dump($id='', $indch=' ', $ind='', $format='{name}') + { + if($id=='') $id = $this->storId; + return parent::dump($id, $indch, $ind, $format); + } + + /** + * + * + */ + function dumpDir($id='', $format='$o["name"]') + { + if($id=='') $id = $this->storId; + $arr = $this->getDir($id, 'id,name'); +// if($this->doDebug){ $this->debug($arr); exit; } + $arr = array_map(create_function('$o', 'return "'.$format.'";'), $arr); + return join('', $arr); + } + + /** + * + * + */ + function debug($va) + { + echo"
\n"; print_r($va); #exit;
+    }
+
+    /**
+     *  deleteData
+     *
+     *  @return void
+     */
+    function deleteData()
+    {
+//        $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->removeObj($item['id']);
+        }
+        parent::deleteData();
+        $this->initData();
+    }
+    /**
+     *  testData
+     *
+     */
+    function testData($d='')
+    {
+        $exdir = '../../../storageServer/var/tests';
+        $o[] = $this->addSubj('test1', 'a');
+        $o[] = $this->addSubj('test2', 'a');
+        $o[] = $this->addSubj('test3', 'a');
+        $o[] = $this->addSubj('test4', 'a');
+
+        $o[] = $t1hd = $this->getObjId('test1', $this->storId);
+        $o[] = $t1d1 = $this->bsCreateFolder($t1hd, 'test1_folder1');
+        $o[] = $this->bsCreateFolder($t1hd, 'test1_folder2');
+        $o[] = $this->bsCreateFolder($t1d1, 'test1_folder1_1');
+        $o[] = $t1d12 = $this->bsCreateFolder($t1d1, 'test1_folder1_2');
+
+        $o[] = $t2hd = $this->getObjId('test2', $this->storId);
+        $o[] = $this->bsCreateFolder($t2hd, 'test2_folder1');
+
+        $o[] = $this->bsPutFile($t1hd, 'file1.mp3', "$exdir/ex1.mp3", '');
+        $o[] = $this->bsPutFile($t1d12, 'file2.wav', "$exdir/ex2.wav", '');
+/*
+*/
+        $this->tdata['storage'] = $o;
+    }
+
+    /**
+     *  test
+     *
+     */
+    function test()
+    {
+//        if(PEAR::isError($p = parent::test())) return $p;
+        $this->deleteData();
+        $this->testData();
+        $this->test_correct = "    StorageRoot
+        root
+        test1
+            test1_folder1
+                test1_folder1_1
+                test1_folder1_2
+                    file2.wav
+            test1_folder2
+            file1.mp3
+        test2
+            test2_folder1
+        test3
+        test4
+";
+        $this->test_dump = $this->dumpTree($this->storId);
+        if($this->test_dump==$this->test_correct)
+            { $this->test_log.="storageServer: OK\n"; return true; }
+        else PEAR::raiseError('GreenBox::test:', 1, PEAR_ERROR_DIE, '%s'.
+            "
\ncorrect:\n.{$this->test_correct}.\n".
+            "dump:\n.{$this->test_dump}.\n
\n"); + } + + /** + * initData - initialize + * + */ + function initData() + { + $this->rootId = $this->getRootNode(); + $this->storId = $this->wd = + $this->addObj('StorageRoot', 'Folder', $this->rootId); + $rootUid = parent::addSubj('root', $this->config['tmpRootPass']); + $res = $this->addPerm($rootUid, '_all', $this->rootId, 'A'); + $fid = $this->bsCreateFolder($this->storId, 'root'); + } + /** + * install - create tables + * + * file states: + * + */ + function install() + { + parent::install(); + $this->dbc->query("CREATE TABLE {$this->filesTable} ( + id int not null, + gunid char(32) not null, -- global unique ID + name varchar(255) not null default'', -- human file id ;) + type varchar(255) not null default'', -- mime type + state varchar(128) not null default'empty', -- file state + currentlyAccessing int not null default 0 -- access counter + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->filesTable}_id_idx + ON {$this->filesTable} (id)"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->filesTable}_gunid_idx + ON {$this->filesTable} (gunid)"); + $this->dbc->query("CREATE INDEX {$this->filesTable}_name_idx + ON {$this->filesTable} (name)"); + + $this->dbc->createSequence("{$this->mdataTable}_id_seq"); + $this->dbc->query("CREATE TABLE {$this->mdataTable} ( + id int not null, + gunid char(32), + subjns varchar(255), -- subject namespace shortcut/uri + subject varchar(255) not null default '', + predns varchar(255), -- predicate namespace shortcut/uri + predicate varchar(255) not null, + predxml char(1) not null default 'T', -- Tag or Attribute + objns varchar(255), -- object namespace shortcut/uri + object text + )"); + $this->dbc->query("CREATE UNIQUE INDEX {$this->mdataTable}_id_idx + ON {$this->mdataTable} (id)"); + $this->dbc->query("CREATE INDEX {$this->mdataTable}_gunid_idx + ON {$this->mdataTable} (gunid)"); + $this->dbc->query("CREATE INDEX {$this->mdataTable}_subj_idx + ON {$this->mdataTable} (subjns, subject)"); + $this->dbc->query("CREATE INDEX {$this->mdataTable}_pred_idx + ON {$this->mdataTable} (predns, predicate)"); + + $this->dbc->query("CREATE TABLE {$this->accessTable} ( + gunid char(32) not null default'', + sessid char(32) not null default'', + token char(32) not null default'', + chsum char(32) not null default'', + ext varchar(128) not null default'', + type varchar(20) not null default'', + ts timestamp + )"); + $this->dbc->query("CREATE INDEX {$this->accessTable}_token_idx + ON {$this->accessTable} (token)"); + $this->dbc->query("CREATE INDEX {$this->accessTable}_gunid_idx + ON {$this->accessTable} (gunid)"); + if(!file_exists($this->bufferDir)){ + mkdir($this->bufferDir, 02775); + chmod($this->bufferDir, 02775); // may be obsolete + } + $this->initData(); + } + /** + * id subjns subject predns predicate objns object + * y1 literal xmbf NULL namespace literal http://www.sotf.org/xbmf + * x1 gunid xbmf contributor NULL NULL + * x2 mdid x1 xbmf role literal Editor + * + * predefined shortcuts: + * _L = literal + * _G = gunid (global id of media file) + * _I = mdid (local id of metadata record) + * _nssshortcut = namespace shortcut definition + * _blank = blank node + */ + + /** + * uninstall + * + * @return void + */ + function uninstall() + { + $this->dbc->query("DROP TABLE {$this->mdataTable}"); + $this->dbc->dropSequence("{$this->mdataTable}_id_seq"); + $this->dbc->query("DROP TABLE {$this->filesTable}"); + $this->dbc->query("DROP TABLE {$this->accessTable}"); + $d = dir($this->storageDir); + while (is_object($d) && (false !== ($entry = $d->read()))){ + if(filetype("{$this->storageDir}/$entry")=='dir' && + $entry!='CVS' && strlen($entry)==3) + { + $dd = dir("{$this->storageDir}/$entry"); + while (false !== ($ee = $dd->read())){ + if(substr($ee, 0, 1)!=='.') + unlink("{$this->storageDir}/$entry/$ee"); + } + $dd->close(); + rmdir("{$this->storageDir}/$entry"); + } + } + if(is_object($d)) $d->close(); + if(file_exists($this->bufferDir)){ + $d = dir($this->bufferDir); + while (false !== ($entry = $d->read())) if(substr($entry,0,1)!='.') + { unlink("{$this->bufferDir}/$entry"); } + $d->close(); + rmdir($this->bufferDir); + } + parent::uninstall(); + } + + /** + * Aux logging for debug + * + * @param msg string - log message + */ + function debugLog($msg) + { + $fp=fopen("{$this->storageDir}/log", "a") or die("Can't write to log\n"); + fputs($fp, date("H:i:s").">$msg<\n"); + fclose($fp); + } + +} +?> \ No newline at end of file diff --git a/livesupport/modules/storageServer/var/GreenBox.php b/livesupport/modules/storageServer/var/GreenBox.php index 848e0ccf7..1ade2ce4f 100644 --- a/livesupport/modules/storageServer/var/GreenBox.php +++ b/livesupport/modules/storageServer/var/GreenBox.php @@ -23,24 +23,11 @@ Author : $Author: tomas $ - Version : $Revision: 1.10 $ + Version : $Revision: 1.11 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/GreenBox.php,v $ ------------------------------------------------------------------------------*/ -define('GBERR_DENY', 40); -define('GBERR_FILEIO', 41); -define('GBERR_FILENEX', 42); -define('GBERR_FOBJNEX', 43); -define('GBERR_WRTYPE', 44); -define('GBERR_NONE', 45); -define('GBERR_AOBJNEX', 46); -define('GBERR_NOTF', 47); - -define('GBERR_NOTIMPL', 50); - -require_once "../../../alib/var/alib.php"; -require_once "StoredFile.php"; -require_once "Transport.php"; +require_once "BasicStor.php"; /** * GreenBox class @@ -48,47 +35,13 @@ require_once "Transport.php"; * LiveSupport file storage module * * @author $Author: tomas $ - * @version $Revision: 1.10 $ - * @see Alib + * @version $Revision: 1.11 $ + * @see BasicStor */ -class GreenBox extends Alib{ - var $filesTable; - var $mdataTable; - var $accessTable; - var $storageDir; - var $bufferDir; - var $accessDir; - var $rootId; - var $storId; - var $doDebug = true; - /** - * Constructor - * - * @param dbc PEAR::db abstract class reference - * @param config config array from conf.php - * @return class instance - */ - function GreenBox(&$dbc, $config) - { - parent::Alib(&$dbc, $config); - $this->config = $config; - $this->filesTable = $config['tblNamePrefix'].'files'; - $this->mdataTable = $config['tblNamePrefix'].'mdata'; - $this->accessTable= $config['tblNamePrefix'].'access'; - $this->storageDir = $config['storageDir']; - $this->bufferDir = $config['bufferDir']; - $this->transDir = $config['transDir']; - $this->accessDir = $config['accessDir']; - $this->dbc->setErrorHandling(PEAR_ERROR_RETURN); - $this->rootId = $this->getRootNode(); - $this->storId = $this->wd = - $this->getObjId('StorageRoot', $this->rootId); - $this->dbc->setErrorHandling(); - } +class GreenBox extends BasicStor{ - /* ======================================================= public methods */ - + /** * Create new folder * @@ -102,7 +55,7 @@ class GreenBox extends Alib{ { if(($res = $this->_authorize('write', $parid, $sessid)) !== TRUE) return $res; - return $this->addObj($folderName , 'Folder', $parid); + return $this->bsCreateFolder($parid, $folderName , 'Folder', $parid); } /** @@ -122,38 +75,9 @@ class GreenBox extends Alib{ { if(($res = $this->_authorize('write', $parid, $sessid)) !== TRUE) return $res; - $name = "$fileName"; - $id = $this->addObj($name , 'File', $parid); - $ac =& StoredFile::insert( - &$this, $id, $name, $mediaFileLP, $mdataFileLP, $gunid + return $this->bsPutFile( + $parid, $fileName, $mediaFileLP, $mdataFileLP, $gunid ); - if(PEAR::isError($ac)) return $ac; - return $id; - } - - /** - * Return raw media file.
- * will be probably removed from API
- * see access() method - * - * @param id int, virt.file's local id - * @param sessid string, session id - * @return file - */ - function getFile($id, $sessid='') - { - return PEAR::raiseError( - 'GreenBox::getFile: probably obsolete API function'); - if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE) - return $res; - $ac =& StoredFile::recall(&$this, $id); - if(PEAR::isError($ac)) return $ac; - else{ - $fname = $ac->accessRawMediaData(); -# readfile($fname); - return join('', file($fname)); - $fname = $ac->releaseRawMediaData(); - } } /** @@ -165,53 +89,11 @@ class GreenBox extends Alib{ */ function analyzeFile($id, $sessid='') { - $ac =& StoredFile::recall(&$this, $id); - if(PEAR::isError($ac)) return $ac; - else{ -# echo"
\n"; print_r($ac); exit;
-            $ia = $ac->analyzeMediaFile();
-            return $ia;
-        }
+        if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE)
+            return $res;
+        return $this->bsAnalyzeFile($id);
     }
     
-    /**
-     *  Create and return access link to media file
-     *
-     *  @param id int, virt.file's local id
-     *  @param sessid string, session id
-     *  @return filename as string or PEAR::error
-     */
-    function access($id, $sessid='')
-    {
-        if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE)
-            return $res;
-        $ac =& StoredFile::recall(&$this, $id);
-        if(PEAR::isError($ac)) return $ac;
-        else{
-            $fname = $ac->accessRawMediaData($sessid);
-            return $fname;
-        }
-    }
-
-    /**
-     *  Release access link to media file
-     *
-     *  @param id int, virt.file's local id
-     *  @param sessid string, session id
-     *  @return boolean or PEAR::error
-     */
-    function release($id, $sessid='')
-    {
-        if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE)
-            return $res;
-        $ac =& StoredFile::recall(&$this, $id);
-        if(PEAR::isError($ac)) return $ac;
-        else{
-            $res = $ac->releaseRawMediaData($sessid);
-            return $res;
-        }
-    }
-
     /**
      *  Rename file
      *
@@ -225,15 +107,7 @@ class GreenBox extends Alib{
         $parid = $this->getParent($id);
         if(($res = $this->_authorize('write', $parid, $sessid)) !== TRUE)
             return $res;
-        $ac =& StoredFile::recall(&$this, $id);
-        if(PEAR::isError($ac)){
-            // catch nonerror exception:
-            if($ac->getCode() != GBERR_FOBJNEX) return $ac;
-        }else{
-            $res = $ac->rename($newName);
-            if(PEAR::isError($res)) return $res;
-        }
-        return $this->renameObj($id, $newName);
+        return $this->bsRenameFile($id, $newName);
     }
 
     /**
@@ -246,14 +120,10 @@ class GreenBox extends Alib{
      */
     function moveFile($id, $did, $sessid='')
     {
-        if($this->getObjType($did) !== 'Folder')
-            return PEAR::raiseError(
-                'GreenBox::moveFile: destination is not folder', GBERR_WRTYPE
-            );
         if(($res = $this->_authorize(
             array('read', 'write'), array($id, $did), $sessid
         )) !== TRUE) return $res;
-        $this->_relocateSubtree($id, $did);
+        return $this->bsMoveFile($id, $did);
     }
 
     /**
@@ -266,14 +136,10 @@ class GreenBox extends Alib{
      */
     function copyFile($id, $did, $sessid='')
     {
-        if($this->getObjType($did)!=='Folder')
-            return PEAR::raiseError(
-                'GreenBox::copyFile: destination is not folder', GBERR_WRTYPE
-            );
         if(($res = $this->_authorize(
             array('read', 'write'), array($id, $did), $sessid
         )) !== TRUE) return $res;
-        return $this->_copySubtree($id, $did);
+        return $this->bsCopyFile($id, $did);
     }
 
     /**
@@ -288,13 +154,41 @@ class GreenBox extends Alib{
         $parid = $this->getParent($id);
         if(($res = $this->_authorize('write', $parid, $sessid)) !== TRUE)
             return $res;
-        $res = $this->removeObj($id);
-        if(PEAR::isError($res)) return $res;
-        return TRUE;
+        return $this->bsDeleteFile($id);
+    }
+
+    /* ----------------------------------------------------- put, access etc. */
+    /**
+     *  Create and return access link to media file
+     *
+     *  @param id int, virt.file's local id
+     *  @param sessid string, session id
+     *  @return array with: seekable filehandle, access token
+     */
+    function access($id, $sessid='')
+    {
+        $ac =& StoredFile::recall(&$this, $id);
+        if(PEAR::isError($ac)) return $ac;
+        if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE)
+            return $res;
+        return $ac->accessRawMediaData($sessid);
+    }
+
+    /**
+     *  Release access link to media file
+     *
+     *  @param sessid string, session id
+     *  @param token string, access token
+     *  @return boolean or PEAR::error
+     */
+    function release($token, $sessid='')
+    {
+        $ac =& StoredFile::recallByToken(&$this, $token);
+        if(PEAR::isError($ac)) return $ac;
+        return $ac->releaseRawMediaData($sessid, $token);
     }
 
     /* ---------------------------------------------- replicas, versions etc. */
-
     /**
      *  Create replica.
* TODO: NOT FINISHED @@ -307,24 +201,10 @@ class GreenBox extends Alib{ */ function createReplica($id, $did, $replicaName='', $sessid='') { - return PEAR::raiseError( - 'GreenBox::createVersion: not implemented', GBERR_NOTIMPL - ); - // --- - if($this->getObjType($did)!=='Folder') - return PEAR::raiseError( - 'GreenBox::createReplica: dest is not folder', GBERR_WRTYPE - ); if(($res = $this->_authorize( array('read', 'write'), array($id, $did), $sessid )) !== TRUE) return $res; - if($replicaName=='') $replicaName = $this->getObjName($id); - while(($exid = $this->getObjId($replicaName, $did))<>'') - { $replicaName.='_R'; } - $rid = $this->addObj($replicaName , 'Replica', $did, 0, $id); - if(PEAR::isError($rid)) return $rid; -# $this->addMdata($this->_pathFromId($rid), 'isReplOf', $id, $sessid); - return $rid; + return $this->bsCreateReplica($id, $did, $replicaName); } /** @@ -339,9 +219,7 @@ class GreenBox extends Alib{ */ function createVersion($id, $did, $versionLabel, $sessid='') { - return PEAR::raiseError( - 'GreenBox::createVersion: not implemented', GBERR_NOTIMPL - ); + return $this->bsCreateVersion($id, $did, $versionLabel); } @@ -359,11 +237,7 @@ class GreenBox extends Alib{ { if(($res = $this->_authorize('write', $id, $sessid)) !== TRUE) return $res; - $ac =& StoredFile::recall(&$this, $id); - if(PEAR::isError($ac)) return $ac; - else{ - return $ac->updateMetaData($mdataFile); - } + return $this->bsUpdateMetadata($id, $mdataFile); } /** @@ -382,11 +256,7 @@ class GreenBox extends Alib{ { if(($res = $this->_authorize('write', $id, $sessid)) !== TRUE) return $res; - $ac =& StoredFile::recall(&$this, $id); - if(PEAR::isError($ac)) return $ac; - else{ - return $ac->updateMetaDataRecord($mdid, $object, $objns); - } + return $this->bsUpdateMetadataRecord($id, $mdid, $object, $objns); } /** @@ -401,14 +271,11 @@ class GreenBox extends Alib{ * @return boolean or PEAR::error * @see MetaData */ - function addMetaDataRecord($id, $propertyName, - $propertyValue, $sessid='') + function addMetaDataRecord($id, $propertyName, $propertyValue, $sessid='') { - //if(($res = $this->_authorize('write', $id, $sessid)) !== TRUE) - // return $res; - return PEAR::raiseError( - 'GreenBox::addMetaDataRecord: not implemented', GBERR_NOTIMPL - ); + if(($res = $this->_authorize('write', $id, $sessid)) !== TRUE) + return $res; + return $this->bsAddMetaDataRecord($id, $propertyName, $propertyValue); } /** @@ -422,21 +289,16 @@ class GreenBox extends Alib{ { if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE) return $res; - $ac =& StoredFile::recall(&$this, $id); - if(PEAR::isError($ac)) return $ac; - else{ - return $ac->getMetaData(); - } + return $this->bsGetMdata($id); } /** * Search in local metadata database.
* TODO: NOT FINISHED
- * Should support structured queries, e.g.:
- * XML file with the structure as metadata, but - * with SQL LIKE terms instead of metadata values.
- * Some standard query format would be better, - * but I've not found it yet. + * It will support structured queries - array of mode and query parts. + * Mode is "match all" or "match any". + * Query parts is array of [fieldname, operator, value] entities. + * * * @param searchData string, search query - * only one SQL LIKE term supported now. @@ -447,211 +309,9 @@ class GreenBox extends Alib{ */ function localSearch($searchData, $sessid='') { - $ftsrch = $searchData; - $res = $this->dbc->getCol("SELECT md.gunid as gunid - FROM {$this->filesTable} f, {$this->mdataTable} md - WHERE f.gunid=md.gunid AND md.objns='_L' AND - md.object like '%$ftsrch%' - GROUP BY md.gunid - "); - if(!is_array($res)) $res = array(); - return $res; + return $this->bsLocalSearch($searchData); } - /* -------------------------------------------- remote repository methods */ - - /** - * Upload file to remote repository - * - * @param id int, virt.file's local id - * @param gunid string, global id - * @param sessid string, session id - * @return string - transfer id or PEAR::error - */ - function uploadFile($id, $gunid, $sessid='') - { - $res = $this->prepareForTransport($id, $gunid, $sessid); - if(PEAR::isError($res)) return $res; - list($mediaFile, $mdataFile, $gunid) = $res; - $tr =& new Transport(&$this->dbc, $this->config); - $res = $tr->uploadOpen($mediaFile, 'media', $sessid, $gunid); - if(PEAR::isError($res)) return $res; - $res2 = $tr->uploadOpen($mdataFile, 'metadata', $sessid, $gunid); - if(PEAR::isError($res2)) return $res2; - $res3 = $tr->getTransportStatus($res); - $res4 = $tr->getTransportStatus($res2); -# return $res; - return array($res, $res2, $res3, $res4); - } - - /** - * Download file from remote repository - * - * @param gunid int, global unique id - * @param sessid string, session id - * @return string - transfer id or PEAR::error - */ - function downloadFile($gunid, $sessid='') - { - $tr =& new Transport(&$this->dbc, $this->config); - // get home dir if needed - $res = $tr->downloadOpen($sessid, 'media', $gunid, - $this->getSessUserId($sessid) - ); - if(PEAR::isError($res)) return $res; - $res2 = $tr->downloadOpen($sessid, 'metadata', $gunid, - $this->getSessUserId($sessid) - ); - if(PEAR::isError($res)) return $res; - $res3 = $tr->getTransportStatus($res); - $res4 = $tr->getTransportStatus($res2); -# return $res; - return array($res, $res2, $res3, $res4); - } - - - - /** - * Method for handling interupted transports via cron - * - */ - function cronJob() - { - $tr =& new Transport(&$this->dbc, $this->config); - $ru = $tr->uploadCron(); - $rd = $tr->downloadCron(&$this); - return array($ru, $rd); - } - - /** - * Get status of asynchronous transfer - * - * @param transferId int, id of asynchronous transfer - * returned by uploadFile or downloadFile methods - * @param sessid string, session id - * @return string or PEAR::error - */ - function getTransferStatus($transferId, $sessid='') - { - return PEAR::raiseError( - 'GreenBox::getTransferStatus: not implemented', GBERR_NOTIMPL - ); - } - - /** - * Prepare symlink to media file and create metadata file for transport - * - * @param id - * @param gunid - * @param sessid - * @return array - */ - function prepareForTransport($id, $gunid, $sessid='') - { - if(!$gunid) $gunid = $this->_gunidFromId($id); - else $id = $this->_idFromGunid($gunid); - $ac =& StoredFile::recallByGunid(&$this, $gunid); - if(PEAR::isError($ac)) return $ac; - $mediaTarget = $ac->_getRealRADFname(); - $mediaFile = "$gunid"; - $mdataFile = "$gunid.xml"; - @symlink($mediaTarget, $this->transDir."/$mediaFile"); - $mdata = $this->getMdata($id, $sessid); - if(PEAR::isError($mdata)) return $mdata; - if(!($fh = fopen($this->transDir."/$mdataFile", 'w'))) $res=FALSE; - else{ - $res = fwrite($fh, $mdata); - fclose($fh); - } - if($res === FALSE) return PEAR::raiseError( - "GreenBox::prepareForTransport:". - " can't write metadata tmp file ($mdataFile)" - ); - return array($mediaFile, $mdataFile, $gunid); - } - - /** - * Insert transported file and metadata into storage.
- * TODO: cals methods from LocStor - it's not good - * - * @param sessid string - session id - * @param file string - local path to filr - * @param type string - media|metadata|search - * @param gunid string - global unique id - */ - function processTransported($sessid, $file, $type, $gunid='X') - { - switch($type){ - case 'media': - if(!file_exists($file)) break; - $res = $this->storeAudioClip($sessid, $gunid, - $file, ''); - if(PEAR::isError($res)) return $res; - @unlink($file); - break; - case 'metadata': - case 'mdata': - if(!file_exists($file)) break; - $res = $this->updateAudioClipMetadata($sessid, $gunid, - $file); - if(PEAR::isError($res)){ - // catch valid exception - if($res->getCode() == GBERR_FOBJNEX){ - $res2 = $this->storeAudioClip($sessid, $gunid, - '', $file); - if(PEAR::isError($res2)) return $res2; - }else return $res; - } - @unlink($file); - break; - case 'search': - //$this->localSearch($criteria); - return PEAR::raiseError("processTranferred: search not implemented"); - break; - default: - return PEAR::raiseError("processTranferred: unknown type ($type)"); - break; - } - } - - /** - * Search in central metadata database - * - * @param searchData string, search query - see localSearch method - * @param sessid string, session id - * @return string - job id or PEAR::error - */ - function globalSearch($searchData, $sessid='') - { - return PEAR::raiseError( - 'GreenBox::globalSearch: not implemented', GBERR_NOTIMPL - ); - /* - $srchid = md5($sessid.mtime()); - $fh = fopen($this->transDir."/$srchid", "w"); - fwrite($fh, serialize($searchData)); - fclose($fh); - $res = $tr->uploadOpen($srchid, 'search', $sessid, $gunid); - if(PEAR::isError($res)) return $res; - return $res; - */ - } - - /** - * Get results from asynchronous search - * - * @param transferId int, transfer id returned by - * @param sessid string, session id - * @return array with results or PEAR::error - */ - function getSearchResults($transferId, $sessid='') - { - return PEAR::raiseError( - 'GreenBox::getSearchResults: not implemented', GBERR_NOTIMPL - ); - } - - /* --------------------------------------------------------- info methods */ /** @@ -665,43 +325,9 @@ class GreenBox extends Alib{ { if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE) return $res; - if($this->getObjType($id)!=='Folder') - return PEAR::raiseError( - 'GreenBox::listFolder: not a folder', GBERR_NOTF - ); - $a = $this->getDir($id, 'id, name, type, param as target', 'name'); - return $a; + return $this->bsListFolder($id); } - /** - * List files in folder - * - * @param id int, local id of object - * @param relPath string, relative path - * @return array - */ - function getObjIdFromRelPath($id, $relPath='.') - { - $a = split('/', $relPath); - if($this->getObjType($id)!=='Folder') $nid = $this->getparent($id); - else $nid = $id; - foreach($a as $i=>$item){ - switch($item){ - case".": - break; - case"..": - $nid = $this->getparent($nid); - break; - case"": - break; - default: - $nid = $this->getObjId($item, $nid); - } - } - return $nid; - } - - /* ---------------------------------------------------- redefined methods */ /** @@ -712,13 +338,15 @@ class GreenBox extends Alib{ */ function logout($sessid) { + /* release all accessed files on logout - probably not useful $acfa = $this->dbc->getAll("SELECT * FROM {$this->accessTable} WHERE sessid='$sessid'"); if(PEAR::isError($acfa)) return $acfa; foreach($acfa as $i=>$acf){ - $ac =& StoredFile::recallFromLink(&$this, $acf['tmplink'], $sessid); - $ac->releaseRawMediaData($sessid); + $ac =& StoredFile::recallByToken(&$this, $acf['token']); + $ac->releaseRawMediaData($sessid, $acf['token']); } + */ return parent::logout($sessid); } @@ -898,248 +526,5 @@ class GreenBox extends Alib{ ); } - /* =============================================== test and debug methods */ - /** - * dump - * - */ - function dump($id='', $indch=' ', $ind='', $format='{name}') - { - if($id=='') $id = $this->storId; - return parent::dump($id, $indch, $ind, $format); - } - - /** - * - * - */ - function dumpDir($id='', $format='$o["name"]') - { - if($id=='') $id = $this->storId; - $arr = $this->getDir($id, 'id,name'); -// if($this->doDebug){ $this->debug($arr); exit; } - $arr = array_map(create_function('$o', 'return "'.$format.'";'), $arr); - return join('', $arr); - } - - /** - * - * - */ - function debug($va) - { - echo"
\n"; print_r($va); #exit;
-    }
-
-    /**
-     *  deleteData
-     *
-     *  @return void
-     */
-    function deleteData()
-    {
-//        $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->removeObj($item['id']);
-        }
-        parent::deleteData();
-        $this->initData();
-    }
-    /**
-     *  testData
-     *
-     */
-    function testData($d='')
-    {
-        $exdir = '../../../storageServer/var/tests';
-        $s = $this->sessid;
-        $o[] = $this->addSubj('test1', 'a');
-        $o[] = $this->addSubj('test2', 'a');
-        $o[] = $this->addSubj('test3', 'a');
-        $o[] = $this->addSubj('test4', 'a');
-
-        $o[] = $t1hd = $this->getObjId('test1', $this->storId);
-        $o[] = $t1d1 = $this->createFolder($t1hd, 'test1_folder1', $s);
-        $o[] = $this->createFolder($t1hd, 'test1_folder2', $s);
-        $o[] = $this->createFolder($t1d1, 'test1_folder1_1', $s);
-        $o[] = $t1d12 = $this->createFolder($t1d1, 'test1_folder1_2', $s);
-
-        $o[] = $t2hd = $this->getObjId('test2', $this->storId);
-        $o[] = $this->createFolder($t2hd, 'test2_folder1', $s);
-
-        $o[] = $this->putFile($t1hd, 'file1.mp3', "$exdir/ex1.mp3", '', $s);
-        $o[] = $this->putFile($t1d12 , 'file2.wav', "$exdir/ex2.wav", '', $s);
-/*
-*/
-        $this->tdata['storage'] = $o;
-    }
-
-    /**
-     *  test
-     *
-     */
-    function test()
-    {
-//        if(PEAR::isError($p = parent::test())) return $p;
-        $this->deleteData();
-        $this->login('root', $this->config['tmpRootPass']);
-        $this->testData();
-        $this->logout($this->sessid);
-        $this->test_correct = "    StorageRoot
-        root
-        test1
-            test1_folder1
-                test1_folder1_1
-                test1_folder1_2
-                    file2.wav
-            test1_folder2
-            file1.mp3
-        test2
-            test2_folder1
-        test3
-        test4
-";
-        $this->test_dump = $this->dumpTree($this->storId);
-        if($this->test_dump==$this->test_correct)
-            { $this->test_log.="storageServer: OK\n"; return true; }
-        else PEAR::raiseError('GreenBox::test:', 1, PEAR_ERROR_DIE, '%s'.
-            "
\ncorrect:\n.{$this->test_correct}.\n".
-            "dump:\n.{$this->test_dump}.\n
\n"); - } - - /** - * initData - initialize - * - */ - function initData() - { - $this->rootId = $this->getRootNode(); - $this->storId = $this->wd = - $this->addObj('StorageRoot', 'Folder', $this->rootId); - $rootUid = parent::addSubj('root', $this->config['tmpRootPass']); - $this->login('root', $this->config['tmpRootPass']); - $res = $this->addPerm($rootUid, '_all', $this->rootId, 'A'); - $fid = $this->createFolder($this->storId, 'root', $this->sessid); -# $id = $this->dbc->nextId("{$this->mdataTable}_id_seq"); - $this->logout($this->sessid); - } - /** - * install - create tables - * - */ - function install() - { - parent::install(); - $this->dbc->query("CREATE TABLE {$this->filesTable} ( - id int not null, - gunid char(32) not null, - name varchar(255) not null default'', - type varchar(255) not null default'', - currentlyAccessing int not null default 0 - )"); - $this->dbc->query("CREATE UNIQUE INDEX {$this->filesTable}_id_idx - ON {$this->filesTable} (id)"); - $this->dbc->query("CREATE UNIQUE INDEX {$this->filesTable}_gunid_idx - ON {$this->filesTable} (gunid)"); - $this->dbc->query("CREATE INDEX {$this->filesTable}_name_idx - ON {$this->filesTable} (name)"); - - $this->dbc->createSequence("{$this->mdataTable}_id_seq"); - $this->dbc->query("CREATE TABLE {$this->mdataTable} ( - id int not null, - gunid char(32), - subjns varchar(255), -- subject namespace shortcut/uri - subject varchar(255) not null default '', - predns varchar(255), -- predicate namespace shortcut/uri - predicate varchar(255) not null, - predxml char(1) not null default 'T', -- Tag or Attribute - objns varchar(255), -- object namespace shortcut/uri - object text - )"); - $this->dbc->query("CREATE UNIQUE INDEX {$this->mdataTable}_id_idx - ON {$this->mdataTable} (id)"); - $this->dbc->query("CREATE INDEX {$this->mdataTable}_gunid_idx - ON {$this->mdataTable} (gunid)"); - $this->dbc->query("CREATE INDEX {$this->mdataTable}_subj_idx - ON {$this->mdataTable} (subjns, subject)"); - $this->dbc->query("CREATE INDEX {$this->mdataTable}_pred_idx - ON {$this->mdataTable} (predns, predicate)"); - - $this->dbc->query("CREATE TABLE {$this->accessTable} ( - gunid char(32) not null, - sessid char(32) not null, - tmpLink varchar(255) not null default'', - ts timestamp - )"); - $this->dbc->query("CREATE INDEX {$this->accessTable}_acc_idx - ON {$this->accessTable} (tmpLink, sessid)"); - if(!file_exists($this->bufferDir)){ - mkdir($this->bufferDir, 02775); - chmod($this->bufferDir, 02775); // may be obsolete - } - $this->initData(); - } - /** - * id subjns subject predns predicate objns object - * y1 literal xmbf NULL namespace literal http://www.sotf.org/xbmf - * x1 gunid xbmf contributor NULL NULL - * x2 mdid x1 xbmf role literal Editor - * - * predefined shortcuts: - * _L = literal - * _G = gunid (global id of media file) - * _I = mdid (local id of metadata record) - * _nssshortcut = namespace shortcut definition - * _blank = blank node - */ - - /** - * uninstall - * - * @return void - */ - function uninstall() - { - $this->dbc->query("DROP TABLE {$this->mdataTable}"); - $this->dbc->dropSequence("{$this->mdataTable}_id_seq"); - $this->dbc->query("DROP TABLE {$this->filesTable}"); - $this->dbc->query("DROP TABLE {$this->accessTable}"); - $d = dir($this->storageDir); - while (is_object($d) && (false !== ($entry = $d->read()))){ - if(filetype("{$this->storageDir}/$entry")=='dir' && - $entry!='CVS' && strlen($entry)==3) - { - $dd = dir("{$this->storageDir}/$entry"); - while (false !== ($ee = $dd->read())){ - if(substr($ee, 0, 1)!=='.') - unlink("{$this->storageDir}/$entry/$ee"); - } - $dd->close(); - rmdir("{$this->storageDir}/$entry"); - } - } - if(is_object($d)) $d->close(); - if(file_exists($this->bufferDir)){ - $d = dir($this->bufferDir); - while (false !== ($entry = $d->read())) if(substr($entry,0,1)!='.') - { unlink("{$this->bufferDir}/$entry"); } - $d->close(); - rmdir($this->bufferDir); - } - parent::uninstall(); - } - - /** - * Aux logging for debug - * - * @param msg string - log message - */ - function debugLog($msg) - { - $fp=fopen("{$this->storageDir}/log", "a") or die("Can't write to log\n"); - fputs($fp, date("H:i:s").">$msg<\n"); - fclose($fp); - } } ?> \ No newline at end of file diff --git a/livesupport/modules/storageServer/var/LocStor.php b/livesupport/modules/storageServer/var/LocStor.php index 0e13fba15..ca09dafcd 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.8 $ + Version : $Revision: 1.9 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/LocStor.php,v $ ------------------------------------------------------------------------------*/ @@ -36,6 +36,212 @@ require_once "GreenBox.php"; * Livesupport local storage interface */ class LocStor extends GreenBox{ + /* ---------------------------------------------------------------- store */ + /** + * Store or replace existing audio clip + * + * @param sessid string + * @param gunid string + * @param metadata string with metadata XML + * @param chsum string, md5 checksum of media file + * @return struct {url:writable URL for HTTP PUT, token:access token + */ + function storeAudioClipOpen($sessid, $gunid, $metadata, $chsum) + { + // test if specified gunid exists: + $ac =& StoredFile::recallByGunid(&$this, $gunid); + if(!PEAR::isError($ac)){ + // gunid exists - do replace + if(($res = $this->_authorize( + 'write', $ac->getId(), $sessid + )) !== TRUE) return $res; + if($ac->isAccessed()){ + return PEAR::raiseError( + 'LocStor.php: storeAudioClip: is accessed' + ); + } + $res = $ac->replace( + $ac->getId(), $ac->name, '', $metadata, 'string' + ); + if(PEAR::isError($res)) return $res; + }else{ + // gunid doesn't exists - do insert + $tmpid = uniqid(''); + $parid = $this->getObjId( + $this->getSessLogin($sessid), $this->storId + ); + if(PEAR::isError($parid)) return $parid; + if(($res = $this->_authorize('write', $parid, $sessid)) !== TRUE) + return $res; + $oid = $this->addObj($tmpid , 'File', $parid); + if(PEAR::isError($oid)) return $oid; + $ac =& StoredFile::insert( + &$this, $oid, '', '', $metadata, 'string', $gunid + ); + if(PEAR::isError($ac)){ + $res = $this->removeObj($oid); + return $ac; + } + $res = $this->renameFile($oid, $ac->gunid, $sessid); + if(PEAR::isError($res)) return $res; + } + $res = $ac->setState('incomplete'); + if(PEAR::isError($res)) return $res; + return $this->bsOpenPut($chsum, $ac->gunid); + } + + /** + * Store or replace existing audio clip + * + * @param sessid string + * @param token string + * @return string gunid or PEAR::error + */ + function storeAudioClipClose($sessid, $token) + { + $ac =& StoredFile::recallByToken(&$this, $token); + $fname = $this->bsClosePut($token); + if(PEAR::isError($ac)){ return $ac; } + $res = $ac->replaceRawMediaData($fname); + if(PEAR::isError($res)){ return $res; } + @unlink($fname); + $res = $ac->setState('ready'); + if(PEAR::isError($res)) return $res; + return $ac->gunid; + } + + /* --------------------------------------------------------------- access */ + /** + * Make access to audio clip + * + * @param sessid string + * @param gunid string + * @return array with: seekable filehandle, access token + */ + function accessRawAudioData($sessid, $gunid) + { + $ac =& StoredFile::recallByGunid(&$this, $gunid); + if(PEAR::isError($ac)) return $ac; + if(($res = $this->_authorize('read', $ac->getId(), $sessid)) !== TRUE) + return $res; + return $ac->accessRawMediaData($sessid); + } + + /** + * Release access to audio clip + * + * @param sessid string + * @param token string, access token + * @return boolean or PEAR::error + */ + function releaseRawAudioData($sessid, $token) + { + $ac =& StoredFile::recallByToken(&$this, $token); + if(PEAR::isError($ac)) return $ac; + return $ac->releaseRawMediaData($token); + } + + /* ------------------------------------------------------------- download */ + /** + * Create and return downloadable URL for audio file + * + * @param sessid string, session id + * @param gunid string, global unique id + * @return array with: downloadable URL, download token + */ + function downloadRawAudioDataOpen($sessid, $gunid) + { + $res = $this->existsAudioClip($sessid, $gunid); + if(PEAR::isError($res)) return $res; + $id = $this->_idFromGunid($gunid); + if(is_null($id)){ + return PEAR::raiseError( + "LocStor::downloadRawAudioDataOpen: gunid not found ($gunid)" + ); + } + if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE) + return $res; + return $this->bsOpenDownload($id); + } + + /** + * Discard downloadable URL for audio file + * + * @param token string, download token + * @return boolean + */ + function downloadRawAudioDataClose($token) + { + return $this->bsCloseDownload($token); + } + + /** + * Create and return downloadable URL for metadata + * + * @param sessid string, session id + * @param gunid string, global unique id + * @return array with: downloadable URL, download token + */ + function downloadMetadataOpen($sessid, $gunid) + { + $res = $this->existsAudioClip($sessid, $gunid); + if(PEAR::isError($res)) return $res; + $id = $this->_idFromGunid($gunid); + if(is_null($id)){ + return PEAR::raiseError( + "LocStor::downloadMetadataOpen: gunid not found ($gunid)" + ); + } + if(($res = $this->_authorize('read', $id, $sessid)) !== TRUE) + return $res; + return $this->bsOpenDownload($id, 'metadata'); + } + + /** + * Discard downloadable URL for metadata + * + * @param token string, download token + * @return boolean + */ + function downloadMetadataClose($token) + { + return $this->bsCloseDownload($token, 'metadata'); + } + + /** + * Return metadata as XML + * + * @param sessid string + * @param gunid string + * @return string or PEAR::error + */ + function getAudioClip($sessid, $gunid) + { + $ac =& StoredFile::recallByGunid(&$this, $gunid); + if(PEAR::isError($ac)) return $ac; + if(($res = $this->_authorize('read', $ac->getId(), $sessid)) !== TRUE) + return $res; + $md = $this->getMdata($ac->getId(), $sessid); + if(PEAR::isError($md)) return $md; + return $md; + } + + /* --------------------------------------------------------------- search */ + /** + * Search in metadata database + * + * @param sessid string + * @param criteria string + * @return array or PEAR::error + * @see GreenBox::localSearch + */ + function searchMetadata($sessid, $criteria) + { + $res = $this->localSearch($criteria, $sessid); + return $res; + } + + /* ----------------------------------------------------------------- etc. */ /** * Check if audio clip exists * @@ -61,56 +267,7 @@ class LocStor extends GreenBox{ return $res; return $ac->exists(); } - /** - * Store or replace existing audio clip - * - * @param sessid string - * @param gunid string - * @param mediaFileLP string, local path to media file - * @param mdataFileLP string, local path to metadata XML file - * @return string gunid or PEAR::error - */ - function storeAudioClip($sessid, $gunid, $mediaFileLP, $mdataFileLP) - { - // test if specified gunid exists: - $ac =& StoredFile::recallByGunid(&$this, $gunid); - if(!PEAR::isError($ac)){ - // gunid exists - do replace - if(($res = $this->_authorize( - 'write', $ac->getId(), $sessid - )) !== TRUE) return $res; - if($ac->isAccessed()){ - return PEAR::raiseError( - 'LocStor.php: storeAudioClip: is accessed' - ); - } - $res = $ac->replace( - $ac->getId(), $ac->name,$mediaFileLP, $mdataFileLP - ); - if(PEAR::isError($res)) return $res; - }else{ - // gunid doesn't exists - do insert - $tmpid = uniqid(''); - $parid = $this->getObjId( - $this->getSessLogin($sessid), $this->storId - ); - if(PEAR::isError($parid)) return $parid; - if(($res = $this->_authorize('write', $parid, $sessid)) !== TRUE) - return $res; - $oid = $this->addObj($tmpid , 'File', $parid); - if(PEAR::isError($oid)) return $oid; - $ac =& StoredFile::insert( - &$this, $oid, '', $mediaFileLP, $mdataFileLP, $gunid - ); - if(PEAR::isError($ac)){ - $res = $this->removeObj($oid); - return $ac; - } - $res = $this->renameFile($oid, $ac->gunid, $sessid); - if(PEAR::isError($res)) return $res; - } - return $ac->gunid; - } + /** * Delete existing audio clip * @@ -133,82 +290,24 @@ class LocStor extends GreenBox{ if(PEAR::isError($res)) return $res; return TRUE; } + /** * Update existing audio clip metadata * * @param sessid string * @param gunid string - * @param mdataFileLP string, local path to metadata XML file + * @param metadata string, metadata XML string * @return boolean or PEAR::error */ - function updateAudioClipMetadata($sessid, $gunid, $mdataFileLP) + function updateAudioClipMetadata($sessid, $gunid, $metadata) { $ac =& StoredFile::recallByGunid(&$this, $gunid); if(PEAR::isError($ac)) return $ac; if(($res = $this->_authorize('write', $ac->getId(), $sessid)) !== TRUE) return $res; - return $ac->replaceMetaData($mdataFileLP); - } - /** - * Make access to audio clip - * - * @param sessid string - * @param gunid string - * @return string - access symlink path or PEAR::error - */ - function accessRawAudioData($sessid, $gunid) - { - $ac =& StoredFile::recallByGunid(&$this, $gunid); - if(PEAR::isError($ac)) return $ac; - if(($res = $this->_authorize('read', $ac->getId(), $sessid)) !== TRUE) - return $res; - return $ac->accessRawMediaData($sessid); - } - /** - * Release access to audio clip - * - * @param sessid string - * @param tmpLink string - * @return boolean or PEAR::error - */ - function releaseRawAudioData($sessid, $tmpLink) - { - $ac =& StoredFile::recallFromLink(&$this, $tmpLink, $sessid); - if(PEAR::isError($ac)) return $ac; - if(($res = $this->_authorize('read', $ac->getId(), $sessid)) !== TRUE) - return $res; - return $ac->releaseRawMediaData($sessid); - } - /** - * Search in metadata database - * - * @param sessid string - * @param criteria string - * @return array or PEAR::error - * @see GreenBox::localSearch - */ - function searchMetadata($sessid, $criteria) - { - $res = $this->localSearch($criteria, $sessid); - return $res; - } - /** - * Return metadata as XML - * - * @param sessid string - * @param gunid string - * @return string or PEAR::error - */ - function getAudioClip($sessid, $gunid) - { - $ac =& StoredFile::recallByGunid(&$this, $gunid); - if(PEAR::isError($ac)) return $ac; - if(($res = $this->_authorize('read', $ac->getId(), $sessid)) !== TRUE) - return $res; - $md = $this->getMdata($ac->getId(), $sessid); - if(PEAR::isError($md)) return $md; - return $md; + return $ac->replaceMetaData($metadata, 'string'); } + /** * Reset storageServer for debugging. * diff --git a/livesupport/modules/storageServer/var/RawMediaData.php b/livesupport/modules/storageServer/var/RawMediaData.php index f10592816..a5e08bf3d 100644 --- a/livesupport/modules/storageServer/var/RawMediaData.php +++ b/livesupport/modules/storageServer/var/RawMediaData.php @@ -23,7 +23,7 @@ Author : $Author: tomas $ - Version : $Revision: 1.3 $ + Version : $Revision: 1.4 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/RawMediaData.php,v $ ------------------------------------------------------------------------------*/ @@ -39,6 +39,7 @@ /* ================== RawMediaData ================== */ class RawMediaData{ + /** * Constructor * @@ -53,6 +54,7 @@ class RawMediaData{ $this->fname = $this->makeFname(); $this->exists = file_exists($this->fname); } + /** * Insert media file to filesystem * @@ -69,11 +71,10 @@ class RawMediaData{ } umask(0002); if(@copy($mediaFileLP, $this->fname)){ -// @chmod($this->fname, 0775); $this->exists = TRUE; return TRUE; }else{ -// @unlink($this->fname); + //@unlink($this->fname); // maybe useless $this->exists = FALSE; return PEAR::raiseError( "RawMediaData::insert: file save failed". @@ -81,6 +82,7 @@ class RawMediaData{ ); } } + /** * Delete and insert media file * @@ -93,6 +95,7 @@ class RawMediaData{ if(PEAR::isError($r)) return $r; return $this->insert($mediaFileLP); } + /** * Return true if file corresponding to the object exists * @@ -102,6 +105,7 @@ class RawMediaData{ { return $this->exists; } + /** * Return filename * @@ -111,38 +115,42 @@ class RawMediaData{ { return $this->fname; } + +/* /** * Make access symlink to the media file * * @param accLinkName string, access symlink name * @return string, access symlink name - */ + * / function access($accLinkName) { if(!$this->exists) return FALSE; if(file_exists($accLinkName)) return $accLinkName; if(@symlink($this->fname, $accLinkName)){ -// @chmod($accLinkName, 0775); return $accLinkName; }else return PEAR::raiseError( "RawMediaData::access: symlink create failed ($accLinkName)", GBERR_FILEIO ); } + /** * Delete access symlink * * @param accLinkName string, access symlink name * @return boolean or PEAR::error - */ + * / function release($accLinkName) { if(!$this->exists) return FALSE; if(@unlink($accLinkName)) return TRUE; else return PEAR::raiseError( - "RawMediaData::release: symlink unlink failed", GBERR_FILEIO + "RawMediaData::release: unlink failed ($accLinkName)", GBERR_FILEIO ); } +*/ + /** * Delete media file from filesystem * @@ -196,6 +204,7 @@ class RawMediaData{ { return "{$this->resDir}/{$this->gunid}"; } + /** * Test method * diff --git a/livesupport/modules/storageServer/var/StoredFile.php b/livesupport/modules/storageServer/var/StoredFile.php index 50f56dad1..b8d59f457 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.6 $ + Version : $Revision: 1.7 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/StoredFile.php,v $ ------------------------------------------------------------------------------*/ @@ -59,7 +59,7 @@ class StoredFile{ $this->gb =& $gb; $this->dbc =& $gb->dbc; $this->filesTable = $gb->filesTable; - $this->accessTable= $gb->accessTable; + $this->accessTable= $gb->accessTable; $this->gunid = $gunid; if(is_null($this->gunid)) $this->gunid = $this->_createGunid(); $this->resDir = $this->_getResDir($this->gunid); @@ -68,6 +68,7 @@ class StoredFile{ $this->md =& new MetaData(&$gb, $this->gunid); return $this->gunid; } + /* ========= 'factory' methods - should be called to construct StoredFile */ /** * Create instace of StoreFile object and insert new file @@ -76,36 +77,41 @@ class StoredFile{ * @param oid int, local object id in the tree * @param name string, name of new file * @param mediaFileLP string, local path to media file - * @param mdataFileLP string, local path to metadata XML file + * @param metadata string, local path to metadata XML file or XML string + * @param mdataLoc string 'file'|'string' (optional) * @param gunid global unique id (optional) - for insert file with gunid * @return instace of StoredFile object */ function insert(&$gb, $oid, $name, - $mediaFileLP='', $mdataFileLP='', $gunid=NULL) + $mediaFileLP='', $metadata='', $mdataLoc='file', $gunid=NULL) { $ac =& new StoredFile(&$gb, ($gunid ? $gunid : NULL)); $ac->name = $name; $ac->id = $oid; $ac->type = "unKnown"; + $emptyState = TRUE; if($ac->name=='') $ac->name=$ac->gunid; $this->dbc->query("BEGIN"); - $res = $ac->dbc->query("INSERT INTO {$ac->filesTable} - (id, name, gunid, type) + $res = $ac->dbc->query(" + INSERT INTO {$ac->filesTable} + (id, name, gunid, type, state) VALUES - ('$oid', '{$ac->name}', '{$ac->gunid}', '{$ac->type}')" - ); + ('$oid', '{$ac->name}', '{$ac->gunid}', '{$ac->type}', + 'incomplete') + "); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } // --- metadata insert: - if($mdataFileLP != ''){ - if(!file_exists($mdataFileLP)) + if($metadata != ''){ + if($mdataLoc=='file' && !file_exists($metadata)) { return PEAR::raiseError("StoredFile::insert: ". - "metadata file doesn't exists ($mdataFileLP)"); + "metadata file doesn't exists ($metadata)"); } - $res = $ac->md->insert($mdataFileLP); + $res = $ac->md->insert($metadata, $mdataLoc); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } + $emptyState = FALSE; } // --- media file insert: if($mediaFileLP != ''){ @@ -121,17 +127,22 @@ class StoredFile{ $mime = $ac->rmd->getMime(); //$gb->debugLog("gunid={$ac->gunid}, mime=$mime"); if($mime !== FALSE){ - $res = $ac->dbc->query("UPDATE {$ac->filesTable} - SET type='$mime' WHERE id='$oid'"); + $res = $ac->setType($mime); if(PEAR::isError($res)){ $ac->dbc->query("ROLLBACK"); return $res; } } + $emptyState = FALSE; + } + if(!$emptyState){ + $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; } return $ac; } + /** * Create instace of StoreFile object and recall existing file.
* Should be supplied oid XOR gunid - not both ;) @@ -144,8 +155,10 @@ class StoredFile{ function recall(&$gb, $oid='', $gunid='') { $cond = ($oid != '' ? "id='".intval($oid)."'" : "gunid='$gunid'" ); - $row = $gb->dbc->getRow("SELECT id, gunid, type, name - FROM {$gb->filesTable} WHERE $cond"); + $row = $gb->dbc->getRow(" + SELECT id, gunid, type, name + FROM {$gb->filesTable} WHERE $cond + "); if(PEAR::isError($row)) return $row; if(is_null($row)){ return PEAR::raiseError( @@ -159,9 +172,10 @@ class StoredFile{ $ac->id = $row['id']; return $ac; } + /** * Create instace of StoreFile object and recall existing file - * by gunid.
+ * by gunid.
* * @param gb reference to GreenBox object * @param gunid string, optional, global unique id of file @@ -171,24 +185,27 @@ class StoredFile{ { return StoredFile::recall(&$gb, '', $gunid); } + /** - * Create instace of StoreFile object and recall existing file from tmpLink + * Create instace of StoreFile object and recall existing file + * by access token.
* * @param gb reference to GreenBox object - * @param tmpLink string - * @param sessid string + * @param token string, access token + * @return instace of StoredFile object */ - function recallFromLink(&$gb, $tmpLink, $sessid) + function recallByToken(&$gb, $token) { $gunid = $gb->dbc->getOne("SELECT gunid FROM {$gb->accessTable} - WHERE tmpLink='$tmpLink' AND sessid='$sessid'"); + WHERE token='$token'"); if(PEAR::isError($gunid)) return $gunid; if(is_null($gunid)) return PEAR::raiseError( - "StoredFile::recallFromLink: accessobj not exist ($tmpLink)", GBERR_AOBJNEX); + "StoredFile::recallByToken: invalid token ($token)", GBERR_AOBJNEX); return StoredFile::recall(&$gb, '', $gunid); } + /** - * Create instace of StoreFile object and make copy of existing file + * Create instace of StoredFile object and make copy of existing file * * @param src reference to source object * @param nid int, new local id @@ -208,35 +225,30 @@ class StoredFile{ * @param oid int, local id * @param name string, name of file * @param mediaFileLP string, local path to media file - * @param mdataFileLP string, local path to metadata XML file or XML string + * @param metadata string, local path to metadata XML file or XML string * @param mdataLoc string 'file'|'string' */ - function replace($oid, $name, $mediaFileLP='', $mdataFileLP='', + function replace($oid, $name, $mediaFileLP='', $metadata='', $mdataLoc='file') { $this->dbc->query("BEGIN"); - $res = $this->dbc->query("UPDATE {$this->filesTable} - SET name='$name', type='{$this->type}' WHERE id='$oid'"); + $res = $this->rename($name); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } - if($mediaFileLP != ''){ - $res = $this->rmd->replace($mediaFileLP, $this->type); - if(PEAR::isError($res)){ - $this->dbc->query("ROLLBACK"); return $res; - } - $mime = $this->rmd->getMime(); - if($mime !== FALSE){ - $res = $this->dbc->query("UPDATE {$this->filesTable} - SET type='$mime' WHERE id='$oid'"); - if(PEAR::isError($res)){ - $this->dbc->query("ROLLBACK"); return $res; - } - } + if($mediaFileLP != ''){ // media + $res = $this->replaceRawMediaData($mediaFileLP); + }else{ + $res = $this->rmd->delete(); } - if($mdataFileLP != ''){ - $res = $this->md->replace($mdataFileLP, $mdataLoc); - if(PEAR::isError($res)){ - $this->dbc->query("ROLLBACK"); return $res; - } + if(PEAR::isError($res)){ + $this->dbc->query("ROLLBACK"); return $res; + } + if($metadata != ''){ // metadata + $res = $this->md->replace($metadata, $mdataLoc); + }else{ + $res = $this->md->delete(); + } + if(PEAR::isError($res)){ + $this->dbc->query("ROLLBACK"); return $res; } $res = $this->dbc->query("COMMIT"); if(PEAR::isError($res)){ @@ -244,97 +256,107 @@ class StoredFile{ } return TRUE; } + /** - * Increase access counter, create access record, + * Increase access counter, create access token, insert access record, * call access method of RawMediaData * * @param sessid string + * @return array with: access URL, access token */ function accessRawMediaData($sessid) { $this->dbc->query("BEGIN"); - $res = $this->dbc->query("UPDATE {$this->filesTable} + $res = $this->dbc->query(" + UPDATE {$this->filesTable} SET currentlyAccessing=currentlyAccessing+1 - WHERE gunid='{$this->gunid}'"); + WHERE gunid='{$this->gunid}' + "); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } - $accLinkName = $this->_getAccessFname($sessid, $this->_getExt()); - $res = $this->dbc->query("INSERT INTO {$this->accessTable} - (gunid, sessid, tmplink, ts) - VALUES - ('{$this->gunid}', '$sessid', '$accLinkName', now())"); +# $token = $this->_createGunid(); + $realFname = $this->_getRealRADFname(); + $ext = $this->_getExt(); + + $res = $this->gb->bsAccess($realFname, $ext, $this->gunid, $sessid); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } - $acc = $this->rmd->access($accLinkName); - if(PEAR::isError($acc)){ $this->dbc->query("ROLLBACK"); return $acc; } - if($acc === FALSE){ - $this->dbc->query("ROLLBACK"); - return PEAR::raiseError( - 'StoredFile::accessRawMediaData: not exists' - ); - } + $resultArray = + array('url'=>"file://{$res['fname']}", 'token'=>$res['token']); $res = $this->dbc->query("COMMIT"); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } - return $acc; + return $resultArray; } + /** * Decrease access couter, delete access record, * call release method of RawMediaData * - * @param sessid string + * @param token string, access token + * @return boolean */ - function releaseRawMediaData($sessid) + function releaseRawMediaData($token) { $this->dbc->query("BEGIN"); $res = $this->dbc->query("UPDATE {$this->filesTable} SET currentlyAccessing=currentlyAccessing-1 - WHERE gunid='{$this->gunid}' AND currentlyAccessing>0" - ); + WHERE gunid='{$this->gunid}' AND currentlyAccessing>0 + "); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } - $ca = $this->dbc->getOne("SELECT currentlyAccessing - FROM {$this->filesTable} - WHERE gunid='{$this->gunid}'" - ); - if(PEAR::isError($ca)){ $this->dbc->query("ROLLBACK"); return $ca; } - $accLinkName = $this->_getAccessFname($sessid, $this->_getExt()); - $res = $this->dbc->query("DELETE FROM {$this->accessTable} - WHERE gunid='{$this->gunid}' AND sessid='$sessid' - AND tmplink='$accLinkName'"); + $res = $this->gb->bsRelease($token); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } $res = $this->dbc->query("COMMIT"); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } - if(intval($ca)==0) return $this->rmd->release($accLinkName); return TRUE; } + + /** + * Replace media file only with new binary file + * + * @param mediaFileLP string, local path to media file + */ + function replaceRawMediaData($mediaFileLP) + { + $res = $this->rmd->replace($mediaFileLP); + if(PEAR::isError($res)){ return $res; } + $mime = $this->rmd->getMime(); + if($mime !== FALSE){ + $res = $this->setType($mime); + if(PEAR::isError($res)){ return $res; } + } + } + /** * Replace metadata with new XML file * - * @param mdataFileLP string, local path to metadata XML file or XML string + * @param metadata string, local path to metadata XML file or XML string * @param mdataLoc string 'file'|'string' */ - function replaceMetaData($mdataFileLP, $mdataLoc='file') + function replaceMetaData($metadata, $mdataLoc='file') { $this->dbc->query("BEGIN"); - $res = $this->md->replace($mdataFileLP, $mdataLoc); + $res = $this->md->replace($metadata, $mdataLoc); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } $res = $this->dbc->query("COMMIT"); if(PEAR::isError($res)) return $res; return TRUE; } + /** * Update metadata with new XML file * - * @param mdataFileLP string, local path to metadata XML file or XML string + * @param metadata string, local path to metadata XML file or XML string * @param mdataLoc string 'file'|'string' * @return boolean or PEAR::error */ - function updateMetaData($mdataFileLP, $mdataLoc='file') + function updateMetaData($metadata, $mdataLoc='file') { $this->dbc->query("BEGIN"); - $res = $this->md->update($mdataFileLP, $mdataLoc); + $res = $this->md->update($metadata, $mdataLoc); if(PEAR::isError($res)){ $this->dbc->query("ROLLBACK"); return $res; } $res = $this->dbc->query("COMMIT"); if(PEAR::isError($res)) return $res; return TRUE; } + /** * Update object namespace and value of one metadata record * @@ -349,6 +371,7 @@ class StoredFile{ { return $this->md->updateRecord($mdid, $object, $objns='_L'); } + /** * Get metadata as XML string * @@ -359,6 +382,7 @@ class StoredFile{ { return $this->md->getMetaData(); } + /** * Analyze file with getid3 module.
* Obtain some metadata stored in media file.
@@ -372,6 +396,7 @@ class StoredFile{ $ia = $this->rmd->analyze(); return $ia; } + /** * Rename stored virtual file * @@ -380,11 +405,46 @@ class StoredFile{ */ function rename($newname) { - $res = $this->dbc->query("UPDATE {$this->filesTable} SET name='$newname' - WHERE gunid='{$this->gunid}'"); + $res = $this->dbc->query(" + UPDATE {$this->filesTable} SET name='$newname' + WHERE gunid='{$this->gunid}' + "); if(PEAR::isError($res)) return $res; return TRUE; } + + /** + * Set state of virtual file + * + * @param state string, 'empty'|'incomplete'|'ready'|'edited' + * @return boolean or error + */ + function setState($state) + { + $res = $this->dbc->query(" + UPDATE {$this->filesTable} SET state='$state' + WHERE gunid='{$this->gunid}' + "); + if(PEAR::isError($res)){ return $res; } + return TRUE; + } + + /** + * Set mime-type of virtual file + * + * @param type string, mime-type + * @return boolean or error + */ + function setType($type) + { + $res = $this->dbc->query(" + UPDATE {$this->filesTable} SET type='$type' + WHERE gunid='{$this->gunid}' + "); + if(PEAR::isError($res)){ return $res; } + return TRUE; + } + /** * Delete stored virtual file * @@ -397,10 +457,11 @@ class StoredFile{ if(PEAR::isError($res)) return $res; $res = $this->md->delete(); if(PEAR::isError($res)) return $res; - $links = $this->dbc->getAll("SELECT tmplink FROM {$this->accessTable} + $tokens = $this->dbc->getAll("SELECT token FROM {$this->accessTable} WHERE gunid='{$this->gunid}'"); - if(is_array($links)) foreach($links as $i=>$item){ - @unlink($item['tmplink']); + if(is_array($tokens)) foreach($tokens as $i=>$item){ + $file = _getAccessFname($item['token'], $item['ext']); + @unlink($file); } $res = $this->dbc->query("DELETE FROM {$this->accessTable} WHERE gunid='{$this->gunid}'"); @@ -425,6 +486,7 @@ class StoredFile{ WHERE gunid='$gunid' ")); } + /** * Returns local id of virtual file * @@ -433,14 +495,17 @@ class StoredFile{ { return $this->id; } + /** * Returns true if raw media file exists * */ function exists() { - $indb = $this->dbc->getRow("SELECT gunid FROM {$this->filesTable} - WHERE gunid='{$this->gunid}'"); + $indb = $this->dbc->getRow(" + SELECT gunid FROM {$this->filesTable} + WHERE gunid='{$this->gunid}' + "); return (!is_null($indb) && $this->rmd->exists()); } @@ -451,9 +516,11 @@ class StoredFile{ */ function _createGunid() { - return md5(microtime().$_SERVER['SERVER_ADDR'].rand(). - "org.mdlf.livesupport"); + return md5( + microtime().$_SERVER['SERVER_ADDR'].rand()."org.mdlf.livesupport" + ); } + /** * Get local id from global id. * Static or dynamic call is possible. @@ -471,6 +538,7 @@ class StoredFile{ ); return $id; } + /** * Return suitable extension.
* TODO: make it general - is any tool for it? @@ -487,6 +555,7 @@ class StoredFile{ } return $ext; } + /** * Get filetype from global id * @@ -494,9 +563,12 @@ class StoredFile{ */ function _getType($gunid) { - return $this->dbc->getOne("SELECT type FROM {$this->filesTable} - WHERE gunid='$gunid'"); + return $this->dbc->getOne(" + SELECT type FROM {$this->filesTable} + WHERE gunid='$gunid' + "); } + /** * Get and optionaly create subdirectory in real filesystem for storing * raw media data @@ -509,6 +581,7 @@ class StoredFile{ if(!file_exists($resDir)){ mkdir($resDir, 02775); chmod($resDir, 02775); } return $resDir; } + /** * Get real filename of raw media data * @@ -518,14 +591,15 @@ class StoredFile{ { return $this->rmd->getFname(); } + /** * Create and return name for temporary symlink.
* TODO: Should be more unique * */ - function _getAccessFname($sessid, $ext='EXT') + function _getAccessFname($token, $ext='EXT') { - $spart = md5("{$sessid}_{$this->gunid}"); + $spart = md5($token); return "{$this->accessDir}/$spart.$ext"; } } diff --git a/livesupport/modules/storageServer/var/html/gbHttp.php b/livesupport/modules/storageServer/var/html/gbHttp.php index 9d5f6e82f..17e5f091e 100644 --- a/livesupport/modules/storageServer/var/html/gbHttp.php +++ b/livesupport/modules/storageServer/var/html/gbHttp.php @@ -23,7 +23,7 @@ Author : $Author: tomas $ - Version : $Revision: 1.6 $ + Version : $Revision: 1.7 $ Location : $ $ ------------------------------------------------------------------------------*/ @@ -33,7 +33,7 @@ require_once"gbHtml_h.php"; * storageServer WWW-form interface * * @author $Author: tomas $ - * @version $Revision: 1.6 $ + * @version $Revision: 1.7 $ * @see Alib * @see GreenBox */ @@ -147,7 +147,7 @@ switch($_REQUEST['act']){ * @param id int, destination folder id */ case"rename": - $parid = $gb->getparent($id); + $parid = $gb->getParent($id); $r = $gb->renameFile($id, $_REQUEST['newname'], $sessid); if(PEAR::isError($r)) $_SESSION['alertMsg'] = $r->getMessage(); $redirUrl = BROWSER."?id=$parid"; @@ -164,7 +164,7 @@ switch($_REQUEST['act']){ case"move": $newPath = urlencode($_REQUEST['newPath']); $did = $gb->getObjIdFromRelPath($id, $newPath); - $parid = $gb->getparent($id); + $parid = $gb->getParent($id); $r = $gb->moveFile($id, $did, $sessid); if(PEAR::isError($r)){ $_SESSION['alertMsg'] = $r->getMessage(); @@ -184,7 +184,7 @@ switch($_REQUEST['act']){ case"copy": $newPath = urldecode($_REQUEST['newPath']); $did = $gb->getObjIdFromRelPath($id, $newPath); - $parid = $gb->getparent($id); + $parid = $gb->getParent($id); $r = $gb->copyFile($id, $did, $sessid); if(PEAR::isError($r)){ $_SESSION['alertMsg'] = $r->getMessage(); @@ -200,7 +200,7 @@ switch($_REQUEST['act']){ * @param id int, local id of deleted file or folder */ case"delete": - $parid = $gb->getparent($id); + $parid = $gb->getParent($id); $r = $gb->deleteFile($id, $sessid); if(PEAR::isError($r)) $_SESSION['alertMsg'] = $r->getMessage(); $redirUrl = BROWSER."?id=$parid"; diff --git a/livesupport/modules/storageServer/var/xmlrpc/put.php b/livesupport/modules/storageServer/var/xmlrpc/put.php new file mode 100644 index 000000000..cfdc58979 --- /dev/null +++ b/livesupport/modules/storageServer/var/xmlrpc/put.php @@ -0,0 +1,77 @@ +setFetchMode(DB_FETCHMODE_ASSOC); +$gb = &new GreenBox(&$dbc, $config); + +$token = $_REQUEST['token']; + +function http_error($code, $err){ + header("HTTP/1.1 $code"); + header("Content-type: text/plain; charset=UTF-8"); + echo "$err\r\n"; + exit; +} + +$tc = $gb->bsCheckToken($token, 'put'); +if(PEAR::isError($tc)){ echo "ERR".$tc->getMessage()."\n"; exit; } +if(!$tc){ http_error(410, "Token not valid."); } +#var_dump($tc); exit; + +header("Content-type: text/plain"); +#var_dump($_SERVER); var_dump($_REQUEST); exit; + +#$destfile = $_SERVER['PATH_TRANSLATED']; +$destfile = "{$config['accessDir']}/{$token}"; + +/* PUT data comes in on the input stream */ +$putdata = @fopen("php://input", "r") or + http_error(500, "put.php: Can't read input"); + +/* Open a file for writing */ +$fp = @fopen($destfile, "ab") or + http_error(500, "put.php: Can't write to destination file (token=$token)"); + +/* Read the data 1 KB at a time and write to the file */ +while ($data = fread($putdata, 1024)){ + fwrite($fp, $data); +} + +/* Close the streams */ +fclose($fp); +fclose($putdata); + +header("HTTP/1.1 200"); +?> \ No newline at end of file diff --git a/livesupport/modules/storageServer/var/xmlrpc/simpleGet.php b/livesupport/modules/storageServer/var/xmlrpc/simpleGet.php new file mode 100644 index 000000000..0ce6be2ed --- /dev/null +++ b/livesupport/modules/storageServer/var/xmlrpc/simpleGet.php @@ -0,0 +1,59 @@ +setFetchMode(DB_FETCHMODE_ASSOC); + +$locStor = &new LocStor(&$dbc, $config); + +function http_error($code, $err){ + header("HTTP/1.1 $code"); + header("Content-type: text/plain; charset=UTF-8"); + echo "$err\r\n"; + exit; +} + +$sessid = $_REQUEST['sessid']; +$gunid = $_REQUEST['id']; + +$res = $locStor->existsAudioClip($sessid, $gunid); +if(PEAR::isError($res)){ http_error(500, $res->getMessage()); } +$ac =& StoredFile::recallByGunid(&$locStor, $gunid); +if(PEAR::isError($ac)){ http_error(500, $ac->getMessage()); } +$realFname = $ac->_getRealRADFname(); +$mime = $ac->rmd->getMime(); +header("Content-type: $mime"); +readfile($realFname); +?> diff --git a/livesupport/modules/storageServer/var/xmlrpc/testRunner.sh b/livesupport/modules/storageServer/var/xmlrpc/testRunner.sh index 022b98146..95485fe6b 100755 --- a/livesupport/modules/storageServer/var/xmlrpc/testRunner.sh +++ b/livesupport/modules/storageServer/var/xmlrpc/testRunner.sh @@ -23,10 +23,12 @@ # # # Author : $Author: tomas $ -# Version : $Revision: 1.6 $ +# Version : $Revision: 1.7 $ # Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/xmlrpc/testRunner.sh,v $ #------------------------------------------------------------------------------- +#DEBUG=yes + COMM=$1 shift GUNID=$1 @@ -54,27 +56,79 @@ existsAudioClip() { $XR_CLI existsAudioClip $SESSID $GUNID || exit $? } -accessRawAudioData() { - echo "# accessRawAudioData: " - FPATH=`$XR_CLI accessRawAudioData $SESSID $GUNID` || exit $? - FPATH="" - FPATH=`echo "$FPATH" | php -q` - echo $FPATH -# ls -l $FPATH - echo -n "# releaseRawAudioData: " - $XR_CLI releaseRawAudioData $SESSID $FPATH || exit $? -#$XR_CLI getAudioClip $SESSID $GUNID -} - storeAudioClip() { - echo -n "# storeAudioClip: " - MEDIA=../tests/ex1.mp3 +# echo -n "# storeAudioClip: " +# MEDIA=../tests/ex1.mp3 + MEDIA=var/tests/ex1.mp3 METADATA=../tests/testStorage.xml - RGUNID=`$XR_CLI storeAudioClip "$SESSID" '' "$MEDIA" "$METADATA"` || \ +# RGUNID=`$XR_CLI storeAudioClip "$SESSID" '' "$MEDIA" "$METADATA"` || \ +# { ERN=$?; echo $RGUNID; exit $ERN; } + MD5=`md5sum $MEDIA`; for i in $MD5; do MD5=$i; break; done + echo -n "# storeAudioClipOpen: " + RES=`$XR_CLI storeAudioClipOpen "$SESSID" '' 'Title XY' "$MD5"` || \ + { ERN=$?; echo $RES; exit $ERN; } + unset URL + for i in $RES; do if [ -z $URL ] ; then URL=$i; else TOKEN=$i; fi; done + echo $TOKEN + echo $URL + if [ $DEBUG ]; then echo -n "Pres a key ..."; read KEY; fi + echo -n "# curl (PUT): " + curl -C 0 -T $MEDIA $URL || { ERN=$?; echo $RGUNID; exit $ERN; } + echo "status: $?" + if [ $DEBUG ]; then echo -n "Pres a key ..."; read KEY; fi + echo -n "# storeAudioClipClose: " + RGUNID=`$XR_CLI storeAudioClipClose "$SESSID" "$TOKEN"` || \ { ERN=$?; echo $RGUNID; exit $ERN; } echo $RGUNID } +accessRawAudioData() { + echo "# accessRawAudioData: " + RES=`$XR_CLI accessRawAudioData $SESSID $GUNID` || \ + { ERN=$?; echo $RES; exit $ERN; } + unset URL + for i in $RES; do if [ -z $URL ] ; then URL=$i; else TOKEN=$i; fi; done + echo $TOKEN + echo $URL + if [ $DEBUG ]; then echo -n "Pres a key ..."; read KEY; fi + echo -n "# releaseRawAudioData: " + $XR_CLI releaseRawAudioData $SESSID $TOKEN || exit $? +} + +downloadRAD() { + echo "# downloadRawAudioDataOpen: " + RES=`$XR_CLI downloadRawAudioDataOpen $SESSID $GUNID` || \ + { ERN=$?; echo $RES; exit $ERN; } + unset URL + for i in $RES; do if [ -z $URL ] ; then URL=$i; else TOKEN=$i; fi; done + echo $TOKEN + echo $URL + if [ $DEBUG ]; then echo -n "Pres a key ..."; read KEY; fi + echo -n "# curl: " + curl -Ifs $URL > /dev/null || { ERN=$?; echo $RES; exit $ERN; } + echo "status: $?" + echo -n "# downloadRawAudioDataClose: " + $XR_CLI downloadRawAudioDataClose $SESSID $TOKEN || exit $? +} + +downloadMeta() { + echo "# downloadMetadataOpen: " + RES=`$XR_CLI downloadMetadataOpen $SESSID $GUNID` || \ + { ERN=$?; echo $RES; exit $ERN; } + unset URL + for i in $RES; do if [ -z $URL ] ; then URL=$i; else TOKEN=$i; fi; done + echo $TOKEN + echo $URL + if [ $DEBUG ]; then echo -n "Pres a key ..."; read KEY; fi + echo -n "# curl: " + if [ $DEBUG ]; then lynx -source $URL; else + curl -Ifs $URL > /dev/null || { ERN=$?; echo $RES; exit $ERN; } + fi + echo "status: $?" + echo -n "# downloadMetadataClose: " + $XR_CLI downloadMetadataClose $SESSID $TOKEN || exit $? +} + deleteAudioClip() { echo -n "# deleteAudioClip: " $XR_CLI deleteAudioClip $SESSID $GUNID || exit $? @@ -145,6 +199,8 @@ elif [ "x$COMM" == "x" ]; then storeAudioClip GUNID=$RGUNID accessRawAudioData + downloadRAD + downloadMeta deleteAudioClip logout echo "#XMLRPC tests: OK." diff --git a/livesupport/modules/storageServer/var/xmlrpc/xrLocStor.php b/livesupport/modules/storageServer/var/xmlrpc/xrLocStor.php index dad35e7b7..515d6c0f0 100644 --- a/livesupport/modules/storageServer/var/xmlrpc/xrLocStor.php +++ b/livesupport/modules/storageServer/var/xmlrpc/xrLocStor.php @@ -23,11 +23,13 @@ Author : $Author: tomas $ - Version : $Revision: 1.8 $ + Version : $Revision: 1.9 $ Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/xmlrpc/xrLocStor.php,v $ ------------------------------------------------------------------------------*/ -#error_reporting(0); + +/* ====================================================== specific PHP config */ +//error_reporting(0); ini_set("error_prepend_string", " @@ -48,11 +50,13 @@ ini_set("error_append_string", " "); header("Content-type: text/xml"); +/* ================================================================= includes */ require_once 'DB.php'; require_once "XML/RPC/Server.php"; require_once '../conf.php'; require_once '../LocStor.php'; +/* ============================================ setting default error handler */ function errHndl($errno, $errmsg, $filename, $linenum, $vars){ if($errno == 8 /*E_NOTICE*/) return; $xr =& new XML_RPC_Response(0, 805, @@ -63,74 +67,14 @@ function errHndl($errno, $errmsg, $filename, $linenum, $vars){ } $old_error_handler = set_error_handler("errHndl"); -PEAR::setErrorHandling(PEAR_ERROR_RETURN); -$dbc = DB::connect($config['dsn'], TRUE); -$dbc->setFetchMode(DB_FETCHMODE_ASSOC); - - +/* ====================================== XML-RPC interface class for LocStor */ +/** + * XML-RPC interface for LocStor class + * + */ class XR_LocStor extends LocStor{ - /** - * Convert PHP variables to XMLRPC objects - * - * @param var mixed - PHP variable - * @param struct boolean - flag for using XMLRPC struct instead of array - * @return XMLRPC object - */ - function _v2xr($var, $struct=true){ - if(is_array($var)){ - $r = array(); - foreach($var as $k=>$v){ - if($struct) $r[$k]=$this->_v2xr($v); - else $r[]=$this->_v2xr($v); - } - return new XML_RPC_Value($r, ($struct ? "struct" : "array")); - }else if(is_int($var)){ - return new XML_RPC_Value($var, "int"); - }else if(is_bool($var)){ - return new XML_RPC_Value($var, "boolean"); - }else{ - return new XML_RPC_Value($var, "string"); - } - } - /** - * Convert XMLRPC struct to PHP array - * - * @param input XMLRPC struct - * @return array - */ - function _xr_getPars($input) - { - $p = $input->getParam(0); - if(isset($p) && $p->scalartyp()=="struct"){ - $p->structreset(); $r = array(); - while(list($k,$v) = $p->structeach()){ $r[$k] = $v->scalarval(); } - return array(TRUE, $r); - } - else return array(FALSE, new XML_RPC_Response(0, 801, - "wrong 1st parameter, struct expected." - )); - } - - /** - * Test XMLRPC - strupper and return given string, - * also return loginname of logged user - * - * @param input XMLRPC struct - * @return XMLRPC struct - */ - function xr_test($input) - { - list($ok, $r) = $this->_xr_getPars($input); - if(!$ok) return $r; - return new XML_RPC_Response($this->_v2xr(array( - 'str'=>strtoupper($r['teststring']), - 'login'=>$this->getSessLogin($r['sessid']), - 'sessid'=>$r['sessid'] - ), true)); - } - - + /* ------------------------------------------------------- authentication */ /** * Checks the login name and password of the user and return * true if login data are correct, othervise return false. @@ -142,9 +86,9 @@ class XR_LocStor extends LocStor{ *
  • login : string - login name
  • *
  • pass : string - password
  • * - * On success, returns a single XML-RPC value: + * On success, returns a XML-RPC struct with single field: *
      - *
    • boolean
    • + *
    • authenticate : boolean
    • *
    * * On errors, returns an XML-RPC error response. @@ -157,7 +101,7 @@ class XR_LocStor extends LocStor{ * * * @param input XMLRPC struct - * @return boolean + * @return XMLRPC struct * @see Subjects::authenticate */ function xr_authenticate($input) @@ -169,7 +113,9 @@ class XR_LocStor extends LocStor{ return new XML_RPC_Response(0, 804,"xr_authenticate: database error"); } $retval = ($res !== FALSE); - return new XML_RPC_Response(new XML_RPC_Value($retval, "boolean")); + return new XML_RPC_Response( + XML_RPC_encode(array('authenticate'=>$retval)) + ); } /** @@ -187,9 +133,9 @@ class XR_LocStor extends LocStor{ *
  • pass : string - password
  • * * - * On success, returns a single XML-RPC value: + * On success, returns a XML-RPC struct with single field: *
      - *
    • string - the newly generated session ID
    • + *
    • sessid : string - the newly generated session ID
    • *
    * * On errors, returns an XML-RPC error response. @@ -204,7 +150,7 @@ class XR_LocStor extends LocStor{ * * * @param input XMLRPC struct - * @return string + * @return XMLRPC struct * @see Alib::login */ function xr_login($input) @@ -220,11 +166,11 @@ class XR_LocStor extends LocStor{ "xr_login: login failed - incorrect username or password." ); else - return new XML_RPC_Response($this->_v2xr($res, false)); + return new XML_RPC_Response(XML_RPC_encode(array('sessid'=>$res))); } /** - * Logout, destroy session and return 'Bye'. + * Logout, destroy session and return status. * If session is not valid error message is returned. * * The XML-RPC name of this method is "locstor.logout". @@ -235,9 +181,9 @@ class XR_LocStor extends LocStor{ *
  • sessid : string - session id
  • * * - * On success, returns a single XML-RPC value: + * On success, returns a XML-RPC struct with single field: *
      - *
    • boolean - TRUE
    • + *
    • status : boolean - TRUE
    • *
    * * On errors, returns an XML-RPC error response. @@ -250,7 +196,7 @@ class XR_LocStor extends LocStor{ * * * @param input XMLRPC struct - * @return string + * @return XMLRPC struct * @see GreenBox::logout */ function xr_logout($input) @@ -258,14 +204,438 @@ class XR_LocStor extends LocStor{ list($ok, $r) = $this->_xr_getPars($input); if(!$ok) return $r; $res = $this->logout($r['sessid']); - if(!PEAR::isError($res)) - return new XML_RPC_Response($this->_v2xr('Bye', false)); - else + if(PEAR::isError($res)){ return new XML_RPC_Response(0, 803, "xr_logout: logout failed - not logged." ); + } + return new XML_RPC_Response(XML_RPC_encode(array('status'=>$res))); } + /* ---------------------------------------------------------------- store */ + /** + * Open writable URL for store new AudioClip or replace existing one. + * Writing to returned URL is possible using HTTP PUT method + * (as e.g. curl -T <filename> command does) + * + * The XML-RPC name of this method is "locstor.storeAudioClipOpen". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • gunid : string - global unique id of AudioCLip
    • + *
    • metadata : metadata XML string
    • + *
    • chsum : md5 checksum of media file
    • + *
    + * + * On success, returns a XML-RPC struct: + *
      + *
    • url : string - writable URL for HTTP PUT
    • + *
    • token : string - access token
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_storeAudioClipOpen: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::storeAudioClipOpen + */ + function xr_storeAudioClipOpen($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->storeAudioClipOpen( + $r['sessid'], $r['gunid'], $r['metadata'], $r['chsum'] + ); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_storeAudioClipOpen: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode($res)); + } + + /** + * Close writable URL for store new AudioClip or replace existing one. + * + * The XML-RPC name of this method is "locstor.storeAudioClip". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • token : string - access token
    • + *
    + * + * On success, returns a XML-RPC struct with single field: + *
      + *
    • gunid : string - gunid of stored file
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_storeAudioClipClose: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::storeAudioClipClose + */ + function xr_storeAudioClipClose($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->storeAudioClipClose($r['sessid'], $r['token']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_storeAudioClipClose: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode(array('gunid'=>$res))); + } + + /* ------------------------------------------------ access raw audio data */ + /** + * Make access to audio clip. + * + * The XML-RPC name of this method is "locstor.accessRawAudioData". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • gunid : string - global unique id of AudioClip
    • + *
    + * + * On success, returns a XML-RPC struct: + *
      + *
    • url : string - local access url
    • + *
    • token : string - access token
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_accessRawAudioData: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::accessRawAudioData + */ + function xr_accessRawAudioData($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->accessRawAudioData($r['sessid'], $r['gunid']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_accessRawAudioData: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode($res)); + } + + /** + * Release access to audio clip + * + * The XML-RPC name of this method is "locstor.releaseRawAudioData". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • token : string - access token + * returned by locstor.accessRawAudioData
    • + *
    + * + * On success, returns a XML-RPC struct with single field: + *
      + *
    • status : boolean
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_releaseRawAudioData: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::releaseRawAudioData + */ + function xr_releaseRawAudioData($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->releaseRawAudioData($r['sessid'], $r['token']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_releaseRawAudioData: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode(array('status'=>$res))); + } + + /* ---------------------------------------------- download raw audio data */ + /** + * Create downlodable URL for stored file + * + * The XML-RPC name of this method is "locstor.downloadRawAudioDataOpen". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • gunid : string - global unique id of AudioClip
    • + *
    + * + * On success, returns a XML-RPC struct: + *
      + *
    • url : string - downloadable url
    • + *
    • token : string - download token
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_accessRawAudioDataOpen: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::downloadRawAudioDataOpen + */ + function xr_downloadRawAudioDataOpen($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->downloadRawAudioDataOpen($r['sessid'], $r['gunid']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_downloadRawAudioDataOpen: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode($res)); + } + + /** + * Delete downlodable URL with media file. + * + * The XML-RPC name of this method is "locstor.downloadRawAudioDataClose". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • token : string - download token + * returned by locstor.downloadRawAudioDataOpen
    • + *
    + * + * On success, returns a XML-RPC struct with single field: + *
      + *
    • status : boolean
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_releaseRawAudioDataClose: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::downloadRawAudioDataClose + */ + function xr_downloadRawAudioDataClose($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->downloadRawAudioDataClose($r['token']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_downloadRawAudioDataClose: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode(array('status'=>$res))); + } + + /* ---------------------------------------------------- download metadata */ + /** + * Create downlodable URL for metadata part of stored file + * + * The XML-RPC name of this method is "locstor.downloadMetadataOpen". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • gunid : string - global unique id of AudioClip
    • + *
    + * + * On success, returns a XML-RPC struct: + *
      + *
    • url : string - downloadable url
    • + *
    • token : string - download token
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_downloadMetadataOpen: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::downloadRawAudioDataOpen + */ + function xr_downloadMetadataOpen($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->downloadMetadataOpen($r['sessid'], $r['gunid']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_downloadMetadataOpen: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode($res)); + } + + /** + * Delete downlodable URL with metadata. + * + * The XML-RPC name of this method is "locstor.downloadMetadataClose". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • token : string - download token + * returned by locstor.downloadRawAudioDataOpen
    • + *
    + * + * On success, returns a XML-RPC struct with single field: + *
      + *
    • status : boolean
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_downloadMetadataClose: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::downloadRawAudioDataClose + */ + function xr_downloadMetadataClose($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->downloadMetadataClose($r['token']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_downloadMetadataClose: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode(array('status'=>$res))); + } + + /* --------------------------------------------------------------- delete */ + /** + * Delete existing audio clip + * + * The XML-RPC name of this method is "locstor.deleteAudioClip". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • gunid : string - global unique id of AudioCLip
    • + *
    + * + * On success, returns a XML-RPC struct with single field: + *
      + *
    • status : boolean - TRUE
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_deleteAudioClip: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::deleteAudioClip + */ + function xr_deleteAudioClip($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->deleteAudioClip($r['sessid'], $r['gunid']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_deleteAudioClip: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode(array('status'=>$res))); + } + + /* ----------------------------------------------------------------- etc. */ /** * Check if audio clip exists and return TRUE/FALSE * @@ -278,9 +648,9 @@ class XR_LocStor extends LocStor{ *
  • gunid : string - global unique id of AudioCLip
  • * * - * On success, returns a single XML-RPC value: + * On success, returns a XML-RPC struct with single field: *
      - *
    • boolean
    • + *
    • exists : boolean
    • *
    * * On errors, returns an XML-RPC error response. @@ -294,7 +664,7 @@ class XR_LocStor extends LocStor{ * * * @param input XMLRPC struct - * @return boolean + * @return XMLRPC struct * @see LocStor::existsAudioClip */ function xr_existsAudioClip($input) @@ -309,289 +679,7 @@ class XR_LocStor extends LocStor{ "xr_existsAudioClip: ".$res->getMessage(). " ".$res->getUserInfo() ); - return new XML_RPC_Response(new XML_RPC_Value($res, "boolean")); - } - - /** - * Store new AudioClip or replace existing one. - * - * The XML-RPC name of this method is "locstor.storeAudioClip". - * - * The input parameters are an XML-RPC struct with the following - * fields: - *
      - *
    • sessid : string - session id
    • - *
    • gunid : string - global unique id of AudioCLip
    • - *
    • mediaFileLP : local path of raw audio file
    • - *
    • mdataFileLP : local path of metadata XML file
    • - *
    - * - * On success, returns a single XML-RPC value: - *
      - *
    • string - gunid of stored file
    • - *
    - * - * On errors, returns an XML-RPC error response. - * The possible error codes and error message are: - *
      - *
    • 3 - Incorrect parameters passed to method: - * Wanted ... , got ... at param
    • - *
    • 801 - wrong 1st parameter, struct expected.
    • - *
    • 805 - xr_storeAudioClip: - * <message from lower layer>
    • - *
    - * - * @param input XMLRPC struct - * @return string - * @see LocStor::storeAudioClip - */ - function xr_storeAudioClip($input) - { - list($ok, $r) = $this->_xr_getPars($input); - if(!$ok) return $r; - $res = $this->storeAudioClip( - $r['sessid'], $r['gunid'], $r['mediaFileLP'], $r['mdataFileLP'] - ); - if(!PEAR::isError($res)) - return new XML_RPC_Response(new XML_RPC_Value($res, "string")); - else - return new XML_RPC_Response(0, 805, - "xr_storeAudioClip: ".$res->getMessage(). - " ".$res->getUserInfo() - ); - } - - /** - * Delete existing audio clip - * - * The XML-RPC name of this method is "locstor.deleteAudioClip". - * - * The input parameters are an XML-RPC struct with the following - * fields: - *
      - *
    • sessid : string - session id
    • - *
    • gunid : string - global unique id of AudioCLip
    • - *
    - * - * On success, returns a single XML-RPC value: - *
      - *
    • boolean - TRUE
    • - *
    - * - * On errors, returns an XML-RPC error response. - * The possible error codes and error message are: - *
      - *
    • 3 - Incorrect parameters passed to method: - * Wanted ... , got ... at param
    • - *
    • 801 - wrong 1st parameter, struct expected.
    • - *
    • 805 - xr_deleteAudioClip: - * <message from lower layer>
    • - *
    - * - * @param input XMLRPC struct - * @return boolean - * @see LocStor::deleteAudioClip - */ - function xr_deleteAudioClip($input) - { - list($ok, $r) = $this->_xr_getPars($input); - if(!$ok) return $r; - $res = $this->deleteAudioClip($r['sessid'], $r['gunid']); - if(!PEAR::isError($res)) - return new XML_RPC_Response(new XML_RPC_Value($res, "boolean")); - else - return new XML_RPC_Response(0, 805, - "xr_deleteAudioClip: ".$res->getMessage(). - " ".$res->getUserInfo() - ); - } - - /** - * Update existing audio clip metadata - * - * The XML-RPC name of this method is "locstor.updateAudioClipMetadata". - * - * The input parameters are an XML-RPC struct with the following - * fields: - *
      - *
    • sessid : string - session id
    • - *
    • gunid : string - global unique id of AudioCLip
    • - *
    • mdataFileLP : local path of metadata XML file
    • - *
    - * - * On success, returns a single XML-RPC value: - *
      - *
    • boolean - TRUE
    • - *
    - * - * On errors, returns an XML-RPC error response. - * The possible error codes and error message are: - *
      - *
    • 3 - Incorrect parameters passed to method: - * Wanted ... , got ... at param
    • - *
    • 801 - wrong 1st parameter, struct expected.
    • - *
    • 805 - xr_updateAudioClipMetadata: - * <message from lower layer>
    • - *
    - * - * @param input XMLRPC struct - * @return boolean - * @see LocStor::updateAudioClipMetadata - */ - function xr_updateAudioClipMetadata($input) - { - list($ok, $r) = $this->_xr_getPars($input); - if(!$ok) return $r; - $res = $this->updateAudioClipMetadata( - $r['sessid'], $r['gunid'], $r['mdataFileLP'] - ); - if(!PEAR::isError($res)) - return new XML_RPC_Response(new XML_RPC_Value($res, "boolean")); - else - return new XML_RPC_Response(0, 805, - "xr_updateAudioClip: ".$res->getMessage(). - " ".$res->getUserInfo() - ); - } - - /** - * Search in local metadata database - * - * The XML-RPC name of this method is "locstor.searchMetadata". - * - * The input parameters are an XML-RPC struct with the following - * fields: - *
      - *
    • sessid : string - session id
    • - *
    • criteria : search string - * - will be searched in object part of RDF tripples - * - this parameter may be changed structured - * queries will be supported in the future
    • - *
    - * - * On success, returns a single XML-RPC value: - *
      - *
    • boolean - TRUE
    • - *
    - * - * On errors, returns an XML-RPC error response. - * The possible error codes and error message are: - *
      - *
    • 3 - Incorrect parameters passed to method: - * Wanted ... , got ... at param
    • - *
    • 801 - wrong 1st parameter, struct expected.
    • - *
    • 805 - xr_searchMetadata: - * <message from lower layer>
    • - *
    - * - * @param input XMLRPC struct - * @return boolean - * @see LocStor::searchMetadata - * @see GreenBox::localSearch - */ - function xr_searchMetadata($input) - { - list($ok, $r) = $this->_xr_getPars($input); - if(!$ok) return $r; - $res = $this->searchMetadata($r['sessid'], $r['criteria']); - if(!PEAR::isError($res)) - return new XML_RPC_Response(XML_RPC_encode($res)); - else - return new XML_RPC_Response(0, 803, - "xr_searchAudioClip: ".$res->getMessage(). - " ".$res->getUserInfo() - ); - } - - /** - * Make access to audio clip. - * - * The XML-RPC name of this method is "locstor.accessRawAudioData". - * - * The input parameters are an XML-RPC struct with the following - * fields: - *
      - *
    • sessid : string - session id
    • - *
    • gunid : string - global unique id of AudioClip
    • - *
    - * - * On success, returns a single XML-RPC value: - *
      - *
    • string - access symlink filename
    • - *
    - * - * On errors, returns an XML-RPC error response. - * The possible error codes and error message are: - *
      - *
    • 3 - Incorrect parameters passed to method: - * Wanted ... , got ... at param
    • - *
    • 801 - wrong 1st parameter, struct expected.
    • - *
    • 805 - xr_accessRawAudioData: - * <message from lower layer>
    • - *
    - * - * @param input XMLRPC struct - * @return string - * @see LocStor::accessRawAudioData - */ - function xr_accessRawAudioData($input) - { - list($ok, $r) = $this->_xr_getPars($input); - if(!$ok) return $r; - $res = $this->accessRawAudioData($r['sessid'], $r['gunid']); - if(!PEAR::isError($res)) - return new XML_RPC_Response(new XML_RPC_Value($res, "string")); - else - return new XML_RPC_Response(0, 805, - "xr_accessRawAudioData: ".$res->getMessage(). - " ".$res->getUserInfo() - ); - } - - /** - * Release access to audio clip - * - * The XML-RPC name of this method is "locstor.releaseRawAudioData". - * - * The input parameters are an XML-RPC struct with the following - * fields: - *
      - *
    • sessid : string - session id
    • - *
    • tmpLink : string - temporary access symlink - * returned by locstor.accessRawAudioData
    • - *
    - * - * On success, returns a single XML-RPC value: - *
      - *
    • boolean
    • - *
    - * - * On errors, returns an XML-RPC error response. - * The possible error codes and error message are: - *
      - *
    • 3 - Incorrect parameters passed to method: - * Wanted ... , got ... at param
    • - *
    • 801 - wrong 1st parameter, struct expected.
    • - *
    • 805 - xr_releaseRawAudioData: - * <message from lower layer>
    • - *
    - * - * @param input XMLRPC struct - * @return boolean - * @see LocStor::releaseRawAudioData - */ - function xr_releaseRawAudioData($input) - { - list($ok, $r) = $this->_xr_getPars($input); - if(!$ok) return $r; - $res = $this->releaseRawAudioData($r['sessid'], $r['tmpLink']); - if(!PEAR::isError($res)) - return new XML_RPC_Response(new XML_RPC_Value($res, "boolean")); - else - return new XML_RPC_Response(0, 805, - "xr_releaseRawAudioData: ".$res->getMessage(). - " ".$res->getUserInfo() - ); + return new XML_RPC_Response(XML_RPC_encode(array('exists'=>$res))); } /** @@ -606,9 +694,9 @@ class XR_LocStor extends LocStor{ *
  • gunid : string - global unique id of AudioCLip
  • * * - * On success, returns a single XML-RPC value: + * On success, returns a XML-RPC struct with single field: *
      - *
    • string - metadata as XML
    • + *
    • metadata : string - metadata as XML
    • *
    * * On errors, returns an XML-RPC error response. @@ -622,7 +710,7 @@ class XR_LocStor extends LocStor{ * * * @param input XMLRPC struct - * @return string + * @return XMLRPC struct * @see LocStor::getAudioClip */ function xr_getAudioClip($input) @@ -630,24 +718,30 @@ class XR_LocStor extends LocStor{ list($ok, $r) = $this->_xr_getPars($input); if(!$ok) return $r; $res = $this->getAudioClip($r['sessid'], $r['gunid']); - if(!PEAR::isError($res)) - return new XML_RPC_Response(new XML_RPC_Value($res, "string")); - else + if(PEAR::isError($res)){ return new XML_RPC_Response(0, 805, "xr_getAudioClip: ".$res->getMessage()." ".$res->getUserInfo() ); + } + return new XML_RPC_Response(XML_RPC_encode(array('metadata'=>$res))); } /** - * Reset storageServer for debugging. + * Update existing audio clip metadata * - * The XML-RPC name of this method is "locstor.resetStorage". + * The XML-RPC name of this method is "locstor.updateAudioClipMetadata". * - * There are no input parameters - * - * On success, returns a single XML-RPC value: + * The input parameters are an XML-RPC struct with the following + * fields: *
      - *
    • array - array with gunids of inserted files
    • + *
    • sessid : string - session id
    • + *
    • gunid : string - global unique id of AudioCLip
    • + *
    • metadata : metadata XML string
    • + *
    + * + * On success, returns a XML-RPC struct with single field: + *
      + *
    • status : boolean - TRUE
    • *
    * * On errors, returns an XML-RPC error response. @@ -656,12 +750,103 @@ class XR_LocStor extends LocStor{ *
  • 3 - Incorrect parameters passed to method: * Wanted ... , got ... at param
  • *
  • 801 - wrong 1st parameter, struct expected.
  • - *
  • 805 - xr_getAudioClip: + *
  • 805 - xr_updateAudioClipMetadata: * <message from lower layer>
  • * * * @param input XMLRPC struct - * @return string + * @return XMLRPC struct + * @see LocStor::updateAudioClipMetadata + */ + function xr_updateAudioClipMetadata($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->updateAudioClipMetadata( + $r['sessid'], $r['gunid'], $r['metadata'] + ); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_updateAudioClip: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode(array('status'=>$res))); + } + + /** + * Search in local metadata database + * + * The XML-RPC name of this method is "locstor.searchMetadata". + * + * The input parameters are an XML-RPC struct with the following + * fields: + *
      + *
    • sessid : string - session id
    • + *
    • criteria : search string + * - will be searched in object part of RDF tripples + * - this parameter may be changed structured + * queries will be supported in the near future
    • + *
    + * + * On success, returns a XML-RPC struct with single field: + *
      + *
    • results: array - array of gunids have founded
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_searchMetadata: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct + * @see LocStor::searchMetadata + * @see GreenBox::localSearch + */ + function xr_searchMetadata($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->searchMetadata($r['sessid'], $r['criteria']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 803, + "xr_searchAudioClip: ".$res->getMessage(). + " ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode(array('results'=>$res))); + } + + /** + * Reset storageServer for debugging. + * + * The XML-RPC name of this method is "locstor.resetStorage". + * + * The input parameters are an empty XML-RPC struct. + * + * On success, returns a XML-RPC struct with single field: + *
      + *
    • gunids : array - array with gunids of inserted files
    • + *
    + * + * On errors, returns an XML-RPC error response. + * The possible error codes and error message are: + *
      + *
    • 3 - Incorrect parameters passed to method: + * Wanted ... , got ... at param
    • + *
    • 801 - wrong 1st parameter, struct expected.
    • + *
    • 805 - xr_resetStorage: + * <message from lower layer>
    • + *
    + * + * @param input XMLRPC struct + * @return XMLRPC struct * @see LocStor::getAudioClip */ function xr_resetStorage($input) @@ -669,14 +854,98 @@ class XR_LocStor extends LocStor{ list($ok, $r) = $this->_xr_getPars($input); if(!$ok) return $r; $res = $this->resetStorage(); - if(!PEAR::isError($res)) - return new XML_RPC_Response(XML_RPC_encode($res)); - else + if(PEAR::isError($res)){ return new XML_RPC_Response(0, 805, "xr_getAudioClip: ".$res->getMessage()." ".$res->getUserInfo() ); + } + return new XML_RPC_Response(XML_RPC_encode(array('gunids'=>$res))); } -} + + + /* ------------------------------------------- test methods for debugging */ + /** + * Test XMLRPC - strupper and return given string, + * also return loginname of logged user + * - debug method only + * + * @param input XMLRPC struct + * @return XMLRPC struct + */ + function xr_test($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + return new XML_RPC_Response(XML_RPC_encode(array( + 'str'=>strtoupper($r['teststring']), + 'login'=>$this->getSessLogin($r['sessid']), + 'sessid'=>$r['sessid'] + ))); + } + + /** + * Open writable URL for put method - debug method only + * + * @param input XMLRPC struct + * @return XMLRPC struct + */ + function xr_openPut($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->bsOpenPut(); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_getAudioClip: ".$res->getMessage()." ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode($res)); + } + + /** + * Close writable URL - debug method only + * + * @param input XMLRPC struct + * @return XMLRPC struct + */ + function xr_closePut($input) + { + list($ok, $r) = $this->_xr_getPars($input); + if(!$ok) return $r; + $res = $this->bsClosePut($r['token'], $r['chsum']); + if(PEAR::isError($res)){ + return new XML_RPC_Response(0, 805, + "xr_getAudioClip: ".$res->getMessage()." ".$res->getUserInfo() + ); + } + return new XML_RPC_Response(XML_RPC_encode(array('fname'=>$res))); + } + + /* ---------------------------------------------------- "private" methods */ + /** + * Check and convert struct of parameters + * + * @param input XMLRPC parameters + * @return array + */ + function _xr_getPars($input) + { + $p = $input->getParam(0); + if(isset($p) && $p->scalartyp()=="struct"){ + $r = XML_RPC_decode($p); + return array(TRUE, $r); + } + else return array(FALSE, new XML_RPC_Response(0, 801, + "wrong 1st parameter, struct expected." + )); + } + +} // end of class definition + +/* ============================================================= runable code */ +PEAR::setErrorHandling(PEAR_ERROR_RETURN); +$dbc = DB::connect($config['dsn'], TRUE); +$dbc->setFetchMode(DB_FETCHMODE_ASSOC); $locStor = &new XR_LocStor(&$dbc, $config); @@ -688,8 +957,18 @@ $methods = array( 'logout' => 'Logout from storage.', 'existsAudioClip' => 'Checks if an Audio clip with the specified '. 'id is stored in local storage.', - 'storeAudioClip' => 'Store a new audio clip or replace '. - 'an existing one.', + 'storeAudioClipOpen' => 'Open channel for store a new audio clip '. + 'or replace an existing one.', + 'storeAudioClipClose' => 'Close channel for store a new audio clip'. + ' or replace an existing one.', + 'downloadRawAudioDataOpen'=> 'Create and return downloadable URL'. + 'for audio file', + 'downloadRawAudioDataClose'=>'Discard downloadable URL for audio file', + 'downloadMetadataOpen' => 'Create and return downloadable URL'. + 'for metadata', + 'downloadMetadataClose' => 'Discard downloadable URL for metadata', + 'openPut' => 'openPut', + 'closePut' => 'closePut', 'deleteAudioClip' => 'Delete an existing Audio clip.', 'updateAudioClipMetadata' => 'Update the metadata of an Audio clip '. 'stored in Local storage.', @@ -714,13 +993,4 @@ foreach($methods as $method=>$description){ } $s=new XML_RPC_Server( $defs ); -#$s=new XML_RPC_Server( $defs , 0 ); -##var_dump($s); -#$r = $s->parseRequest(); -#$r = $r[0]; -#var_dump($r); -#echo ($cn = get_class($r))."\n"; -#$a = get_class_methods($cn); -#var_dump($a); -#echo $r->serialize(); ?> diff --git a/livesupport/modules/storageServer/var/xmlrpc/xr_cli_test.py b/livesupport/modules/storageServer/var/xmlrpc/xr_cli_test.py index 7d686ecdb..20b4bd30e 100755 --- a/livesupport/modules/storageServer/var/xmlrpc/xr_cli_test.py +++ b/livesupport/modules/storageServer/var/xmlrpc/xr_cli_test.py @@ -24,7 +24,7 @@ # # # Author : $Author: tomas $ -# Version : $Revision: 1.3 $ +# Version : $Revision: 1.4 $ # Location : $Source: /home/paul/cvs2svn-livesupport/newcvsrepo/livesupport/modules/storageServer/var/xmlrpc/Attic/xr_cli_test.py,v $ # #------------------------------------------------------------------------------ @@ -84,29 +84,47 @@ try: elif method=="test": print server.locstor.test({'sessid':pars[0], 'teststring':pars[1]}) elif method=="authenticate": - print server.locstor.authenticate({'login':pars[0], 'pass':pars[1]}) + print server.locstor.authenticate({'login':pars[0], 'pass':pars[1]})['authenticate'] elif method=="login": - print server.locstor.login({'login':pars[0], 'pass':pars[1]}) + print server.locstor.login({'login':pars[0], 'pass':pars[1]})['sessid'] elif method=="logout": print server.locstor.logout({'sessid':pars[0]}) - elif method=="existsAudioClip": - print server.locstor.existsAudioClip({'sessid':pars[0], 'gunid':pars[1]} ) - elif method=="storeAudioClip": - print server.locstor.storeAudioClip({'sessid':pars[0], 'gunid':pars[1], 'mediaFileLP':pars[2], 'mdataFileLP':pars[3]}) + elif method=="storeAudioClipOpen": + r = server.locstor.storeAudioClipOpen({'sessid':pars[0], 'gunid':pars[1], 'metadata':pars[2], 'chsum':pars[3]}) + print r['url']+'\n'+r['token'] + elif method=="storeAudioClipClose": + print server.locstor.storeAudioClipClose({'sessid':pars[0], 'token':pars[1]})['gunid'] + elif method=="accessRawAudioData": + r = server.locstor.accessRawAudioData({'sessid':pars[0], 'gunid':pars[1]}) + print r['url']+'\n'+r['token'] + elif method=="releaseRawAudioData": + print server.locstor.releaseRawAudioData({'sessid':pars[0], 'token':pars[1]}) + elif method=="downloadRawAudioDataOpen": + r = server.locstor.downloadRawAudioDataOpen({'sessid':pars[0], 'gunid':pars[1]}) + print r['url']+'\n'+r['token'] + elif method=="downloadRawAudioDataClose": + print server.locstor.downloadRawAudioDataClose({'sessid':pars[0], 'token':pars[1]}) + elif method=="downloadMetadataOpen": + r = server.locstor.downloadMetadataOpen({'sessid':pars[0], 'gunid':pars[1]}) + print r['url']+'\n'+r['token'] + elif method=="downloadMetadataClose": + print server.locstor.downloadMetadataClose({'sessid':pars[0], 'token':pars[1]}) elif method=="deleteAudioClip": print server.locstor.deleteAudioClip({'sessid':pars[0], 'gunid':pars[1]}) + elif method=="existsAudioClip": + print server.locstor.existsAudioClip({'sessid':pars[0], 'gunid':pars[1]} )['exists'] elif method=="updateAudioClipMetadata": print server.locstor.updateAudioClipMetadata({'sessid':pars[0], 'gunid':pars[1], 'mdataFileLP':pars[2]}) elif method=="searchMetadata": print server.locstor.searchMetadata({'sessid':pars[0], 'criteria':pars[1]}) - elif method=="accessRawAudioData": - print server.locstor.accessRawAudioData({'sessid':pars[0], 'gunid':pars[1]}) - elif method=="releaseRawAudioData": - print server.locstor.releaseRawAudioData({'sessid':pars[0], 'tmpLink':pars[1]}) elif method=="getAudioClip": print server.locstor.getAudioClip({'sessid':pars[0], 'gunid':pars[1]}) elif method=="resetStorage": print server.locstor.resetStorage({}) + elif method=="openPut": + r = server.locstor.openPut({}); print r['url']+'\n'+r['token'] + elif method=="closePut": + print server.locstor.closePut({'token':pars[0], 'chsum':pars[1]}) else: print "Unknown command: "+method sys.exit(1)