This commit is contained in:
li
2026-01-28 23:48:20 +08:00
commit b8cd0c9418
1293 changed files with 184011 additions and 0 deletions
@@ -0,0 +1,208 @@
<?php
namespace think\swoole\concerns;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\Server;
use Symfony\Component\VarDumper\VarDumper;
use think\App;
use think\Container;
use think\Cookie;
use think\Event;
use think\exception\Handle;
use think\Http;
use think\Middleware;
use think\swoole\middleware\ResetVarDumper;
use Throwable;
/**
* Trait InteractsWithHttp
* @package think\swoole\concerns
* @property App $app
* @property Container $container
* @method Server getServer()
*/
trait InteractsWithHttp
{
public static $statusTexts = [
100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing', // RFC2518
103 => 'Early Hints',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
207 => 'Multi-Status', // RFC4918
208 => 'Already Reported', // RFC5842
226 => 'IM Used', // RFC3229
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
308 => 'Permanent Redirect', // RFC7238
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Payload Too Large',
414 => 'URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Range Not Satisfiable',
417 => 'Expectation Failed',
418 => 'I\'m a teapot', // RFC2324
421 => 'Misdirected Request', // RFC7540
422 => 'Unprocessable Entity', // RFC4918
423 => 'Locked', // RFC4918
424 => 'Failed Dependency', // RFC4918
425 => 'Too Early', // RFC-ietf-httpbis-replay-04
426 => 'Upgrade Required', // RFC2817
428 => 'Precondition Required', // RFC6585
429 => 'Too Many Requests', // RFC6585
431 => 'Request Header Fields Too Large', // RFC6585
449 => 'Retry With',
451 => 'Unavailable For Legal Reasons', // RFC7725
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported',
506 => 'Variant Also Negotiates', // RFC2295
507 => 'Insufficient Storage', // RFC4918
508 => 'Loop Detected', // RFC5842
510 => 'Not Extended', // RFC2774
511 => 'Network Authentication Required', // RFC6585
];
/**
* "onRequest" listener.
*
* @param Request $req
* @param Response $res
*/
public function onRequest($req, $res)
{
$args = func_get_args();
$this->runInSandbox(function (Http $http, Event $event, App $app, Middleware $middleware) use ($args, $req, $res) {
$event->trigger('swoole.request', $args);
//兼容var-dumper
if (class_exists(VarDumper::class)) {
$middleware->add(ResetVarDumper::class);
}
$request = $this->prepareRequest($req);
try {
$response = $this->handleRequest($http, $request);
} catch (Throwable $e) {
$response = $this->app
->make(Handle::class)
->render($request, $e);
}
$this->sendResponse($res, $response, $app->cookie);
});
}
protected function handleRequest(Http $http, $request)
{
$level = ob_get_level();
ob_start();
$response = $http->run($request);
$content = $response->getContent();
if (ob_get_level() == 0) {
ob_start();
}
$http->end($response);
if (ob_get_length() > 0) {
$response->content(ob_get_contents() . $content);
}
while (ob_get_level() > $level) {
ob_end_clean();
}
return $response;
}
protected function prepareRequest(Request $req)
{
$header = $req->header ?: [];
$server = $req->server ?: [];
foreach ($header as $key => $value) {
$server["http_" . str_replace('-', '_', $key)] = $value;
}
// 重新实例化请求对象 处理swoole请求数据
/** @var \think\Request $request */
$request = $this->app->make('request', [], true);
return $request->withHeader($header)
->withServer($server)
->withGet($req->get ?: [])
->withPost($req->post ?: [])
->withCookie($req->cookie ?: [])
->withFiles($req->files ?: [])
->withInput($req->rawContent())
->setBaseUrl($req->server['request_uri'])
->setUrl($req->server['request_uri'] . (!empty($req->server['query_string']) ? '?' . $req->server['query_string'] : ''))
->setPathinfo(ltrim($req->server['path_info'], '/'));
}
protected function sendResponse(Response $res, \think\Response $response, Cookie $cookie)
{
// 发送Header
foreach ($response->getHeader() as $key => $val) {
$res->header($key, $val);
}
// 发送状态码
$code = $response->getCode();
$res->status($code, isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : 'unknown status');
foreach ($cookie->getCookie() as $name => $val) {
[$value, $expire, $option] = $val;
$res->cookie($name, $value, $expire, $option['path'], $option['domain'], $option['secure'] ? true : false, $option['httponly'] ? true : false);
}
$content = $response->getContent();
$this->sendByChunk($res, $content);
}
protected function sendByChunk(Response $res, $content)
{
if (!empty($content)) {
$chunkSize = 8192;
foreach (str_split($content, $chunkSize) as $chunk) {
$res->write($chunk);
}
}
$res->end();
}
}
@@ -0,0 +1,64 @@
<?php
namespace think\swoole\concerns;
use Exception;
use Smf\ConnectionPool\ConnectionPool;
use Smf\ConnectionPool\Connectors\ConnectorInterface;
use Swoole\Server;
use think\App;
use think\helper\Arr;
use think\swoole\Pool;
use Throwable;
/**
* Trait InteractsWithRpc
* @package think\swoole\concerns
* @property App $app
* @method Server getServer()
*/
trait InteractsWithPools
{
/**
* @return Pool
*/
public function getPools()
{
return $this->app->make(Pool::class);
}
protected function preparePools()
{
$createPools = function () {
/** @var Pool $pool */
$pools = $this->getPools();
foreach ($this->getConfig('pool', []) as $name => $config) {
$type = Arr::pull($config, 'type');
if ($type && is_subclass_of($type, ConnectorInterface::class)) {
$pool = new ConnectionPool(
Pool::pullPoolConfig($config),
$this->app->make($type),
$config
);
$pools->add($name, $pool);
//注入到app
$this->app->instance("swoole.pool.{$name}", $pool);
}
}
};
$closePools = function () {
try {
$this->getPools()->closeAll();
} catch (Exception | Throwable $e) {
}
};
$this->onEvent('workerStart', $createPools);
$this->onEvent('workerStop', $closePools);
$this->onEvent('workerError', $closePools);
$this->onEvent('workerExit', $closePools);
}
}
@@ -0,0 +1,130 @@
<?php
namespace think\swoole\concerns;
use Smf\ConnectionPool\ConnectionPool;
use Swoole\Server;
use think\App;
use think\swoole\exception\RpcClientException;
use think\swoole\Pool;
use think\swoole\pool\Client;
use think\swoole\rpc\client\Connector;
use think\swoole\rpc\client\Gateway;
use think\swoole\rpc\client\Proxy;
use think\swoole\rpc\JsonParser;
use think\swoole\rpc\Packer;
/**
* Trait InteractsWithRpcClient
* @package think\swoole\concerns
* @property App $app
* @property App $container
* @method Server getServer()
* @method Pool getPools()
*/
trait InteractsWithRpcClient
{
protected $rpcServices = [];
protected function prepareRpcClient()
{
//引入rpc接口文件
if (file_exists($rpc = $this->container->getBasePath() . 'rpc.php')) {
$this->rpcServices = (array) include $rpc;
}
$this->onEvent('workerStart', function () {
$this->bindRpcClientPool();
});
}
protected function bindRpcClientPool()
{
if (!empty($clients = $this->getConfig('rpc.client'))) {
//创建client连接池
foreach ($clients as $name => $config) {
$pool = new ConnectionPool(
Pool::pullPoolConfig($config),
new Client(),
array_merge(
$config,
[
'open_length_check' => true,
'package_length_type' => Packer::HEADER_PACK,
'package_length_offset' => 0,
'package_body_offset' => 8,
]
)
);
$this->getPools()->add("rpc.client.{$name}", $pool);
}
//绑定rpc接口
try {
foreach ($this->rpcServices as $name => $abstracts) {
$parserClass = $this->getConfig("rpc.client.{$name}.parser", JsonParser::class);
$parser = $this->app->make($parserClass);
$gateway = new Gateway($this->createRpcConnector($name), $parser);
foreach ($abstracts as $abstract) {
$this->app->bind($abstract, function () use ($gateway, $name, $abstract) {
return $this->app->invokeClass(Proxy::getClassName($name, $abstract), [$gateway]);
});
}
}
} catch (\Exception | \Throwable $e) {
}
}
}
protected function createRpcConnector($name)
{
$pool = $this->getPools()->get("rpc.client.{$name}");
return new class($pool) implements Connector {
protected $pool;
public function __construct(ConnectionPool $pool)
{
$this->pool = $pool;
}
public function sendAndRecv($data)
{
if (!$data instanceof \Generator) {
$data = [$data];
}
/** @var \Swoole\Coroutine\Client $client */
$client = $this->pool->borrow();
try {
foreach ($data as $string) {
if (!$client->send($string)) {
$this->onError($client);
}
}
$response = $client->recv();
if ($response === false || empty($response)) {
$this->onError($client);
}
return $response;
} finally {
$this->pool->return($client);
}
}
protected function onError(\Swoole\Coroutine\Client $client)
{
$client->close();
throw new RpcClientException(swoole_strerror($client->errCode), $client->errCode);
}
};
}
}
@@ -0,0 +1,36 @@
<?php
namespace think\swoole\concerns;
use Swoole\Server;
use think\App;
use think\swoole\Pool;
use think\swoole\RpcManager;
/**
* Trait InteractsWithRpc
* @package think\swoole\concerns
* @property App $app
* @property App $container
* @method Server getServer()
* @method Pool getPools()
*/
trait InteractsWithRpcServer
{
protected function prepareRpcServer()
{
if ($this->getConfig('rpc.server.enable', false)) {
$host = $this->getConfig('server.host');
$port = $this->getConfig('rpc.server.port', 9000);
$rpcServer = $this->getServer()->addlistener($host, $port, SWOOLE_SOCK_TCP);
/** @var RpcManager $rpcManager */
$rpcManager = $this->container->make(RpcManager::class);
$rpcManager->attachToServer($rpcServer);
}
}
}
@@ -0,0 +1,224 @@
<?php
namespace think\swoole\concerns;
use Exception;
use Swoole\Process;
use Swoole\Runtime;
use Swoole\Server;
use Swoole\Server\Task;
use think\App;
use think\console\Output;
use think\Event;
use think\exception\Handle;
use think\helper\Str;
use think\swoole\FileWatcher;
use Throwable;
/**
* Trait InteractsWithServer
* @package think\swoole\concerns
* @property App $container
*/
trait InteractsWithServer
{
/**
* 启动服务
*/
public function run(): void
{
$this->getServer()->set([
'task_enable_coroutine' => true,
'send_yield' => true,
'reload_async' => true,
'enable_coroutine' => true,
'max_request' => 0,
'task_max_request' => 0,
]);
$this->initialize();
$this->triggerEvent('init');
//热更新
if ($this->getConfig('hot_update.enable', false)) {
$this->addHotUpdateProcess();
}
$this->getServer()->start();
}
/**
* 停止服务
*/
public function stop(): void
{
$this->getServer()->shutdown();
}
/**
* "onStart" listener.
*/
public function onStart()
{
$this->setProcessName('master process');
$this->triggerEvent("start", func_get_args());
}
/**
* The listener of "managerStart" event.
*
* @return void
*/
public function onManagerStart()
{
$this->setProcessName('manager process');
$this->triggerEvent("managerStart", func_get_args());
}
/**
* "onWorkerStart" listener.
*
* @param \Swoole\Http\Server|mixed $server
*
* @throws Exception
*/
public function onWorkerStart($server)
{
Runtime::enableCoroutine(
$this->getConfig('coroutine.enable', true),
$this->getConfig('coroutine.flags', SWOOLE_HOOK_ALL)
);
$this->clearCache();
$this->setProcessName($server->taskworker ? 'task process' : 'worker process');
$this->prepareApplication();
$this->triggerEvent("workerStart", $this->app);
}
/**
* Set onTask listener.
*
* @param mixed $server
* @param Task $task
*/
public function onTask($server, Task $task)
{
$this->runInSandbox(function (Event $event) use ($task) {
$event->trigger('swoole.task', $task);
}, $task->id);
}
/**
* Set onShutdown listener.
*/
public function onShutdown()
{
$this->triggerEvent('shutdown');
}
/**
* @return Server
*/
public function getServer()
{
return $this->container->make(Server::class);
}
/**
* Set swoole server listeners.
*/
protected function setSwooleServerListeners()
{
foreach ($this->events as $event) {
$listener = Str::camel("on_$event");
$callback = method_exists($this, $listener) ? [$this, $listener] : function () use ($event) {
$this->triggerEvent($event, func_get_args());
};
$this->getServer()->on($event, $callback);
}
}
/**
* 热更新
*/
protected function addHotUpdateProcess()
{
$process = new Process(function () {
$watcher = new FileWatcher(
$this->getConfig('hot_update.include', []),
$this->getConfig('hot_update.exclude', []),
$this->getConfig('hot_update.name', [])
);
$watcher->watch(function () {
$this->getServer()->reload();
});
}, false, 0);
$this->addProcess($process);
}
/**
* Add process to http server
*
* @param Process $process
*/
public function addProcess(Process $process): void
{
$this->getServer()->addProcess($process);
}
/**
* 清除apc、op缓存
*/
protected function clearCache()
{
if (extension_loaded('apc')) {
apc_clear_cache();
}
if (extension_loaded('Zend OPcache')) {
opcache_reset();
}
}
/**
* Set process name.
*
* @param $process
*/
protected function setProcessName($process)
{
// Mac OSX不支持进程重命名
if (stristr(PHP_OS, 'DAR')) {
return;
}
$serverName = 'swoole_http_server';
$appName = $this->container->config->get('app.name', 'ThinkPHP');
$name = sprintf('%s: %s for %s', $serverName, $process, $appName);
swoole_set_process_name($name);
}
/**
* Log server error.
*
* @param Throwable|Exception $e
*/
public function logServerError(Throwable $e)
{
/** @var Handle $handle */
$handle = $this->container->make(Handle::class);
$handle->renderForConsole(new Output(), $e);
$handle->report($e);
}
}
@@ -0,0 +1,69 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think\swoole\concerns;
use Swoole\Table as SwooleTable;
use think\App;
use think\Container;
use think\swoole\Table;
/**
* Trait InteractsWithSwooleTable
*
* @property Container $container
* @property App $app
*/
trait InteractsWithSwooleTable
{
/**
* @var Table
*/
protected $currentTable;
/**
* Register customized swoole tables.
*/
protected function prepareTables()
{
$this->currentTable = new Table();
$this->registerTables();
$this->onEvent('workerStart', function () {
$this->app->instance(Table::class, $this->currentTable);
foreach ($this->currentTable->getAll() as $name => $table) {
$this->app->instance("swoole.table.{$name}", $table);
}
});
}
/**
* Register user-defined swoole tables.
*/
protected function registerTables()
{
$tables = $this->container->make('config')->get('swoole.tables', []);
foreach ($tables as $key => $value) {
$table = new SwooleTable($value['size']);
$columns = $value['columns'] ?? [];
foreach ($columns as $column) {
if (isset($column['size'])) {
$table->column($column['name'], $column['type'], $column['size']);
} else {
$table->column($column['name'], $column['type']);
}
}
$table->create();
$this->currentTable->add($key, $table);
}
}
}
@@ -0,0 +1,267 @@
<?php
namespace think\swoole\concerns;
use Swoole\Http\Request;
use Swoole\Server\Task;
use Swoole\Websocket\Frame;
use Swoole\Websocket\Server;
use think\App;
use think\Container;
use think\Event;
use think\helper\Str;
use think\Pipeline;
use think\swoole\contract\websocket\HandlerInterface;
use think\swoole\contract\websocket\ParserInterface;
use think\swoole\contract\websocket\RoomInterface;
use think\swoole\Websocket;
use think\swoole\websocket\Pusher;
use think\swoole\websocket\Room;
use think\swoole\websocket\socketio\Handler;
use think\swoole\websocket\socketio\Parser as SocketioParser;
/**
* Trait InteractsWithWebsocket
* @package think\swoole\concerns
*
* @property App $app
* @property Container $container
* @method \Swoole\Server getServer()
*/
trait InteractsWithWebsocket
{
/**
* @var boolean
*/
protected $isWebsocketServer = false;
/**
* @var RoomInterface
*/
protected $websocketRoom;
/**
* Websocket server events.
*
* @var array
*/
protected $wsEvents = ['open', 'message', 'close'];
/**
* "onOpen" listener.
*
* @param Server $server
* @param Request $req
*/
public function onOpen($server, $req)
{
/** @var Websocket $websocket */
$websocket = $this->app->make(Websocket::class);
$websocket->setSender($req->fd);
$this->runInSandbox(function (Event $event, HandlerInterface $handler, App $app) use ($req) {
$request = $this->prepareRequest($req);
$request = $this->setRequestThroughMiddleware($app, $request);
if (!$handler->onOpen($req->fd, $request)) {
$event->trigger("swoole.websocket.Connect", $request);
}
}, $req->fd, true);
}
/**
* "onMessage" listener.
*
* @param Server $server
* @param Frame $frame
*/
public function onMessage($server, $frame)
{
/** @var Websocket $websocket */
$websocket = $this->app->make(Websocket::class);
$websocket->setSender($frame->fd);
$this->runInSandbox(function (Event $event, ParserInterface $parser, HandlerInterface $handler) use ($frame) {
if (!$handler->onMessage($frame)) {
$payload = $parser->decode($frame);
['event' => $name, 'data' => $data] = $payload;
$name = Str::studly($name);
if (!in_array($name, ['Close', 'Connect'])) {
$event->trigger("swoole.websocket." . $name, $data);
}
}
}, $frame->fd, true);
}
/**
* "onClose" listener.
*
* @param Server $server
* @param int $fd
* @param int $reactorId
*/
public function onClose($server, $fd, $reactorId)
{
if (!$this->isWebsocketServer($fd) || !$server instanceof Server) {
return;
}
/** @var Websocket $websocket */
$websocket = $this->app->make(Websocket::class);
$websocket->setSender($fd);
$this->runInSandbox(function (Event $event, HandlerInterface $handler) use ($websocket, $fd, $reactorId) {
try {
if (!$handler->onClose($fd, $reactorId)) {
$event->trigger("swoole.websocket.Close");
}
} finally {
// leave all rooms
$websocket->leave();
}
}, $fd);
}
/**
* @param App $app
* @param \think\Request $request
* @return \think\Request
*/
protected function setRequestThroughMiddleware(App $app, \think\Request $request)
{
$middleware = $this->getConfig('websocket.middleware', []);
return (new Pipeline())
->send($request)
->through(array_map(function ($middleware) use ($app) {
return function ($request, $next) use ($app, $middleware) {
if (is_array($middleware)) {
list($middleware, $param) = $middleware;
}
if (is_string($middleware)) {
$middleware = [$app->make($middleware), 'handle'];
}
return call_user_func($middleware, $request, $next, $param ?? null);
};
}, $middleware))
->then(function ($request) {
return $request;
});
}
/**
* Prepare settings if websocket is enabled.
*/
protected function prepareWebsocket()
{
if (!$this->isWebsocketServer = $this->getConfig('websocket.enable', false)) {
return;
}
$this->events = array_merge($this->events ?? [], $this->wsEvents);
$this->prepareWebsocketRoom();
$this->onEvent('workerStart', function () {
$this->bindWebsocketRoom();
$this->bindWebsocketParser();
$this->bindWebsocketHandler();
$this->prepareWebsocketListener();
});
}
/**
* Check if it's a websocket fd.
*
* @param int $fd
*
* @return bool
*/
protected function isWebsocketServer(int $fd): bool
{
return $this->getServer()->getClientInfo($fd)['websocket_status'] ?? false;
}
/**
* Prepare websocket room.
*/
protected function prepareWebsocketRoom()
{
// create room instance and initialize
$this->websocketRoom = $this->container->make(Room::class);
$this->websocketRoom->prepare();
}
protected function prepareWebsocketListener()
{
$listeners = $this->getConfig('websocket.listen', []);
foreach ($listeners as $event => $listener) {
$this->app->event->listen('swoole.websocket.' . Str::studly($event), $listener);
}
$subscribers = $this->getConfig('websocket.subscribe', []);
foreach ($subscribers as $subscriber) {
$this->app->event->observe($subscriber, 'swoole.websocket.');
}
//消息推送任务
$this->app->event->listen('swoole.task', function (Task $task, App $app) {
if ($this->isWebsocketPushPayload($task->data)) {
$pusher = $app->make(Pusher::class, $task->data['data']);
$pusher->push();
}
});
}
/**
* Prepare websocket handler for onOpen and onClose callback.
*
* @throws \Exception
*/
protected function bindWebsocketHandler()
{
$handlerClass = $this->getConfig('websocket.handler', Handler::class);
$this->app->bind(HandlerInterface::class, $handlerClass);
$this->app->make(HandlerInterface::class);
}
protected function bindWebsocketParser()
{
$parserClass = $this->getConfig('websocket.parser', SocketioParser::class);
$this->app->bind(ParserInterface::class, $parserClass);
$this->app->make(ParserInterface::class);
}
/**
* Bind room instance to app container.
*/
protected function bindWebsocketRoom(): void
{
$this->app->instance(Room::class, $this->websocketRoom);
}
/**
* Indicates if the payload is websocket push.
*
* @param mixed $payload
*
* @return boolean
*/
public function isWebsocketPushPayload($payload): bool
{
if (!is_array($payload)) {
return false;
}
return $this->isWebsocketServer
&& ($payload['action'] ?? null) === Websocket::PUSH_ACTION
&& array_key_exists('data', $payload);
}
}
@@ -0,0 +1,18 @@
<?php
namespace think\swoole\concerns;
use ReflectionObject;
trait ModifyProperty
{
protected function modifyProperty($object, $value, $property = 'app')
{
$reflectObject = new ReflectionObject($object);
if ($reflectObject->hasProperty($property)) {
$reflectProperty = $reflectObject->getProperty($property);
$reflectProperty->setAccessible(true);
$reflectProperty->setValue($object, $value);
}
}
}
@@ -0,0 +1,118 @@
<?php
namespace think\swoole\concerns;
use Closure;
use Swoole\Server;
use think\App;
use think\swoole\App as SwooleApp;
use think\swoole\pool\Cache;
use think\swoole\pool\Db;
use think\swoole\Sandbox;
use Throwable;
/**
* Trait WithApplication
* @package think\swoole\concerns
* @property App $container
*/
trait WithApplication
{
/**
* @var SwooleApp
*/
protected $app;
/**
* 获取配置
* @param string $name
* @param null $default
* @return mixed
*/
public function getConfig(string $name, $default = null)
{
return $this->container->config->get("swoole.{$name}", $default);
}
/**
* 触发事件
* @param $event
* @param $params
*/
protected function triggerEvent(string $event, $params = null): void
{
$this->container->event->trigger("swoole.{$event}", $params);
}
/**
* 监听事件
* @param string $event
* @param $listener
* @param bool $first
*/
public function onEvent(string $event, $listener, bool $first = false): void
{
$this->container->event->listen("swoole.{$event}", $listener, $first);
}
protected function prepareApplication()
{
if (!$this->app instanceof SwooleApp) {
$this->app = new SwooleApp($this->container->getRootPath());
$this->app->bind(SwooleApp::class, App::class);
$this->app->bind(Server::class, $this->getServer());
$this->app->bind("swoole.server", Server::class);
//绑定连接池
if ($this->getConfig('pool.db.enable', true)) {
$this->app->bind('db', Db::class);
}
if ($this->getConfig('pool.cache.enable', true)) {
$this->app->bind('cache', Cache::class);
}
$this->app->initialize();
$this->prepareConcretes();
}
}
/**
* 预加载
*/
protected function prepareConcretes()
{
$defaultConcretes = ['db', 'cache', 'event'];
$concretes = array_merge($defaultConcretes, $this->getConfig('concretes', []));
foreach ($concretes as $concrete) {
if ($this->app->has($concrete)) {
$this->app->make($concrete);
}
}
}
/**
* 获取沙箱
* @return Sandbox
*/
protected function getSandbox()
{
return $this->app->make(Sandbox::class);
}
/**
* 在沙箱中执行
* @param Closure $callable
* @param null $fd
* @param bool $persistent
*/
protected function runInSandbox(Closure $callable, $fd = null, $persistent = false)
{
try {
$this->getSandbox()->run($callable, $fd, $persistent);
} catch (Throwable $e) {
$this->logServerError($e);
}
}
}