XBMC   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 168
Duplicated Lines 0 %

Importance

Changes 5
Bugs 2 Features 0
Metric Value
eloc 49
c 5
b 2
f 0
dl 0
loc 168
rs 10
wmc 11

6 Methods

Rating   Name   Duplication   Size   Complexity  
A handleRequestException() 0 28 2
A init() 0 19 1
A getVFSHelper() 0 3 1
A performRequestUncached() 0 11 2
A performRequest() 0 31 3
A sendNotification() 0 11 2
1
<?php
2
3
use SimpleJsonRpcClient\Client\HttpPostClient as JsonRPCClient;
4
5
/**
6
 * Application component for accessing XBMC's JSON-RPC API and related functions
7
 *
8
 * @author Sam Stenvall <[email protected]>
9
 * @copyright Copyright &copy; Sam Stenvall 2013-
10
 * @license https://www.gnu.org/licenses/gpl.html The GNU General Public License v3.0
11
 */
12
class XBMC extends CApplicationComponent
13
{
14
	
15
	/**
16
	 * @var Backend the current backend
17
	 */
18
	private $_backend;
19
	
20
	/**
21
	 * @var JsonRPCClient the JSON-RPC client
22
	 */
23
	private $_client;
24
	
25
	/**
26
	 * @var VFSHelper the VFS helper
27
	 */
28
	private $_vfsHelper;
29
	
30
	/**
31
	 * Initializes the component
32
	 */
33
	public function init()
34
	{
35
		// Connect to the current backend
36
		$this->_backend = Yii::app()->backendManager->getCurrent();
37
		
38
		$hostname = Backend::normalizeAddress($this->_backend->hostname);
39
		$endpoint = 'http://'.$hostname.':'.$this->_backend->port.'/jsonrpc';
40
41
		$clientFlags = JsonRPCClient::FLAG_ATTEMPT_UTF8_RECOVERY;
42
		$clientOptions = array('timeout'=>Setting::getInteger('requestTimeout'));
43
		
44
		$this->_client = new JsonRPCClient($endpoint, 
45
				$this->_backend->username, $this->_backend->password, 
46
				$clientFlags, $clientOptions);
47
		
48
		// Initialize the VFS helper
49
		$this->_vfsHelper = new VFSHelper();
50
51
		parent::init();
52
	}
53
	
54
	/**
55
	 * Wrapper for performRequestInternal(). It caches the results indefinitely 
56
	 * if the "cacheApiCalls" setting is enabled.
57
	 * @param string $method
58
	 * @param mixed $params
59
	 * @param integer $id
60
	 */
61
	public function performRequest($method, $params = null, $id = 0)
62
	{
63
		if (Setting::getBoolean('cacheApiCalls'))
64
		{
65
			// Calculate a unique cache ID for this API call to this backend
66
			$cacheId = md5(serialize($this->_backend->attributes).
67
					serialize($method).
68
					serialize($params).
69
					serialize($id).
70
					1); // increment to invalidate all previous caches
71
72
			$result = Yii::app()->apiCallCache->get($cacheId);
73
74
			// Not found in cache
75
			if ($result === false)
76
			{
77
				$result = $this->performRequestUncached($method, $params, $id);
78
				
79
				// Store the raw response instead of the object
80
				Yii::app()->apiCallCache->set($cacheId, $result->getRawResponse());
81
			}
82
			else
83
			{
84
				// Recreate the full object based on the stored JSON
85
				$result = new SimpleJsonRpcClient\Response\Response($result);
86
			}
87
			
88
			return $result;
89
		}
90
		else
91
			return $this->performRequestUncached($method, $params, $id);
92
	}
93
	
94
	/**
95
	 * Wrapper for \SimpleJsonRpcClient\Request
96
	 * @param string $method
97
	 * @param mixed $params
98
	 * @param integer $id
99
	 * @return SimpleJsonRpcClient\Response\Response
100
	 */
101
	public function performRequestUncached($method, $params = null, $id = 0)
102
	{
103
		try
104
		{
105
			$request = new SimpleJsonRpcClient\Request\Request($method, $params, $id);
106
			
107
			return $this->_client->sendRequest($request);
108
		}
109
		catch (SimpleJsonRpcClient\Exception\BaseException $e)
110
		{
111
			$this->handleRequestException($e, $request);
112
		}
113
	}
114
	
115
	/**
116
	 * Sends a notification
117
	 * @param string $method
118
	 * @param mixed $params
119
	 */
120
	public function sendNotification($method, $params = null)
121
	{
122
		try
123
		{
124
			$notification = new SimpleJsonRpcClient\Request\Notification($method, $params);
125
			
126
			$this->_client->sendNotification($notification);
127
		}
128
		catch (SimpleJsonRpcClient\Exception\BaseException $e)
129
		{
130
			$this->handleRequestException($e, $notification);
131
		}
132
	}
133
	
134
	/**
135
	 * Handles exceptions from the JSON-RPC client. The exceptions are re-
136
	 * thrown as CHttpException so we can provide a less confusing error 
137
	 * message. The exact error and the request that caused it will be logged 
138
	 * separately in the system log when available.
139
	 * @param SimpleJsonRpcClient\Exception\BaseException $exception
140
	 * @param SimpleJsonRpcClient\Request\BaseRequest $request the request that 
141
	 * triggered the exception
142
	 * @throws CHttpException always
143
	 */
144
	private function handleRequestException($exception, $request)
145
	{
146
		/**
147
		 * Formats the object into pretty-printed JSON
148
		 * @param $object the data object
149
		 */
150
		$formatData = function($object)
151
		{
152
			return CHtml::tag('pre', array(), json_encode($object, JSON_PRETTY_PRINT));
153
		};
154
		
155
		// Log the detailed error data for easier debugging
156
		if ($exception instanceof SimpleJsonRpcClient\Exception\ResponseErrorException)
157
		{
158
			$data = $formatData($exception->getData());
159
			$message = 'Response error data from the upcoming exception: '.$data;
160
			
161
			// Include the original request body in the message. We'll need 
162
			// to reincode it in order to get it prettyprinted
163
			$requestBody = $formatData(json_decode($request->__toString()));
164
			$message .= PHP_EOL.'The request that triggered the exception was:'.PHP_EOL.$requestBody;
165
166
			Yii::log($message, CLogger::LEVEL_ERROR, 'jsonrpc');
167
		}
168
169
		$message = 'Exception caught while calling XBMC API: '.$exception->getMessage().' ('.$exception->getCode().')';
170
171
		throw new CHttpException(500, $message);
172
	}
173
	
174
	/**
175
	 * @return VFSHelper the VFS helper
176
	 */
177
	public function getVFSHelper()
178
	{
179
		return $this->_vfsHelper;
180
	}
181
	
182
}
183