libretime/backend/Restore.php

436 lines
14 KiB
PHP

<?php
define('ACCESS_TYPE', 'restore');
/**
* @package Campcaster
* @subpackage StorageServer
* @copyright 2010 Sourcefabric O.P.S.
* @license http://www.gnu.org/licenses/gpl.txt
*/
class Restore {
/**
* Name of logfile
* @var string
*/
private $logFile;
/**
* session id
* @var string
*/
private $sessid;
/**
* @var string
*/
private $token;
/**
* Name of statusfile
* @var string
*/
private $statusFile;
/**
* Name of temporary directory, to here extract the backup tarball
* @var string
*/
private $tmpDir;
/**
* @var string
*/
// private $loglevel = 'warn';
public $loglevel = 'warn';
// public $loglevel = 'debug';
/**
* @var GreenBox
*/
private $gb;
/**
* @param GreenBox $gb
* greenbox object reference
*/
public function __construct(&$gb)
{
global $CC_CONFIG;
$this->gb =& $gb;
$this->token = null;
$this->logFile = $CC_CONFIG['bufferDir'].'/'.ACCESS_TYPE.'.log';
if ($this->loglevel == 'debug') {
$this->addLogItem("-I- ".date("Ymd-H:i:s")." construct\n");
}
}
/**
* Call asyncronously the restore procedure. Restore from backup.
*
* @param string $sessid
* session id
* @param string $backup_file
* path of the backup file
* @return array
* hasharray with field:
* token string: backup token
*/
function openRestore($sessid, $backup_file)
{
if ($this->loglevel=='debug') {
$this->addLogItem("-I-".date("Ymd-H:i:s")." doRestore - sessid:$sessid\n");
}
$this->sessid = $sessid;
// generate token
$this->token = StoredFile::CreateGunid();
// status file -> working
$this->setEnviroment();
file_put_contents($this->statusFile, 'working');
//call the restore script in background
$command = dirname(__FILE__).'/../bin/restore.php';
$runLog = "/dev/null";
$params = "{$backup_file} {$this->statusFile} {$this->token} {$sessid}>> $runLog &";
$ret = system("$command $params", $st);
if ($this->loglevel=='debug') {
$this->addLogItem("-I-".date("Ymd-H:i:s")." restore.php call: $st/$ret\n");
}
return array('token'=>$this->token);
}
/**
* Check the status of restore
*
* @param string $token
* @return array
* hasharray with field:
* status : string - susccess | working | fault
* faultString : string - description of fault
* token : stirng - backup token
* url : string - access url
* tmpfile : string - access filename
*/
function checkRestore($token)
{
if ($this->loglevel == 'debug') {
$this->addLogItem("-I- ".date("Ymd-H:i:s")." checkBackup - token:$token\n");
}
$this->token = $token;
$this->setEnviroment();
if (is_file($this->statusFile)) {
$r = array();
$stat = file_get_contents($this->statusFile);
if (strpos($stat,'fault|') !== false) {
list($stat,$message) = explode('|',$stat);
}
$r['status'] = $stat;
if ($stat=='fault') {
$r['faultString'] = $message;
} else {
$r['faultString'] = '';
}
return $r;
} else {
return PEAR::raiseError('Restore::checkRestore: invalid token!');
}
}
/**
* Check the status of restore.
*
* @param string $token
* @return array
* hasharray with field:
* status : boolean - is success
*/
function closeRestore($token)
{
if ($this->loglevel=='debug') {
$this->addLogItem("-I- ".date("Ymd-H:i:s")." checkBackup - token:$token\n");
}
$this->token = $token;
$this->setEnviroment();
$this->rRmDir($this->tmpDir);
unlink($this->statusFile);
return array("status" => !is_file($this->statusFile));
}
/**
* Do restore in background
*
* this function is called from the asyncron commandline script
* ../bin/restore.php
*
* @param string $backupfile
* path of backupfile
* @param string $token
* restore token
* @param string $sessid
* session id
*/
function startRestore($backupfile, $token, $sessid)
{
if ($this->loglevel=='debug') {
$this->addLogItem("-I- ".date("Ymd-H:i:s")." startRestore - bufile:$backupfile | token:$token\n");
}
$this->token = $token;
$this->sessid = $sessid;
$this->setEnviroment();
// extract tarball
$command = 'tar -xf '.$backupfile .' --directory '.$this->tmpDir;
$res = system($command);
//$this->addLogItem('command: '.$command."\n");
//$this->addLogItem('res: '.$res."\n");
//simple check of archive format
if (is_dir($this->tmpDir.'audioClip/') &&
is_dir($this->tmpDir.'meta-inf/') &&
is_dir($this->tmpDir.'playlist/')) {
//search metafiles
$this->metafiles = $this->getMetaFiles();
#$this->addLogItem('metafiles:'.print_r($this->metafiles,true));
//add to storage server
foreach ($this->metafiles as $info) {
$r = $this->addFileToStorage($info['file'],$info['type'],$info['id']);
if (PEAR::isError($r)) {
$this->addLogItem("-E- ".date("Ymd-H:i:s").
" startRestore - addFileToStorage \n".
"(".$put->getMessage()."/".$put->getUserInfo().")\n"
);
file_put_contents($this->statusFile, 'fault|'.$put->getMessage()."/".$put->getUserInfo());
return;
}
}
} else {
$this->addLogItem("-E- ".date("Ymd-H:i:s")." startRestore - invalid archive format\n");
file_put_contents($this->statusFile, 'fault|invalid archive format');
return;
}
file_put_contents($this->statusFile, 'success');
// unlink($backupfile);
}
/**
* Get the metafiles.
*
* @return array
* array of hasharray with field:
* file : string - metafile path
* type : stirng - audioClip | playlist
* id : string - the backuped gunid
*/
function getMetaFiles()
{
if ($this->loglevel=='debug') {
$this->addLogItem("-I- ".date("Ymd-H:i:s")." getMetaFiles - tmpDir:{$this->tmpDir}\n");
}
$audioclips = scandir($this->tmpDir.'audioClip/');
$playlists = scandir($this->tmpDir.'playlist/');
for ($i = 0; $i < count($audioclips); $i++) {
if (strpos($audioclips[$i],'xml')!==false)
$r[] = array('file' => $this->tmpDir.'audioClip/'.$audioclips[$i],
'type' => 'audioClip',
'id' => str_replace('.xml','',$audioclips[$i]));
}
for ($i = 0; $i < count($playlists); $i++) {
if (strpos($playlists[$i],'xml') !== false)
$r[] = array('file' => $this->tmpDir.'playlist/'.$playlists[$i],
'type' => 'playlist',
'id' => str_replace('.xml','',$playlists[$i]));
}
return $r;
}
/**
* Add the file to the storage server.
*
* @param string $file
* path of metafile
* @param string $type
* restore token
* @param string $sessid
* session id
*
* @return mixed
* true if success or PEAR_error
*/
function addFileToStorage($file,$type,$gunid)
{
if ($this->loglevel=='debug') {
$this->addLogItem("-I- ".date("Ymd-H:i:s")." addFileToStorage - file:$file | type:$type | id:$gunid\n");
}
require_once("XmlParser.php");
$tree = XmlParser::parse($file);
$mediaFileLP = str_replace('.xml','',$file);
$mediaFileLP = ($type=='audioClip' && is_file($mediaFileLP))?$mediaFileLP:'';
$ex = $this->gb->existsFile($this->sessid,$gunid);
if (PEAR::isError($ex)) {
$this->addLogItem("-E- ".date("Ymd-H:i:s").
" addFileToStorage - existsFile($gunid) ".
"(".$ex->getMessage()."/".$ex->getUserInfo().")\n"
);
}
if (!PEAR::isError($ex) && $ex) { // file is exists in storage server
//replace it
$id = BasicStor::IdFromGunid($gunid);
$replace = $this->gb->replaceFile(
$id, # id int, virt.file's local id
$mediaFileLP, # mediaFileLP string, local path of media file
$file, # mdataFileLP string, local path of metadata file
$this->sessid); # sessid string, session id
if (PEAR::isError($replace)) {
$this->addLogItem("-E- ".date("Ymd-H:i:s").
" addFileToStorage - replaceFile Error ".
"(".$replace->getMessage()."/".$replace->getUserInfo().")\n"
);
file_put_contents($this->statusFile, 'fault|'.$replace->getMessage()."/".$replace->getUserInfo());
return $replace;
}
#$this->addLogItem("replace it \n");
} else {
// add as new
$name = $tree->children[0]->children[0]->content;
if (empty($name)) {
$name = $tree->attrs['title']->val;
}
if (empty($name)) {
$name = '???';
}
if ($this->loglevel=='debug') {
$this->addLogItem("-I- ".date("Ymd-H:i:s")." putFile\n".
"$name, $mediaFileLP, $file, {$this->sessid}, $gunid, $type \n"
);
}
$values = array(
"filename" => $name,
"filepath" => $mediaFileLP,
"metadata" => $file,
"gunid" => $gunid,
"filetype" => $type
);
$put = $this->gb->putFile($values, $this->sessid);
//$this->addLogItem("add as new \n");
if (PEAR::isError($put)) {
$this->addLogItem("-E- ".date("Ymd-H:i:s").
" addFileToStorage - putFile Error ".
"(".$put->getMessage()."/".$put->getUserInfo().")\n"
."\n---\n".file_get_contents($file)."\n---\n"
);
file_put_contents($this->statusFile, 'fault|'.$put->getMessage()."/".$put->getUserInfo());
//$this->addLogItem("Error Object: ".print_r($put,true)."\n");
return $put;
}
}
$ac = StoredFile::RecallByGunid($gunid);
if (is_null($ac) || PEAR::isError($ac)) {
return $ac;
}
$res = $ac->setState('ready');
if (PEAR::isError($res)) {
return $res;
}
return true;
}
/**
* Figure out the environment to the backup.
*
*/
function setEnviroment()
{
global $CC_CONFIG;
if ($this->loglevel=='debug') {
$this->addLogItem("-I- ".date("Ymd-H:i:s")." setEnviroment\n");
}
$this->statusFile = $CC_CONFIG['accessDir'].'/'.$this->token.'.status';
$this->tmpDir = '/tmp/ls_restore/'.$this->token.'/';
$this->rMkDir($this->tmpDir);
}
/**
* Add a line to the logfile.
*
* @param string $item
* the new row of log file
*/
function addLogItem($item)
{
$f = fopen ($this->logFile,'a');
flock($f,LOCK_SH);
fwrite($f,$item);
flock($f,LOCK_UN);
fclose($f);
//echo file_get_contents($this->logFile)."<BR><BR>\n\n";
}
/**
* Delete a directory recursive
*
* @param string $dirname
* path of dir
*
* @return boolean
* is success
*/
function rRmDir($dirname)
{
if (is_dir($dirname)) {
$dir_handle = opendir($dirname);
}
while ($file = readdir($dir_handle)) {
if ($file!="." && $file!="..") {
if (!is_dir($dirname."/".$file)) {
unlink ($dirname."/".$file);
} else {
Restore::rRmDir($dirname."/".$file);
}
}
}
closedir($dir_handle);
rmdir($dirname);
return true;
}
/**
* Create a directory recursive
*
* @param string $dirname
* path of dir.
* @param int $mode
* octal - rights of dir.
* @param boolean $recursive
* do it recursive.
*
* @return boolean
*/
function rMkDir($dirname, $mode=0777, $recursive=true)
{
if (is_null($dirname) || $dirname === "" ) {
return false;
}
if (is_dir($dirname) || $dirname === "/" ) {
return true;
}
if ($this->rMkDir(dirname($dirname), $mode, $recursive)) {
return mkdir($dirname, $mode);
}
return false;
}
} // class Restore
?>