add async service for plugin

This commit is contained in:
joyqi 2017-11-15 14:25:02 +08:00
parent 5f3620e058
commit f180e8452d
6 changed files with 174 additions and 4 deletions

View File

@ -63,6 +63,17 @@ class Helper
return $widget;
}
/**
* 请求异步服务
*
* @param $method
* @param $params
*/
public static function requestService($method, $params)
{
Typecho_Widget::widget('Widget_Service')->requestService($method, $params);
}
/**
* 强行删除某个插件
*

View File

@ -22,7 +22,7 @@ define('__TYPECHO_MB_SUPPORTED__', function_exists('mb_get_info') && function_ex
class Typecho_Common
{
/** 程序版本 */
const VERSION = '1.1/17.10.30';
const VERSION = '1.1/17.11.15';
/**
* 允许的属性
@ -910,6 +910,39 @@ EOF;
}
}
/**
* 创建一个会过期的Token
*
* @param $secret
* @return string
*/
public static function timeToken($secret)
{
return sha1($secret . '&' . time());
}
/**
* 在时间范围内验证token
*
* @param $token
* @param $secret
* @param int $timeout
* @return bool
*/
public static function timeTokenValidate($token, $secret, $timeout = 5)
{
$now = time();
$from = $now - $timeout;
for ($i = $now; $i >= $from; $i --) {
if (sha1($secret . '&' . $i) == $token) {
return true;
}
}
return false;
}
/**
* 将路径转化为链接
*

View File

@ -87,6 +87,13 @@ class Typecho_Response
*/
private static $_instance = null;
/**
* 结束前回调函数
*
* @var array
*/
private static $_callbacks = array();
/**
* 获取单例句柄
*
@ -126,6 +133,33 @@ class Typecho_Response
}
}
/**
* 结束前的统一回调函数
*/
public static function callback()
{
static $called;
if ($called) {
return;
}
$called = true;
foreach (self::$_callbacks as $callback) {
call_user_func($callback);
}
}
/**
* 新增回调
*
* @param $callback
*/
public static function addCallback($callback)
{
self::$_callbacks[] = $callback;
}
/**
* 设置默认回执编码
*
@ -211,6 +245,7 @@ class Typecho_Response
'</response>';
/** 终止后续输出 */
self::callback();
exit;
}
@ -229,6 +264,7 @@ class Typecho_Response
echo Json::encode($message);
/** 终止后续输出 */
self::callback();
exit;
}
@ -246,9 +282,11 @@ class Typecho_Response
$location = Typecho_Common::safeUrl($location);
if ($isPermanently) {
self::callback();
header('Location: ' . $location, false, 301);
exit;
} else {
self::callback();
header('Location: ' . $location, false, 302);
exit;
}
@ -296,6 +334,7 @@ class Typecho_Response
$this->redirect($default);
}
self::callback();
exit;
}
}

View File

@ -138,6 +138,7 @@ class Typecho_Router
$widget->{$route['action']}();
}
Typecho_Response::callback();
return;
} catch (Exception $e) {

View File

@ -51,7 +51,7 @@ class Widget_Ajax extends Widget_Abstract_Options implements Widget_Interface_Do
/** 匹配内容体 */
$response = $client->getResponseBody();
$json = json_decode($response, true);
$json = Json::decode($response, true);
if (!empty($json)) {
list($soft, $version) = explode(' ', $this->options->generator);

View File

@ -19,6 +19,13 @@ if (!defined('__TYPECHO_ROOT_DIR__')) exit;
*/
class Widget_Service extends Widget_Abstract_Options implements Widget_Interface_Do
{
/**
* 异步请求
*
* @var array
*/
public $asyncRequests = array();
/**
* 发送pingback实现
*
@ -31,7 +38,13 @@ class Widget_Service extends Widget_Abstract_Options implements Widget_Interface
$this->user->pass('contributor');
/** 忽略超时 */
ignore_user_abort(true);
if (function_exists('ignore_user_abort')) {
ignore_user_abort(true);
}
if (function_exists('set_time_limit')) {
set_time_limit(30);
}
/** 获取post */
$post = $this->widget('Widget_Archive', "type=post", "cid={$this->request->cid}");
@ -138,7 +151,7 @@ class Widget_Service extends Widget_Abstract_Options implements Widget_Interface
$client->setCookie('__typecho_uid', Typecho_Cookie::get('__typecho_uid'))
->setCookie('__typecho_authCode', Typecho_Cookie::get('__typecho_authCode'))
->setHeader('User-Agent', $this->options->generator)
->setTimeout(3)
->setTimeout(2)
->setData($input)
->send(Typecho_Common::url('/action/service', $this->options->index));
@ -148,6 +161,78 @@ class Widget_Service extends Widget_Abstract_Options implements Widget_Interface
}
}
/**
* 请求异步服务
*
* @param $method
* @param mixed $params
*/
public function requestService($method, $params = NULL)
{
static $called;
if (!$called) {
$self = $this;
Typecho_Response::addCallback(function () use ($self) {
if (!empty($self->asyncRequests) && $client = Typecho_Http_Client::get()) {
try {
$client->setHeader('User-Agent', $this->options->generator)
->setTimeout(2)
->setData(array(
'do' => 'async',
'requests' => Json::encode($self->asyncRequests),
'token' => Typecho_Common::timeToken($this->options->secret)
))
->setMethod(Typecho_Http_Client::METHOD_POST)
->send(Typecho_Common::url('/action/service', $this->options->index));
} catch (Typecho_Http_Client_Exception $e) {
return;
}
}
});
$called = true;
}
$this->asyncRequests[] = array($method, $params);
}
/**
* 执行回调
*
* @throws Typecho_Widget_Exception
*/
public function asyncHandle()
{
/** 验证权限 */
$token = $this->request->token;
if (!Typecho_Common::timeTokenValidate($token, $this->options->secret, 3)) {
throw new Typecho_Widget_Exception(_t('禁止访问'), 403);
}
/** 忽略超时 */
if (function_exists('ignore_user_abort')) {
ignore_user_abort(true);
}
if (function_exists('set_time_limit')) {
set_time_limit(30);
}
$requests = Json::decode($this->request->requests, true);
$plugin = Typecho_Plugin::factory(__CLASS__);
if (!empty($requests)) {
foreach ($requests as $request) {
list ($method, $params) = $request;
$plugin->{$method}($params);
}
}
}
/**
* 异步请求入口
*
@ -157,5 +242,6 @@ class Widget_Service extends Widget_Abstract_Options implements Widget_Interface
public function action()
{
$this->on($this->request->is('do=ping'))->sendPingHandle();
$this->on($this->request->is('do=async'))->asyncHandle();
}
}