namespace support;
use Respect\Validation\Rules\Time;
use Workerman\Timer;
/**
* Class LongPollingResponse
* @package support
*/
class LongPollingResponse extends Response
{
/** @var float 等待时长 */
protected float $_wait;
/** @var Request 长轮询请求对象 */
protected Request $_request;
/** @var int 长轮询定时器计数 */
protected static int $_count = 0;
/**
* @param Request $request
* @param $status
* @param $headers
* @param $body
* @param float $wait 等待时长
*/
public function __construct(Request $request, $status = 200, $headers = [], $body = '', float $wait = 0)
{
$this->_wait = $wait;
$this->_request = $request;
parent::__construct($status, $headers, $body);
if ($this->_wait > 0) {
Timer::add($wait, function () {
self::$_count ++;
\Webman\App::send($this->_request->connection, $this, $this->_request);
self::$_count --;
}, [], false);
}
}
/**
* @return int
*/
public static function getLongPollingCount(): int
{
return self::$_count;
}
}
/**
* OnMessage.
* @param TcpConnection|mixed $connection
* @param Request|mixed $request
* @return null
*/
public function onMessage($connection, $request)
{
try {
Context::set(Request::class, $request);
$path = $request->path();
$key = $request->method() . $path;
if (isset(static::$callbacks[$key])) {
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$callbacks[$key];
$response = $callback($request);
if ($response instanceof LongPollingResponse) {
return;
}
static::send($connection, $response, $request);
return null;
}
$routeRes = static::findRoute($connection, $path, $key, $request);
if (
static::unsafeUri($connection, $path, $request) ||
static::findFile($connection, $path, $key, $request) ||
$routeRes !== false
) {
if ($routeRes === null) {
return;
}
return null;
}
$controllerAndAction = static::parseControllerAction($path);
$plugin = $controllerAndAction['plugin'] ?? static::getPluginByPath($path);
if (!$controllerAndAction || Route::hasDisableDefaultRoute($plugin)) {
$request->plugin = $plugin;
$callback = static::getFallback($plugin);
$request->app = $request->controller = $request->action = '';
$response = $callback($request);
if ($response instanceof LongPollingResponse) {
return;
}
static::send($connection, $response, $request);
return null;
}
$app = $controllerAndAction['app'];
$controller = $controllerAndAction['controller'];
$action = $controllerAndAction['action'];
$callback = static::getCallback($plugin, $app, [$controller, $action]);
static::collectCallbacks($key, [$callback, $plugin, $app, $controller, $action, null]);
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$callbacks[$key];
$response = $callback($request);
if ($response instanceof LongPollingResponse) {
return;
}
static::send($connection, $response, $request);
} catch (Throwable $e) {
$response =static::exceptionResponse($e, $request);
if ($response instanceof LongPollingResponse) {
return;
}
static::send($connection, static::exceptionResponse($e, $request), $request);
}
return null;
}
/**
* Find Route.
* @param TcpConnection $connection
* @param string $path
* @param string $key
* @param Request|mixed $request
* @return bool|null
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws ReflectionException
*/
protected static function findRoute(TcpConnection $connection, string $path, string $key, $request): ?bool
{
$routeInfo = Route::dispatch($request->method(), $path);
if ($routeInfo[0] === Dispatcher::FOUND) {
$routeInfo[0] = 'route';
$callback = $routeInfo[1]['callback'];
$route = clone $routeInfo[1]['route'];
$app = $controller = $action = '';
$args = !empty($routeInfo[2]) ? $routeInfo[2] : null;
if ($args) {
$route->setParams($args);
}
if (is_array($callback)) {
$controller = $callback[0];
$plugin = static::getPluginByClass($controller);
$app = static::getAppByController($controller);
$action = static::getRealMethod($controller, $callback[1]) ?? '';
} else {
$plugin = static::getPluginByPath($path);
}
$callback = static::getCallback($plugin, $app, $callback, $args, true, $route);
static::collectCallbacks($key, [$callback, $plugin, $app, $controller ?: '', $action, $route]);
[$callback, $request->plugin, $request->app, $request->controller, $request->action, $request->route] = static::$callbacks[$key];
$response = $callback($request);
if ($response instanceof LongPollingResponse) {
return null;
}
static::send($connection, $response, $request);
return true;
}
return false;
}
public function test(Request $request): Response
{
return (new LongPollingResponse($request,200, [], '{"info": "this is long polling response. "}', 20));
}
PS:
1. 此方法需要修改框架库webman-framework
2. 目前是一个思路demo,还有比较多的功能性需要完善
3. PR地址:https://github.com/walkor/webman-framework/pull/88