<?php
/**
* 定时器
*
* 一个进程只执行一次任务
* @author hzqghost <313143468@qq.com>
* @copyright 2020 yipart.com
* @version 1.0.0
*/
set_time_limit(0);
ignore_user_abort(true);
define('MVC_OS',strtolower(substr(PHP_OS,0,3)));
define('MVC_OS_IS_WIN',MVC_OS=='win'); //是否是windows
$name = $argv[1];
$timerPath = $argv[2];
$oldProcessFile = (isset($argv[3]) && $argv[3]!='&') ? $argv[3] : '';
$processPath = $timerPath . '/process';
$cfg = require_once($timerPath.'/config.php');
cli_set_process_title($name);
$pid = getmypid();
$processFile = $processPath.'/'.$name.'.'.$pid;
$wiatFile = $processPath.'/wait_'.$name;
file_put_contents($processFile,''); //写进程文件
if($oldProcessFile!='') @unlink($oldProcessFile); //删除前一个进程的文件标记

$item = $cfg[$name];
$interval = $item['interval'];
$phpfile = $timerPath . '/../'.trim($item['site']).'/index.php';
$action = trim($item['action']);
$actionTimeLimit = trim($item['actionTimeLimit']);
$lock = $item['lock'];
$lockMaxTime = $item['lockMaxTime'];
$runOnce = $item['runOnce'];  
$startTime = trim($item['startTime']);
$endTime = trim($item['endTime']);

if(!empty($startTime)){
	//开始时间处理
	$i = 0;
	while(time() < strtotime($startTime)){
		sleep(1);
		$i++;
		if($i>30){
			if(MVC_OS_IS_WIN){
				pclose(popen('start /B php '.__FILE__ . ' ' . $argv[1]. ' ' . $argv[2] . ' '. $processFile . " &", 'r'));
			}else{
				pclose(popen('php '.__FILE__ . ' ' . $argv[1]. ' ' . $argv[2] . ' '. $processFile . ' > /dev/null &', 'r'));
			}
			exit();
		}
	}
}
if(!empty($endTime)){
	//结束时间处理
	if(time() > strtotime($endTime)){
		unlink($processFile);
		@unlink($lockFile);
		exit();
	}
}

sleep($interval);

//间隔时间
if(!file_exists($wiatFile)) file_put_contents($wiatFile,'');
$checkTime = filemtime($wiatFile) + ($interval*1);
$i = 0;
while(time() < $checkTime ){
	sleep(1);
	$i++;
	if($i>30){
		if(MVC_OS_IS_WIN){
			pclose(popen('start /B php '.__FILE__ . ' ' . $argv[1]. ' ' . $argv[2] . ' '. $processFile . " &", 'r'));
		}else{
			pclose(popen('php '.__FILE__ . ' ' . $argv[1]. ' ' . $argv[2] . ' '. $processFile . ' > /dev/null &', 'r'));
		}
		exit();
	}
}
@unlink($wiatFile);


//创建进程执行，业务模块
if($lock){
	//加锁模式
	$lockFile = $processPath.'/lock_'.$name;
	$lockMaxTime = $lockMaxTime * 1;
	if($lockMaxTime>0 && file_exists($lockFile)){
		$mtime = filemtime($lockFile);
		if( (time()-$mtime) > $lockMaxTime){
			//超过最大加锁时间
			$processActionDir =  $processPath.'/action';
			if(is_dir($processActionDir)){
				$files = scandir($processActionDir);
				foreach($files as $file){
					if($file!='.' && $file!='..'){
						@list($outname,$pid) = explode('.',$file);
						if($pid=='') continue;
						if($outname==$name){
							if(MVC_OS_IS_WIN){
								pclose(popen(escapeshellcmd('taskkill /pid '.$pid.' -t -f'),'r'));
							}else{
								pclose(popen(escapeshellcmd("sudo kill ".$pid),'r')); //todo linux 下还没有测试
							}
							@unlink($processActionDir.'/'.$file);
						}
					}
				}
			}
			@unlink($lockFile);
		}
	}
	//如果没有锁标记则执行，并加个锁标记
	if(!file_exists($lockFile)){
		file_put_contents($lockFile,'');
		//将定时器名传递过去，用于解锁
		//在 MVC_SAPI_IS_CLI 中的 register_shutdown_function 解锁
		if($actionTimeLimit=='') $actionTimeLimit = 600;
		if(strpos($action,'?')!==false){
			$action = $action . '&___timer='.$name.'&___timeout='.$actionTimeLimit;
		}else{
			$action = $action . '?___timer='.$name.'&___timeout='.$actionTimeLimit;
		}
		if(MVC_OS_IS_WIN){
			pclose(popen('start /B php '.$phpfile. ' "' . $action . ' &', 'r'));
		}else{
			pclose(popen('php '.$phpfile. ' ' . $action . ' > /dev/null &', 'r'));
		}
	}
}else{
	//不加锁模式
	if(MVC_OS_IS_WIN){
		pclose(popen('start /B php '.$phpfile. ' ' . $action . ' &', 'r'));
	}else{
		pclose(popen('php '.$phpfile. ' ' . $action . ' > /dev/null &', 'r'));
	}
}

//将自己打开在一个新的进程中,如果没有stop标记文件及runOnce=false的前提下
//一个进程只执行一次任务
$stopFile = $processPath.'/stop';
$stopFileThis = $processPath.'/stop_'.$name;
if(!$runOnce && !file_exists($stopFile) && !file_exists($stopFileThis)){
	if(MVC_OS_IS_WIN){
		pclose(popen('start /B php '.__FILE__ . ' ' . $argv[1]. ' ' . $argv[2] . ' '. $processFile . " &", 'r'));
	}else{
		pclose(popen('php '.__FILE__ . ' ' . $argv[1]. ' ' . $argv[2] . ' '. $processFile . ' > /dev/null &', 'r'));
	}
}else{
	//有stop标记时，删除进程文件标记
	unlink($processFile);
	@unlink($lockFile);
}
