From 66f4dec369ac8c2526b3675c2a5d7d69ea6300f1 Mon Sep 17 00:00:00 2001
From: Tim Steiner <tsteiner2@unl.edu>
Date: Mon, 27 Oct 2008 16:24:00 +0000
Subject: [PATCH] Podcast producer updates

---
 library/Unl/Service/PodcastProducer.php       |  47 ++-
 library/Unl/Service/PodcastProducer/Agent.php | 293 ++++++++++++++++++
 2 files changed, 338 insertions(+), 2 deletions(-)
 create mode 100644 library/Unl/Service/PodcastProducer/Agent.php

diff --git a/library/Unl/Service/PodcastProducer.php b/library/Unl/Service/PodcastProducer.php
index db6fc049..1e1f0d9c 100644
--- a/library/Unl/Service/PodcastProducer.php
+++ b/library/Unl/Service/PodcastProducer.php
@@ -218,7 +218,7 @@ class Unl_Service_PodcastProducer extends Zend_Service_Abstract
         $postData = 'workflow_name='. urlencode($workflow->getName())
                   . '&camera_name=' . urlencode($camera->getName());
         foreach ($metadata as $key => $value) {
-        	$postData .= '&' . urlencode($key) . '=' . urlencode($value);
+        	$postData .= '&UserMetadata_' . urlencode($key) . '=' . urlencode($value);
         }
         curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $postData);
         $response = curl_exec($this->_curl);
@@ -226,4 +226,47 @@ class Unl_Service_PodcastProducer extends Zend_Service_Abstract
             echo curl_error($this->_curl);
         }
     }
-}
\ No newline at end of file
+
+    public function bindCamera($name, $sharedSecret = '')
+    {
+        if (!$sharedSecret) {
+            $sharedSecret = hash('md5', microtime(true) . rand(0, getrandmax()), true);
+        }
+        
+        $uri = clone $this->_uri;
+        $uri->setPath('/podcastproducer/cameras/bind');
+        
+        curl_setopt($this->_curl, CURLOPT_URL, $uri->__toString());
+        curl_setopt($this->_curl, CURLOPT_HTTPHEADER, array());
+        curl_setopt($this->_curl, CURLOPT_POST, true);
+        $postData = 'camera_name='. urlencode($name)
+                  . '&shared_secret=' . urlencode(base64_encode($sharedSecret));
+        curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $postData);
+        $response = curl_exec($this->_curl);
+        if ($response === false) {
+            echo curl_error($this->_curl);
+        }
+        
+        $agent = Unl_Service_PodcastProducer_Agent::fromXML($this, $response);
+        $agent->setSharedSecret($sharedSecret);
+        $agent->connect();
+        
+        return $agent;
+    }
+
+    public function unbindCamera($name)
+    {   
+        $uri = clone $this->_uri;
+        $uri->setPath('/podcastproducer/cameras/unbind');
+        
+        curl_setopt($this->_curl, CURLOPT_URL, $uri->__toString());
+        curl_setopt($this->_curl, CURLOPT_HTTPHEADER, array());
+        curl_setopt($this->_curl, CURLOPT_POST, true);
+        $postData = 'camera_name='. urlencode($name);
+        curl_setopt($this->_curl, CURLOPT_POSTFIELDS, $postData);
+        $response = curl_exec($this->_curl);
+        if ($response === false) {
+            echo curl_error($this->_curl);
+        }
+    }
+}
diff --git a/library/Unl/Service/PodcastProducer/Agent.php b/library/Unl/Service/PodcastProducer/Agent.php
new file mode 100644
index 00000000..e629c28b
--- /dev/null
+++ b/library/Unl/Service/PodcastProducer/Agent.php
@@ -0,0 +1,293 @@
+<?php
+
+class Unl_Service_PodcastProducer_Agent
+{
+	protected $_serverUuid;
+	protected $_tunnelHost;
+	protected $_tunnelPort;
+    protected $_protocol;
+    protected $_sharedSecret;
+    protected $_camera;
+    protected $_socket;
+    protected $_mcrypt;
+    protected $_recordStatus;
+    protected $_startTime;
+    protected $_endTime;
+    
+    static public function fromXML(Unl_Service_PodcastProducer $pcast, $xml)
+    {
+        $dom = DOMDocument::loadXML($xml);
+        $xPath = new DOMXPath($dom);
+        if ($xPath->query('/podcast_producer_result/status')->item(0)->textContent != 'success') {
+            return;
+        }
+        
+        $agent = new self();
+        $agent->_serverUuid = $xPath->query('/podcast_producer_result/server_uuid')->item(0)->textContent;
+        $agent->_tunnelHost = $xPath->query('/podcast_producer_result/tunnel_host')->item(0)->textContent;
+        $agent->_tunnelPort = $xPath->query('/podcast_producer_result/tunnel_port')->item(0)->textContent;
+        $agent->_camera = $pcast->getCamera($xPath->query('/podcast_producer_result/camera_uuid')->item(0)->textContent);
+        
+        return $agent;
+    }
+    
+    protected function __construct()
+    {	
+        $this->_mcrypt = mcrypt_module_open('rijndael-128', '', 'cbc', '');
+        $this->_recordStatus = self::RECORD_STATUS_READY;
+        $this->_startTime = 0;
+    }
+    
+    public function setSharedSecret($sharedSecret)
+    {
+    	$this->_sharedSecret = $sharedSecret;
+    }
+    
+    public function connect()
+    {
+    	$iv = hash('md5', microtime(true) . rand(0, getrandmax()), true);
+    	mcrypt_generic_init($this->_mcrypt, $this->_sharedSecret, $iv);	
+    	$errno = 0;
+    	$errstr = '';
+    	$this->_socket = fsockopen('tcp://' . $this->_tunnelHost, $this->_tunnelPort, $errno, $errstr);
+    	$message = 'AGENT protocol=1,agent_uuid=' . $this->_camera->getUuid() . ',iv=' . base64_encode($iv) . ',version=75';
+    	echo $message . "\n";
+    	fwrite($this->_socket, $message . "\n");
+    	$pid = pcntl_fork();
+    	if ($pid == 0) {
+    		$this->_daemon();
+    	}
+    }
+    
+    protected function _getMessage()
+    {
+    	$message = '';
+    	while (!$message) {
+            $message = fgets($this->_socket);
+    	}
+    	
+		$message = mdecrypt_generic($this->_mcrypt, base64_decode($message));
+		/*
+		for ($i = 0; $i < strlen($message); $i++) {
+			if ($i == 32) {
+				echo "\n";
+			}
+			if ($i % 4 == 0) {
+				echo "\n";
+			}
+			printf("%02x ", ord($message[$i]));
+		}
+		echo "\n";
+        */
+		$message = substr($message, 32);
+		$message = strtr($message, array(chr(0x05) => '', chr(0x0a) => '', chr(0x0b) => '', chr(0x0c) => ''));
+		return $message;
+    }
+    
+    protected function _serializeParameters($parameters)
+    {
+    	$serial = array();
+    	foreach ($parameters as $key => $value)
+    	{
+    		$serial[] = $key . '=' . $value;
+    	}
+    	$serial = implode(',', $serial);
+    	return $serial;
+    }
+    
+    protected function _sendMessage($message)
+    {
+    	echo substr($message, 0, 100) . "\n";
+        $nonce = hash('sha256', microtime(true) . rand(0, getrandmax()), true);
+        echo 'Nonce length: ' . strlen($nonce) . "\n";
+        $message = $nonce . $message;
+        echo 'Message length: ' . strlen($message) . "\n";
+        while (strlen($message) % 16 != 0) {
+        	$message .= chr(0x05);
+        }
+        echo 'Message length: ' . strlen($message) . "\n";
+        $message = mcrypt_generic($this->_mcrypt, $message);
+        $message = base64_encode($message);
+        fwrite($this->_socket, $message . "\n");
+    }
+    
+    protected function _daemon()
+    {
+        while(true) {
+            $message = $this->_getMessage();
+            
+            $cmdEnd = strpos($message, ' ');
+            if ($cmdEnd === FALSE) {
+            	$command = $message;
+            	$params = array();
+            } else {
+                $command = substr($message, 0, $cmdEnd);
+	            $params = substr($message, $cmdEnd + 1);
+	            $params = explode(',', $params);
+            }
+            $parameters = array();
+            foreach ($params as $param) {
+            	$keyEnd = strpos($param, '=');
+            	$key = substr($param, 0, $keyEnd);
+            	$value = substr($param, $keyEnd + 1);
+            	$parameters[$key] = trim($value);
+            }
+            
+            echo $command . "\n";
+            print_r($parameters);
+            $this->_doCommand($command, $parameters);
+        }
+    }
+    
+    protected function _doCommand($command, $parameters = array())
+    {
+    	switch ($command) {
+    		case 'SERVER':
+    			$this->_doServer($parameters);
+    			break;
+    		case 'STATUS':
+    			$this->_doStatus($parameters);
+    			break;
+    		case 'START':
+    			$this->_doStart($parameters);
+    			break;
+    		case 'PAUSE':
+    			$this->_doPause($parameters);
+    			break;
+    		case 'STOP':
+    			$this->_doStop($parameters);
+    			break;
+    		case 'CANCEL':
+    			$this->_doCancel($parameters);
+    			break;
+    		default:
+    			break;
+    	}
+    }
+    
+    protected function _doServer($parameters)
+    {
+    	
+    }
+    
+    const RECORD_STATUS_READY     = 0;
+    const RECORD_STATUS_PAUSED    = 1;
+    const RECORD_STATUS_RECORDING = 2;
+    
+    protected function _doStatus($parameters)
+    {
+    	var_dump($parameters);
+    	$status = array(
+            'cmdStatus' =>     0,
+    	    'recordStatus' =>  $this->_recordStatus,
+    	    'start' =>         $this->_getStartTime(),
+    	    'elapsedTime' =>   $this->_getElapsedTime(),
+    	    'stop' =>          $this->_getEndTime(),
+    	    'hard_stop' =>     0,
+    	    'lastError' =>     0,
+    	    'availDiskInMB' => '-26815622355363595601659544849062032869829237996999576376827051738916941540340353331752992578407331193284881852690388450712033975077640599757568336933683200',
+    	    'totalDiskInMB' => 0,
+    	);
+    	if (true || $parameters['include_preview'] == 'true') {
+	        $preview = file_get_contents('./preview.jpg');
+	        $preview = base64_encode($preview);
+	        $status['preview'] = $preview;
+    	}
+    	$status = $this->_serializeParameters($status);
+    	$this->_sendMessage($status);
+    }
+    
+    protected function _getStartTime()
+    {
+    	switch ($this->_recordStatus) {
+    		case self::RECORD_STATUS_READY:
+    		default:
+                return time();
+                break;
+                
+    		case self::RECORD_STATUS_PAUSED:
+    		case self::RECORD_STATUS_RECORDING:
+    			return $this->_startTime;
+    			break;
+    	}
+    }
+    
+    protected function _getEndTime()
+    {
+    	switch ($this->_recordStatus) {
+    		case self::RECORD_STATUS_READY:
+    		default:
+    			return time()+1;
+    			break;
+    			
+    		case self::RECORD_STATUS_PAUSED:
+    			return $this->_endTime;
+    			break;
+    			
+            case self::RECORD_STATUS_RECORDING:
+            	return 0;
+            	break;
+    	}
+    }
+    
+    protected function _getElapsedTime()
+    {
+    	switch ($this->_recordStatus) {
+    		case self::RECORD_STATUS_READY:
+    		default: 
+    			return 1;
+    			break;
+
+            case self::RECORD_STATUS_PAUSED:
+                return $this->_getEndTime() - $this->_getStartTime();
+                break;
+
+            case self::RECORD_STATUS_RECORDING:
+                return time() - $this->_getStartTime();
+                break;
+    	}
+    }
+    
+    protected function _doStart($parameters)
+    {
+    	$this->_recordStatus = self::RECORD_STATUS_RECORDING;
+    	$this->_startTime = time();
+    	$status = array(
+            'cmdStatus' => 0
+    	);
+    	$status = $this->_serializeParameters($status);
+    	$this->_sendMessage($status);
+    }
+    
+    protected function _doPause($parameters)
+    {
+    	$this->_recordStatus = self::RECORD_STATUS_PAUSED;
+    	$this->_endTime = time();
+        $status = array(
+            'cmdStatus' => 0
+        );
+        $status = $this->_serializeParameters($status);
+        $this->_sendMessage($status);
+    }
+    
+    protected function _doStop($parameters)
+    {
+    	$this->_recordStatus = self::RECORD_STATUS_READY;
+        $status = array(
+            'cmdStatus' => 0
+        );
+        $status = $this->_serializeParameters($status);
+        $this->_sendMessage($status);
+    }
+    
+    protected function _doCancel($parameters)
+    {
+        $this->_recordStatus = self::RECORD_STATUS_READY;
+        $status = array(
+            'cmdStatus' => 0
+        );
+        $status = $this->_serializeParameters($status);
+        $this->_sendMessage($status);
+    }
+    
+}
\ No newline at end of file
-- 
GitLab