├── LICENSE ├── README.md ├── composer.json └── src ├── swoole ├── Swoole │ ├── Async │ │ └── Client.php │ ├── Atomic.php │ ├── Atomic │ │ └── Long.php │ ├── Client.php │ ├── Client │ │ └── Exception.php │ ├── Connection │ │ └── Iterator.php │ ├── Coroutine.php │ ├── Coroutine │ │ ├── Channel.php │ │ ├── Client.php │ │ ├── Context.php │ │ ├── Curl │ │ │ └── Exception.php │ │ ├── Http │ │ │ ├── Client.php │ │ │ ├── Client │ │ │ │ └── Exception.php │ │ │ └── Server.php │ │ ├── Http2 │ │ │ ├── Client.php │ │ │ └── Client │ │ │ │ └── Exception.php │ │ ├── Iterator.php │ │ ├── Lock.php │ │ ├── Scheduler.php │ │ ├── Socket.php │ │ ├── Socket │ │ │ └── Exception.php │ │ └── System.php │ ├── Error.php │ ├── Event.php │ ├── Exception.php │ ├── ExitException.php │ ├── Http │ │ ├── Cookie.php │ │ ├── Request.php │ │ ├── Response.php │ │ └── Server.php │ ├── Http2 │ │ ├── Request.php │ │ └── Response.php │ ├── Lock.php │ ├── NameResolver │ │ └── Context.php │ ├── Process.php │ ├── Process │ │ └── Pool.php │ ├── Redis │ │ └── Server.php │ ├── Runtime.php │ ├── Server.php │ ├── Server │ │ ├── Event.php │ │ ├── Packet.php │ │ ├── PipeMessage.php │ │ ├── Port.php │ │ ├── StatusInfo.php │ │ ├── Task.php │ │ └── TaskResult.php │ ├── Table.php │ ├── Thread.php │ ├── Thread │ │ ├── ArrayList.php │ │ ├── Atomic.php │ │ ├── Atomic │ │ │ └── Long.php │ │ ├── Barrier.php │ │ ├── Error.php │ │ ├── Lock.php │ │ ├── Map.php │ │ └── Queue.php │ ├── Timer.php │ ├── Timer │ │ └── Iterator.php │ └── WebSocket │ │ ├── CloseFrame.php │ │ ├── Frame.php │ │ └── Server.php ├── constants.php ├── functions.php └── shortnames.php └── swoole_library └── src ├── __init__.php ├── alias.php ├── alias_ns.php ├── core ├── ArrayObject.php ├── ConnectionPool.php ├── Constant.php ├── Coroutine │ ├── Barrier.php │ ├── FastCGI │ │ ├── Client.php │ │ ├── Client │ │ │ └── Exception.php │ │ └── Proxy.php │ ├── Http │ │ ├── ClientProxy.php │ │ └── functions.php │ ├── Server.php │ ├── Server │ │ └── Connection.php │ ├── WaitGroup.php │ └── functions.php ├── Curl │ ├── Exception.php │ └── Handler.php ├── Database │ ├── DetectsLostConnections.php │ ├── MysqliConfig.php │ ├── MysqliException.php │ ├── MysqliPool.php │ ├── MysqliProxy.php │ ├── MysqliStatementProxy.php │ ├── ObjectProxy.php │ ├── PDOConfig.php │ ├── PDOPool.php │ ├── PDOProxy.php │ ├── PDOStatementProxy.php │ ├── RedisConfig.php │ └── RedisPool.php ├── Exception │ └── ArrayKeyNotExists.php ├── FastCGI.php ├── FastCGI │ ├── FrameParser.php │ ├── HttpRequest.php │ ├── HttpResponse.php │ ├── Message.php │ ├── Record.php │ ├── Record │ │ ├── AbortRequest.php │ │ ├── BeginRequest.php │ │ ├── Data.php │ │ ├── EndRequest.php │ │ ├── GetValues.php │ │ ├── GetValuesResult.php │ │ ├── Params.php │ │ ├── Stderr.php │ │ ├── Stdin.php │ │ ├── Stdout.php │ │ └── UnknownType.php │ ├── Request.php │ └── Response.php ├── Http │ └── Status.php ├── MultibyteStringObject.php ├── NameResolver.php ├── NameResolver │ ├── Cluster.php │ ├── Consul.php │ ├── Exception.php │ ├── Nacos.php │ └── Redis.php ├── ObjectProxy.php ├── Process │ └── Manager.php ├── Server │ ├── Admin.php │ └── Helper.php ├── StringObject.php └── Thread │ ├── Pool.php │ └── Runnable.php └── functions.php /README.md: -------------------------------------------------------------------------------- 1 | # Swoole IDE Helper 2 | 3 | [![Twitter](https://badgen.net/badge/icon/twitter?icon=twitter&label)](https://twitter.com/phpswoole) 4 | [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.swoole.dev) 5 | [![Latest Stable Version](https://poser.pugx.org/swoole/ide-helper/v/stable.svg)](https://packagist.org/packages/swoole/ide-helper) 6 | [![License](https://poser.pugx.org/swoole/ide-helper/license)](LICENSE) 7 | 8 | This package contains IDE help files for [Swoole](https://github.com/swoole/swoole-src). You may use it in your IDE to provide accurate autocompletion. 9 | 10 | ## Install 11 | 12 | You can add this package to your project using [Composer](https://getcomposer.org): 13 | 14 | ```bash 15 | composer require swoole/ide-helper:~5.0.0 16 | # or 17 | composer require --dev swoole/ide-helper:~5.0.0 18 | ``` 19 | 20 | To use the latest stubs from the `master` branch: 21 | 22 | ```bash 23 | composer require swoole/ide-helper:@dev 24 | # or 25 | composer require --dev swoole/ide-helper:@dev 26 | ``` 27 | 28 | ## PHP Configuration Settings 29 | 30 | * `swoole.display_errors`: Boolean. Default `On`. Display/hide error information from Swoole. 31 | * `swoole.enable_coroutine`: Boolean. Default `On`. Turn on/off coroutine support. 32 | * `swoole.enable_library`: Boolean. Default `On`. Load the source code from [Swoole Library](https://github.com/swoole/library) or not. 33 | * `swoole.enable_preemptive_scheduler`: Boolean. Default `Off`. Enable preemptive scheduler or not. To understand how it works, please check examples under section "CPU-intensive job scheduling" of repository [deminy/swoole-by-examples](https://github.com/deminy/swoole-by-examples). 34 | * `swoole.unixsock_buffer_size`: Integer (in bytes). By default, it's 256 KiB on Macintosh or FreeBSD, otherwise 8 MiB. The total buffer sizes for the socket connections between the master process and the worker processes in Swoole. 35 | * `swoole.use_shortname`: Boolean. Default `On`. Support short names or not. Short names are all the aliases listed in file [src/swoole/shortnames.php](src/swoole/shortnames.php). 36 | 37 | All the directives can be set anywhere except `swoole.use_shortname`, which can only be set in `php.ini` files. 38 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "swoole/ide-helper", 3 | "type": "library", 4 | "description": "IDE help files for Swoole.", 5 | "license": "Apache-2.0", 6 | "authors": [ 7 | { 8 | "name": "Team Swoole", 9 | "email": "team@swoole.com" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/swoole/Swoole/Async/Client.php: -------------------------------------------------------------------------------- 1 | cmpset(11, 20); // This will not change the value of the counter. 76 | * - $atomic->cmpset(10, 20); // This will set the value to 20. 77 | * 78 | * @param int $cmp_value The value to be compared with the current value of the counter. 79 | * @param int $new_value The new value of the counter. 80 | * @return bool True if the value of the counter was changed, false otherwise. 81 | */ 82 | public function cmpset(int $cmp_value, int $new_value): bool 83 | { 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/swoole/Swoole/Client/Exception.php: -------------------------------------------------------------------------------- 1 | 10 | * @implements \ArrayAccess 11 | */ 12 | class Iterator implements \Iterator, \ArrayAccess, \Countable 13 | { 14 | /** 15 | * Creating an object of this class directly is not allowed. It will always throw an error. 16 | * 17 | * @throws \Error 18 | */ 19 | public function __construct() 20 | { 21 | } 22 | 23 | /** 24 | * @see \Iterator::rewind() 25 | * @see https://www.php.net/manual/en/iterator.rewind.php 26 | * {@inheritDoc} 27 | */ 28 | public function rewind(): void 29 | { 30 | } 31 | 32 | /** 33 | * @see \Iterator::next() 34 | * @see https://www.php.net/manual/en/iterator.next.php 35 | * {@inheritDoc} 36 | */ 37 | public function next(): void 38 | { 39 | } 40 | 41 | public function current(): mixed 42 | { 43 | } 44 | 45 | public function key(): mixed 46 | { 47 | } 48 | 49 | /** 50 | * @see \Iterator::valid() 51 | * @see https://www.php.net/manual/en/iterator.valid.php 52 | * {@inheritDoc} 53 | */ 54 | public function valid(): bool 55 | { 56 | } 57 | 58 | public function count(): int 59 | { 60 | } 61 | 62 | public function offsetExists($fd): bool 63 | { 64 | } 65 | 66 | /** 67 | * @param mixed $fd 68 | * @return mixed 69 | */ 70 | public function offsetGet($fd) 71 | { 72 | } 73 | 74 | /** 75 | * This method doesn't do anything. DON'T use it. 76 | * 77 | * @see \ArrayAccess::offsetSet() 78 | * @see https://www.php.net/manual/en/arrayaccess.offsetset.php 79 | * {@inheritDoc} 80 | */ 81 | public function offsetSet($fd, $value): void 82 | { 83 | } 84 | 85 | /** 86 | * This method doesn't do anything. DON'T use it. 87 | * 88 | * @see \ArrayAccess::offsetUnset() 89 | * @see https://www.php.net/manual/en/arrayaccess.offsetunset.php 90 | * {@inheritDoc} 91 | */ 92 | public function offsetUnset($fd): void 93 | { 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/swoole/Swoole/Coroutine/Channel.php: -------------------------------------------------------------------------------- 1 | errCode is set 26 | * to one of the following values: SWOOLE_CHANNEL_TIMEOUT, SWOOLE_CHANNEL_CLOSED, or SWOOLE_CHANNEL_CANCELED. 27 | * 28 | * @see SWOOLE_CHANNEL_OK 29 | * @see SWOOLE_CHANNEL_TIMEOUT 30 | * @see SWOOLE_CHANNEL_CLOSED 31 | * @see SWOOLE_CHANNEL_CANCELED 32 | */ 33 | public int $errCode = SWOOLE_CHANNEL_OK; 34 | 35 | /** 36 | * @param int $size Size of the channel. This indicates the maximum number of elements that can be stored in the channel. It has to be greater than 0. 37 | * @pseudocode-included This is a built-in method in Swoole. The PHP code included inside this method is for explanation purpose only. 38 | */ 39 | public function __construct(int $size = 1) 40 | { 41 | // Here are some statements to create the channel using local memory within the process. 42 | 43 | $this->capacity = max(1, $size); 44 | } 45 | 46 | /** 47 | * Push an element into the channel. 48 | * 49 | * @param TData $data The element to be pushed into the channel. It's allowed to be any type of value. However, to avoid any confusion, it's recommended not to use empty values like 0, 0.0, false, ' ', null, etc. 50 | * @param float $timeout > 0 means waiting for the specified number of seconds. other means no waiting. 51 | * @return bool TRUE on success. If failed, return FALSE and set the error code ($this->errCode) with a non-zero value. 52 | */ 53 | public function push(mixed $data, float $timeout = -1): bool 54 | { 55 | } 56 | 57 | /** 58 | * Pop an element from the channel. 59 | * 60 | * This pop operation works in a FIFO (first-in-first-out) manner, since elements in the channel are stored in a queue but not a stack. 61 | * 62 | * @param float $timeout > 0 means waiting for the specified number of seconds. other means no waiting. 63 | * @return TData|false Remove an element from the front end of the channel, and return the element back. If failed, return FALSE and set the error code ($this->errCode) with a non-zero value. 64 | */ 65 | public function pop(float $timeout = -1): mixed 66 | { 67 | } 68 | 69 | /** 70 | * @return bool Returns true if the channel is empty, false otherwise. 71 | */ 72 | public function isEmpty(): bool 73 | { 74 | } 75 | 76 | /** 77 | * @return bool Returns true if the channel is full, false otherwise. 78 | */ 79 | public function isFull(): bool 80 | { 81 | } 82 | 83 | /** 84 | * Close the channel. 85 | * 86 | * After the channel is closed, 87 | * 1. no more elements can be pushed into it, nor can elements be popped out of it. 88 | * 2. coroutines that are waiting for elements to be pushed into the channel will be woken up; inside the coroutines, calls to method push() return FALSE. 89 | * 3. coroutines that are waiting for elements to be popped out of the channel will be woken up; inside the coroutines, calls to method pop() return FALSE. 90 | * 91 | * @return bool Returns true on success or false on failure. 92 | */ 93 | public function close(): bool 94 | { 95 | } 96 | 97 | /** 98 | * Returns stats of the channel. 99 | * 100 | * The array returned contains three fields: 101 | * 1. consumer_num: Number of calls to method `pop()` that are waiting for elements to be pushed into the channel. This happens when the channel is empty. 102 | * 2. producer_num: Number of calls to method `push()` that are waiting for elements to be popped from the channel. This happens when the channel is full. 103 | * 3. queue_num: Number of elements in the channel. This is the same as the return value of statement `self::length()`. 104 | * 105 | * For example: 106 | * [ 107 | * 'consumer_num' => 0, // No calls to method `pop()` in waiting at the moment. 108 | * 'producer_num' => 1, // The channel is full, and there is one method call to method `push()` that is waiting for elements to be popped from the channel. 109 | * 'queue_num' => 2, // There are two elements in the channel. In this case, the size of the channel is also two. 110 | * ] 111 | */ 112 | public function stats(): array 113 | { 114 | } 115 | 116 | /** 117 | * @return int Number of elements in the channel. 118 | */ 119 | public function length(): int 120 | { 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/swoole/Swoole/Coroutine/Client.php: -------------------------------------------------------------------------------- 1 | 15 | * foreach (\Swoole\Coroutine::list() as $cid) { 16 | * var_dump(\Swoole\Coroutine::getBackTrace($cid)); 17 | * }; 18 | *
19 |  *
20 |  * @see \Swoole\Coroutine::list()
21 |  * @see \Swoole\Coroutine::listCoroutines()
22 |  *
23 |  * @alias It's safe to assume that this class is an alias of PHP class \ArrayIterator.
24 |  * @see https://www.php.net/ArrayIterator
25 |  *
26 |  * @alias This class has an alias of "\Co\Iterator" when directive "swoole.use_shortname" is not explicitly turned off.
27 |  * @see \Co\Iterator
28 |  */
29 | class Iterator extends \ArrayIterator
30 | {
31 | }
32 | 


--------------------------------------------------------------------------------
/src/swoole/Swoole/Coroutine/Lock.php:
--------------------------------------------------------------------------------
 1 | add($func, ...$params);
37 |         }
38 |     }
39 | 
40 |     /**
41 |      * To set runtime configurations of coroutines.
42 |      *
43 |      * @alias This method is an alias of method \Swoole\Coroutine::set().
44 |      * @see \Swoole\Coroutine::set()
45 |      */
46 |     public function set(array $settings): void
47 |     {
48 |     }
49 | 
50 |     /**
51 |      * To get runtime configurations of coroutines.
52 |      *
53 |      * @alias This method is an alias of method \Swoole\Coroutine::getOptions().
54 |      * @see \Swoole\Coroutine::getOptions()
55 |      * @since Swoole 4.6.0
56 |      */
57 |     public function getOptions(): ?array
58 |     {
59 |     }
60 | 
61 |     /**
62 |      * Start running the list of tasks (callbacks) added through method self::add() and/or self::parallel().
63 |      *
64 |      * For each task, Swoole creates a new coroutine to run its callback function. The scheduler will wait for all the
65 |      * coroutines to finish.
66 |      *
67 |      * @return bool Returns TRUE if all the coroutines have finished successfully; otherwise returns FALSE.
68 |      * @see \Swoole\Coroutine\Scheduler::add()
69 |      * @see \Swoole\Coroutine\Scheduler::parallel()
70 |      */
71 |     public function start(): bool
72 |     {
73 |     }
74 | }
75 | 


--------------------------------------------------------------------------------
/src/swoole/Swoole/Coroutine/Socket/Exception.php:
--------------------------------------------------------------------------------
 1 | flags;
40 |     }
41 | 
42 |     /**
43 |      * Get the exit status.
44 |      *
45 |      * @pseudocode-included This is a built-in method in Swoole. The PHP code included inside this method is for explanation purpose only.
46 |      */
47 |     public function getStatus(): mixed
48 |     {
49 |         return $this->status;
50 |     }
51 | }
52 | 


--------------------------------------------------------------------------------
/src/swoole/Swoole/Http/Cookie.php:
--------------------------------------------------------------------------------
 1 |  false]);
 28 |      * $request->parse($data);
 29 |      * var_dump($request->cookie); // NULL
 30 |      * ```
 31 |      */
 32 |     public ?array $cookie;
 33 | 
 34 |     public $get;
 35 | 
 36 |     public $files;
 37 | 
 38 |     public $post;
 39 | 
 40 |     public $tmpfiles;
 41 | 
 42 |     /**
 43 |      * Get the request content, kind of like function call fopen('php://input').
 44 |      *
 45 |      * @return string|false Return the request content back; return FALSE when error happens.
 46 |      * @alias This method has an alias of \Swoole\Http\Request::rawContent().
 47 |      * @see \Swoole\Http\Request::rawContent()
 48 |      * @since 4.5.0
 49 |      */
 50 |     public function getContent(): string|false
 51 |     {
 52 |     }
 53 | 
 54 |     /**
 55 |      * Get the request content, kind of like function call fopen('php://input').
 56 |      *
 57 |      * @return string|false Return the request content back; return FALSE when error happens.
 58 |      * @alias Alias of method \Swoole\Http\Request::getContent().
 59 |      * @see \Swoole\Http\Request::getContent()
 60 |      */
 61 |     public function rawContent(): string|false
 62 |     {
 63 |     }
 64 | 
 65 |     public function getData(): string|false
 66 |     {
 67 |     }
 68 | 
 69 |     /**
 70 |      * Create an HTTP request object.
 71 |      *
 72 |      * @param array $options The options for the Request object. Only the following options are supported:
 73 |      *                       - 'parse_cookie' (boolean; default is TRUE): To parse the cookies or not.
 74 |      *                       - 'parse_body' (boolean; default is TRUE): To parse the HTTP body or not.
 75 |      *                       - 'parse_files' (boolean; default is TRUE): To parse the uploaded files or not.
 76 |      *                       - 'upload_tmp_dir' (string; default is "/tmp"): The temporary directory to store the uploaded files.
 77 |      *                       - 'enable_compression' (boolean; default is TRUE if Swoole is installed with zlib/Brotli/zstd, otherwise FALSE): To enable HTTP compression or not.
 78 |      *                       - 'compression_level' (integer): Compression level. 1-9 are supported. The higher the level, the better the compression, but the more CPU it will consume. The default is 1.
 79 |      *                       - 'websocket_compression' (boolean; default is TRUE if zlib extension is enabled, otherwise FALSE): To enable WebSocket compression or not. This is for WebSocket requests only.
 80 |      * @since 4.6.0
 81 |      */
 82 |     public static function create(array $options = []): Request
 83 |     {
 84 |     }
 85 | 
 86 |     /**
 87 |      * Parse the raw HTTP request data.
 88 |      *
 89 |      * @return int|false Return the parsed length of the data; return FALSE when error happens.
 90 |      * @since 4.6.0
 91 |      */
 92 |     public function parse(string $data): int|false
 93 |     {
 94 |     }
 95 | 
 96 |     /**
 97 |      * @since 4.6.0
 98 |      */
 99 |     public function isCompleted(): bool
100 |     {
101 |     }
102 | 
103 |     public function getMethod(): string|false
104 |     {
105 |     }
106 | }
107 | 


--------------------------------------------------------------------------------
/src/swoole/Swoole/Http/Server.php:
--------------------------------------------------------------------------------
 1 | source_worker_id. Both properties are retained for backward compatibility.
20 |      *
21 |      * @since 6.0.0 This property was accessible as a dynamic property in versions prior to Swoole 6.0.0, but it has been explicitly declared as of Swoole 6.0.0.
22 |      * @see PipeMessage::$source_worker_id
23 |      */
24 |     public int $worker_id = 0;
25 | 
26 |     /**
27 |      * The time when the message was dispatched.
28 |      *
29 |      * The value is in the same format as the return value of PHP function `microtime(true)`. i.e., the value is a float
30 |      * representing the time in seconds since the Unix epoch accurate to the nearest microsecond.
31 |      */
32 |     public float $dispatch_time = 0;
33 | 
34 |     public $data;
35 | }
36 | 


--------------------------------------------------------------------------------
/src/swoole/Swoole/Server/Port.php:
--------------------------------------------------------------------------------
  1 | 
14 |  * $server->on('WorkerError', function (Swoole\Server $serv, Swoole\Server\StatusInfo $info) {
15 |  *   var_dump($info);
16 |  * });
17 |  * 
18 |  */
19 | class StatusInfo
20 | {
21 |     /**
22 |      * @var int ID of the worker.
23 |      */
24 |     public int $worker_id = 0;
25 | 
26 |     /**
27 |      * @var int Process ID of the worker.
28 |      */
29 |     public int $worker_pid = 0;
30 | 
31 |     /**
32 |      * @var int The status field that was filled in by the waitpid function after the worker process was created.
33 |      */
34 |     public int $status = 0;
35 | 
36 |     /**
37 |      * @var int Exit status of the worker process.
38 |      */
39 |     public int $exit_code = 0;
40 | 
41 |     /**
42 |      * @var int The signal that caused the worker process to exit.
43 |      */
44 |     public int $signal = 0;
45 | }
46 | 


--------------------------------------------------------------------------------
/src/swoole/Swoole/Server/Task.php:
--------------------------------------------------------------------------------
 1 | toArray();
 97 |         sort($array);
 98 |         $this->__construct($array);
 99 |     }
100 | }
101 | 


--------------------------------------------------------------------------------
/src/swoole/Swoole/Thread/Atomic.php:
--------------------------------------------------------------------------------
 1 | toArray();
111 |         asort($array);
112 |         $this->__construct($array);
113 |     }
114 | }
115 | 


--------------------------------------------------------------------------------
/src/swoole/Swoole/Thread/Queue.php:
--------------------------------------------------------------------------------
 1 | 
54 |  * go(function () {      // The surrounding function of a coroutine.
55 |  *   echo '1';
56 |  *   defer(function () { // The callback function to be deferred.
57 |  *     echo '3';
58 |  *   });
59 |  *   echo '2';
60 |  * });
61 |  * 
62 |  */
63 | function defer(callable $callback): void
64 | {
65 | }
66 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/__init__.php:
--------------------------------------------------------------------------------
  1 |  'swoole',
 13 |     'checkFileChange' => !getenv('SWOOLE_LIBRARY_DEV'),
 14 |     'output'          => getenv('SWOOLE_DIR') . '/ext-src/php_swoole_library.h',
 15 |     'stripComments'   => false,
 16 |     /* Notice: Sort by dependency */
 17 |     'files' => [
 18 |         #  #
 19 |         'constants.php',
 20 |         #  #
 21 |         'std/exec.php',
 22 |         #  #
 23 |         'core/Constant.php',
 24 |         'core/StringObject.php',
 25 |         'core/MultibyteStringObject.php',
 26 |         'core/Exception/ArrayKeyNotExists.php',
 27 |         'core/ArrayObject.php',
 28 |         'core/ObjectProxy.php',
 29 |         'core/Coroutine/WaitGroup.php',
 30 |         'core/Coroutine/Server.php',
 31 |         'core/Coroutine/Server/Connection.php',
 32 |         'core/Coroutine/Barrier.php',
 33 |         'core/Coroutine/Http/ClientProxy.php',
 34 |         'core/Coroutine/Http/functions.php',
 35 |         #  #
 36 |         'core/ConnectionPool.php',
 37 |         'core/Database/ObjectProxy.php',
 38 |         'core/Database/MysqliConfig.php',
 39 |         'core/Database/MysqliException.php',
 40 |         'core/Database/MysqliPool.php',
 41 |         'core/Database/MysqliProxy.php',
 42 |         'core/Database/MysqliStatementProxy.php',
 43 |         'core/Database/DetectsLostConnections.php',
 44 |         'core/Database/PDOConfig.php',
 45 |         'core/Database/PDOPool.php',
 46 |         'core/Database/PDOProxy.php',
 47 |         'core/Database/PDOStatementProxy.php',
 48 |         'core/Database/RedisConfig.php',
 49 |         'core/Database/RedisPool.php',
 50 |         #  #
 51 |         'core/Http/Status.php',
 52 |         #  #
 53 |         'core/Curl/Exception.php',
 54 |         'core/Curl/Handler.php',
 55 |         #  #
 56 |         'core/FastCGI.php',
 57 |         'core/FastCGI/Record.php',
 58 |         'core/FastCGI/Record/Params.php',
 59 |         'core/FastCGI/Record/AbortRequest.php',
 60 |         'core/FastCGI/Record/BeginRequest.php',
 61 |         'core/FastCGI/Record/Data.php',
 62 |         'core/FastCGI/Record/EndRequest.php',
 63 |         'core/FastCGI/Record/GetValues.php',
 64 |         'core/FastCGI/Record/GetValuesResult.php',
 65 |         'core/FastCGI/Record/Stdin.php',
 66 |         'core/FastCGI/Record/Stdout.php',
 67 |         'core/FastCGI/Record/Stderr.php',
 68 |         'core/FastCGI/Record/UnknownType.php',
 69 |         'core/FastCGI/FrameParser.php',
 70 |         'core/FastCGI/Message.php',
 71 |         'core/FastCGI/Request.php',
 72 |         'core/FastCGI/Response.php',
 73 |         'core/FastCGI/HttpRequest.php',
 74 |         'core/FastCGI/HttpResponse.php',
 75 |         'core/Coroutine/FastCGI/Client.php',
 76 |         'core/Coroutine/FastCGI/Client/Exception.php',
 77 |         'core/Coroutine/FastCGI/Proxy.php',
 78 |         #  #
 79 |         'core/Process/Manager.php',
 80 |         #  #
 81 |         'core/Server/Admin.php',
 82 |         'core/Server/Helper.php',
 83 |         #  #
 84 |         'core/NameResolver.php',
 85 |         'core/NameResolver/Exception.php',
 86 |         'core/NameResolver/Cluster.php',
 87 |         'core/NameResolver/Redis.php',
 88 |         'core/NameResolver/Nacos.php',
 89 |         'core/NameResolver/Consul.php',
 90 |         #  #
 91 |         'core/Thread/Pool.php',
 92 |         'core/Thread/Runnable.php',
 93 |         #  #
 94 |         'core/Coroutine/functions.php',
 95 |         #  #
 96 |         'ext/curl.php',
 97 |         'ext/sockets.php',
 98 |         #  #
 99 |         'functions.php',
100 |         'alias.php',
101 |         'alias_ns.php',
102 |     ],
103 | ];
104 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/alias.php:
--------------------------------------------------------------------------------
 1 | pool        = new Channel($this->size = $size);
32 |         $this->constructor = $constructor;
33 |     }
34 | 
35 |     public function fill(): void
36 |     {
37 |         while ($this->size > $this->num) {
38 |             $this->make();
39 |         }
40 |     }
41 | 
42 |     /**
43 |      * Get a connection from the pool.
44 |      *
45 |      * @param float $timeout > 0 means waiting for the specified number of seconds. other means no waiting.
46 |      * @return mixed|false Returns a connection object from the pool, or false if the pool is full and the timeout is reached.
47 |      */
48 |     public function get(float $timeout = -1)
49 |     {
50 |         if ($this->pool === null) {
51 |             throw new \RuntimeException('Pool has been closed');
52 |         }
53 |         if ($this->pool->isEmpty() && $this->num < $this->size) {
54 |             $this->make();
55 |         }
56 |         return $this->pool->pop($timeout);
57 |     }
58 | 
59 |     public function put($connection): void
60 |     {
61 |         if ($this->pool === null) {
62 |             return;
63 |         }
64 |         if ($connection !== null) {
65 |             $this->pool->push($connection);
66 |         } else {
67 |             /* connection broken */
68 |             $this->num -= 1;
69 |             $this->make();
70 |         }
71 |     }
72 | 
73 |     public function close(): void
74 |     {
75 |         $this->pool->close();
76 |         $this->pool = null;
77 |         $this->num  = 0;
78 |     }
79 | 
80 |     protected function make(): void
81 |     {
82 |         $this->num++;
83 |         try {
84 |             if ($this->proxy) {
85 |                 $connection = new $this->proxy($this->constructor);
86 |             } else {
87 |                 $constructor = $this->constructor;
88 |                 $connection  = $constructor();
89 |             }
90 |         } catch (\Throwable $throwable) {
91 |             $this->num--;
92 |             throw $throwable;
93 |         }
94 |         $this->put($connection);
95 |     }
96 | }
97 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Coroutine/Barrier.php:
--------------------------------------------------------------------------------
 1 | timer !== -1) {
29 |             Timer::clear($this->timer);
30 |             if (isset(self::$cancel_list[$this->cid])) {
31 |                 unset(self::$cancel_list[$this->cid]);
32 |                 return;
33 |             }
34 |         }
35 |         if ($this->cid !== -1 && $this->cid !== Coroutine::getCid()) {
36 |             Coroutine::resume($this->cid);
37 |         } else {
38 |             self::$cancel_list[$this->cid] = true;
39 |         }
40 |     }
41 | 
42 |     public static function make(): self
43 |     {
44 |         return new self();
45 |     }
46 | 
47 |     /**
48 |      * @param-out null $barrier
49 |      */
50 |     public static function wait(Barrier &$barrier, float $timeout = -1): void
51 |     {
52 |         if ($barrier->cid !== -1) {
53 |             throw new Exception('The barrier is waiting, cannot wait again.');
54 |         }
55 |         $cid          = Coroutine::getCid();
56 |         $barrier->cid = $cid;
57 |         if ($timeout > 0 && ($timeout_ms = (int) ($timeout * 1000)) > 0) {
58 |             $barrier->timer = Timer::after($timeout_ms, function () use ($cid) {
59 |                 self::$cancel_list[$cid] = true;
60 |                 Coroutine::resume($cid);
61 |             });
62 |         }
63 |         $barrier = null;
64 |         if (!isset(self::$cancel_list[$cid])) {
65 |             Coroutine::yield();
66 |         } else {
67 |             unset(self::$cancel_list[$cid]);
68 |         }
69 |     }
70 | }
71 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Coroutine/FastCGI/Client/Exception.php:
--------------------------------------------------------------------------------
 1 | headers = $headers ?? [];
23 |         $this->cookies = $cookies ?? [];
24 |     }
25 | 
26 |     public function getBody(): string
27 |     {
28 |         return $this->body;
29 |     }
30 | 
31 |     public function getStatusCode(): int
32 |     {
33 |         return $this->statusCode;
34 |     }
35 | 
36 |     public function getHeaders(): array
37 |     {
38 |         return $this->headers;
39 |     }
40 | 
41 |     public function getCookies(): array
42 |     {
43 |         return $this->cookies;
44 |     }
45 | }
46 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Coroutine/Server.php:
--------------------------------------------------------------------------------
  1 | contains('::')) {
 56 |             $this->type = AF_INET6;
 57 |         } elseif ($_host->startsWith('unix:/')) {
 58 |             $host       = $_host->substr(5)->__toString();
 59 |             $this->type = AF_UNIX;
 60 |         } else {
 61 |             $this->type = AF_INET;
 62 |         }
 63 |         $this->host = $host;
 64 | 
 65 |         $socket = new Socket($this->type, SOCK_STREAM, 0);
 66 |         if ($reuse_port and defined('SO_REUSEPORT')) {
 67 |             $socket->setOption(SOL_SOCKET, SO_REUSEPORT, true);
 68 |         }
 69 |         if (!$socket->bind($this->host, $port)) {
 70 |             throw new Exception("bind({$this->host}:{$port}) failed", $socket->errCode);
 71 |         }
 72 |         if (!$socket->listen()) {
 73 |             throw new Exception('listen() failed', $socket->errCode);
 74 |         }
 75 |         $this->port                = $socket->getsockname()['port'] ?? 0;
 76 |         $this->fd                  = $socket->fd;
 77 |         $this->socket              = $socket;
 78 |         $this->setting['open_ssl'] = $ssl;
 79 |     }
 80 | 
 81 |     public function set(array $setting): void
 82 |     {
 83 |         $this->setting = array_merge($this->setting, $setting);
 84 |     }
 85 | 
 86 |     public function handle(callable $fn): void
 87 |     {
 88 |         $this->fn = $fn;
 89 |     }
 90 | 
 91 |     public function shutdown(): bool
 92 |     {
 93 |         $this->running = false;
 94 |         return $this->socket->cancel();
 95 |     }
 96 | 
 97 |     public function start(): bool
 98 |     {
 99 |         $this->running = true;
100 |         if ($this->fn === null) {
101 |             $this->errCode = SOCKET_EINVAL;
102 |             return false;
103 |         }
104 |         $socket = $this->socket;
105 |         if (!$socket->setProtocol($this->setting)) {
106 |             $this->errCode = SOCKET_EINVAL;
107 |             return false;
108 |         }
109 | 
110 |         while ($this->running) { // @phpstan-ignore while.alwaysTrue
111 |             $conn = null;
112 |             /** @var Socket $conn */
113 |             $conn = $socket->accept();
114 |             if ($conn) { // @phpstan-ignore if.alwaysTrue
115 |                 $conn->setProtocol($this->setting);
116 |                 if (!empty($this->setting[Constant::OPTION_OPEN_SSL])) {
117 |                     $fn = static function ($fn, $connection) {
118 |                         /* @var $connection Connection */
119 |                         if (!$connection->exportSocket()->sslHandshake()) {
120 |                             return;
121 |                         }
122 |                         $fn($connection);
123 |                     };
124 |                     $arguments = [$this->fn, new Connection($conn)];
125 |                 } else {
126 |                     $fn        = $this->fn;
127 |                     $arguments = [new Connection($conn)];
128 |                 }
129 |                 if (Coroutine::create($fn, ...$arguments) < 0) {
130 |                     goto _wait;
131 |                 }
132 |             } else {
133 |                 if ($socket->errCode == SOCKET_EMFILE or $socket->errCode == SOCKET_ENFILE) {
134 |                     _wait:
135 |                     Coroutine::sleep(1);
136 |                     continue;
137 |                 }
138 |                 if ($socket->errCode == SOCKET_ETIMEDOUT) {
139 |                     continue;
140 |                 }
141 |                 if ($socket->errCode == SOCKET_ECANCELED) {
142 |                     break;
143 |                 }
144 |                 trigger_error("accept failed, Error: {$socket->errMsg}[{$socket->errCode}]", E_USER_WARNING);
145 |                 break;
146 |             }
147 |         }
148 | 
149 |         return true; // @phpstan-ignore deadCode.unreachable
150 |     }
151 | }
152 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Coroutine/Server/Connection.php:
--------------------------------------------------------------------------------
 1 | socket = $conn;
23 |     }
24 | 
25 |     public function recv(float $timeout = 0)
26 |     {
27 |         return $this->socket->recvPacket($timeout);
28 |     }
29 | 
30 |     public function send(string $data)
31 |     {
32 |         return $this->socket->sendAll($data);
33 |     }
34 | 
35 |     public function close(): bool
36 |     {
37 |         return $this->socket->close();
38 |     }
39 | 
40 |     public function exportSocket(): Socket
41 |     {
42 |         return $this->socket;
43 |     }
44 | }
45 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Coroutine/WaitGroup.php:
--------------------------------------------------------------------------------
 1 | chan = new Channel(1);
25 |         if ($delta > 0) {
26 |             $this->add($delta);
27 |         }
28 |     }
29 | 
30 |     public function add(int $delta = 1): void
31 |     {
32 |         if ($this->waiting) {
33 |             throw new \BadMethodCallException('WaitGroup misuse: add called concurrently with wait');
34 |         }
35 |         $count = $this->count + $delta;
36 |         if ($count < 0) {
37 |             throw new \InvalidArgumentException('WaitGroup misuse: negative counter');
38 |         }
39 |         $this->count = $count;
40 |     }
41 | 
42 |     public function done(): void
43 |     {
44 |         $count = $this->count - 1;
45 |         if ($count < 0) {
46 |             throw new \BadMethodCallException('WaitGroup misuse: negative counter');
47 |         }
48 |         $this->count = $count;
49 |         if ($count === 0 && $this->waiting) {
50 |             $this->chan->push(true);
51 |         }
52 |     }
53 | 
54 |     public function wait(float $timeout = -1): bool
55 |     {
56 |         if ($this->waiting) {
57 |             throw new \BadMethodCallException('WaitGroup misuse: reused before previous wait has returned');
58 |         }
59 |         if ($this->count > 0) {
60 |             $this->waiting = true;
61 |             $done          = $this->chan->pop($timeout);
62 |             $this->waiting = false;
63 |             return $done;
64 |         }
65 |         return true;
66 |     }
67 | 
68 |     public function count(): int
69 |     {
70 |         return $this->count;
71 |     }
72 | }
73 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Coroutine/functions.php:
--------------------------------------------------------------------------------
  1 | set(['hook_flags' => SWOOLE_HOOK_ALL]);
 22 |     }
 23 |     $s->add($fn, ...$args);
 24 |     return $s->start();
 25 | }
 26 | 
 27 | function go(callable $fn, ...$args)
 28 | {
 29 |     return Coroutine::create($fn, ...$args);
 30 | }
 31 | 
 32 | function defer(callable $fn)
 33 | {
 34 |     Coroutine::defer($fn);
 35 | }
 36 | 
 37 | function batch(array $tasks, float $timeout = -1): array
 38 | {
 39 |     $wg = new WaitGroup(count($tasks));
 40 |     foreach ($tasks as $id => $task) {
 41 |         Coroutine::create(function () use ($wg, &$tasks, $id, $task) {
 42 |             $tasks[$id] = null;
 43 |             $tasks[$id] = $task();
 44 |             $wg->done();
 45 |         });
 46 |     }
 47 |     $wg->wait($timeout);
 48 |     return $tasks;
 49 | }
 50 | 
 51 | function parallel(int $n, callable $fn): void
 52 | {
 53 |     $count = $n;
 54 |     $wg    = new WaitGroup($n);
 55 |     while ($count--) {
 56 |         Coroutine::create(function () use ($fn, $wg) {
 57 |             $fn();
 58 |             $wg->done();
 59 |         });
 60 |     }
 61 |     $wg->wait();
 62 | }
 63 | 
 64 | /**
 65 |  * Applies the callback to the elements of the given list.
 66 |  *
 67 |  * The callback function takes on two parameters. The list parameter's value being the first, and the key/index second.
 68 |  * Each callback runs in a new coroutine, allowing the list to be processed in parallel.
 69 |  *
 70 |  * @param array $list A list of key/value paired input data.
 71 |  * @param callable $fn The callback function to apply to each item on the list. The callback takes on two parameters.
 72 |  *                     The list parameter's value being the first, and the key/index second.
 73 |  * @param float $timeout > 0 means waiting for the specified number of seconds. other means no waiting.
 74 |  * @return array Returns an array containing the results of applying the callback function to the corresponding value
 75 |  *               and key of the list (used as arguments for the callback). The returned array will preserve the keys of
 76 |  *               the list.
 77 |  */
 78 | function map(array $list, callable $fn, float $timeout = -1): array
 79 | {
 80 |     $wg = new WaitGroup(count($list));
 81 |     foreach ($list as $id => $elem) {
 82 |         Coroutine::create(function () use ($wg, &$list, $id, $elem, $fn): void {
 83 |             $list[$id] = null;
 84 |             $list[$id] = $fn($elem, $id);
 85 |             $wg->done();
 86 |         });
 87 |     }
 88 |     $wg->wait($timeout);
 89 |     return $list;
 90 | }
 91 | 
 92 | function deadlock_check()
 93 | {
 94 |     $all_coroutines = Coroutine::listCoroutines();
 95 |     $count          = Coroutine::stats()['coroutine_num'];
 96 |     echo "\n===================================================================",
 97 |     "\n [FATAL ERROR]: all coroutines (count: {$count}) are asleep - deadlock!",
 98 |     "\n===================================================================\n";
 99 | 
100 |     $options = Coroutine::getOptions();
101 |     if (empty($options['deadlock_check_disable_trace'])) {
102 |         $index = 0;
103 |         $limit = empty($options['deadlock_check_limit']) ? 32 : intval($options['deadlock_check_limit']);
104 |         $depth = empty($options['deadlock_check_depth']) ? 32 : intval($options['deadlock_check_depth']);
105 |         foreach ($all_coroutines as $cid) {
106 |             echo "\n [Coroutine-{$cid}]";
107 |             echo "\n--------------------------------------------------------------------\n";
108 |             echo Coroutine::printBackTrace($cid, DEBUG_BACKTRACE_IGNORE_ARGS, $depth);
109 |             echo "\n";
110 |             $index++;
111 |             // limit the number of maximum outputs
112 |             if ($index >= $limit) {
113 |                 break;
114 |             }
115 |         }
116 |     }
117 | }
118 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Curl/Exception.php:
--------------------------------------------------------------------------------
 1 | 
18 |      */
19 |     private const ERROR_MESSAGES = [
20 |         'server has gone away',
21 |         'no connection to the server',
22 |         'Lost connection',
23 |         'is dead or not enabled',
24 |         'Error while sending',
25 |         'decryption failed or bad record mac',
26 |         'server closed the connection unexpectedly',
27 |         'SSL connection has been closed unexpectedly',
28 |         'Error writing data to the connection',
29 |         'Resource deadlock avoided',
30 |         'Transaction() on null',
31 |         'child connection forced to terminate due to client_idle_limit',
32 |         'query_wait_timeout',
33 |         'reset by peer',
34 |         'Physical connection is not usable',
35 |         'TCP Provider: Error code 0x68',
36 |         'ORA-03113',
37 |         'ORA-03114',
38 |         'Packets out of order. Expected',
39 |         'Adaptive Server connection failed',
40 |         'Communication link failure',
41 |         'connection is no longer usable',
42 |         'Login timeout expired',
43 |         'SQLSTATE[HY000] [2002] Connection refused',
44 |         'running with the --read-only option so it cannot execute this statement',
45 |         'The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection.',
46 |         'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Try again',
47 |         'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name or service not known',
48 |         'SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo for',
49 |         'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: EOF detected',
50 |         'SQLSTATE[HY000]: General error: 1105 The last transaction was aborted due to Seamless Scaling. Please retry.',
51 |         'Temporary failure in name resolution',
52 |         'SQLSTATE[08S01]: Communication link failure',
53 |         'SQLSTATE[08006] [7] could not connect to server: Connection refused Is the server running on host',
54 |         'SQLSTATE[HY000]: General error: 7 SSL SYSCALL error: No route to host',
55 |         'The client was disconnected by the server because of inactivity. See wait_timeout and interactive_timeout for configuring this behavior.',
56 |         'SQLSTATE[08006] [7] could not translate host name',
57 |         'TCP Provider: Error code 0x274C',
58 |         'SQLSTATE[HY000] [2002] No such file or directory',
59 |         'Reason: Server is in script upgrade mode. Only administrator can connect at this time.',
60 |         'Unknown $curl_error_code: 77',
61 |         'SQLSTATE[08006] [7] SSL error: sslv3 alert unexpected message',
62 |         'SQLSTATE[08006] [7] unrecognized SSL error code:',
63 |         'SQLSTATE[HY000] [2002] No connection could be made because the target machine actively refused it',
64 |         'Broken pipe',
65 |         // PDO::prepare(): Send of 77 bytes failed with errno=110 Operation timed out
66 |         // SSL: Handshake timed out
67 |         // SSL: Operation timed out
68 |         // SSL: Connection timed out
69 |         // SQLSTATE[HY000] [2002] Connection timed out
70 |         'timed out',
71 |         'Error reading result',
72 |     ];
73 | 
74 |     public static function causedByLostConnection(\Throwable $e): bool
75 |     {
76 |         $message = $e->getMessage();
77 |         foreach (self::ERROR_MESSAGES as $needle) {
78 |             if (mb_strpos($message, $needle) !== false) {
79 |                 return true;
80 |             }
81 |         }
82 | 
83 |         return false;
84 |     }
85 | }
86 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/MysqliConfig.php:
--------------------------------------------------------------------------------
  1 | host;
 35 |     }
 36 | 
 37 |     public function withHost(string $host): self
 38 |     {
 39 |         $this->host = $host;
 40 |         return $this;
 41 |     }
 42 | 
 43 |     public function getPort(): int
 44 |     {
 45 |         return $this->port;
 46 |     }
 47 | 
 48 |     public function getUnixSocket(): ?string
 49 |     {
 50 |         return $this->unixSocket ?? null;
 51 |     }
 52 | 
 53 |     public function withUnixSocket(?string $unixSocket): self
 54 |     {
 55 |         $this->unixSocket = $unixSocket;
 56 |         return $this;
 57 |     }
 58 | 
 59 |     public function withPort(int $port): self
 60 |     {
 61 |         $this->port = $port;
 62 |         return $this;
 63 |     }
 64 | 
 65 |     public function getDbname(): string
 66 |     {
 67 |         return $this->dbname;
 68 |     }
 69 | 
 70 |     public function withDbname(string $dbname): self
 71 |     {
 72 |         $this->dbname = $dbname;
 73 |         return $this;
 74 |     }
 75 | 
 76 |     public function getCharset(): string
 77 |     {
 78 |         return $this->charset;
 79 |     }
 80 | 
 81 |     public function withCharset(string $charset): self
 82 |     {
 83 |         $this->charset = $charset;
 84 |         return $this;
 85 |     }
 86 | 
 87 |     public function getUsername(): string
 88 |     {
 89 |         return $this->username;
 90 |     }
 91 | 
 92 |     public function withUsername(string $username): self
 93 |     {
 94 |         $this->username = $username;
 95 |         return $this;
 96 |     }
 97 | 
 98 |     public function getPassword(): string
 99 |     {
100 |         return $this->password;
101 |     }
102 | 
103 |     public function withPassword(string $password): self
104 |     {
105 |         $this->password = $password;
106 |         return $this;
107 |     }
108 | 
109 |     public function getOptions(): array
110 |     {
111 |         return $this->options;
112 |     }
113 | 
114 |     public function withOptions(array $options): self
115 |     {
116 |         $this->options = $options;
117 |         return $this;
118 |     }
119 | }
120 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/MysqliException.php:
--------------------------------------------------------------------------------
 1 | config->getOptions() as $option => $value) {
28 |                 $mysqli->set_opt($option, $value);
29 |             }
30 |             $mysqli->real_connect(
31 |                 $this->config->getHost(),
32 |                 $this->config->getUsername(),
33 |                 $this->config->getPassword(),
34 |                 $this->config->getDbname(),
35 |                 $this->config->getPort(),
36 |                 $this->config->getUnixSocket()
37 |             );
38 |             if ($mysqli->connect_errno) {
39 |                 throw new MysqliException($mysqli->connect_error, $mysqli->connect_errno);
40 |             }
41 |             $mysqli->set_charset($this->config->getCharset());
42 |             return $mysqli;
43 |         }, $size, MysqliProxy::class);
44 |     }
45 | }
46 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/MysqliProxy.php:
--------------------------------------------------------------------------------
  1 | constructor = $constructor;
 45 |     }
 46 | 
 47 |     public function __call(string $name, array $arguments)
 48 |     {
 49 |         for ($n = 3; $n--;) {
 50 |             $ret = @$this->__object->{$name}(...$arguments);
 51 |             if ($ret === false) {
 52 |                 /* non-IO method */
 53 |                 if (!preg_match(static::IO_METHOD_REGEX, $name)) {
 54 |                     break;
 55 |                 }
 56 |                 /* no more chances or non-IO failures */
 57 |                 if (!in_array($this->__object->errno, static::IO_ERRORS, true) || ($n === 0)) {
 58 |                     throw new MysqliException($this->__object->error, $this->__object->errno);
 59 |                 }
 60 |                 $this->reconnect();
 61 |                 continue;
 62 |             }
 63 |             if (strcasecmp($name, 'prepare') === 0) {
 64 |                 $ret = new MysqliStatementProxy($ret, $arguments[0], $this);
 65 |             } elseif (strcasecmp($name, 'stmt_init') === 0) {
 66 |                 $ret = new MysqliStatementProxy($ret, null, $this);
 67 |             }
 68 |             break;
 69 |         }
 70 |         /* @noinspection PhpUndefinedVariableInspection */
 71 |         return $ret;
 72 |     }
 73 | 
 74 |     public function getRound(): int
 75 |     {
 76 |         return $this->round;
 77 |     }
 78 | 
 79 |     public function reconnect(): void
 80 |     {
 81 |         $constructor = $this->constructor;
 82 |         parent::__construct($constructor());
 83 |         $this->round++;
 84 |         /* restore context */
 85 |         if (!empty($this->charsetContext)) {
 86 |             $this->__object->set_charset($this->charsetContext);
 87 |         }
 88 |         foreach ($this->setOptContext as $opt => $val) {
 89 |             $this->__object->set_opt($opt, $val);
 90 |         }
 91 |         if (!empty($this->changeUserContext)) {
 92 |             $this->__object->change_user(...$this->changeUserContext);
 93 |         }
 94 |     }
 95 | 
 96 |     public function options(int $option, $value): bool
 97 |     {
 98 |         $this->setOptContext[$option] = $value;
 99 |         return $this->__object->options($option, $value);
100 |     }
101 | 
102 |     public function set_opt(int $option, $value): bool
103 |     {
104 |         return $this->options($option, $value);
105 |     }
106 | 
107 |     public function set_charset(string $charset): bool
108 |     {
109 |         $this->charsetContext = $charset;
110 |         return $this->__object->set_charset($charset);
111 |     }
112 | 
113 |     public function change_user(string $user, string $password, ?string $database): bool
114 |     {
115 |         $this->changeUserContext = [$user, $password, $database];
116 |         return $this->__object->change_user($user, $password, $database);
117 |     }
118 | }
119 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/MysqliStatementProxy.php:
--------------------------------------------------------------------------------
  1 | queryString = $queryString;
 37 |         $this->parent      = $parent;
 38 |         $this->parentRound = $parent->getRound();
 39 |     }
 40 | 
 41 |     public function __call(string $name, array $arguments)
 42 |     {
 43 |         for ($n = 3; $n--;) {
 44 |             $ret = @$this->__object->{$name}(...$arguments);
 45 |             if ($ret === false) {
 46 |                 /* non-IO method */
 47 |                 if (!preg_match(static::IO_METHOD_REGEX, $name)) {
 48 |                     break;
 49 |                 }
 50 |                 /* no more chances or non-IO failures or in transaction */
 51 |                 if (!in_array($this->__object->errno, $this->parent::IO_ERRORS, true) || ($n === 0)) {
 52 |                     throw new MysqliException($this->__object->error, $this->__object->errno);
 53 |                 }
 54 |                 if ($this->parent->getRound() === $this->parentRound) {
 55 |                     /* if not equal, parent has reconnected */
 56 |                     $this->parent->reconnect();
 57 |                 }
 58 |                 $parent         = $this->parent->__getObject();
 59 |                 $this->__object = $this->queryString ? @$parent->prepare($this->queryString) : @$parent->stmt_init();
 60 |                 if ($this->__object === false) {
 61 |                     throw new MysqliException($parent->error, $parent->errno);
 62 |                 }
 63 |                 if (!empty($this->bindParamContext)) {
 64 |                     $this->__object->bind_param($this->bindParamContext[0], ...$this->bindParamContext[1]);
 65 |                 }
 66 |                 if (!empty($this->bindResultContext)) {
 67 |                     $this->__object->bind_result($this->bindResultContext);
 68 |                 }
 69 |                 foreach ($this->attrSetContext as $attr => $value) {
 70 |                     $this->__object->attr_set($attr, $value);
 71 |                 }
 72 |                 continue;
 73 |             }
 74 |             if (strcasecmp($name, 'prepare') === 0) {
 75 |                 $this->queryString = $arguments[0];
 76 |             }
 77 |             break;
 78 |         }
 79 |         /* @noinspection PhpUndefinedVariableInspection */
 80 |         return $ret;
 81 |     }
 82 | 
 83 |     public function attr_set($attr, $mode): bool
 84 |     {
 85 |         $this->attrSetContext[$attr] = $mode;
 86 |         return $this->__object->attr_set($attr, $mode);
 87 |     }
 88 | 
 89 |     public function bind_param($types, &...$arguments): bool
 90 |     {
 91 |         $this->bindParamContext = [$types, $arguments];
 92 |         return $this->__object->bind_param($types, ...$arguments);
 93 |     }
 94 | 
 95 |     public function bind_result(&...$arguments): bool
 96 |     {
 97 |         $this->bindResultContext = $arguments;
 98 |         return $this->__object->bind_result(...$arguments);
 99 |     }
100 | }
101 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/ObjectProxy.php:
--------------------------------------------------------------------------------
 1 | driver;
 39 |     }
 40 | 
 41 |     public function withDriver(string $driver): self
 42 |     {
 43 |         $this->driver = $driver;
 44 |         return $this;
 45 |     }
 46 | 
 47 |     public function getHost(): string
 48 |     {
 49 |         return $this->host;
 50 |     }
 51 | 
 52 |     public function withHost(string $host): self
 53 |     {
 54 |         $this->host = $host;
 55 |         return $this;
 56 |     }
 57 | 
 58 |     public function getPort(): int
 59 |     {
 60 |         return $this->port;
 61 |     }
 62 | 
 63 |     public function hasUnixSocket(): bool
 64 |     {
 65 |         return !empty($this->unixSocket);
 66 |     }
 67 | 
 68 |     public function getUnixSocket(): ?string
 69 |     {
 70 |         return $this->unixSocket ?? null;
 71 |     }
 72 | 
 73 |     public function withUnixSocket(?string $unixSocket): self
 74 |     {
 75 |         $this->unixSocket = $unixSocket;
 76 |         return $this;
 77 |     }
 78 | 
 79 |     public function withPort(int $port): self
 80 |     {
 81 |         $this->port = $port;
 82 |         return $this;
 83 |     }
 84 | 
 85 |     public function getDbname(): string
 86 |     {
 87 |         return $this->dbname;
 88 |     }
 89 | 
 90 |     public function withDbname(string $dbname): self
 91 |     {
 92 |         $this->dbname = $dbname;
 93 |         return $this;
 94 |     }
 95 | 
 96 |     public function getCharset(): string
 97 |     {
 98 |         return $this->charset;
 99 |     }
100 | 
101 |     public function withCharset(string $charset): self
102 |     {
103 |         $this->charset = $charset;
104 |         return $this;
105 |     }
106 | 
107 |     public function getUsername(): string
108 |     {
109 |         return $this->username;
110 |     }
111 | 
112 |     public function withUsername(string $username): self
113 |     {
114 |         $this->username = $username;
115 |         return $this;
116 |     }
117 | 
118 |     public function getPassword(): string
119 |     {
120 |         return $this->password;
121 |     }
122 | 
123 |     public function withPassword(string $password): self
124 |     {
125 |         $this->password = $password;
126 |         return $this;
127 |     }
128 | 
129 |     public function getOptions(): array
130 |     {
131 |         return $this->options;
132 |     }
133 | 
134 |     public function withOptions(array $options): self
135 |     {
136 |         $this->options = $options;
137 |         return $this;
138 |     }
139 | 
140 |     /**
141 |      * Returns the list of available drivers
142 |      *
143 |      * @return string[]
144 |      */
145 |     public static function getAvailableDrivers(): array
146 |     {
147 |         return [
148 |             self::DRIVER_MYSQL,
149 |         ];
150 |     }
151 | }
152 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/PDOPool.php:
--------------------------------------------------------------------------------
 1 | config->getDriver();
26 |             if ($driver === 'sqlite') {
27 |                 return new \PDO($this->createDSN('sqlite'));
28 |             }
29 | 
30 |             return new \PDO($this->createDSN($driver), $this->config->getUsername(), $this->config->getPassword(), $this->config->getOptions());
31 |         }, $size, PDOProxy::class);
32 |     }
33 | 
34 |     /**
35 |      * Get a PDO connection from the pool. The PDO connection (a PDO object) is wrapped in a PDOProxy object returned.
36 |      *
37 |      * @param float $timeout > 0 means waiting for the specified number of seconds. other means no waiting.
38 |      * @return PDOProxy|false Returns a PDOProxy object from the pool, or false if the pool is full and the timeout is reached.
39 |      *                        {@inheritDoc}
40 |      */
41 |     public function get(float $timeout = -1)
42 |     {
43 |         /* @var \Swoole\Database\PDOProxy|false $pdo */
44 |         $pdo = parent::get($timeout);
45 |         if ($pdo === false) {
46 |             return false;
47 |         }
48 | 
49 |         $pdo->reset();
50 | 
51 |         return $pdo;
52 |     }
53 | 
54 |     /**
55 |      * @purpose create DSN
56 |      * @throws \Exception
57 |      */
58 |     private function createDSN(string $driver): string
59 |     {
60 |         switch ($driver) {
61 |             case 'mysql':
62 |                 if ($this->config->hasUnixSocket()) {
63 |                     $dsn = "mysql:unix_socket={$this->config->getUnixSocket()};dbname={$this->config->getDbname()};charset={$this->config->getCharset()}";
64 |                 } else {
65 |                     $dsn = "mysql:host={$this->config->getHost()};port={$this->config->getPort()};dbname={$this->config->getDbname()};charset={$this->config->getCharset()}";
66 |                 }
67 |                 break;
68 |             case 'pgsql':
69 |                 $dsn = 'pgsql:host=' . ($this->config->hasUnixSocket() ? $this->config->getUnixSocket() : $this->config->getHost()) . ";port={$this->config->getPort()};dbname={$this->config->getDbname()}";
70 |                 break;
71 |             case 'oci':
72 |                 $dsn = 'oci:dbname=' . ($this->config->hasUnixSocket() ? $this->config->getUnixSocket() : $this->config->getHost()) . ':' . $this->config->getPort() . '/' . $this->config->getDbname() . ';charset=' . $this->config->getCharset();
73 |                 break;
74 |             case 'sqlite':
75 |                 // There are three types of SQLite databases: databases on disk, databases in memory, and temporary
76 |                 // databases (which are deleted when the connections are closed). It doesn't make sense to use
77 |                 // connection pool for the latter two types of databases, because each connection connects to a
78 |                 //different in-memory or temporary SQLite database.
79 |                 if ($this->config->getDbname() === '') {
80 |                     throw new \Exception('Connection pool in Swoole does not support temporary SQLite databases.');
81 |                 }
82 |                 if ($this->config->getDbname() === ':memory:') {
83 |                     throw new \Exception('Connection pool in Swoole does not support creating SQLite databases in memory.');
84 |                 }
85 |                 $dsn = 'sqlite:' . $this->config->getDbname();
86 |                 break;
87 |             default:
88 |                 throw new \Exception('Unsupported Database Driver:' . $driver);
89 |         }
90 |         return $dsn;
91 |     }
92 | }
93 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/PDOProxy.php:
--------------------------------------------------------------------------------
 1 | __object->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
35 |         $this->constructor = $constructor;
36 |     }
37 | 
38 |     public function __call(string $name, array $arguments)
39 |     {
40 |         try {
41 |             $ret = $this->__object->{$name}(...$arguments);
42 |         } catch (\PDOException $e) {
43 |             if (!$this->__object->inTransaction() && DetectsLostConnections::causedByLostConnection($e)) {
44 |                 $this->reconnect();
45 |                 $ret = $this->__object->{$name}(...$arguments);
46 |             } else {
47 |                 throw $e;
48 |             }
49 |         }
50 | 
51 |         if (strcasecmp($name, 'beginTransaction') === 0) {
52 |             $this->inTransaction++;
53 |         }
54 | 
55 |         if ((strcasecmp($name, 'commit') === 0 || strcasecmp($name, 'rollback') === 0) && $this->inTransaction > 0) {
56 |             $this->inTransaction--;
57 |         }
58 | 
59 |         if ((strcasecmp($name, 'prepare') === 0) || (strcasecmp($name, 'query') === 0)) {
60 |             $ret = new PDOStatementProxy($ret, $this);
61 |         }
62 | 
63 |         return $ret;
64 |     }
65 | 
66 |     public function getRound(): int
67 |     {
68 |         return $this->round;
69 |     }
70 | 
71 |     public function reconnect(): void
72 |     {
73 |         $constructor = $this->constructor;
74 |         parent::__construct($constructor());
75 |         $this->__object->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
76 |         $this->round++;
77 |         /* restore context */
78 |         foreach ($this->setAttributeContext as $attribute => $value) {
79 |             $this->__object->setAttribute($attribute, $value);
80 |         }
81 |     }
82 | 
83 |     public function setAttribute(int $attribute, $value): bool
84 |     {
85 |         $this->setAttributeContext[$attribute] = $value;
86 |         return $this->__object->setAttribute($attribute, $value);
87 |     }
88 | 
89 |     public function inTransaction(): bool
90 |     {
91 |         return $this->inTransaction > 0;
92 |     }
93 | 
94 |     public function reset(): void
95 |     {
96 |         $this->inTransaction = 0;
97 |     }
98 | }
99 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/PDOStatementProxy.php:
--------------------------------------------------------------------------------
  1 | parent      = $parent;
 43 |         $this->parentRound = $parent->getRound();
 44 |     }
 45 | 
 46 |     public function __call(string $name, array $arguments)
 47 |     {
 48 |         try {
 49 |             $ret = $this->__object->{$name}(...$arguments);
 50 |         } catch (\PDOException $e) {
 51 |             if (!$this->parent->inTransaction() && DetectsLostConnections::causedByLostConnection($e)) {
 52 |                 if ($this->parent->getRound() === $this->parentRound) {
 53 |                     /* if not equal, parent has reconnected */
 54 |                     $this->parent->reconnect();
 55 |                 }
 56 |                 $parent         = $this->parent->__getObject();
 57 |                 $this->__object = $parent->prepare($this->__object->queryString);
 58 | 
 59 |                 foreach ($this->setAttributeContext as $attribute => $value) {
 60 |                     $this->__object->setAttribute($attribute, $value);
 61 |                 }
 62 |                 if (!empty($this->setFetchModeContext)) {
 63 |                     $this->__object->setFetchMode(...$this->setFetchModeContext);
 64 |                 }
 65 |                 foreach ($this->bindParamContext as $param => $item) {
 66 |                     $this->__object->bindParam($param, ...$item);
 67 |                 }
 68 |                 foreach ($this->bindColumnContext as $column => $item) {
 69 |                     $this->__object->bindColumn($column, ...$item);
 70 |                 }
 71 |                 foreach ($this->bindValueContext as $value => $item) {
 72 |                     $this->__object->bindParam($value, ...$item);
 73 |                 }
 74 |                 $ret = $this->__object->{$name}(...$arguments);
 75 |             } else {
 76 |                 throw $e;
 77 |             }
 78 |         }
 79 | 
 80 |         return $ret;
 81 |     }
 82 | 
 83 |     public function setAttribute(int $attribute, $value): bool
 84 |     {
 85 |         $this->setAttributeContext[$attribute] = $value;
 86 |         return $this->__object->setAttribute($attribute, $value);
 87 |     }
 88 | 
 89 |     /**
 90 |      * Set the default fetch mode for this statement.
 91 |      *
 92 |      * @see https://www.php.net/manual/en/pdostatement.setfetchmode.php
 93 |      */
 94 |     public function setFetchMode(int $mode, ...$params): bool
 95 |     {
 96 |         $this->setFetchModeContext = func_get_args();
 97 |         return $this->__object->setFetchMode(...$this->setFetchModeContext);
 98 |     }
 99 | 
100 |     public function bindParam($parameter, &$variable, $data_type = \PDO::PARAM_STR, $length = 0, $driver_options = null): bool
101 |     {
102 |         $this->bindParamContext[$parameter] = [$variable, $data_type, $length, $driver_options];
103 |         return $this->__object->bindParam($parameter, $variable, $data_type, $length, $driver_options);
104 |     }
105 | 
106 |     public function bindColumn($column, &$param, $type = null, $maxlen = null, $driverdata = null): bool
107 |     {
108 |         $this->bindColumnContext[$column] = [$param, $type, $maxlen, $driverdata];
109 |         return $this->__object->bindColumn($column, $param, $type, $maxlen, $driverdata);
110 |     }
111 | 
112 |     public function bindValue($parameter, $value, $data_type = \PDO::PARAM_STR): bool
113 |     {
114 |         $this->bindValueContext[$parameter] = [$value, $data_type];
115 |         return $this->__object->bindValue($parameter, $value, $data_type);
116 |     }
117 | }
118 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/RedisConfig.php:
--------------------------------------------------------------------------------
  1 | 
 34 |      */
 35 |     protected array $options = [];
 36 | 
 37 |     public function getHost(): string
 38 |     {
 39 |         return $this->host;
 40 |     }
 41 | 
 42 |     public function withHost(string $host): self
 43 |     {
 44 |         $this->host = $host;
 45 |         return $this;
 46 |     }
 47 | 
 48 |     public function getPort(): int
 49 |     {
 50 |         return $this->port;
 51 |     }
 52 | 
 53 |     public function withPort(int $port): self
 54 |     {
 55 |         $this->port = $port;
 56 |         return $this;
 57 |     }
 58 | 
 59 |     public function getTimeout(): float
 60 |     {
 61 |         return $this->timeout;
 62 |     }
 63 | 
 64 |     public function withTimeout(float $timeout): self
 65 |     {
 66 |         $this->timeout = $timeout;
 67 |         return $this;
 68 |     }
 69 | 
 70 |     public function getReserved(): string
 71 |     {
 72 |         return $this->reserved;
 73 |     }
 74 | 
 75 |     public function withReserved(string $reserved): self
 76 |     {
 77 |         $this->reserved = $reserved;
 78 |         return $this;
 79 |     }
 80 | 
 81 |     public function getRetryInterval(): int
 82 |     {
 83 |         return $this->retry_interval;
 84 |     }
 85 | 
 86 |     public function withRetryInterval(int $retry_interval): self
 87 |     {
 88 |         $this->retry_interval = $retry_interval;
 89 |         return $this;
 90 |     }
 91 | 
 92 |     public function getReadTimeout(): float
 93 |     {
 94 |         return $this->read_timeout;
 95 |     }
 96 | 
 97 |     public function withReadTimeout(float $read_timeout): self
 98 |     {
 99 |         $this->read_timeout = $read_timeout;
100 |         return $this;
101 |     }
102 | 
103 |     public function getAuth(): string
104 |     {
105 |         return $this->auth;
106 |     }
107 | 
108 |     public function withAuth(string $auth): self
109 |     {
110 |         $this->auth = $auth;
111 |         return $this;
112 |     }
113 | 
114 |     public function getDbIndex(): int
115 |     {
116 |         return $this->dbIndex;
117 |     }
118 | 
119 |     public function withDbIndex(int $dbIndex): self
120 |     {
121 |         $this->dbIndex = $dbIndex;
122 |         return $this;
123 |     }
124 | 
125 |     /**
126 |      * Add a configurable option.
127 |      */
128 |     public function withOption(int $option, mixed $value): self
129 |     {
130 |         $this->options[$option] = $value;
131 |         return $this;
132 |     }
133 | 
134 |     /**
135 |      * Add/override configurable options.
136 |      *
137 |      * @param array $options
138 |      */
139 |     public function setOptions(array $options): self
140 |     {
141 |         $this->options = $options;
142 |         return $this;
143 |     }
144 | 
145 |     /**
146 |      * Get configurable options.
147 |      *
148 |      * @return array
149 |      */
150 |     public function getOptions(): array
151 |     {
152 |         return $this->options;
153 |     }
154 | }
155 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Database/RedisPool.php:
--------------------------------------------------------------------------------
 1 | config->getHost(),
30 |                 $this->config->getPort(),
31 |             ];
32 |             if ($this->config->getTimeout() !== 0.0) {
33 |                 $arguments[] = $this->config->getTimeout();
34 |             }
35 |             if ($this->config->getRetryInterval() !== 0) {
36 |                 /* reserved should always be NULL */
37 |                 $arguments[] = null;
38 |                 $arguments[] = $this->config->getRetryInterval();
39 |             }
40 |             if ($this->config->getReadTimeout() !== 0.0) {
41 |                 $arguments[] = $this->config->getReadTimeout();
42 |             }
43 |             $redis->connect(...$arguments);
44 |             if ($this->config->getAuth()) {
45 |                 $redis->auth($this->config->getAuth());
46 |             }
47 |             if ($this->config->getDbIndex() !== 0) {
48 |                 $redis->select($this->config->getDbIndex());
49 |             }
50 | 
51 |             /* Set Redis options. */
52 |             foreach ($this->config->getOptions() as $key => $value) {
53 |                 $redis->setOption($key, $value);
54 |             }
55 | 
56 |             return $redis;
57 |         }, $size);
58 |     }
59 | }
60 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Exception/ArrayKeyNotExists.php:
--------------------------------------------------------------------------------
 1 | 
 36 |      */
 37 |     protected static array $classMapping = [
 38 |         FastCGI::BEGIN_REQUEST     => BeginRequest::class,
 39 |         FastCGI::ABORT_REQUEST     => AbortRequest::class,
 40 |         FastCGI::END_REQUEST       => EndRequest::class,
 41 |         FastCGI::PARAMS            => Params::class,
 42 |         FastCGI::STDIN             => Stdin::class,
 43 |         FastCGI::STDOUT            => Stdout::class,
 44 |         FastCGI::STDERR            => Stderr::class,
 45 |         FastCGI::DATA              => Data::class,
 46 |         FastCGI::GET_VALUES        => GetValues::class,
 47 |         FastCGI::GET_VALUES_RESULT => GetValuesResult::class,
 48 |         FastCGI::UNKNOWN_TYPE      => UnknownType::class,
 49 |     ];
 50 | 
 51 |     /**
 52 |      * Checks if the buffer contains a valid frame to parse
 53 |      */
 54 |     public static function hasFrame(string $binaryBuffer): bool
 55 |     {
 56 |         $bufferLength = strlen($binaryBuffer);
 57 |         if ($bufferLength < FastCGI::HEADER_LEN) {
 58 |             return false;
 59 |         }
 60 | 
 61 |         /** @phpstan-var false|array{version: int, type: int, requestId: int, contentLength: int, paddingLength: int} */
 62 |         $fastInfo = unpack(FastCGI::HEADER_FORMAT, $binaryBuffer);
 63 |         if ($fastInfo === false) {
 64 |             throw new \RuntimeException('Can not unpack data from the binary buffer');
 65 |         }
 66 |         if ($bufferLength < FastCGI::HEADER_LEN + $fastInfo['contentLength'] + $fastInfo['paddingLength']) {
 67 |             return false;
 68 |         }
 69 | 
 70 |         return true;
 71 |     }
 72 | 
 73 |     /**
 74 |      * Parses a frame from the binary buffer
 75 |      *
 76 |      * @return Record One of the corresponding FastCGI record
 77 |      */
 78 |     public static function parseFrame(string &$binaryBuffer): Record
 79 |     {
 80 |         $bufferLength = strlen($binaryBuffer);
 81 |         if ($bufferLength < FastCGI::HEADER_LEN) {
 82 |             throw new \RuntimeException('Not enough data in the buffer to parse');
 83 |         }
 84 |         /** @phpstan-var false|array{version: int, type: int, requestId: int, contentLength: int, paddingLength: int} */
 85 |         $recordHeader = unpack(FastCGI::HEADER_FORMAT, $binaryBuffer);
 86 |         if ($recordHeader === false) {
 87 |             throw new \RuntimeException('Can not unpack data from the binary buffer');
 88 |         }
 89 |         $recordType = $recordHeader['type'];
 90 |         if (!isset(self::$classMapping[$recordType])) {
 91 |             throw new \DomainException("Invalid FastCGI record type {$recordType} received");
 92 |         }
 93 | 
 94 |         /** @var Record $className */
 95 |         $className = self::$classMapping[$recordType];
 96 |         $record    = $className::unpack($binaryBuffer);
 97 | 
 98 |         $offset       = FastCGI::HEADER_LEN + $record->getContentLength() + $record->getPaddingLength();
 99 |         $binaryBuffer = substr($binaryBuffer, $offset);
100 | 
101 |         return $record;
102 |     }
103 | }
104 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/HttpResponse.php:
--------------------------------------------------------------------------------
  1 | 
 29 |      */
 30 |     protected array $headers = [];
 31 | 
 32 |     /**
 33 |      * @var array
 34 |      */
 35 |     protected array $headersMap = [];
 36 | 
 37 |     /**
 38 |      * @var array
 39 |      */
 40 |     protected array $setCookieHeaderLines = [];
 41 | 
 42 |     /**
 43 |      * @param array $records
 44 |      */
 45 |     public function __construct(array $records = [])
 46 |     {
 47 |         parent::__construct($records);
 48 |         $body = $this->getBody();
 49 |         if (strlen($body) === 0) {
 50 |             return;
 51 |         }
 52 |         $array = explode("\r\n\r\n", $body, 2); // An array that contains the HTTP headers and the body.
 53 |         if (count($array) != 2) {
 54 |             $this->withStatusCode(Status::BAD_GATEWAY)->withReasonPhrase('Invalid FastCGI Response')->withError($body);
 55 |             return;
 56 |         }
 57 |         $headers = explode("\r\n", $array[0]);
 58 |         $body    = $array[1];
 59 |         foreach ($headers as $header) {
 60 |             $array = explode(':', $header, 2); // An array that contains the name and the value of an HTTP header.
 61 |             if (count($array) != 2) {
 62 |                 continue; // Invalid HTTP header? Ignore it!
 63 |             }
 64 |             $name  = trim($array[0]);
 65 |             $value = trim($array[1]);
 66 |             if (strcasecmp($name, 'Status') === 0) {
 67 |                 $array        = explode(' ', $value, 2); // An array that contains the status code (and the reason phrase).
 68 |                 $statusCode   = $array[0];
 69 |                 $reasonPhrase = $array[1] ?? null;
 70 |             } elseif (strcasecmp($name, 'Set-Cookie') === 0) {
 71 |                 $this->withSetCookieHeaderLine($value);
 72 |             } else {
 73 |                 $this->withHeader($name, $value);
 74 |             }
 75 |         }
 76 |         $statusCode   = (int) ($statusCode ?? Status::OK);
 77 |         $reasonPhrase = $reasonPhrase ?? Status::getReasonPhrase($statusCode);
 78 |         $this->withStatusCode($statusCode)->withReasonPhrase($reasonPhrase);
 79 |         $this->withBody($body);
 80 |     }
 81 | 
 82 |     public function getStatusCode(): int
 83 |     {
 84 |         return $this->statusCode;
 85 |     }
 86 | 
 87 |     public function withStatusCode(int $statusCode): self
 88 |     {
 89 |         $this->statusCode = $statusCode;
 90 |         return $this;
 91 |     }
 92 | 
 93 |     public function getReasonPhrase(): string
 94 |     {
 95 |         return $this->reasonPhrase;
 96 |     }
 97 | 
 98 |     public function withReasonPhrase(string $reasonPhrase): self
 99 |     {
100 |         $this->reasonPhrase = $reasonPhrase;
101 |         return $this;
102 |     }
103 | 
104 |     public function getHeader(string $name): ?string
105 |     {
106 |         $name = $this->headersMap[strtolower($name)] ?? null;
107 |         return $name ? $this->headers[$name] : null;
108 |     }
109 | 
110 |     /**
111 |      * @return array
112 |      */
113 |     public function getHeaders(): array
114 |     {
115 |         return $this->headers;
116 |     }
117 | 
118 |     public function withHeader(string $name, string $value): self
119 |     {
120 |         $this->headers[$name]                = $value;
121 |         $this->headersMap[strtolower($name)] = $name;
122 |         return $this;
123 |     }
124 | 
125 |     /**
126 |      * @param array $headers
127 |      */
128 |     public function withHeaders(array $headers): self
129 |     {
130 |         foreach ($headers as $name => $value) {
131 |             $this->withHeader($name, $value);
132 |         }
133 |         return $this;
134 |     }
135 | 
136 |     /**
137 |      * @return array
138 |      */
139 |     public function getSetCookieHeaderLines(): array
140 |     {
141 |         return $this->setCookieHeaderLines;
142 |     }
143 | 
144 |     public function withSetCookieHeaderLine(string $value): self
145 |     {
146 |         $this->setCookieHeaderLines[] = $value;
147 |         return $this;
148 |     }
149 | }
150 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Message.php:
--------------------------------------------------------------------------------
 1 | params[$name] ?? null;
25 |     }
26 | 
27 |     public function withParam(string $name, string $value): static
28 |     {
29 |         $this->params[$name] = $value;
30 |         return $this;
31 |     }
32 | 
33 |     public function withoutParam(string $name): static
34 |     {
35 |         unset($this->params[$name]);
36 |         return $this;
37 |     }
38 | 
39 |     public function getParams(): array
40 |     {
41 |         return $this->params;
42 |     }
43 | 
44 |     public function withParams(array $params): static
45 |     {
46 |         $this->params = $params;
47 |         return $this;
48 |     }
49 | 
50 |     public function withAddedParams(array $params): static
51 |     {
52 |         $this->params = $params + $this->params;
53 |         return $this;
54 |     }
55 | 
56 |     public function getBody(): string
57 |     {
58 |         return $this->body;
59 |     }
60 | 
61 |     public function withBody(string|\Stringable $body): self
62 |     {
63 |         $this->body = (string) $body;
64 |         return $this;
65 |     }
66 | 
67 |     public function getError(): string
68 |     {
69 |         return $this->error;
70 |     }
71 | 
72 |     public function withError(string $error): static
73 |     {
74 |         $this->error = $error;
75 |         return $this;
76 |     }
77 | }
78 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/AbortRequest.php:
--------------------------------------------------------------------------------
 1 | type = FastCGI::ABORT_REQUEST;
25 |         $this->setRequestId($requestId);
26 |     }
27 | }
28 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/BeginRequest.php:
--------------------------------------------------------------------------------
  1 | type      = FastCGI::BEGIN_REQUEST;
 49 |         $this->role      = $role;
 50 |         $this->flags     = $flags;
 51 |         $this->reserved1 = $reserved;
 52 |         $this->setContentData($this->packPayload());
 53 |     }
 54 | 
 55 |     /**
 56 |      * Returns the role
 57 |      *
 58 |      * The role component sets the role the Web server expects the application to play.
 59 |      * The currently-defined roles are:
 60 |      *   FCGI_RESPONDER
 61 |      *   FCGI_AUTHORIZER
 62 |      *   FCGI_FILTER
 63 |      */
 64 |     public function getRole(): int
 65 |     {
 66 |         return $this->role;
 67 |     }
 68 | 
 69 |     /**
 70 |      * Returns the flags
 71 |      *
 72 |      * The flags component contains a bit that controls connection shutdown.
 73 |      *
 74 |      * flags & FCGI_KEEP_CONN:
 75 |      *   If zero, the application closes the connection after responding to this request.
 76 |      *   If not zero, the application does not close the connection after responding to this request;
 77 |      *   the Web server retains responsibility for the connection.
 78 |      */
 79 |     public function getFlags(): int
 80 |     {
 81 |         return $this->flags;
 82 |     }
 83 | 
 84 |     /**
 85 |      * {@inheritdoc}
 86 |      * @param static $self
 87 |      */
 88 |     protected static function unpackPayload(Record $self, string $binaryData): void
 89 |     {
 90 |         assert($self instanceof self); // @phpstan-ignore function.alreadyNarrowedType,instanceof.alwaysTrue
 91 | 
 92 |         /** @phpstan-var false|array{role: int, flags: int, reserved: string} */
 93 |         $payload = unpack('nrole/Cflags/a5reserved', $binaryData);
 94 |         if ($payload === false) {
 95 |             throw new \RuntimeException('Can not unpack data from the binary buffer');
 96 |         }
 97 |         [
 98 |             $self->role,
 99 |             $self->flags,
100 |             $self->reserved1,
101 |         ] = array_values($payload);
102 |     }
103 | 
104 |     /** {@inheritdoc} */
105 |     protected function packPayload(): string
106 |     {
107 |         return pack(
108 |             'nCa5',
109 |             $this->role,
110 |             $this->flags,
111 |             $this->reserved1
112 |         );
113 |     }
114 | }
115 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/Data.php:
--------------------------------------------------------------------------------
 1 | type = FastCGI::DATA;
27 |         $this->setContentData($contentData);
28 |     }
29 | }
30 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/EndRequest.php:
--------------------------------------------------------------------------------
  1 | type           = FastCGI::END_REQUEST;
 51 |         $this->protocolStatus = $protocolStatus;
 52 |         $this->appStatus      = $appStatus;
 53 |         $this->reserved1      = $reserved;
 54 |         $this->setContentData($this->packPayload());
 55 |     }
 56 | 
 57 |     /**
 58 |      * Returns app status
 59 |      *
 60 |      * The appStatus component is an application-level status code. Each role documents its usage of appStatus.
 61 |      */
 62 |     public function getAppStatus(): int
 63 |     {
 64 |         return $this->appStatus;
 65 |     }
 66 | 
 67 |     /**
 68 |      * Returns the protocol status
 69 |      *
 70 |      * The possible protocolStatus values are:
 71 |      *   FCGI_REQUEST_COMPLETE: normal end of request.
 72 |      *   FCGI_CANT_MPX_CONN: rejecting a new request.
 73 |      *      This happens when a Web server sends concurrent requests over one connection to an application that is
 74 |      *      designed to process one request at a time per connection.
 75 |      *   FCGI_OVERLOADED: rejecting a new request.
 76 |      *      This happens when the application runs out of some resource, e.g. database connections.
 77 |      *   FCGI_UNKNOWN_ROLE: rejecting a new request.
 78 |      *      This happens when the Web server has specified a role that is unknown to the application.
 79 |      */
 80 |     public function getProtocolStatus(): int
 81 |     {
 82 |         return $this->protocolStatus;
 83 |     }
 84 | 
 85 |     /**
 86 |      * {@inheritdoc}
 87 |      * @param static $self
 88 |      */
 89 |     protected static function unpackPayload(Record $self, string $binaryData): void
 90 |     {
 91 |         assert($self instanceof self); // @phpstan-ignore function.alreadyNarrowedType,instanceof.alwaysTrue
 92 | 
 93 |         /** @phpstan-var false|array{appStatus: int, protocolStatus: int, reserved: string} */
 94 |         $payload = unpack('NappStatus/CprotocolStatus/a3reserved', $binaryData);
 95 |         if ($payload === false) {
 96 |             throw new \RuntimeException('Can not unpack data from the binary buffer');
 97 |         }
 98 |         [
 99 |             $self->appStatus,
100 |             $self->protocolStatus,
101 |             $self->reserved1,
102 |         ] = array_values($payload);
103 |     }
104 | 
105 |     /** {@inheritdoc} */
106 |     protected function packPayload(): string
107 |     {
108 |         return pack(
109 |             'NCa3',
110 |             $this->appStatus,
111 |             $this->protocolStatus,
112 |             $this->reserved1
113 |         );
114 |     }
115 | }
116 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/GetValues.php:
--------------------------------------------------------------------------------
 1 |  $keys
44 |      */
45 |     public function __construct(array $keys)
46 |     {
47 |         parent::__construct(array_fill_keys($keys, ''));
48 |         $this->type = FastCGI::GET_VALUES;
49 |     }
50 | }
51 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/GetValuesResult.php:
--------------------------------------------------------------------------------
 1 |  $values
42 |      */
43 |     public function __construct(array $values)
44 |     {
45 |         parent::__construct($values);
46 |         $this->type = FastCGI::GET_VALUES_RESULT;
47 |     }
48 | }
49 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/Params.php:
--------------------------------------------------------------------------------
  1 | 
 27 |      */
 28 |     protected array $values = [];
 29 | 
 30 |     /**
 31 |      * Constructs a param request
 32 |      *
 33 |      * @phpstan-param array $values
 34 |      */
 35 |     public function __construct(array $values)
 36 |     {
 37 |         $this->type   = FastCGI::PARAMS;
 38 |         $this->values = $values;
 39 |         $this->setContentData($this->packPayload());
 40 |     }
 41 | 
 42 |     /**
 43 |      * Returns an associative list of parameters
 44 |      *
 45 |      * @phpstan-return array
 46 |      */
 47 |     public function getValues(): array
 48 |     {
 49 |         return $this->values;
 50 |     }
 51 | 
 52 |     /**
 53 |      * {@inheritdoc}
 54 |      * @param static $self
 55 |      */
 56 |     protected static function unpackPayload(Record $self, string $binaryData): void
 57 |     {
 58 |         assert($self instanceof self); // @phpstan-ignore function.alreadyNarrowedType,instanceof.alwaysTrue
 59 |         $currentOffset = 0;
 60 |         do {
 61 |             /** @phpstan-var false|array{nameLengthHigh: int} */
 62 |             $payload = unpack('CnameLengthHigh', $binaryData);
 63 |             if ($payload === false) {
 64 |                 throw new \RuntimeException('Can not unpack data from the binary buffer');
 65 |             }
 66 |             [$nameLengthHigh] = array_values($payload);
 67 |             $isLongName       = ($nameLengthHigh >> 7 == 1);
 68 |             $valueOffset      = $isLongName ? 4 : 1;
 69 | 
 70 |             /** @phpstan-var false|array{valueLengthHigh: int} */
 71 |             $payload = unpack('CvalueLengthHigh', substr($binaryData, $valueOffset));
 72 |             if ($payload === false) {
 73 |                 throw new \RuntimeException('Can not unpack data from the binary buffer');
 74 |             }
 75 |             [$valueLengthHigh] = array_values($payload);
 76 |             $isLongValue       = ($valueLengthHigh >> 7 == 1);
 77 |             $dataOffset        = $valueOffset + ($isLongValue ? 4 : 1);
 78 | 
 79 |             $formatParts = [
 80 |                 $isLongName ? 'NnameLength' : 'CnameLength',
 81 |                 $isLongValue ? 'NvalueLength' : 'CvalueLength',
 82 |             ];
 83 |             $format      = join('/', $formatParts);
 84 | 
 85 |             /** @phpstan-var false|array{nameLength: int, valueLength: int} */
 86 |             $payload = unpack($format, $binaryData);
 87 |             if ($payload === false) {
 88 |                 throw new \RuntimeException('Can not unpack data from the binary buffer');
 89 |             }
 90 |             [$nameLength, $valueLength] = array_values($payload);
 91 | 
 92 |             // Clear top bit for long record
 93 |             $nameLength &= ($isLongName ? 0x7FFFFFFF : 0x7F);
 94 |             $valueLength &= ($isLongValue ? 0x7FFFFFFF : 0x7F);
 95 | 
 96 |             /** @phpstan-var false|array{nameData: string, valueData: string} */
 97 |             $payload = unpack(
 98 |                 "a{$nameLength}nameData/a{$valueLength}valueData",
 99 |                 substr($binaryData, $dataOffset)
100 |             );
101 |             if ($payload === false) {
102 |                 throw new \RuntimeException('Can not unpack data from the binary buffer');
103 |             }
104 |             [$nameData, $valueData] = array_values($payload);
105 | 
106 |             $self->values[$nameData] = $valueData;
107 | 
108 |             $keyValueLength = $dataOffset + $nameLength + $valueLength;
109 |             $binaryData     = substr($binaryData, $keyValueLength);
110 |             $currentOffset += $keyValueLength;
111 |         } while ($currentOffset < $self->getContentLength());
112 |     }
113 | 
114 |     /**
115 |      * {@inheritdoc}
116 |      */
117 |     protected function packPayload(): string
118 |     {
119 |         $payload = '';
120 |         foreach ($this->values as $nameData => $valueData) {
121 |             if ($valueData === null) { // @phpstan-ignore identical.alwaysFalse
122 |                 continue;
123 |             }
124 |             $nameLength  = strlen($nameData);
125 |             $valueLength = strlen((string) $valueData);
126 |             $isLongName  = $nameLength > 127;
127 |             $isLongValue = $valueLength > 127;
128 |             $formatParts = [
129 |                 $isLongName ? 'N' : 'C',
130 |                 $isLongValue ? 'N' : 'C',
131 |                 "a{$nameLength}",
132 |                 "a{$valueLength}",
133 |             ];
134 | 
135 |             $format = join('', $formatParts);
136 | 
137 |             $payload .= pack(
138 |                 $format,
139 |                 $isLongName ? ($nameLength | 0x80000000) : $nameLength,
140 |                 $isLongValue ? ($valueLength | 0x80000000) : $valueLength,
141 |                 $nameData,
142 |                 $valueData
143 |             );
144 |         }
145 | 
146 |         return $payload;
147 |     }
148 | }
149 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/Stderr.php:
--------------------------------------------------------------------------------
 1 | type = FastCGI::STDERR;
27 |         $this->setContentData($contentData);
28 |     }
29 | }
30 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/Stdin.php:
--------------------------------------------------------------------------------
 1 | type = FastCGI::STDIN;
27 |         $this->setContentData($contentData);
28 |     }
29 | }
30 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/Stdout.php:
--------------------------------------------------------------------------------
 1 | type = FastCGI::STDOUT;
27 |         $this->setContentData($contentData);
28 |     }
29 | }
30 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Record/UnknownType.php:
--------------------------------------------------------------------------------
 1 | type      = FastCGI::UNKNOWN_TYPE;
40 |         $this->type1     = $type;
41 |         $this->reserved1 = $reserved;
42 |         $this->setContentData($this->packPayload());
43 |     }
44 | 
45 |     /**
46 |      * Returns the unrecognized type
47 |      */
48 |     public function getUnrecognizedType(): int
49 |     {
50 |         return $this->type1;
51 |     }
52 | 
53 |     /**
54 |      * {@inheritdoc}
55 |      * @param static $self
56 |      */
57 |     public static function unpackPayload(Record $self, string $binaryData): void
58 |     {
59 |         assert($self instanceof self); // @phpstan-ignore function.alreadyNarrowedType,instanceof.alwaysTrue
60 | 
61 |         /** @phpstan-var false|array{type: int, reserved: string} */
62 |         $payload = unpack('Ctype/a7reserved', $binaryData);
63 |         if ($payload === false) {
64 |             throw new \RuntimeException('Can not unpack data from the binary buffer');
65 |         }
66 |         [$self->type1, $self->reserved1] = array_values($payload);
67 |     }
68 | 
69 |     /**
70 |      * {@inheritdoc}
71 |      */
72 |     protected function packPayload(): string
73 |     {
74 |         return pack(
75 |             'Ca7',
76 |             $this->type1,
77 |             $this->reserved1
78 |         );
79 |     }
80 | }
81 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Request.php:
--------------------------------------------------------------------------------
 1 | getBody();
26 |         $beginRequestFrame = new BeginRequest(FastCGI::RESPONDER, $this->keepConn ? FastCGI::KEEP_CONN : 0);
27 |         $paramsFrame       = new Params($this->getParams());
28 |         $paramsEofFrame    = new Params([]);
29 |         if (empty($body)) {
30 |             $message = "{$beginRequestFrame}{$paramsFrame}{$paramsEofFrame}";
31 |         } else {
32 |             $stdinList = [];
33 |             while (true) {
34 |                 $stdinList[] = $stdin = new Stdin($body);
35 |                 $stdinLength = $stdin->getContentLength();
36 |                 if ($stdinLength === strlen($body)) {
37 |                     break;
38 |                 }
39 |                 $body = substr($body, $stdinLength);
40 |             }
41 |             $stdinList[] = new Stdin('');
42 |             $stdin       = implode('', $stdinList);
43 |             $message     = "{$beginRequestFrame}{$paramsFrame}{$paramsEofFrame}{$stdin}";
44 |         }
45 |         return $message;
46 |     }
47 | 
48 |     public function getKeepConn(): bool
49 |     {
50 |         return $this->keepConn;
51 |     }
52 | 
53 |     public function withKeepConn(bool $keepConn): self
54 |     {
55 |         $this->keepConn = $keepConn;
56 |         return $this;
57 |     }
58 | }
59 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/FastCGI/Response.php:
--------------------------------------------------------------------------------
 1 |  $records
22 |      */
23 |     public function __construct(array $records)
24 |     {
25 |         if (!static::verify($records)) {
26 |             throw new \InvalidArgumentException('Bad records');
27 |         }
28 | 
29 |         $body = $error = '';
30 |         foreach ($records as $record) {
31 |             if ($record instanceof Stdout) {
32 |                 if ($record->getContentLength() > 0) {
33 |                     $body .= $record->getContentData();
34 |                 }
35 |             } elseif ($record instanceof Stderr) {
36 |                 if ($record->getContentLength() > 0) {
37 |                     $error .= $record->getContentData();
38 |                 }
39 |             }
40 |         }
41 |         $this->withBody($body)->withError($error);
42 |     }
43 | 
44 |     /**
45 |      * @param array $records
46 |      */
47 |     protected static function verify(array $records): bool
48 |     {
49 |         return !empty($records) && $records[array_key_last($records)] instanceof EndRequest;
50 |     }
51 | }
52 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/MultibyteStringObject.php:
--------------------------------------------------------------------------------
 1 | string);
19 |     }
20 | 
21 |     public function indexOf(string $needle, int $offset = 0, ?string $encoding = null): false|int
22 |     {
23 |         return mb_strpos($this->string, $needle, $offset, $encoding);
24 |     }
25 | 
26 |     public function lastIndexOf(string $needle, int $offset = 0, ?string $encoding = null): false|int
27 |     {
28 |         return mb_strrpos($this->string, $needle, $offset, $encoding);
29 |     }
30 | 
31 |     public function pos(string $needle, int $offset = 0, ?string $encoding = null): false|int
32 |     {
33 |         return mb_strpos($this->string, $needle, $offset, $encoding);
34 |     }
35 | 
36 |     public function rpos(string $needle, int $offset = 0, ?string $encoding = null): false|int
37 |     {
38 |         return mb_strrpos($this->string, $needle, $offset, $encoding);
39 |     }
40 | 
41 |     public function ipos(string $needle, int $offset = 0, ?string $encoding = null): int|false
42 |     {
43 |         return mb_stripos($this->string, $needle, $offset, $encoding);
44 |     }
45 | 
46 |     /**
47 |      * @see https://www.php.net/mb_substr
48 |      */
49 |     public function substr(int $start, ?int $length = null, ?string $encoding = null): static
50 |     {
51 |         return new static(mb_substr($this->string, $start, $length, $encoding)); // @phpstan-ignore new.static
52 |     }
53 | 
54 |     /**
55 |      * {@inheritDoc}
56 |      * @see https://www.php.net/mb_str_split
57 |      */
58 |     public function chunk(int $length = 1): ArrayObject
59 |     {
60 |         return static::detectArrayType(mb_str_split($this->string, $length));
61 |     }
62 | }
63 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/NameResolver.php:
--------------------------------------------------------------------------------
  1 | checkServerUrl($url);
 30 |     }
 31 | 
 32 |     abstract public function join(string $name, string $ip, int $port, array $options = []): bool;
 33 | 
 34 |     abstract public function leave(string $name, string $ip, int $port): bool;
 35 | 
 36 |     abstract public function getCluster(string $name): ?Cluster;
 37 | 
 38 |     public function withFilter(callable $fn): self
 39 |     {
 40 |         $this->filter_fn = $fn;
 41 |         return $this;
 42 |     }
 43 | 
 44 |     public function getFilter()
 45 |     {
 46 |         return $this->filter_fn;
 47 |     }
 48 | 
 49 |     public function hasFilter(): bool
 50 |     {
 51 |         return !empty($this->filter_fn);
 52 |     }
 53 | 
 54 |     /**
 55 |      * return string: final result, non-empty string must be a valid IP address,
 56 |      * and an empty string indicates name lookup failed, and lookup operation will not continue.
 57 |      * return Cluster: has multiple nodes and failover is possible
 58 |      * return false or null: try another name resolver
 59 |      * @return Cluster|false|string|null
 60 |      */
 61 |     public function lookup(string $name)
 62 |     {
 63 |         if ($this->hasFilter() and ($this->getFilter())($name) !== true) {
 64 |             return null;
 65 |         }
 66 |         $cluster = $this->getCluster($name);
 67 |         // lookup failed, terminate execution
 68 |         if ($cluster == null) {
 69 |             return '';
 70 |         }
 71 |         // only one node, cannot retry
 72 |         if ($cluster->count() == 1) {
 73 |             return $cluster->pop();
 74 |         }
 75 |         return $cluster;
 76 |     }
 77 | 
 78 |     /**
 79 |      * !!! The host MUST BE IP ADDRESS
 80 |      */
 81 |     protected function checkServerUrl(string $url)
 82 |     {
 83 |         $info = parse_url($url);
 84 |         if (empty($info['scheme']) or empty($info['host'])) {
 85 |             throw new \RuntimeException("invalid url parameter '{$url}'");
 86 |         }
 87 |         if (!filter_var($info['host'], FILTER_VALIDATE_IP)) {
 88 |             $info['ip'] = gethostbyname($info['host']);
 89 |             if (!filter_var($info['ip'], FILTER_VALIDATE_IP)) {
 90 |                 throw new \RuntimeException("Failed to resolve host '{$info['host']}'");
 91 |             }
 92 |         } else {
 93 |             $info['ip'] = $info['host'];
 94 |         }
 95 |         $baseUrl = $info['scheme'] . '://' . $info['ip'];
 96 |         if (!empty($info['port'])) {
 97 |             $baseUrl .= ":{$info['port']}";
 98 |         }
 99 |         if (!empty($info['path'])) {
100 |             $baseUrl .= rtrim($info['path'], '/');
101 |         }
102 |         $this->baseUrl = $baseUrl;
103 |         $this->info    = $info;
104 |     }
105 | 
106 |     protected function checkResponse(ClientProxy $response): bool
107 |     {
108 |         if ($response->getStatusCode() === Status::OK) {
109 |             return true;
110 |         }
111 | 
112 |         throw new Exception('Http Body: ' . $response->getBody(), $response->getStatusCode());
113 |     }
114 | }
115 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/NameResolver/Cluster.php:
--------------------------------------------------------------------------------
 1 |  65535) {
29 |             throw new Exception("Bad Port [{$port}]");
30 |         }
31 |         if ($weight < 0 or $weight > 100) {
32 |             throw new Exception("Bad Weight [{$weight}]");
33 |         }
34 |         $this->nodes[] = ['host' => $host, 'port' => $port, 'weight' => $weight];
35 |     }
36 | 
37 |     /**
38 |      * @return false|string
39 |      */
40 |     public function pop()
41 |     {
42 |         if (empty($this->nodes)) {
43 |             return false;
44 |         }
45 |         $index = array_rand($this->nodes, 1);
46 |         $node  = $this->nodes[$index];
47 |         unset($this->nodes[$index]);
48 |         return $node;
49 |     }
50 | 
51 |     public function count(): int
52 |     {
53 |         return count($this->nodes);
54 |     }
55 | }
56 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/NameResolver/Consul.php:
--------------------------------------------------------------------------------
 1 |  $this->getServiceId($name, $ip, $port),
33 |             'Name'              => $this->prefix . $name,
34 |             'Address'           => $ip,
35 |             'Port'              => $port,
36 |             'EnableTagOverride' => false,
37 |             'Weights'           => [
38 |                 'Passing' => $weight,
39 |                 'Warning' => 1,
40 |             ],
41 |         ];
42 |         $url = $this->baseUrl . '/v1/agent/service/register';
43 |         $r   = request($url, 'PUT', json_encode($data, JSON_THROW_ON_ERROR));
44 |         return $this->checkResponse($r);
45 |     }
46 | 
47 |     public function leave(string $name, string $ip, int $port): bool
48 |     {
49 |         $url = $this->baseUrl . '/v1/agent/service/deregister/' . $this->getServiceId(
50 |             $name,
51 |             $ip,
52 |             $port
53 |         );
54 |         $r = request($url, 'PUT');
55 |         return $this->checkResponse($r);
56 |     }
57 | 
58 |     public function enableMaintenanceMode(string $name, string $ip, int $port): bool
59 |     {
60 |         $url = $this->baseUrl . '/v1/agent/service/maintenance/' . $this->getServiceId(
61 |             $name,
62 |             $ip,
63 |             $port
64 |         );
65 |         $r = request($url, 'PUT');
66 |         return $this->checkResponse($r);
67 |     }
68 | 
69 |     public function getCluster(string $name): ?Cluster
70 |     {
71 |         $url = $this->baseUrl . '/v1/catalog/service/' . $this->prefix . $name;
72 |         $r   = get($url);
73 |         if (!$this->checkResponse($r)) {
74 |             return null;
75 |         }
76 |         $list = json_decode($r->getBody(), null, 512, JSON_THROW_ON_ERROR);
77 |         if (empty($list)) {
78 |             return null;
79 |         }
80 |         $cluster = new Cluster();
81 |         foreach ($list as $li) {
82 |             $cluster->add($li->ServiceAddress, $li->ServicePort, $li->ServiceWeights->Passing);
83 |         }
84 |         return $cluster;
85 |     }
86 | 
87 |     private function getServiceId(string $name, string $ip, int $port): string
88 |     {
89 |         return $this->prefix . $name . "_{$ip}:{$port}";
90 |     }
91 | }
92 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/NameResolver/Exception.php:
--------------------------------------------------------------------------------
 1 | prefix . $name;
38 | 
39 |         $url = $this->baseUrl . '/nacos/v1/ns/instance?' . http_build_query($params);
40 |         $r   = Coroutine\Http\post($url, []);
41 |         return $this->checkResponse($r);
42 |     }
43 | 
44 |     /**
45 |      * @throws Coroutine\Http\Client\Exception|Exception
46 |      */
47 |     public function leave(string $name, string $ip, int $port): bool
48 |     {
49 |         $params['port']        = $port;
50 |         $params['ip']          = $ip;
51 |         $params['serviceName'] = $this->prefix . $name;
52 | 
53 |         $url = $this->baseUrl . '/nacos/v1/ns/instance?' . http_build_query($params);
54 |         $r   = Coroutine\Http\request($this->baseUrl . '/nacos/v1/ns/instance?' . http_build_query($params), 'DELETE');
55 |         return $this->checkResponse($r);
56 |     }
57 | 
58 |     /**
59 |      * @throws Coroutine\Http\Client\Exception|Exception|\Swoole\Exception
60 |      */
61 |     public function getCluster(string $name): ?Cluster
62 |     {
63 |         $params['serviceName'] = $this->prefix . $name;
64 | 
65 |         $url = $this->baseUrl . '/nacos/v1/ns/instance/list?' . http_build_query($params);
66 |         $r   = Coroutine\Http\get($url);
67 |         if (!$this->checkResponse($r)) {
68 |             return null;
69 |         }
70 |         $result = json_decode($r->getBody(), null, 512, JSON_THROW_ON_ERROR);
71 |         if (empty($result)) {
72 |             return null;
73 |         }
74 |         $cluster = new Cluster();
75 |         foreach ($result->hosts as $node) {
76 |             $cluster->add($node->ip, $node->port, $node->weight);
77 |         }
78 |         return $cluster;
79 |     }
80 | }
81 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/NameResolver/Redis.php:
--------------------------------------------------------------------------------
 1 | serverHost = $this->info['ip'];
33 |         $this->serverPort = $this->info['port'] ?? 6379;
34 |     }
35 | 
36 |     public function join(string $name, string $ip, int $port, array $options = []): bool
37 |     {
38 |         if (($redis = $this->connect()) === false) {
39 |             return false;
40 |         }
41 |         if ($redis->sAdd($this->prefix . $name, $ip . ':' . $port) === false) {
42 |             return false;
43 |         }
44 |         return true;
45 |     }
46 | 
47 |     public function leave(string $name, string $ip, int $port): bool
48 |     {
49 |         if (($redis = $this->connect()) === false) {
50 |             return false;
51 |         }
52 |         if ($redis->sRem($this->prefix . $name, $ip . ':' . $port) === false) {
53 |             return false;
54 |         }
55 |         return true;
56 |     }
57 | 
58 |     public function getCluster(string $name): ?Cluster
59 |     {
60 |         if (($redis = $this->connect()) === false) {
61 |             return null;
62 |         }
63 |         $members = $redis->sMembers($this->prefix . $name);
64 |         if (empty($members)) {
65 |             return null;
66 |         }
67 |         $cluster = new Cluster();
68 |         foreach ($members as $m) {
69 |             [$host, $port] = explode(':', $m);
70 |             $cluster->add($host, intval($port));
71 |         }
72 |         return $cluster;
73 |     }
74 | 
75 |     protected function connect()
76 |     {
77 |         $redis = new \Redis();
78 |         if ($redis->connect($this->serverHost, $this->serverPort) === false) {
79 |             return false;
80 |         }
81 |         return $redis;
82 |     }
83 | }
84 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/ObjectProxy.php:
--------------------------------------------------------------------------------
 1 | __object = $object;
22 |     }
23 | 
24 |     public function __getObject()
25 |     {
26 |         return $this->__object;
27 |     }
28 | 
29 |     public function __get(string $name)
30 |     {
31 |         return $this->__object->{$name};
32 |     }
33 | 
34 |     public function __set(string $name, $value): void
35 |     {
36 |         $this->__object->{$name} = $value;
37 |     }
38 | 
39 |     public function __isset($name)
40 |     {
41 |         return isset($this->__object->{$name});
42 |     }
43 | 
44 |     public function __unset(string $name): void
45 |     {
46 |         unset($this->__object->{$name});
47 |     }
48 | 
49 |     public function __call(string $name, array $arguments)
50 |     {
51 |         return $this->__object->{$name}(...$arguments);
52 |     }
53 | 
54 |     public function __invoke(...$arguments)
55 |     {
56 |         /** @var mixed $object */
57 |         $object = $this->__object;
58 |         return $object(...$arguments);
59 |     }
60 | }
61 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Process/Manager.php:
--------------------------------------------------------------------------------
 1 | setIPCType($ipcType)->setMsgQueueKey($msgQueueKey);
43 |     }
44 | 
45 |     public function add(callable $func, bool $enableCoroutine = false): self
46 |     {
47 |         $this->addBatch(1, $func, $enableCoroutine);
48 |         return $this;
49 |     }
50 | 
51 |     public function addBatch(int $workerNum, callable $func, bool $enableCoroutine = false): self
52 |     {
53 |         for ($i = 0; $i < $workerNum; $i++) {
54 |             $this->startFuncMap[] = [$func, $enableCoroutine];
55 |         }
56 |         return $this;
57 |     }
58 | 
59 |     public function start(): void
60 |     {
61 |         $this->pool = new Pool(count($this->startFuncMap), $this->ipcType, $this->msgQueueKey, false);
62 | 
63 |         $this->pool->on(Constant::EVENT_WORKER_START, function (Pool $pool, int $workerId) {
64 |             [$func, $enableCoroutine] = $this->startFuncMap[$workerId];
65 |             if ($enableCoroutine) {
66 |                 run($func, $pool, $workerId);
67 |             } else {
68 |                 $func($pool, $workerId);
69 |             }
70 |         });
71 | 
72 |         $this->pool->start();
73 |     }
74 | 
75 |     public function setIPCType(int $ipcType): self
76 |     {
77 |         $this->ipcType = $ipcType;
78 |         return $this;
79 |     }
80 | 
81 |     public function getIPCType(): int
82 |     {
83 |         return $this->ipcType;
84 |     }
85 | 
86 |     public function setMsgQueueKey(int $msgQueueKey): self
87 |     {
88 |         $this->msgQueueKey = $msgQueueKey;
89 |         return $this;
90 |     }
91 | 
92 |     public function getMsgQueueKey(): int
93 |     {
94 |         return $this->msgQueueKey;
95 |     }
96 | }
97 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/core/Thread/Runnable.php:
--------------------------------------------------------------------------------
 1 | running = $running;
26 |         $this->id      = $index;
27 |     }
28 | 
29 |     abstract public function run(array $args): void;
30 | 
31 |     protected function isRunning(): bool
32 |     {
33 |         return $this->running->get() === 1;
34 |     }
35 | 
36 |     protected function shutdown(): void
37 |     {
38 |         $this->running->set(0);
39 |     }
40 | }
41 | 


--------------------------------------------------------------------------------
/src/swoole_library/src/functions.php:
--------------------------------------------------------------------------------
  1 | 
 37 |      */
 38 |     public static array $options = [];
 39 | }
 40 | 
 41 | /**
 42 |  * @param array $options
 43 |  */
 44 | function swoole_library_set_options(array $options): void
 45 | {
 46 |     SwooleLibrary::$options = $options;
 47 | }
 48 | 
 49 | function swoole_library_get_options(): array
 50 | {
 51 |     return SwooleLibrary::$options;
 52 | }
 53 | 
 54 | function swoole_library_set_option(string $key, mixed $value): void
 55 | {
 56 |     SwooleLibrary::$options[$key] = $value;
 57 | }
 58 | 
 59 | function swoole_library_get_option(string $key): mixed
 60 | {
 61 |     return SwooleLibrary::$options[$key] ?? null;
 62 | }
 63 | 
 64 | function swoole_string(string $string = ''): Swoole\StringObject
 65 | {
 66 |     return new Swoole\StringObject($string);
 67 | }
 68 | 
 69 | function swoole_mbstring(string $string = ''): Swoole\MultibyteStringObject
 70 | {
 71 |     return new Swoole\MultibyteStringObject($string);
 72 | }
 73 | 
 74 | function swoole_array(array $array = []): Swoole\ArrayObject
 75 | {
 76 |     return new Swoole\ArrayObject($array);
 77 | }
 78 | 
 79 | function swoole_table(int $size, string $fields): Swoole\Table
 80 | {
 81 |     $_fields = swoole_string($fields)->trim()->split(',');
 82 | 
 83 |     $table = new Swoole\Table($size, 0.25);
 84 | 
 85 |     foreach ($_fields as $f) {
 86 |         $_f   = swoole_string($f)->trim()->split(':');
 87 |         $name = $_f->get(0)->trim()->toString();
 88 |         $type = $_f->get(1)->trim();
 89 | 
 90 |         switch ($type) {
 91 |             case 'i':
 92 |             case 'int':
 93 |                 $table->column($name, Swoole\Table::TYPE_INT);
 94 |                 break;
 95 |             case 'f':
 96 |             case 'float':
 97 |                 $table->column($name, Swoole\Table::TYPE_FLOAT);
 98 |                 break;
 99 |             case 's':
100 |             case 'string':
101 |                 if ($_f->count() < 3) {
102 |                     throw new RuntimeException('need to give string length');
103 |                 }
104 |                 $length = (int) $_f->get(2)->trim()->toString();
105 |                 if ($length <= 0) {
106 |                     throw new RuntimeException("invalid string length[{$length}]");
107 |                 }
108 |                 $table->column($name, Swoole\Table::TYPE_STRING, $length);
109 |                 break;
110 |             default:
111 |                 throw new RuntimeException("unknown field type[{$type}]");
112 |         }
113 |     }
114 | 
115 |     if (!$table->create()) {
116 |         throw new RuntimeException('failed to create table');
117 |     }
118 | 
119 |     return $table;
120 | }
121 | 
122 | function swoole_array_list(...$arrray): Swoole\ArrayObject
123 | {
124 |     return new Swoole\ArrayObject($arrray);
125 | }
126 | 
127 | function swoole_array_default_value(array $array, $key, $default_value = null)
128 | {
129 |     return array_key_exists($key, $array) ? $array[$key] : $default_value;
130 | }
131 | 
132 | function swoole_is_in_container()
133 | {
134 |     $mountinfo = file_get_contents('/proc/self/mountinfo');
135 |     return strpos($mountinfo, 'kubepods') > 0 || strpos($mountinfo, 'docker') > 0;
136 | }
137 | 
138 | function swoole_container_cpu_num()
139 | {
140 |     $swoole_cpu_num = intval(getenv('SWOOLE_CPU_NUM'));
141 |     if ($swoole_cpu_num > 0) {
142 |         return $swoole_cpu_num;
143 |     }
144 |     if (!swoole_is_in_container()) {
145 |         return swoole_cpu_num();
146 |     }
147 |     // cgroup v2
148 |     $cpu_max = '/sys/fs/cgroup/cpu.max';
149 |     if (file_exists($cpu_max)) {
150 |         $cpu_max  = file_get_contents($cpu_max);
151 |         $fields   = explode($cpu_max, ' ');
152 |         $quota_us = $fields[0];
153 |         if ($quota_us === 'max') { // @phpstan-ignore identical.alwaysFalse
154 |             return swoole_cpu_num();
155 |         }
156 |         $period_us = $fields[1] ?? 100000;
157 |     } else {
158 |         $quota_us  = file_get_contents('/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us');
159 |         $period_us = file_get_contents('/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_period_us');
160 |     }
161 |     $cpu_num = floatval($quota_us) / floatval($period_us);
162 |     if ($cpu_num < 1) {
163 |         return swoole_cpu_num();
164 |     }
165 |     return intval(floor($cpu_num));
166 | }
167 | 


--------------------------------------------------------------------------------