Skip to content

Commit f180e84

Browse files
committed
add async service for plugin
1 parent 5f3620e commit f180e84

File tree

6 files changed

+174
-4
lines changed

6 files changed

+174
-4
lines changed

var/Helper.php

+11
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ public static function widgetById($table, $pkId)
6363
return $widget;
6464
}
6565

66+
/**
67+
* 请求异步服务
68+
*
69+
* @param $method
70+
* @param $params
71+
*/
72+
public static function requestService($method, $params)
73+
{
74+
Typecho_Widget::widget('Widget_Service')->requestService($method, $params);
75+
}
76+
6677
/**
6778
* 强行删除某个插件
6879
*

var/Typecho/Common.php

+34-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
class Typecho_Common
2323
{
2424
/** 程序版本 */
25-
const VERSION = '1.1/17.10.30';
25+
const VERSION = '1.1/17.11.15';
2626

2727
/**
2828
* 允许的属性
@@ -910,6 +910,39 @@ public static function hashValidate($from, $to)
910910
}
911911
}
912912

913+
/**
914+
* 创建一个会过期的Token
915+
*
916+
* @param $secret
917+
* @return string
918+
*/
919+
public static function timeToken($secret)
920+
{
921+
return sha1($secret . '&' . time());
922+
}
923+
924+
/**
925+
* 在时间范围内验证token
926+
*
927+
* @param $token
928+
* @param $secret
929+
* @param int $timeout
930+
* @return bool
931+
*/
932+
public static function timeTokenValidate($token, $secret, $timeout = 5)
933+
{
934+
$now = time();
935+
$from = $now - $timeout;
936+
937+
for ($i = $now; $i >= $from; $i --) {
938+
if (sha1($secret . '&' . $i) == $token) {
939+
return true;
940+
}
941+
}
942+
943+
return false;
944+
}
945+
913946
/**
914947
* 将路径转化为链接
915948
*

var/Typecho/Response.php

+39
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ class Typecho_Response
8787
*/
8888
private static $_instance = null;
8989

90+
/**
91+
* 结束前回调函数
92+
*
93+
* @var array
94+
*/
95+
private static $_callbacks = array();
96+
9097
/**
9198
* 获取单例句柄
9299
*
@@ -126,6 +133,33 @@ private function _parseXml($message)
126133
}
127134
}
128135

136+
/**
137+
* 结束前的统一回调函数
138+
*/
139+
public static function callback()
140+
{
141+
static $called;
142+
143+
if ($called) {
144+
return;
145+
}
146+
147+
$called = true;
148+
foreach (self::$_callbacks as $callback) {
149+
call_user_func($callback);
150+
}
151+
}
152+
153+
/**
154+
* 新增回调
155+
*
156+
* @param $callback
157+
*/
158+
public static function addCallback($callback)
159+
{
160+
self::$_callbacks[] = $callback;
161+
}
162+
129163
/**
130164
* 设置默认回执编码
131165
*
@@ -211,6 +245,7 @@ public function throwXml($message)
211245
'</response>';
212246

213247
/** 终止后续输出 */
248+
self::callback();
214249
exit;
215250
}
216251

@@ -229,6 +264,7 @@ public function throwJson($message)
229264
echo Json::encode($message);
230265

231266
/** 终止后续输出 */
267+
self::callback();
232268
exit;
233269
}
234270

@@ -246,9 +282,11 @@ public function redirect($location, $isPermanently = false)
246282
$location = Typecho_Common::safeUrl($location);
247283

248284
if ($isPermanently) {
285+
self::callback();
249286
header('Location: ' . $location, false, 301);
250287
exit;
251288
} else {
289+
self::callback();
252290
header('Location: ' . $location, false, 302);
253291
exit;
254292
}
@@ -296,6 +334,7 @@ public function goBack($suffix = NULL, $default = NULL)
296334
$this->redirect($default);
297335
}
298336

337+
self::callback();
299338
exit;
300339
}
301340
}

var/Typecho/Router.php

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public static function dispatch()
138138
$widget->{$route['action']}();
139139
}
140140

141+
Typecho_Response::callback();
141142
return;
142143

143144
} catch (Exception $e) {

var/Widget/Ajax.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public function checkVersion()
5151

5252
/** 匹配内容体 */
5353
$response = $client->getResponseBody();
54-
$json = json_decode($response, true);
54+
$json = Json::decode($response, true);
5555

5656
if (!empty($json)) {
5757
list($soft, $version) = explode(' ', $this->options->generator);

var/Widget/Service.php

+88-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919
*/
2020
class Widget_Service extends Widget_Abstract_Options implements Widget_Interface_Do
2121
{
22+
/**
23+
* 异步请求
24+
*
25+
* @var array
26+
*/
27+
public $asyncRequests = array();
28+
2229
/**
2330
* 发送pingback实现
2431
*
@@ -31,7 +38,13 @@ public function sendPingHandle()
3138
$this->user->pass('contributor');
3239

3340
/** 忽略超时 */
34-
ignore_user_abort(true);
41+
if (function_exists('ignore_user_abort')) {
42+
ignore_user_abort(true);
43+
}
44+
45+
if (function_exists('set_time_limit')) {
46+
set_time_limit(30);
47+
}
3548

3649
/** 获取post */
3750
$post = $this->widget('Widget_Archive', "type=post", "cid={$this->request->cid}");
@@ -138,7 +151,7 @@ public function sendPing($cid, array $trackback = NULL)
138151
$client->setCookie('__typecho_uid', Typecho_Cookie::get('__typecho_uid'))
139152
->setCookie('__typecho_authCode', Typecho_Cookie::get('__typecho_authCode'))
140153
->setHeader('User-Agent', $this->options->generator)
141-
->setTimeout(3)
154+
->setTimeout(2)
142155
->setData($input)
143156
->send(Typecho_Common::url('/action/service', $this->options->index));
144157

@@ -148,6 +161,78 @@ public function sendPing($cid, array $trackback = NULL)
148161
}
149162
}
150163

164+
/**
165+
* 请求异步服务
166+
*
167+
* @param $method
168+
* @param mixed $params
169+
*/
170+
public function requestService($method, $params = NULL)
171+
{
172+
static $called;
173+
174+
if (!$called) {
175+
$self = $this;
176+
177+
Typecho_Response::addCallback(function () use ($self) {
178+
if (!empty($self->asyncRequests) && $client = Typecho_Http_Client::get()) {
179+
try {
180+
$client->setHeader('User-Agent', $this->options->generator)
181+
->setTimeout(2)
182+
->setData(array(
183+
'do' => 'async',
184+
'requests' => Json::encode($self->asyncRequests),
185+
'token' => Typecho_Common::timeToken($this->options->secret)
186+
))
187+
->setMethod(Typecho_Http_Client::METHOD_POST)
188+
->send(Typecho_Common::url('/action/service', $this->options->index));
189+
190+
} catch (Typecho_Http_Client_Exception $e) {
191+
return;
192+
}
193+
}
194+
});
195+
196+
$called = true;
197+
}
198+
199+
$this->asyncRequests[] = array($method, $params);
200+
}
201+
202+
/**
203+
* 执行回调
204+
*
205+
* @throws Typecho_Widget_Exception
206+
*/
207+
public function asyncHandle()
208+
{
209+
/** 验证权限 */
210+
$token = $this->request->token;
211+
212+
if (!Typecho_Common::timeTokenValidate($token, $this->options->secret, 3)) {
213+
throw new Typecho_Widget_Exception(_t('禁止访问'), 403);
214+
}
215+
216+
/** 忽略超时 */
217+
if (function_exists('ignore_user_abort')) {
218+
ignore_user_abort(true);
219+
}
220+
221+
if (function_exists('set_time_limit')) {
222+
set_time_limit(30);
223+
}
224+
225+
$requests = Json::decode($this->request->requests, true);
226+
$plugin = Typecho_Plugin::factory(__CLASS__);
227+
228+
if (!empty($requests)) {
229+
foreach ($requests as $request) {
230+
list ($method, $params) = $request;
231+
$plugin->{$method}($params);
232+
}
233+
}
234+
}
235+
151236
/**
152237
* 异步请求入口
153238
*
@@ -157,5 +242,6 @@ public function sendPing($cid, array $trackback = NULL)
157242
public function action()
158243
{
159244
$this->on($this->request->is('do=ping'))->sendPingHandle();
245+
$this->on($this->request->is('do=async'))->asyncHandle();
160246
}
161247
}

0 commit comments

Comments
 (0)