仓库初始化

This commit is contained in:
2025-08-13 10:43:56 +08:00
commit e8f9b46680
5180 changed files with 859303 additions and 0 deletions

View File

@@ -0,0 +1,142 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine;
use Hyperf\Engine\Contract\ChannelInterface;
use Hyperf\Engine\Exception\RuntimeException;
if (PHP_VERSION_ID > 80000 && SWOOLE_VERSION_ID >= 50000) {
class Channel extends \Swoole\Coroutine\Channel implements ChannelInterface
{
protected bool $closed = false;
public function push(mixed $data, float $timeout = -1): bool
{
return parent::push($data, $timeout);
}
public function pop(float $timeout = -1): mixed
{
return parent::pop($timeout);
}
public function getCapacity(): int
{
return $this->capacity;
}
public function getLength(): int
{
return $this->length();
}
public function isAvailable(): bool
{
return ! $this->isClosing();
}
public function close(): bool
{
$this->closed = true;
return parent::close();
}
public function hasProducers(): bool
{
throw new RuntimeException('Not supported.');
}
public function hasConsumers(): bool
{
throw new RuntimeException('Not supported.');
}
public function isReadable(): bool
{
throw new RuntimeException('Not supported.');
}
public function isWritable(): bool
{
throw new RuntimeException('Not supported.');
}
public function isClosing(): bool
{
return $this->closed || $this->errCode === SWOOLE_CHANNEL_CLOSED;
}
public function isTimeout(): bool
{
return ! $this->closed && $this->errCode === SWOOLE_CHANNEL_TIMEOUT;
}
}
} else {
class Channel extends \Swoole\Coroutine\Channel implements ChannelInterface
{
/**
* @var bool
*/
protected $closed = false;
public function getCapacity(): int
{
return $this->capacity;
}
public function getLength(): int
{
return $this->length();
}
public function isAvailable(): bool
{
return ! $this->isClosing();
}
public function close(): bool
{
$this->closed = true;
return parent::close();
}
public function hasProducers(): bool
{
throw new RuntimeException('Not supported.');
}
public function hasConsumers(): bool
{
throw new RuntimeException('Not supported.');
}
public function isReadable(): bool
{
throw new RuntimeException('Not supported.');
}
public function isWritable(): bool
{
throw new RuntimeException('Not supported.');
}
public function isClosing(): bool
{
return $this->closed || $this->errCode === SWOOLE_CHANNEL_CLOSED;
}
public function isTimeout(): bool
{
return ! $this->closed && $this->errCode === SWOOLE_CHANNEL_TIMEOUT;
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine;
use Swoole\Coroutine\Http\Server as HttpServer;
use Swoole\Coroutine\Server;
class Constant
{
public const ENGINE = 'Swoole';
public static function isCoroutineServer($server): bool
{
return $server instanceof Server || $server instanceof HttpServer;
}
}

View File

@@ -0,0 +1,134 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Contract;
if (PHP_VERSION_ID > 80000 && SWOOLE_VERSION_ID >= 50000) {
interface ChannelInterface
{
/**
* @param float|int $timeout [optional] = -1
*/
public function push(mixed $data, float $timeout = -1): bool;
/**
* @param float $timeout seconds [optional] = -1
* @return mixed when pop failed, return false
*/
public function pop(float $timeout = -1): mixed;
/**
* Swow: When the channel is closed, all the data in it will be destroyed.
* Swoole: When the channel is closed, the data in it can still be popped out, but push behavior will no longer succeed.
*/
public function close(): bool;
public function getCapacity(): int;
public function getLength(): int;
public function isAvailable(): bool;
public function hasProducers(): bool;
public function hasConsumers(): bool;
public function isEmpty(): bool;
public function isFull(): bool;
public function isReadable(): bool;
public function isWritable(): bool;
public function isClosing(): bool;
public function isTimeout(): bool;
}
} else {
interface ChannelInterface
{
/**
* @param mixed $data [required]
* @param float|int $timeout [optional] = -1
* @return bool
*/
public function push($data, $timeout = -1);
/**
* @param float $timeout seconds [optional] = -1
* @return mixed when pop failed, return false
*/
public function pop($timeout = -1);
/**
* Swow: When the channel is closed, all the data in it will be destroyed.
* Swoole: When the channel is closed, the data in it can still be popped out, but push behavior will no longer succeed.
* @return mixed
*/
public function close(): bool;
/**
* @return int
*/
public function getCapacity();
/**
* @return int
*/
public function getLength();
/**
* @return bool
*/
public function isAvailable();
/**
* @return bool
*/
public function hasProducers();
/**
* @return bool
*/
public function hasConsumers();
/**
* @return bool
*/
public function isEmpty();
/**
* @return bool
*/
public function isFull();
/**
* @return bool
*/
public function isReadable();
/**
* @return bool
*/
public function isWritable();
/**
* @return bool
*/
public function isClosing();
/**
* @return bool
*/
public function isTimeout();
}
}

View File

@@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Contract;
use Hyperf\Engine\Exception\CoroutineDestroyedException;
use Hyperf\Engine\Exception\RunningInNonCoroutineException;
interface CoroutineInterface
{
/**
* @param callable $callable [required]
*/
public function __construct(callable $callable);
/**
* @param mixed ...$data
* @return $this
*/
public function execute(...$data);
/**
* @return int
*/
public function getId();
/**
* @param callable $callable [required]
* @param mixed ...$data
* @return $this
*/
public static function create(callable $callable, ...$data);
/**
* @return int returns coroutine id from current coroutine, -1 in non coroutine environment
*/
public static function id();
/**
* Returns the parent coroutine ID.
* Returns 0 when running in the top level coroutine.
* @throws RunningInNonCoroutineException when running in non-coroutine context
* @throws CoroutineDestroyedException when the coroutine has been destroyed
*/
public static function pid(?int $id = null);
/**
* Set config to coroutine.
*/
public static function set(array $config);
/**
* @param null|int $id coroutine id
* @return null|\ArrayObject
*/
public static function getContextFor(?int $id = null);
/**
* Execute callback when coroutine destruct.
*/
public static function defer(callable $callable);
}

View File

@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Contract\Http;
use Hyperf\Engine\Http\RawResponse;
interface ClientInterface
{
public function set(array $settings): bool;
/**
* @param string[][] $headers
*/
public function request(string $method = 'GET', string $path = '/', array $headers = [], string $contents = '', string $version = '1.1'): RawResponse;
}

View File

@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Contract\WebSocket;
interface WebSocketInterface
{
public const ON_MESSAGE = 'message';
public const ON_CLOSE = 'close';
public function on(string $event, callable $callback): void;
public function start(): void;
}

View File

@@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine;
use Hyperf\Engine\Contract\CoroutineInterface;
use Hyperf\Engine\Exception\CoroutineDestroyedException;
use Hyperf\Engine\Exception\RunningInNonCoroutineException;
use Hyperf\Engine\Exception\RuntimeException;
use Swoole\Coroutine as SwooleCo;
class Coroutine implements CoroutineInterface
{
/**
* @var callable
*/
private $callable;
/**
* @var int
*/
private $id;
public function __construct(callable $callable)
{
$this->callable = $callable;
}
public static function create(callable $callable, ...$data)
{
$coroutine = new static($callable);
$coroutine->execute(...$data);
return $coroutine;
}
public function execute(...$data)
{
$this->id = SwooleCo::create($this->callable, ...$data);
return $this;
}
public function getId()
{
if (is_null($this->id)) {
throw new RuntimeException('Coroutine was not be executed.');
}
return $this->id;
}
public static function id()
{
return SwooleCo::getCid();
}
public static function pid(?int $id = null)
{
if ($id) {
$cid = SwooleCo::getPcid($id);
if ($cid === false) {
throw new CoroutineDestroyedException(sprintf('Coroutine #%d has been destroyed.', $id));
}
} else {
$cid = SwooleCo::getPcid();
}
if ($cid === false) {
throw new RunningInNonCoroutineException('Non-Coroutine environment don\'t has parent coroutine id.');
}
return max(0, $cid);
}
public static function set(array $config)
{
SwooleCo::set($config);
}
/**
* @return null|\ArrayObject
*/
public static function getContextFor(?int $id = null)
{
if ($id === null) {
return SwooleCo::getContext();
}
return SwooleCo::getContext($id);
}
public static function defer(callable $callable)
{
SwooleCo::defer($callable);
}
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Exception;
class CoroutineDestroyedException extends RuntimeException
{
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Exception;
class HttpClientException extends RuntimeException
{
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Exception;
class RunningInNonCoroutineException extends RuntimeException
{
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Exception;
class RuntimeException extends \RuntimeException
{
}

View File

@@ -0,0 +1,20 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine;
class Extension
{
public static function isLoaded(): bool
{
return extension_loaded('Swoole');
}
}

View File

@@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Http;
use Hyperf\Engine\Contract\Http\ClientInterface;
use Hyperf\Engine\Exception\HttpClientException;
use Swoole\Coroutine\Http\Client as HttpClient;
class Client extends HttpClient implements ClientInterface
{
public function set(array $settings): bool
{
return parent::set($settings);
}
/**
* @param string[][] $headers
*/
public function request(string $method = 'GET', string $path = '/', array $headers = [], string $contents = '', string $version = '1.1'): RawResponse
{
$this->setMethod($method);
$this->setData($contents);
$this->setHeaders($this->encodeHeaders($headers));
$this->execute($path);
if ($this->errCode !== 0) {
throw new HttpClientException($this->errMsg, $this->errCode);
}
return new RawResponse(
$this->statusCode,
$this->decodeHeaders($this->headers ?? []),
$this->body,
$version
);
}
/**
* @param string[] $headers
* @return string[][]
*/
private function decodeHeaders(array $headers): array
{
$result = [];
foreach ($headers as $name => $header) {
// The key of header is lower case.
$result[$name][] = $header;
}
if ($this->set_cookie_headers) {
$result['set-cookie'] = $this->set_cookie_headers;
}
return $result;
}
/**
* Swoole engine not support two dimensional array.
* @param string[][] $headers
* @return string[]
*/
private function encodeHeaders(array $headers): array
{
$result = [];
foreach ($headers as $name => $value) {
$result[$name] = is_array($value) ? implode(',', $value) : $value;
}
return $result;
}
}

View File

@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Http;
use Swoole\Http\Response;
class FdGetter
{
public function get(Response $response): int
{
return $response->fd;
}
}

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\Http;
final class RawResponse
{
/**
* @var int
*/
public $statusCode = 0;
/**
* @var string[][]
*/
public $headers = [];
/**
* @var string
*/
public $body = '';
/**
* Protocol version.
* @var string
*/
public $version = '';
/**
* @param string[][] $headers
*/
public function __construct(int $statusCode, array $headers, string $body, string $version)
{
$this->statusCode = $statusCode;
$this->headers = $headers;
$this->body = $body;
$this->version = $version;
}
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine;
class Socket extends \Swoole\Coroutine\Socket
{
}

View File

@@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine;
class WaitGroup extends \Swoole\Coroutine\WaitGroup
{
}

View File

@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\WebSocket;
class Frame
{
public const PING = '27890027';
public const PONG = '278a0027';
}

View File

@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\WebSocket;
class Opcode
{
public const CONTINUATION = 0;
public const TEXT = 1;
public const BINARY = 2;
public const CLOSE = 8;
public const PING = 9;
public const PONG = 10;
}

View File

@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace Hyperf\Engine\WebSocket;
use Hyperf\Engine\Contract\WebSocket\WebSocketInterface;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\WebSocket\CloseFrame;
class WebSocket implements WebSocketInterface
{
/**
* @var Response
*/
protected $connection;
/**
* @var array<string, callable>
*/
protected $events = [];
public function __construct(Response $connection, Request $request)
{
$this->connection = $connection;
$this->connection->upgrade();
}
public function on(string $event, callable $callback): void
{
$this->events[$event] = $callback;
}
public function start(): void
{
while (true) {
$frame = $this->connection->recv();
if ($frame === false || $frame instanceof CloseFrame || $frame === '') {
$callback = $this->events[static::ON_CLOSE];
$callback($this->connection, $this->connection->fd);
break;
}
$callback = $this->events[static::ON_MESSAGE];
$callback($this->connection, $frame);
}
$this->connection = null;
$this->events = [];
}
}