diff --git a/HandBrakeCluster/ClientLogEntry.class.php b/HandBrakeCluster/ClientLogEntry.class.php new file mode 100644 index 0000000..9aa16fa --- /dev/null +++ b/HandBrakeCluster/ClientLogEntry.class.php @@ -0,0 +1,13 @@ + diff --git a/HandBrakeCluster/Config.class.php b/HandBrakeCluster/Config.class.php index b4455f9..4218a2a 100644 --- a/HandBrakeCluster/Config.class.php +++ b/HandBrakeCluster/Config.class.php @@ -2,10 +2,53 @@ class HandBrakeCluster_Config { - private $filename; + private $dbconfig; + private $database; - public function __construct($filename) { - $this->filename = $filename; + private $databaseConfig = array(); + private $settings = array(); + + public function __construct($dbconfig) { + $this->dbconfig = $dbconfig; + + $this->parseDatabaseConfig(); + } + + public function parseDatabaseConfig() { + $this->databaseConfig = parse_ini_file($this->dbconfig); + } + + public function getDatabase($key) { + if (!isset($this->databaseConfig[$key])) { + throw new HandBrakeCluster_Exception_DatabaseConfigMissing($key); + } + + return $this->databaseConfig[$key]; + } + + public function setDatabase(HandBrakeCluster_Database $database) { + $this->database = $database; + $this->preload(); + } + + public function preload() { + if (!$this->database) { + throw new HandBrakeCluster_Exception_NoDatabaseConnection(); + } + + $this->settings = $this->database->selectAssoc('SELECT name,value FROM settings', 'name', 'value'); + } + + public function exists($key) { + return isset($this->settings[$key]); + } + + public function get($key) { + if (!isset($this->settings[$key])) { + throw new HandBrakeCluster_Exception_UnknownSetting($key); + } + + return $this->settings[$key]; } }; diff --git a/HandBrakeCluster/Database.class.php b/HandBrakeCluster/Database.class.php index 23945de..5f2075a 100644 --- a/HandBrakeCluster/Database.class.php +++ b/HandBrakeCluster/Database.class.php @@ -3,9 +3,95 @@ class HandBrakeCluster_Database { private $config; + private $dbh; + + private $hostname; + private $username; + private $password; + private $dbname; + + private $prepared_statements = array(); public function __construct(HandBrakeCluster_Config $config) { - $this->config = $config; + $this->config = $config; + + $this->hostname = $this->config->getDatabase('hostname'); + $this->username = $this->config->getDatabase('username'); + $this->password = $this->config->getDatabase('password'); + $this->dbname = $this->config->getDatabase('dbname'); + + try { + $this->dbh = new PDO("mysql:host={$this->hostname};dbname={$this->dbname}", $this->username, $this->password); + } catch (PDOException $e) { + throw new HandBrakeCluster_Exception_DatabaseConnectionFailed($e->getMessage()); + } + + } + + public function __destruct() { + $this->dbh = null; + } + + public function selectAssoc($sql, $key_col, $value_col) { + $results = array(); + + foreach ($this->dbh->query($sql) as $row) { + $results[$row[$key_col]] = $row[$value_col]; + } + + return $results; + } + + public function selectList($sql, $bind_params = null) { + if ($bind_params) { + $stmt = $this->dbh->prepare($sql); + + foreach ($bind_params as $param) { + $stmt->bindValue(':'.$param['name'], $param['value'], $param['type']); + } + + $result = $stmt->execute(); + if (!$result) { + throw new HandBrakeCluster_Exception_DatabaseQueryFailed(); + } + + return $stmt->fetchAll(); + + } else { + $results = array(); + + $result = $this->dbh->query($sql); + foreach ($result as $row) { + $results[] = $row; + } + + return $results; + } + } + + public function selectOne($sql, $bind_params = null) { + $rows = $this->selectList($sql, $bind_params); + if (count($rows) != 1) { + throw new HandBrakeCluster_Exception_ResultCountMismatch(count($rows)); + } + + return $rows[0]; + } + + public function insert($sql, $bind_params = null) { + $stmt = $this->dbh->prepare($sql); + + if ($bind_params) { + foreach ($bind_params as $param) { + $stmt->bindValue(':'.$param['name'], $param['value'], $param['type']); + } + } + + return $stmt->execute(); + } + + public function errorInfo() { + return $this->dbh->errorInfo(); } } diff --git a/HandBrakeCluster/Exceptions.class.php b/HandBrakeCluster/Exceptions.class.php new file mode 100644 index 0000000..6e02620 --- /dev/null +++ b/HandBrakeCluster/Exceptions.class.php @@ -0,0 +1,13 @@ + diff --git a/HandBrakeCluster/Job.class.php b/HandBrakeCluster/Job.class.php index f739033..e10c99f 100644 --- a/HandBrakeCluster/Job.class.php +++ b/HandBrakeCluster/Job.class.php @@ -3,15 +3,127 @@ class HandBrakeCluster_Job { private $id; + private $name; + private $source; + private $destination; + private $title; + private $format; + private $video_codec; + private $video_width; + private $video_height; + private $quantizer; + private $deinterlace; + private $audio_tracks; + private $audio_codecs; + private $audio_names; + private $subtitle_tracks; - public function __construct($id) { - $this->id = $id; + private $statuses = null; + + + public function __construct($id, $name, $source, $destination, $title, $format, $video_codec, $video_width, $video_height, $quantizer, $deinterlace, $audio_tracks, $audio_codecs, $audio_names, $subtitle_tracks) { + $this->id = $id; + $this->name = $name; + $this->source = $source; + $this->destination = $destination; + $this->title = $title; + $this->format = $format; + $this->video_codec = $video_codec; + $this->video_width = $video_width; + $this->video_height = $video_height; + $this->quantizer = $quantizer; + $this->deinterlace = $deinterlace; + $this->audio_tracks = $audio_tracks; + $this->audio_codecs = $audio_codecs; + $this->audio_names = $audio_names; + $this->subtitle_tracks = $subtitle_tracks; + } + + public static function fromDatabaseRow($row) { + return new HandBrakeCluster_Job( + $row['id'], + $row['name'], + $row['source'], + $row['destination'], + $row['title'], + $row['format'], + $row['video_codec'], + $row['video_width'], + $row['video_height'], + $row['quantizer'], + $row['deinterlace'], + $row['audio_tracks'], + $row['audio_codecs'], + $row['audio_names'], + $row['subtitle_tracks'] + ); + } + + public static function fromId($id) { + $database = HandBrakeCluster_Main::instance()->database(); + return HandBrakeCluster_Job::fromDatabaseRow( + $database->selectOne('SELECT * FROM jobs WHERE id=:id', array( + array('name' => 'id', 'value' => $id, 'type' => PDO::PARAM_INT) + ) + ) + ); + } + + public static function all() { + $jobs = array(); + + $database = HandBrakeCluster_Main::instance()->database(); + foreach ($database->selectList('SELECT * FROM jobs') as $row) { + $jobs[] = self::fromDatabaseRow($row); + } + + return $jobs; + } + + public static function allWithStatus($status) { + $jobs = array(); + + $database = HandBrakeCluster_Main::instance()->database(); + foreach ($database->selectList('SELECT * FROM jobs WHERE id IN (SELECT id FROM job_status_current WHERE status=:status)', array( + array('name' => 'status', 'value' => $status, 'type' => PDO::PARAM_INT) + )) as $row) { + $jobs[] = self::fromDatabaseRow($row); + } + + return $jobs; + } + + protected function loadStatuses() { + if ($this->statuses == null) { + $this->statuses = HandBrakeCluster_JobStatus::allForJob($this->id); + } + } + + public function currentStatus() { + $this->loadStatuses(); + return $this->statuses[count($this->statuses) - 1]; } public function id() { return $this->id; } + public function name() { + return $this->name; + } + + public function source() { + return $this->source; + } + + public function destination() { + return $this->destination; + } + + public function title() { + return $this->title; + } + }; ?> diff --git a/HandBrakeCluster/JobStatus.class.php b/HandBrakeCluster/JobStatus.class.php new file mode 100644 index 0000000..29b9adc --- /dev/null +++ b/HandBrakeCluster/JobStatus.class.php @@ -0,0 +1,73 @@ + 'Queued', + self::FAILED => 'Failed', + self::RUNNING => 'Running', + self::COMPLETE => 'Complete' + ); + + protected $id; + protected $job_id; + protected $status; + protected $ctime; + + protected function __construct($id, $job_id, $status, $ctime) { + $this->id = $id; + $this->job_id = $job_id; + $this->status = $status; + $this->ctime = $ctime; + } + + public static function fromDatabaseRow($row) { + return new HandBrakeCluster_JobStatus( + $row['id'], + $row['job_id'], + $row['status'], + $row['ctime'] + ); + } + + public static function allForJob($job_id) { + $statuses = array(); + + $database = HandBrakeCluster_Main::instance()->database(); + foreach ($database->selectList('SELECT * FROM job_status WHERE job_id=:job_id ORDER BY ctime ASC', array( + array('name' => 'job_id', 'value' => $job_id, 'type' => PDO::PARAM_INT), + )) as $row) { + $statuses[] = HandBrakeCluster_JobStatus::fromDatabaseRow($row); + } + + return $statuses; + } + + public function id() { + return $this->id; + } + + public function jobId() { + return $this->job_id; + } + + public function status() { + return $this->status; + } + + public function statusName() { + return self::$status_names[$this->status]; + } + + public function ctime() { + return $this->ctime; + } + +}; + +?> diff --git a/HandBrakeCluster/Log.class.php b/HandBrakeCluster/Log.class.php index 54c8b24..837372c 100644 --- a/HandBrakeCluster/Log.class.php +++ b/HandBrakeCluster/Log.class.php @@ -2,14 +2,58 @@ class HandBrakeCluster_Log { + private static $hostname = ''; + private $database; private $config; public function __construct(HandBrakeCluster_Database $database, HandBrakeCluster_Config $config) { $this->database = $database; $this->config = $config; + + } + + public function log($severity, $message, $job_id = 0) { + $result = $this->database->insert('INSERT INTO client_log (job_id,level,ctime,pid,hostname,progname,line,message) VALUES(:job_id, :level, :ctime, :pid, :hostname, :progname, :line, :message)', + array( + array('name' => 'job_id', 'value' => $job_id, 'type' => PDO::PARAM_INT), + array('name' => 'level', 'value' => $severity, 'type' => PDO::PARAM_STR), + array('name' => 'ctime', 'value' => time(), 'type' => PDO::PARAM_INT), + array('name' => 'pid', 'value' => 0, 'type' => PDO::PARAM_INT), + array('name' => 'hostname', 'value' => self::$hostname, 'type' => PDO::PARAM_STR), + array('name' => 'progname', 'value' => 'webui', 'type' => PDO::PARAM_STR), + array('name' => 'line', 'value' => 0, 'type' => PDO::PARAM_INT), + array('name' => 'message', 'value' => $message, 'type' => PDO::PARAM_STR) + ) + ); + + if (!$result) { + var_dump($this->database->errorInfo()); + } + } + + public function debug($message, $job_id = 0) { + return $this->log('DEBUG', $message, $job_id); + } + + public function info($messgae, $job_id = 0) { + return $this->log('INFO', $message, $job_id); + } + + public function warning($message, $job_id = 0) { + return $this->log('WARNING', $message, $job_id); + } + + public function error($message, $job_id = 0) { + return $this->log('ERROR', $message, $job_id); + } + + public static function initialise() { + self::$hostname = trim(`hostname`); } } +HandBrakeCluster_Log::initialise(); + ?> diff --git a/HandBrakeCluster/LogEntry.class.php b/HandBrakeCluster/LogEntry.class.php new file mode 100644 index 0000000..408399e --- /dev/null +++ b/HandBrakeCluster/LogEntry.class.php @@ -0,0 +1,122 @@ +id = $id; + $this->job_id = $job_id; + $this->level = $level; + $this->ctime = $ctime; + $this->pid = $pid; + $this->hostname = $hostname; + $this->progname = $progname; + $this->line = $line; + $this->message = $message; + } + + public static function fromDatabaseRow($row) { + return new HandBrakeCluster_ClientLogEntry( + $row['id'], + $row['job_id'], + $row['level'], + $row['ctime'], + $row['pid'], + $row['hostname'], + $row['progname'], + $row['line'], + $row['message'] + ); + } + + public static function fromId($id) { + $database = HandBrakeCluster_Main::instance()->database(); + return HandBrakeCluster_ClientLogEntry::fromDatabaseRow( + $database->selectOne('SELECT * FROM '.self::$table_name.' WHERE id=:id', array( + array('name' => 'id', 'value' => $id, 'type' => PDO::PARAM_INT) + ) + ) + ); + } + + public static function recent($limit = 100) { + $entries = array(); + + $database = HandBrakeCluster_Main::instance()->database(); + foreach ($database->selectList('SELECT * FROM '.self::$table_name.' ORDER BY ctime DESC LIMIT :limit', array( + array('name' => 'limit', 'value' => $limit, 'type' => PDO::PARAM_INT) + )) as $row) { + $entries[] = self::fromDatabaseRow($row); + } + + return $entries; + } + + public static function recentForJob($job_id, $limit = 100) { + $entries = array(); + + $database = HandBrakeCluster_Main::instance()->database(); + foreach ($database->selectList('SELECT * FROM '.self::$table_name.' WHERE job_id=:job_id ORDER BY ctime DESC LIMIT :limit', array( + array('name' => 'job_id', 'value' => $job_id, 'type' => PDO::PARAM_INT), + array('name' => 'limit', 'value' => $limit, 'type' => PDO::PARAM_INT) + )) as $row) { + $entries[] = self::fromDatabaseRow($row); + } + + return $entries; + } + + public static function allForNoJob() { + return self::allForJob(0); + } + + public function id() { + return $this->id; + } + + public function jobId() { + return $this->job_id; + } + + public function level() { + return $this->level; + } + + public function ctime() { + return $this->ctime; + } + + public function pid() { + return $this->pid; + } + + public function hostname() { + return $this->hostname; + } + + public function progname() { + return $this->progname; + } + + public function line() { + return $this->line; + } + + public function message() { + return $this->message; + } + +}; + +?> diff --git a/HandBrakeCluster/Main.class.php b/HandBrakeCluster/Main.class.php index e6fbd89..216e5cb 100644 --- a/HandBrakeCluster/Main.class.php +++ b/HandBrakeCluster/Main.class.php @@ -13,8 +13,16 @@ class HandBrakeCluster_Main { private $request; private function __construct() { - $this->smarty = new Smarty(); + $request_string = isset($_GET['l']) ? $_GET['l'] : ''; + $this->config = new HandBrakeCluster_Config("dbconfig.conf"); + $this->database = new HandBrakeCluster_Database($this->config); + $this->config->setDatabase($this->database); + + $this->log = new HandBrakeCluster_Log($this->database, $this->config); + $this->request = new HandBrakeCluster_RequestParser($request_string); + + $this->smarty = new Smarty(); $this->smarty->template_dir = './templates'; $this->smarty->compile_dir = './tmp/templates'; $this->smarty->cache_dir = './tmp/cache'; @@ -23,8 +31,6 @@ class HandBrakeCluster_Main { $this->smarty->assign('version', '0.1'); $this->smarty->assign('base_uri', '/handbrake/'); - $request_string = isset($_GET['l']) ? $_GET['l'] : ''; - $this->request = new HandBrakeCluster_RequestParser($request_string); } public static function instance() { @@ -70,6 +76,12 @@ class HandBrakeCluster_Main { return; } + // Special case: All exceptions are stored in the same file + if (preg_match('/^HandBrakeCluster_Exception_/', $classname)) { + require_once('HandBrakeCluster/Exceptions.class.php'); + return; + } + // Replace any underscores with directory separators $filename = preg_replace('/_/', '/', $classname); diff --git a/HandBrakeCluster/RequestParser.class.php b/HandBrakeCluster/RequestParser.class.php index 3d58a56..24e4f39 100644 --- a/HandBrakeCluster/RequestParser.class.php +++ b/HandBrakeCluster/RequestParser.class.php @@ -39,6 +39,7 @@ class HandBrakeCluster_RequestParser { if (isset($this->vars[$key])) { return $this->vars[$key]; } + return null; } diff --git a/HandBrakeCluster/WorkerLogEntry.class.php b/HandBrakeCluster/WorkerLogEntry.class.php new file mode 100644 index 0000000..bd0fa14 --- /dev/null +++ b/HandBrakeCluster/WorkerLogEntry.class.php @@ -0,0 +1,13 @@ +