Implemented strict http request serialization for APIs that forbid a session to be used in concurrent requests (e.g. dedimania).
Updated all API requests in DedimaniaPlugin to be serialized by this mechanism. Closes #139.
This commit is contained in:
		| @@ -36,6 +36,7 @@ class AsyncHttpRequest implements UsageInformationAble { | ||||
| 	private $contentType = 'text/xml; charset=UTF-8;'; | ||||
| 	private $timeout     = 60; | ||||
| 	private $headers     = array(); | ||||
| 	private $serialize   = false; | ||||
|  | ||||
| 	public function __construct($maniaControl, $url) { | ||||
| 		$this->maniaControl = $maniaControl; | ||||
| @@ -58,6 +59,7 @@ class AsyncHttpRequest implements UsageInformationAble { | ||||
| 		        ->set(CURLOPT_RETURNTRANSFER, true)// | ||||
| 		        ->set(CURLOPT_FOLLOWLOCATION, true)// support redirect | ||||
| 		        ->set(CURLOPT_SSL_VERIFYPEER, false); | ||||
| 		$request->setSerialize($this->serialize); // serialize requests to this host | ||||
| 		return $request; | ||||
| 	} | ||||
|  | ||||
| @@ -228,4 +230,13 @@ class AsyncHttpRequest implements UsageInformationAble { | ||||
| 	public function setTimeout($timeout) { | ||||
| 		$this->timeout = $timeout; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets whether the request to the same host should be serialized. | ||||
| 	 * | ||||
| 	 * @param bool $serialize | ||||
| 	 */ | ||||
| 	public function setSerialize($serialize = true) { | ||||
| 		$this->serialize = $serialize; | ||||
| 	} | ||||
| } | ||||
| @@ -23,6 +23,9 @@ class AsynchronousFileReader implements UsageInformationAble { | ||||
| 	 */ | ||||
| 	const CONTENT_TYPE_JSON = 'application/json'; | ||||
|  | ||||
| 	const QUEUE_NONSERIALIZING = 0; | ||||
| 	const QUEUE_SERIALIZING = 1; | ||||
|  | ||||
| 	/* | ||||
| 	 * Private properties | ||||
| 	 */ | ||||
| @@ -30,7 +33,7 @@ class AsynchronousFileReader implements UsageInformationAble { | ||||
| 	private $maniaControl = null; | ||||
|  | ||||
| 	/** @var \cURL\RequestsQueue|null $requestQueue */ | ||||
| 	private $requestQueue = null; | ||||
| 	private $requestQueue = array(null, null); | ||||
|  | ||||
| 	/** | ||||
| 	 * Construct a new Asynchronous File Reader Instance | ||||
| @@ -39,22 +42,30 @@ class AsynchronousFileReader implements UsageInformationAble { | ||||
| 	 */ | ||||
| 	public function __construct(ManiaControl $maniaControl) { | ||||
| 		$this->maniaControl = $maniaControl; | ||||
| 		$this->requestQueue = new RequestsQueue(); | ||||
|  | ||||
| 		// Queue for non-serializing requests (parallel is preferred) | ||||
| 		$this->requestQueue[self::QUEUE_NONSERIALIZING] = new RequestsQueue(); | ||||
|  | ||||
| 		// Queue for per host serialized requests | ||||
| 		$this->requestQueue[self::QUEUE_SERIALIZING] = new RequestsQueue(); | ||||
| 		$this->requestQueue[self::QUEUE_SERIALIZING]->setOption(CURLMOPT_MAX_HOST_CONNECTIONS, 1); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Append available Data of active Requests | ||||
| 	 */ | ||||
| 	public function appendData() { | ||||
| 		foreach ($this->requestQueue as &$queue) { | ||||
| 			do { | ||||
| 			if (($count = $this->requestQueue->count()) == 0) { | ||||
| 				if (($count = $queue->count()) == 0) { | ||||
| 					break; | ||||
| 				} | ||||
|  | ||||
| 			if ($this->requestQueue->socketPerform()) { | ||||
| 				$this->requestQueue->socketSelect(); | ||||
| 				if ($queue->socketPerform()) { | ||||
| 					$queue->socketSelect(); | ||||
| 				} | ||||
| 			} while ($count != $queue->count()); | ||||
| 		} | ||||
| 		} while ($count != $this->requestQueue->count()); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| @@ -96,6 +107,10 @@ class AsynchronousFileReader implements UsageInformationAble { | ||||
| 	 * @param Request $request | ||||
| 	 */ | ||||
| 	public function addRequest(Request $request) { | ||||
| 		$request->attachTo($this->requestQueue); | ||||
| 		$queueId = $request->getSerialize() | ||||
| 			? self::QUEUE_SERIALIZING | ||||
| 			: self::QUEUE_NONSERIALIZING; | ||||
| 		$queue = $this->requestQueue[$queueId]; | ||||
| 		$request->attachTo($queue); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -20,6 +20,11 @@ class Request extends EventDispatcher implements RequestInterface | ||||
|      */ | ||||
|     protected $options = null; | ||||
|  | ||||
| 	/** | ||||
| 	 * @var bool Whether requests to the target host should be serialized or not. | ||||
| 	 */ | ||||
|     protected $serializeRequests = false; | ||||
|      | ||||
|     /** | ||||
|      * Create new cURL handle | ||||
|      * | ||||
| @@ -121,7 +126,8 @@ class Request extends EventDispatcher implements RequestInterface | ||||
| 	 * @param \cURL\RequestsQueue $requestsQueue | ||||
| 	 * @throws \cURL\Exception | ||||
| 	 */ | ||||
| 	public function attachTo(RequestsQueue $requestsQueue) { | ||||
| 	public function attachTo(RequestsQueue $requestsQueue) | ||||
| 	{ | ||||
| 		if (isset($this->queue)) { | ||||
| 			throw new Exception('Already bound to a RequestQueue.'); | ||||
| 		} | ||||
| @@ -129,6 +135,24 @@ class Request extends EventDispatcher implements RequestInterface | ||||
| 		$this->queue->attach($this); | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Whether to serialize requests to the same host or not. | ||||
| 	 * | ||||
| 	 * @param bool $serialize | ||||
| 	 */ | ||||
| 	public function setSerialize($serialize = true) | ||||
| 	{ | ||||
| 		$this->serializeRequests = $serialize; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @return bool | ||||
| 	 */ | ||||
| 	public function getSerialize() | ||||
| 	{ | ||||
| 		return $this->serializeRequests; | ||||
| 	} | ||||
|  | ||||
|     /** | ||||
|      * Creates new RequestsQueue with single Request attached to it | ||||
|      * and calls RequestsQueue::socketPerform() method. | ||||
|   | ||||
| @@ -217,4 +217,12 @@ class RequestsQueue extends EventDispatcher implements RequestsQueueInterface, \ | ||||
| 		} | ||||
| 		return curl_multi_select($this->mh, $timeout) !== -1; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * @param $option | ||||
| 	 * @param $value | ||||
| 	 */ | ||||
| 	public function setOption($option, $value) { | ||||
| 		curl_multi_setopt($this->mh, $option, $value); | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -83,6 +83,7 @@ class DedimaniaWebHandler implements TimerListener { | ||||
| 		$asyncHttpRequest->setContent($content); | ||||
| 		$asyncHttpRequest->setCompression(true); | ||||
| 		$asyncHttpRequest->setTimeout(500); | ||||
| 		$asyncHttpRequest->setSerialize(); | ||||
| 		$asyncHttpRequest->postData(); | ||||
| 	} | ||||
|  | ||||
| @@ -171,6 +172,7 @@ class DedimaniaWebHandler implements TimerListener { | ||||
| 		$asyncHttpRequest->setContent($content); | ||||
| 		$asyncHttpRequest->setCompression(true); | ||||
| 		$asyncHttpRequest->setTimeout(500); | ||||
| 		$asyncHttpRequest->setSerialize(); | ||||
| 		$asyncHttpRequest->postData(); | ||||
|  | ||||
| 		return true; | ||||
| @@ -218,6 +220,7 @@ class DedimaniaWebHandler implements TimerListener { | ||||
| 		$asyncHttpRequest->setContent($content); | ||||
| 		$asyncHttpRequest->setCompression(true); | ||||
| 		$asyncHttpRequest->setTimeout(500); | ||||
| 		$asyncHttpRequest->setSerialize(); | ||||
| 		$asyncHttpRequest->postData(); | ||||
| 	} | ||||
|  | ||||
| @@ -309,6 +312,7 @@ class DedimaniaWebHandler implements TimerListener { | ||||
| 		$asyncHttpRequest->setContent($content); | ||||
| 		$asyncHttpRequest->setCompression(false); | ||||
| 		$asyncHttpRequest->setTimeout(500); | ||||
| 		$asyncHttpRequest->setSerialize(); | ||||
| 		$asyncHttpRequest->postData(); | ||||
| 	} | ||||
|  | ||||
| @@ -361,6 +365,7 @@ class DedimaniaWebHandler implements TimerListener { | ||||
| 		$asyncHttpRequest->setContent($content); | ||||
| 		$asyncHttpRequest->setCompression(true); | ||||
| 		$asyncHttpRequest->setTimeout(500); | ||||
| 		$asyncHttpRequest->setSerialize(); | ||||
| 		$asyncHttpRequest->postData(); | ||||
| 	} | ||||
|  | ||||
| @@ -403,6 +408,7 @@ class DedimaniaWebHandler implements TimerListener { | ||||
| 		$asyncHttpRequest->setContent($content); | ||||
| 		$asyncHttpRequest->setCompression(true); | ||||
| 		$asyncHttpRequest->setTimeout(500); | ||||
| 		$asyncHttpRequest->setSerialize(); | ||||
| 		$asyncHttpRequest->postData(); | ||||
| 	} | ||||
|  | ||||
| @@ -447,6 +453,7 @@ class DedimaniaWebHandler implements TimerListener { | ||||
| 		$asyncHttpRequest->setContent($content); | ||||
| 		$asyncHttpRequest->setCompression(true); | ||||
| 		$asyncHttpRequest->setTimeout(500); | ||||
| 		$asyncHttpRequest->setSerialize(); | ||||
| 		$asyncHttpRequest->postData(); | ||||
| 	} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user