.gitattributes000064400000000105151360553160007440 0ustar00/.github export-ignore /examples export-ignore /tests export-ignore .gitignore000064400000000044151360553160006537 0ustar00/vendor/ composer.lock *.cache *.log.php-cs-fixer.php000064400000004755151360553160007660 0ustar00setRiskyAllowed(true) ->setRules([ '@PSR2' => true, '@Symfony' => true, '@DoctrineAnnotation' => true, '@PhpCsFixer' => true, 'header_comment' => [ 'comment_type' => 'PHPDoc', 'header' => $header, 'separate' => 'none', 'location' => 'after_declare_strict', ], 'array_syntax' => [ 'syntax' => 'short' ], 'list_syntax' => [ 'syntax' => 'short' ], 'concat_space' => [ 'spacing' => 'one' ], 'blank_line_before_statement' => [ 'statements' => [ 'declare', ], ], 'general_phpdoc_annotation_remove' => [ 'annotations' => [ 'author' ], ], 'ordered_imports' => [ 'imports_order' => [ 'class', 'function', 'const', ], 'sort_algorithm' => 'alpha', ], 'single_line_comment_style' => [ 'comment_types' => [ ], ], 'yoda_style' => [ 'always_move_variable' => false, 'equal' => false, 'identical' => false, ], 'phpdoc_align' => [ 'align' => 'left', ], 'multiline_whitespace_before_semicolons' => [ 'strategy' => 'no_multi_line', ], 'constant_case' => [ 'case' => 'lower', ], 'class_attributes_separation' => true, 'combine_consecutive_unsets' => true, 'declare_strict_types' => true, 'linebreak_after_opening_tag' => true, 'lowercase_static_reference' => true, 'no_useless_else' => true, 'no_unused_imports' => true, 'not_operator_with_successor_space' => true, 'not_operator_with_space' => false, 'ordered_class_elements' => true, 'php_unit_strict' => false, 'phpdoc_separation' => false, 'single_quote' => true, 'standardize_not_equals' => true, 'multiline_comment_opening_closing' => true, ]) ->setFinder( PhpCsFixer\Finder::create() ->exclude('vendor') ->in(__DIR__) ) ->setUsingCache(false); .phpstorm.meta.php000064400000000164151360553160010142 0ustar00" version="1.0" license="MIT" app.name="Hyperf" ARG timezone ARG PHP_VERSION ENV TIMEZONE=${timezone:-"Asia/Shanghai"} ENV COMPOSER_ROOT_VERSION="v1.2.0" # update RUN set -ex \ # show php version and extensions && php -v \ && php -m \ && php --ri swoole \ # ---------- some config ---------- && cd "/etc/php${PHP_VERSION%\.*}" \ # - config PHP && { \ echo "upload_max_filesize=128M"; \ echo "post_max_size=128M"; \ echo "memory_limit=1G"; \ echo "date.timezone=${TIMEZONE}"; \ } | tee conf.d/99_overrides.ini \ # - config timezone && ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \ && echo "${TIMEZONE}" > /etc/timezone \ # ---------- clear works ---------- && rm -rf /var/cache/apk/* /tmp/* /usr/share/man \ && echo -e "\033[42;37m Build Completed :).\033[0m\n" WORKDIR /opt/www COPY . /opt/www RUN composer install -o README.md000064400000000234151360553160006027 0ustar00# Swoole Engine ![Swoole Engine Test](https://github.com/hyperf/engine/workflows/Swoole%20Engine%20Test/badge.svg) ``` composer require hyperf/engine ``` composer.json000064400000002112151360553160007267 0ustar00{ "name": "hyperf/engine", "type": "library", "license": "MIT", "keywords": [ "php", "hyperf" ], "description": "", "autoload": { "psr-4": { "Hyperf\\Engine\\": "src/" } }, "autoload-dev": { "psr-4": { "HyperfTest\\": "tests" } }, "require": { "php": ">=7.4" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.0", "hyperf/guzzle": "^2.2", "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.4", "swoole/ide-helper": "dev-master" }, "suggest": { "ext-swoole": ">=4.5" }, "minimum-stability": "dev", "prefer-stable": true, "config": { "optimize-autoloader": true, "sort-packages": true }, "extra": { "branch-alias": { "dev-master": "1.2-dev" } }, "scripts": { "test": "phpunit -c phpunit.xml --colors=always", "analyse": "phpstan analyse --memory-limit 1024M -l 0 ./src", "cs-fix": "php-cs-fixer fix $1" } } phpunit.xml000064400000000755151360553160006771 0ustar00 ./tests/ src/Channel.php000064400000006522151360553160007426 0ustar00 80000 && SWOOLE_VERSION_ID >= 40900) { 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; } } } src/Constant.php000064400000001041151360553160007636 0ustar00 80000 && SWOOLE_VERSION_ID >= 40900) { 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(); } } src/Contract/CoroutineInterface.php000064400000003274151360553160013424 0ustar00callable = $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); } } src/Exception/CoroutineDestroyedException.php000064400000000521151360553160015516 0ustar00setMethod($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; } } src/Http/FdGetter.php000064400000000626151360553160010500 0ustar00fd; } } src/Http/RawResponse.php000064400000001544151360553160011244 0ustar00statusCode = $statusCode; $this->headers = $headers; $this->body = $body; $this->version = $version; } } src/WebSocket/Frame.php000064400000000553151360553160010774 0ustar00 */ 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 = []; } }