Psyduck - 可達鴨 之 鴨力山大

Current Path : home/irplbiz/www/iwp/controllers/
Upload File :
Current File : /home/irplbiz/www/iwp/controllers/processManager.php

<?php
/************************************************************
 * InfiniteWP Admin panel									*
 * Copyright (c) 2012 Revmakx								*
 * www.revmakx.com											*
 *															*
 ************************************************************/

$settings = Reg::get('settings');
define('MAX_SIMULTANEOUS_REQUEST_PER_IP', $settings['MAX_SIMULTANEOUS_REQUEST_PER_IP'] > 0 ? $settings['MAX_SIMULTANEOUS_REQUEST_PER_IP'] : 2 );

define('MAX_SIMULTANEOUS_REQUEST', $settings['MAX_SIMULTANEOUS_REQUEST'] > 0 ? $settings['MAX_SIMULTANEOUS_REQUEST'] : 3 );
//define('MAX_SIMULTANEOUS_REQUEST_PER_SERVERGROUP', $settings['MAX_SIMULTANEOUS_REQUEST_PER_SERVERGROUP']);

define('TIME_DELAY_BETWEEN_REQUEST_PER_IP', $settings['TIME_DELAY_BETWEEN_REQUEST_PER_IP'] >= 0 ? $settings['TIME_DELAY_BETWEEN_REQUEST_PER_IP'] : 200 );

function executeJobs($callCount = 1){
	
	if(isset($GLOBALS['IS_EXECUTE_JOBS_OPEN']) && $GLOBALS['IS_EXECUTE_JOBS_OPEN']){
		echo 'recurrsive execute jobs call';
		return false;//recurrsive call
	}
	$GLOBALS['IS_EXECUTE_JOBS_OPEN'] = true;
	
	$settings = Reg::get('settings');
        $connectionMethod = getOption('connectionMethod');
        $connectionMode = getOption('connectionMode');
        $upperConnectionLevel = getOption('upperConnectionLevel');
	  $noRequestRunning = true;
	  $requestInitiated = 0;
	  $requestPending 	= 0;
	  $isExecuteRequest = false;
	  static $lastIPRequestInitiated = '';
	  

	  $totalCurrentRunningRequest = DB::getField("?:history H LEFT JOIN ?:sites S ON H.siteID = S.siteID", "COUNT(H.historyID)", "H.status IN ('initiated', 'running')");
	  
	  if($totalCurrentRunningRequest >= MAX_SIMULTANEOUS_REQUEST){ $GLOBALS['IS_EXECUTE_JOBS_OPEN'] = false; return false; }//dont execute any request
			  
	  $runningRequestByIP = DB::getFields("?:history H LEFT JOIN ?:sites S ON H.siteID = S.siteID", "COUNT(H.historyID), S.IP", "H.status IN ('initiated', 'running') AND H.isPluginResponse = '1' GROUP BY S.IP", "IP");//H.isPluginResponse = 1 only WP sites call
	  
	  if(!empty($runningRequestByIP)){ //some request(s) are running
		  $noRequestRunning = false;
		  $runningRequestByServer = DB::getFields("?:history H LEFT JOIN ?:sites S ON H.siteID = S.siteID", "COUNT(H.historyID), S.serverGroup", "H.status IN ('initiated', 'running') GROUP BY S.serverGroup", "serverGroup");			
	  }
	  
	  //get pending request
	  $where = array(
		      		'query' =>  "(H.status = 'pending' OR (H.status = ':status' AND H.timescheduled <= :timescheduled AND H.timescheduled > 0) OR H.status = 'retry') ORDER BY H.historyID",
		      		'params' => array(
		               ':status'=>'scheduled',
		               ':timescheduled'=>time()
	   				)
				); 
	  $pendingRequests = DB::getArray("?:history H LEFT JOIN ?:sites S ON H.siteID = S.siteID", "H.historyID, S.IP, S.serverGroup, H.actionID, H.type, H.status, H.runCondition, H.isPluginResponse, H.retried, H.siteID", $where);
	  
	  if($noRequestRunning){		
		  $runningRequestByIP 	= array();
		  $runningRequestByServer = array();				
	  }
	  
	  
	  if(!empty($runningRequestByIP) && $settings['CONSIDER_3PART_IP_ON_SAME_SERVER'] == 1){//running IP information
		  $tempRunningRequestByIP = $runningRequestByIP;
		  $runningRequestByIP 	= array();
		  foreach($tempRunningRequestByIP as $tempIP => $tempCount){//only for IPv4
			  $IP3Part = explode('.', $tempIP);
			  array_pop($IP3Part);
			  $newTempIP = implode('.', $IP3Part);			  
			  $runningRequestByIP[$newTempIP] = $tempCount;
			  
		  }
	  }
	  
	if(!empty($pendingRequests) && is_array($pendingRequests)){
	  foreach($pendingRequests as $request){
		  $checkIPRestriction = true;
		  
		  $IPConsidered = $request['IP'];
		  
		  if($request['isPluginResponse'] === '0'){
			  $request['IP'] = '';
			  $checkIPRestriction = false;
		  }
		  
		  if($checkIPRestriction && $settings['CONSIDER_3PART_IP_ON_SAME_SERVER'] == 1){//only for IPv4
			  $IP3Part = explode('.', $IPConsidered);
			  array_pop($IP3Part);
			  $IP3Part = implode('.', $IP3Part);			  
			  $IPConsidered = $IP3Part;
		  }
		  
		  $isWritingRequest = updatePTCHistoryStatus($request, 'writingRequest');

		  if ($request['type'] === 'PTC' && $request['status'] !== 'retry' && $isWritingRequest<=0){
		  	 continue;
		  }

		  if(!empty($request['runCondition']) && !isTaskRunConditionSatisfied($request['runCondition'])){
		  	   updatePTCHistoryStatus($request, $request['status']);
			   continue;  
		  }
		  if (manageClientsUpdate::isUpdateRunning($request['historyID'], $request['siteID'])) { //Right now we changed the check in runCondition
		  		updatePTCHistoryStatus($request, $request['status']);
		  		continue;
		  }
		  if (!isV3Compatible($request['historyID'])) {
		  		updatePTCHistoryStatus($request, $request['status']);
		  		continue;
		  }
		  if($checkIPRestriction && !isset($runningRequestByIP[ $IPConsidered ])) $runningRequestByIP[ $IPConsidered ] = 0;
		 // if(!isset($runningRequestByServer[ $request['serverGroup'] ])) $runningRequestByServer[ $request['serverGroup'] ] = 0;
		  
		  if($totalCurrentRunningRequest >= MAX_SIMULTANEOUS_REQUEST){ 
		  	$GLOBALS['IS_EXECUTE_JOBS_OPEN'] = false; 
		  	updatePTCHistoryStatus($request, $request['status']);
		  	return false; 
		  }
		  
		  //check already request are running in allowed level 
		  if($checkIPRestriction && $runningRequestByIP[ $IPConsidered ] >= MAX_SIMULTANEOUS_REQUEST_PER_IP /*|| $runningRequestByServer[ $request['serverGroup'] ] >=  MAX_SIMULTANEOUS_REQUEST_PER_SERVERGROUP*/){
			 
			  
			  if($runningRequestByIP[ $IPConsidered ] >= MAX_SIMULTANEOUS_REQUEST_PER_IP ){}
			 /* if($runningRequestByServer[ $request['serverGroup'] ] >=  MAX_SIMULTANEOUS_REQUEST_PER_SERVERGROUP)
			  echo 'MAX_SIMULTANEOUS_REQUEST_PER_SERVERGROUP<br>';*/
			  updatePTCHistoryStatus($request, $request['status']);
			  continue; //already request are running on the limits
		  }

		  isIPReqAndTotalRunReqOne($callCount, $runningRequestByIP[ $IPConsidered ], $totalCurrentRunningRequest, $request);
		  
		  $updateRequest = array('H.status' => 'initiated', 'H.microtimeInitiated' => microtime(true));
		  
		  $where = array(
		      		'query' =>   "(H.status = ':pending' OR (H.status = ':scheduled' AND H.timescheduled <= :timescheduled AND H.timescheduled > 0) OR (H.status = ':writingRequest' AND H.type = 'PTC')) AND H.historyID = :historyID",
		      		'params' => array(
		               ':pending'=>'pending',
		               ':scheduled'=>'scheduled',
		               ':timescheduled'=>time(),
		               ':writingRequest' => 'writingRequest',
		               ':historyID'=>$request['historyID']
	   				)
				);
		  $isUpdated = DB::update("?:history H", $updateRequest, $where);
		  //panelRequestManager::addSyatemActiveJobs($request['historyID']); For now this functionality no need 			 	
		  $isUpdated = DB::affectedRows();
		  
		  if($isUpdated){
			  //ready to run a child php to run the request
			  
			  if($lastIPRequestInitiated == $IPConsidered){
				  usleep((TIME_DELAY_BETWEEN_REQUEST_PER_IP * 1000));
			  }
			  $forceCurlMode = false;
			  if (forceCurlMode($request['historyID'])) {
			  	  $forceCurlMode = true;
			  }

			  //(defined('CRON_MODE')  && ( CRON_MODE == 'systemCronShortTime'  || CRON_MODE == 'systemCronDefault') ) //need to avoid balance idle time when systemCron is triggered. so that new trigger call(multiCall) can be called soon
			 // echo '<br>executing child process';
			  if(/*defined('IS_EXECUTE_FILE') || */(defined('CRON_MODE')  && ( CRON_MODE == 'systemCronShortTime'  || CRON_MODE == 'systemCronDefault') ) || /*$settings['executeUsingBrowser'] == 1*/ $connectionMode == 'curlMode' || ($connectionMethod=='auto' && $upperConnectionLevel=='curlMode') || $forceCurlMode){//this will also statisfy Reg::get('settings.executeUsingBrowser') == 1
                  $curlConnection = array('mode'=>'curl');
				  //echo '<br>executing_directly';
				  executeRequest($request['historyID']);
                                  updateConnectionMode($curlConnection,$request['historyID']);
				  $isExecuteRequest = true;
				  $requestPending++;
			  }
			  else{
				 // echo '<br>executing_async';
				 //$callAsyncInfo = callURLAsync(APP_URL.EXECUTE_FILE, array('historyID' =>  $request['historyID'], 'actionID' => $request['actionID']));					 
                                 $callAsyncInfo = nonBlockingBackgroundJob(array('historyID' =>  $request['historyID'], 'actionID' => $request['actionID']));
                                 if(!$callAsyncInfo['status'] && $connectionMethod==='auto'){
                                 	$curlConnection = array('mode'=>'curl');
                                 	Reg::set('settings.executeUsingBrowser', true);
                                    executeRequest($request['historyID']);
                                    updateConnectionMode($curlConnection,$request['historyID']);
                                    $isExecuteRequest = true;
                                    $requestPending++;
                                 }else{
                                    onAsyncFailUpdate($request['historyID'], $callAsyncInfo);
                                 }
				 // echo '<pre>callExecuted:'; echo'</pre>';
			  }

			  $requestInitiated++; 
			  
			  if($checkIPRestriction) $runningRequestByIP[ $IPConsidered ]++;
			 // $runningRequestByServer[ $request['serverGroup'] ] ++;
			  $totalCurrentRunningRequest++;
			  
			  
			  if($checkIPRestriction) $lastIPRequestInitiated = $IPConsidered;
			  
			  if($isExecuteRequest){ break; }//breaking here once executeRequest runs(direct call) next forloop job might be executed by other instance because that job loaded in array which already loaded from DB, still only the job inititated here will run  $isUpdated = DB::affectedRows();
		  }
		  else{
		  	updatePTCHistoryStatus($request, $request['status']);
			// echo 'update error, this request might be executed by someother instance.';  
		  }
	  }
	 } 
	  //return process
	  $GLOBALS['IS_EXECUTE_JOBS_OPEN'] = false;
	  return array('requestInitiated' => $requestInitiated, 'requestPending' => $requestPending);
}


function retryFailedTasks($historyID, $actionID, $request){
	$where = array(
		      		'query' =>  "actionID = ':actionID' AND status NOT IN ('retry', 'completed', 'netError', 'error')",
			      	'params' => array(
		               ':actionID'=>$actionID
					)
				);
	$runningTask = DB::getField("?:history", "COUNT(historyID)", $where);
	if($runningTask == 0) {
		if ($request['type'] === 'PTC' && !empty($request['runCondition'])) {
			$runCondition = unserialize($request['runCondition']);
			$where = $runCondition['query'];
			$lastHistoryID = $where['lastHistoryID'];
			if (!empty($lastHistoryID)) {
				$lastHistoryIDWhere = array(
				      		'query' =>  "historyID=':historyID'",
					      	'params' => array(
				               ':historyID'=>$lastHistoryID
							)
						);
				$lastHistoryIDStatus = DB::getField("?:history", "status", $lastHistoryIDWhere);
				if ($lastHistoryIDStatus != 'completed' && $lastHistoryIDStatus != 'error' && $lastHistoryIDStatus != 'netError' ) {
					return;
				}
			}
			$changedCondition = 	array();
			$changedCondition['satisfyType'] = 'OR';
			$changedCondition['query'] = array('table' => "history_additional_data",
											  'select' => 'historyID',
											  'where' => "historyID = ".$lastHistoryID." AND status IN('success', 'error', 'netError')",
											  'lastHistoryID' => $lastHistoryID
											);
			$updateRequest = array('H.status' => 'pending', 'runCondition' => serialize($changedCondition), 'H.retried' => '1', 'H.microtimeInitiated' => microtime(true));
		}else{
			$updateRequest = array('H.status' => 'pending', 'H.retried' => '1', 'H.microtimeInitiated' => microtime(true));
		}
		$where = array(
		      		'query' =>  "H.historyID=':historyID'",
			      	'params' => array(
		               ':historyID'=>$historyID
					)
				);
		$isUpdated = DB::update("?:history H", $updateRequest, $where);
	}
}

function isIPReqAndTotalRunReqOne($callCount, $runningRequestByIP, $totalCurrentRunningRequest, $request){
	if ($callCount == 1 && $runningRequestByIP <= 1 && $totalCurrentRunningRequest <= 1) {
		if ($request['retried'] == '0'){
		 	if($request['status'] == 'retry') {
				retryFailedTasks($request['historyID'], $request['actionID'], $request);
			} 
		}
	}
}

function isTaskRunConditionSatisfied($runCondition){
	
	if(empty($runCondition)){ return true; }
	
	$runCondition = unserialize($runCondition);
	
	if(empty($runCondition['satisfyType'])){
		$runCondition['satisfyType'] = 'OR';
	}
	
	if($runCondition['satisfyType'] != 'AND' && $runCondition['satisfyType'] != 'OR'){
		return ;
	}
	
	$OK = true;
	
	
	if(!empty($runCondition['query'])){
		$query = $runCondition['query'];
		$tempResult = DB::getExists('?:'.$query['table'], $query['select'], $query['where']);
		if($runCondition['satisfyType'] == 'OR' && !empty($tempResult)){
			return true;
		}elseif ($runCondition['satisfyType'] == 'OR' && empty($tempResult) && isHistoryCompleted($runCondition)) {
			return true;
		}
		elseif($runCondition['satisfyType'] == 'AND' && empty($tempResult)){
			$OK = false;
		}
	}
	if(!empty($runCondition['maxWaitTime'])){
		$tempResult = ($runCondition['maxWaitTime'] <= time());
		if($runCondition['satisfyType'] == 'OR' && !empty($tempResult)){
			return true;
		}
		elseif($runCondition['satisfyType'] == 'AND' && empty($tempResult)){
			$OK = false;
		}
	}
	
	if($runCondition['satisfyType'] == 'OR'){
		return false;
	}
	elseif($runCondition['satisfyType'] == 'AND'){
		return $OK;
	}
	return ;	
}

function forceCurlMode($hisID){
	if (empty($hisID)) {
		return false;
	}
	$forceCurlModeActions = array('staging');
	$where = array(
		      		'query' =>  "historyID=':historyID'",
			      	'params' => array(
		               ':historyID'=>$hisID
					)
				);
	$forceCurlMode = DB::getField("?:history", 'type', $where);
	if (!empty($forceCurlMode) && in_array($forceCurlMode, $forceCurlModeActions)) {
		return true;
	}
	return false;

}

function isHistoryCompleted($runCondition){
	if (empty($runCondition['query']['where'])) {
		return false;
	}
	$where = $runCondition['query']['where'];
	$conditionHisID = str_replace(array('historyID = ', " AND status IN('success', 'error', 'netError')"), '', $where);
	if (empty($conditionHisID)) {
		return false;
	}
	$where = array(
		      		'query' =>  "historyID=':historyID'",
			      	'params' => array(
		               ':historyID'=>$conditionHisID
					)
				);
	$status = DB::getField("?:history", 'status', $where);
	if (!empty($status) && $status == 'completed') {
		$where = array(
		      		'query' =>  "historyID=':historyID'",
			      	'params' => array(
		               ':historyID'=>$conditionHisID
					)
				);
		$additionaStatus = DB::getField("?:history_additional_data", 'status', $where);
		if (!empty($additionaStatus) && $additionaStatus == 'pending') {
			$success = DB::update("?:history_additional_data", array('status' => 'error', 'errorMsg' => 'Task killed because history table marked as completed', 'error' =>'not_history_add'), $where);
			if ($success) {
				return true;
			}

		}
	}
	return false;
}

function isV3Compatible($historyID){
	$responseProcessor = array();
	$responseProcessor['plugins']['install'] = $responseProcessor['themes']['install'] = 'installPluginsThemes';
	$responseProcessor['plugins']['manage'] = $responseProcessor['themes']['manage'] = 'managePluginsThemes';	
	$responseProcessor['plugins']['get'] = $responseProcessor['themes']['get'] = 'getPluginsThemes';
	$responseProcessor['stats']['getStats'] = 'getStats';
	if (isV3Panel()) {
		$responseProcessor['addtionalStats']['getAdditionalStats'] = 'getAdditionalStats';
	}
	$responseProcessor['PTC']['update'] = 'updateAll';
	$responseProcessor['backup']['now'] = 'backup';
	$responseProcessor['backup']['multiCallNow'] = 'backup';
	$responseProcessor['backup']['restore'] = 'restoreBackup';
	$responseProcessor['backup']['multiCallRestore'] = 'restoreBridgeUpload';
	$responseProcessor['backup']['bridgeExtractMulticallRestore'] = 'bridgeExtractMulticallRestore';
	$responseProcessor['backup']['restoreNew'] = 'restoreNewBackup';
	$responseProcessor['backup']['restoreBackupDownlaod'] = 'restoreBackupDownlaod';
	$responseProcessor['backup']['triggerBackupDownlaod'] = 'triggerBackupDownlaod';
	$responseProcessor['backup']['remove'] = 'removeBackup';
	$responseProcessor['cronTask']['runCron'] = 'pheonixBackupCron';
	$responseProcessor['cronDoAction']['pheonixBackupCronDoAction'] = 'pheonixBackupCronDoAction';
	$responseProcessor['site']['add'] = 'addSite';
	$responseProcessor['site']['readd'] = 'readdSite';
	$responseProcessor['site']['maintain'] = 'iwpMaintenance';
	$responseProcessor['site']['auto_updater_settings'] = 'editSite';
	$responseProcessor['site']['remove'] = 'removeSite';
	$responseProcessor['site']['backupTest'] = 'backupTest';
	$responseProcessor['clientPlugin']['update'] = 'updateClient';
	$responseProcessor['backup']['trigger'] = 'triggerRecheck';
	$responseProcessor['cookie']['get'] = 'getCookie';
	setHook('responseProcessors', $responseProcessor);
	$historyData = getHistory($historyID);
	$actionResponse = $responseProcessor[$historyData['type']][$historyData['action']];
	if(manageClients::methodResponseExists($actionResponse)){
		return true;
	}

	return false;
}

function updatePTCHistoryStatus($request, $status){
	$isUpdated = false;
	if ($request['type'] === 'PTC' && $request['status'] !== 'retry') {
		$historyID = $request['historyID'];
		$updateRequest = array('status' => $status);
		if ($status == 'writingRequest') {
			$where = array(
			      		'query' =>  "historyID=':historyID' AND status IN( 'pending', 'scheduled')",
				      	'params' => array(
			               ':historyID'=>$historyID
						)
					);
		}else{
			$where = array(
			      		'query' =>  "historyID=':historyID'",
				      	'params' => array(
			               ':historyID'=>$historyID
						)
					);
		}
		DB::update("?:history", $updateRequest, $where);
		$isUpdated = DB::affectedRows();
	}
	return $isUpdated;
}

?>