diff --git a/.github/ISSUE_TEMPLATE/---bug-report.md b/.github/ISSUE_TEMPLATE/---bug-report.md deleted file mode 100644 index ef7296a..0000000 --- a/.github/ISSUE_TEMPLATE/---bug-report.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -name: "\U0001F41B Bug report" -about: Create a report to help us improve -title: "[BUG]" -labels: bug -assignees: sy-records - ---- - -Execute the command and paste the result below. - -Command: `php -v && php --ri swoole` - -```bash -# Paste the result here. -``` - -### Description: - - -### Reproducible codes: - -```php -# Paste your code here. -``` - -> You can also provide tcpdump's packet capture logs, Use a command like this: `tcpdump -i en0 port 1883 -w mqtt.pcap`, Please give me the `mqtt.pcap` file. -> Also remember to change to your network card and port. diff --git a/.github/ISSUE_TEMPLATE/---support-question.md b/.github/ISSUE_TEMPLATE/---support-question.md deleted file mode 100644 index e485e78..0000000 --- a/.github/ISSUE_TEMPLATE/---support-question.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: "\U0001F9D0 Support Question" -about: Ask for help -title: "[QUESTION]" -labels: question -assignees: sy-records - ---- - - diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 0000000..8c35143 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,46 @@ +name: "🐛 Bug report" +description: Create a report to help us improve +labels: + - bug +assignees: + - sy-records +body: + - type: textarea + id: description + attributes: + label: Description + description: Describe the bug and expected behavior. + validations: + required: true + + - type: textarea + id: environment + attributes: + label: Environment + description: | + Execute the command and paste the result below. + + Command: `php -v && php --ri swoole` + render: bash + validations: + required: true + + - type: textarea + id: reproducible-code + attributes: + label: Reproducible codes + description: Provide the minimum code needed to reproduce the issue. + placeholder: "# Paste your code here." + render: php + validations: + required: true + + - type: textarea + id: packet-capture + attributes: + label: Optional packet capture logs + description: | + You can also provide tcpdump packet capture logs. + Example command: `tcpdump -i en0 port 1883 -w mqtt.pcap` + Please change the network card and port to match your environment, then attach `mqtt.pcap`. + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index cababa3..3ba13e0 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1 @@ blank_issues_enabled: false -contact_links: - - name: Simps - the community chat - url: https://discord.gg/u4YAqeh - about: Join Simps community and chat about Simps, Swoole, MQTT... diff --git a/.github/ISSUE_TEMPLATE/support-question.yml b/.github/ISSUE_TEMPLATE/support-question.yml new file mode 100644 index 0000000..ec2ddc8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/support-question.yml @@ -0,0 +1,21 @@ +name: "🧐 Support Question" +description: Ask for help +labels: + - question +assignees: + - sy-records +body: + - type: textarea + id: question + attributes: + label: Question + description: Describe the problem or question you need help with. + validations: + required: true + + - type: textarea + id: context + attributes: + label: Context + description: Add relevant code snippets, logs, or environment details. + diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index eac1bfe..3d49cca 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php-version: [ '8.1', '8.2', '8.3', '8.4' ] + php-version: [ '8.3', '8.4', '8.5' ] max-parallel: 5 fail-fast: false steps: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index af2b0d2..3689713 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,22 +23,20 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] php-version: [ '8.1', '8.2', '8.3', '8.4', '8.5' ] - swoole-version: [ 'v4.8.13', 'v5.1.8', 'v6.1.6', 'master' ] + swoole-version: [ 'v4.8.13', 'v5.1.8-end', 'v6.2.0', 'master' ] exclude: - php-version: '8.5' - swoole-version: 'v6.1.6' - - php-version: '8.5' - swoole-version: 'v5.1.8' + swoole-version: 'v5.1.8-end' - php-version: '8.5' swoole-version: 'v4.8.13' - php-version: '8.4' - swoole-version: 'v5.1.8' + swoole-version: 'v5.1.8-end' - php-version: '8.4' swoole-version: 'v4.8.13' - php-version: '8.3' swoole-version: 'v4.8.13' - php-version: '8.1' - swoole-version: 'v6.1.5' + swoole-version: 'v6.2.0' - php-version: '8.1' swoole-version: 'master' max-parallel: 10 diff --git a/README-CN.md b/README-CN.md index e95ccd9..151ba49 100644 --- a/README-CN.md +++ b/README-CN.md @@ -17,7 +17,7 @@ [![PHP Version](https://img.shields.io/badge/php-%3E=7.1-blue.svg)](https://www.php.net) [![Swoole Version](https://img.shields.io/badge/swoole-%3E=4.4.20-blue.svg)](https://github.com/swoole/swoole-src) -[![GitHub Actions](https://github.com/simps/mqtt/workflows/PHPUnit%20for%20MQTT/badge.svg)](https://github.com/simps/mqtt/actions) +[![PHPUnit for MQTT](https://github.com/simps/mqtt/actions/workflows/test.yml/badge.svg)](https://github.com/simps/mqtt/actions/workflows/test.yml) [![Static Code Analysis](https://github.com/simps/mqtt/actions/workflows/phpstan.yml/badge.svg)](https://github.com/simps/mqtt/actions/workflows/phpstan.yml) [![Gitee Star](https://gitee.com/phpmqtt/mqtt/badge/star.svg?theme=dark)](https://gitee.com/phpmqtt/mqtt/stargazers) [![GitCode Star](https://gitcode.com/simps/mqtt/star/badge.svg)](https://gitcode.com/simps/mqtt/stargazers) diff --git a/README.md b/README.md index e7a9ff5..234a5fe 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Support for MQTT over WebSocket. [![PHP Version](https://img.shields.io/badge/php-%3E=7.1-blue.svg)](https://www.php.net) [![Swoole Version](https://img.shields.io/badge/swoole-%3E=4.4.20-blue.svg)](https://github.com/swoole/swoole-src) -[![GitHub Actions](https://github.com/simps/mqtt/workflows/PHPUnit%20for%20MQTT/badge.svg)](https://github.com/simps/mqtt/actions) +[![PHPUnit for MQTT](https://github.com/simps/mqtt/actions/workflows/test.yml/badge.svg)](https://github.com/simps/mqtt/actions/workflows/test.yml) [![Static Code Analysis](https://github.com/simps/mqtt/actions/workflows/phpstan.yml/badge.svg)](https://github.com/simps/mqtt/actions/workflows/phpstan.yml) [![Gitee Star](https://gitee.com/phpmqtt/mqtt/badge/star.svg?theme=dark)](https://gitee.com/phpmqtt/mqtt/stargazers) [![GitCode Star](https://gitcode.com/simps/mqtt/star/badge.svg)](https://gitcode.com/simps/mqtt/stargazers) diff --git a/composer.json b/composer.json index a6e52aa..6ae2bff 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,7 @@ "phpunit/phpunit": "^8.5", "swoole/ide-helper": ">=4.4.20", "simps/mqtt-cli": "*", - "phpstan/phpstan": "^1.0" + "phpstan/phpstan": "^2.0" }, "suggest": { "ext-swoole": "The ext-swoole >= v4.4.20 or v4.5.3 needs to be loaded when using the MQTT Client." diff --git a/examples/bootstrap.php b/examples/bootstrap.php index 200ca44..c72bd22 100644 --- a/examples/bootstrap.php +++ b/examples/bootstrap.php @@ -31,13 +31,14 @@ const SWOOLE_MQTT_CONFIG = [ 'open_mqtt_protocol' => true, 'package_max_length' => 2 * 1024 * 1024, - 'connect_timeout' => 5.0, - 'write_timeout' => 5.0, - 'read_timeout' => 5.0, + 'connect_timeout' => 10.0, + 'write_timeout' => 10.0, + 'read_timeout' => 10.0, ]; const SIMPS_MQTT_LOCAL_HOST = '127.0.0.1'; const SIMPS_MQTT_REMOTE_HOST = 'broker.emqx.io'; +const SIMPS_MQTT_MOSQUITTO = 'test.mosquitto.org'; const SIMPS_MQTT_PORT = 1883; const SIMPS_MQTT_OVER_WEBSOCKET_PORT = 8083; diff --git a/examples/ssl_ca.php b/examples/ssl_ca.php index 61af0ea..76734ed 100644 --- a/examples/ssl_ca.php +++ b/examples/ssl_ca.php @@ -34,7 +34,7 @@ ->setSwooleConfig($swooleConfig) ->setSockType(SWOOLE_SOCK_TCP | SWOOLE_SSL); - $client = new Client('test.mosquitto.org', 8883, $config); + $client = new Client(SIMPS_MQTT_MOSQUITTO, 8883, $config); $client->connect(); $topics['testtopic/#'] = 0; $client->subscribe($topics); diff --git a/examples/ssl_ca_client.php b/examples/ssl_ca_client.php index 6acef3f..2ad4b0a 100644 --- a/examples/ssl_ca_client.php +++ b/examples/ssl_ca_client.php @@ -36,7 +36,7 @@ ->setSwooleConfig($swooleConfig) ->setSockType(SWOOLE_SOCK_TCP | SWOOLE_SSL); - $client = new Client('test.mosquitto.org', 8884, $config); + $client = new Client(SIMPS_MQTT_MOSQUITTO, 8884, $config); $client->connect(); $topics['testtopic/#'] = 0; $client->subscribe($topics); diff --git a/phpstan.neon b/phpstan.neon index 2a891f6..e9c7737 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,9 @@ +includes: + - phar://phpstan.phar/conf/bleedingEdge.neon + parameters: level: 6 inferPrivatePropertyTypeFromConstructor: true - checkMissingIterableValueType: false bootstrapFiles: - examples/bootstrap.php paths: diff --git a/src/BaseClient.php b/src/BaseClient.php index bf6c20c..b688e33 100644 --- a/src/BaseClient.php +++ b/src/BaseClient.php @@ -20,6 +20,14 @@ use Swoole\Coroutine; use Swoole\Coroutine\Http\Client as WebSocketClient; +/** + * @phpstan-import-type ConnectData from \Simps\MQTT\PhpStanTypes + * @phpstan-import-type MqttProperties from \Simps\MQTT\PhpStanTypes + * @phpstan-import-type PacketData from \Simps\MQTT\PhpStanTypes + * @phpstan-import-type SubscribeTopics from \Simps\MQTT\PhpStanTypes + * @phpstan-import-type UnsubscribeTopics from \Simps\MQTT\PhpStanTypes + * @phpstan-import-type WillData from \Simps\MQTT\PhpStanTypes + */ abstract class BaseClient { public const COROUTINE_CLIENT_TYPE = 1; @@ -34,7 +42,7 @@ abstract class BaseClient /** @var int */ private $messageId = 0; - /** @var array */ + /** @var ConnectData */ private $connectData = []; /** @var string */ @@ -155,6 +163,10 @@ public function getSsl(): bool return $this->ssl; } + /** + * @param ConnectData $connectData + * @return $this + */ public function setConnectData(array $connectData): self { $this->connectData = $connectData; @@ -163,7 +175,7 @@ public function setConnectData(array $connectData): self } /** - * @return null|array|string + * @return ($key is null ? ConnectData : mixed|null) */ public function getConnectData(?string $key = null) { @@ -238,6 +250,9 @@ protected function handleException(): void throw new ConnectException($errMsg, $this->client->errCode); } + /** + * @param array{}|WillData $will + */ public function connect(bool $clean = true, array $will = []) { $data = [ @@ -263,6 +278,10 @@ public function connect(bool $clean = true, array $will = []) return $this->send($data); } + /** + * @param SubscribeTopics $topics + * @param MqttProperties $properties + */ public function subscribe(array $topics, array $properties = []) { return $this->send([ @@ -273,6 +292,10 @@ public function subscribe(array $topics, array $properties = []) ]); } + /** + * @param UnsubscribeTopics $topics + * @param MqttProperties $properties + */ public function unSubscribe(array $topics, array $properties = []) { return $this->send([ @@ -283,6 +306,9 @@ public function unSubscribe(array $topics, array $properties = []) ]); } + /** + * @param MqttProperties $properties + */ public function publish( string $topic, string $message, @@ -329,6 +355,9 @@ public function ping(bool $response = true) return $this->send(['type' => Protocol\Types::PINGREQ], $response); } + /** + * @param MqttProperties $properties + */ public function close(int $code = ReasonCode::NORMAL_DISCONNECTION, array $properties = []): bool { $this->send(['type' => Protocol\Types::DISCONNECT, 'code' => $code, 'properties' => $properties], false); @@ -336,6 +365,9 @@ public function close(int $code = ReasonCode::NORMAL_DISCONNECTION, array $prope return $this->client->close(); } + /** + * @param MqttProperties $properties + */ public function auth(int $code = ReasonCode::SUCCESS, array $properties = []) { return $this->send(['type' => Protocol\Types::AUTH, 'code' => $code, 'properties' => $properties]); @@ -343,6 +375,9 @@ public function auth(int $code = ReasonCode::SUCCESS, array $properties = []) abstract protected function reConnect(): void; + /** + * @param PacketData $data + */ abstract public function send(array $data, bool $response = true); abstract public function recv(); diff --git a/src/Client.php b/src/Client.php index cdbea82..0410e3c 100644 --- a/src/Client.php +++ b/src/Client.php @@ -79,7 +79,7 @@ public function recv() $this->connect($this->getConnectData('clean_session') ?? true, $this->getConnectData('will') ?? []); } elseif ($response === false && $this->getClient()->errCode !== SOCKET_ETIMEDOUT) { $this->handleException(); - } elseif (is_string($response) && strlen($response) !== 0) { + } elseif (is_string($response)) { $this->handleVerbose($response); return $this->getConfig()->isMQTT5() ? Protocol\V5::unpack($response) : Protocol\V3::unpack($response); diff --git a/src/Config/AbstractConfig.php b/src/Config/AbstractConfig.php index d599d10..de3edce 100644 --- a/src/Config/AbstractConfig.php +++ b/src/Config/AbstractConfig.php @@ -12,8 +12,14 @@ */ namespace Simps\MQTT\Config; +/** + * @phpstan-import-type ArrayMap from \Simps\MQTT\PhpStanTypes + */ abstract class AbstractConfig { + /** + * @param ArrayMap $data + */ public function __construct(array $data = []) { foreach ($data as $k => $v) { diff --git a/src/Config/ClientConfig.php b/src/Config/ClientConfig.php index 4675896..f813b13 100644 --- a/src/Config/ClientConfig.php +++ b/src/Config/ClientConfig.php @@ -14,17 +14,22 @@ use Simps\MQTT\Protocol\ProtocolInterface; +/** + * @phpstan-import-type ArrayMap from \Simps\MQTT\PhpStanTypes + * @phpstan-import-type StringMap from \Simps\MQTT\PhpStanTypes + * @phpstan-import-type MqttProperties from \Simps\MQTT\PhpStanTypes + */ class ClientConfig extends AbstractConfig { /** @var string */ protected $clientId = ''; - /** @var array */ + /** @var ArrayMap */ protected $swooleConfig = [ 'open_mqtt_protocol' => true, ]; - /** @var array */ + /** @var StringMap */ protected $headers = [ 'Sec-Websocket-Protocol' => 'mqtt', ]; @@ -44,7 +49,7 @@ class ClientConfig extends AbstractConfig /** @var int */ protected $protocolLevel = ProtocolInterface::MQTT_PROTOCOL_LEVEL_3_1_1; - /** @var array */ + /** @var MqttProperties */ protected $properties = []; /** @var int */ @@ -71,11 +76,17 @@ public function setClientId(string $clientId): self return $this; } + /** + * @return ArrayMap + */ public function getSwooleConfig(): array { return $this->swooleConfig; } + /** + * @param ArrayMap $config + */ public function setSwooleConfig(array $config): self { $this->swooleConfig = array_merge($this->swooleConfig, $config); @@ -83,11 +94,17 @@ public function setSwooleConfig(array $config): self return $this; } + /** + * @return StringMap + */ public function getHeaders(): array { return $this->headers; } + /** + * @param StringMap $headers + */ public function setHeaders(array $headers): self { $this->headers = array_merge($this->headers, $headers); @@ -159,11 +176,17 @@ public function setProtocolLevel(int $protocolLevel): self return $this; } + /** + * @return MqttProperties + */ public function getProperties(): array { return $this->properties; } + /** + * @param MqttProperties $properties + */ public function setProperties(array $properties): self { $this->properties = $properties; diff --git a/src/Hex/ReasonCode.php b/src/Hex/ReasonCode.php index fd344bd..886d8ff 100644 --- a/src/Hex/ReasonCode.php +++ b/src/Hex/ReasonCode.php @@ -14,6 +14,7 @@ /** * @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901031 + * @phpstan-import-type IntStringMap from \Simps\MQTT\PhpStanTypes */ abstract class ReasonCode { @@ -108,7 +109,7 @@ abstract class ReasonCode public const WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED = 0xA2; /** - * @var array + * @var IntStringMap * @see https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901079 */ protected static $reasonPhrases = [ @@ -155,13 +156,16 @@ abstract class ReasonCode self::PACKET_IDENTIFIER_NOT_FOUND => 'Packet Identifier not found', ]; - /** @var array */ + /** @var IntStringMap */ protected static $qosReasonPhrases = [ self::GRANTED_QOS_0 => 'Granted QoS 0', self::GRANTED_QOS_1 => 'Granted QoS 1', self::GRANTED_QOS_2 => 'Granted QoS 2', ]; + /** + * @return IntStringMap + */ public static function getReasonPhrases(bool $isQos = false): array { if ($isQos) { diff --git a/src/Message/AbstractMessage.php b/src/Message/AbstractMessage.php index 0b51d57..e1dd3d7 100644 --- a/src/Message/AbstractMessage.php +++ b/src/Message/AbstractMessage.php @@ -14,12 +14,20 @@ use Simps\MQTT\Protocol\ProtocolInterface; +/** + * @phpstan-import-type MessageData from \Simps\MQTT\PhpStanTypes + * @phpstan-import-type MqttProperties from \Simps\MQTT\PhpStanTypes + */ abstract class AbstractMessage { protected $protocolLevel = ProtocolInterface::MQTT_PROTOCOL_LEVEL_3_1_1; + /** @var MqttProperties */ protected $properties = []; + /** + * @param MessageData $data + */ public function __construct(array $data = []) { foreach ($data as $k => $v) { @@ -48,11 +56,17 @@ public function setProtocolLevel(int $protocolLevel): self return $this; } + /** + * @return MqttProperties + */ public function getProperties(): array { return $this->properties; } + /** + * @param MqttProperties $properties + */ public function setProperties(array $properties): self { $this->properties = $properties; @@ -67,6 +81,9 @@ public function isMQTT5(): bool abstract public function getContents(bool $getArray = false); + /** + * @return MessageData + */ public function toArray(): array { return $this->getContents(true); diff --git a/src/Message/SubAck.php b/src/Message/SubAck.php index f9cfef6..5389d97 100644 --- a/src/Message/SubAck.php +++ b/src/Message/SubAck.php @@ -16,10 +16,14 @@ use Simps\MQTT\Protocol\V3; use Simps\MQTT\Protocol\V5; +/** + * @phpstan-import-type IntList from \Simps\MQTT\PhpStanTypes + */ class SubAck extends AbstractMessage { protected $messageId = 0; + /** @var IntList */ protected $codes = []; public function getMessageId(): int @@ -34,11 +38,17 @@ public function setMessageId(int $messageId): self return $this; } + /** + * @return IntList + */ public function getCodes(): array { return $this->codes; } + /** + * @param IntList $codes + */ public function setCodes(array $codes): self { $this->codes = $codes; diff --git a/src/Message/UnSubAck.php b/src/Message/UnSubAck.php index 31bdfe8..18b3330 100644 --- a/src/Message/UnSubAck.php +++ b/src/Message/UnSubAck.php @@ -16,10 +16,14 @@ use Simps\MQTT\Protocol\V3; use Simps\MQTT\Protocol\V5; +/** + * @phpstan-import-type IntList from \Simps\MQTT\PhpStanTypes + */ class UnSubAck extends AbstractMessage { protected $messageId = 0; + /** @var IntList */ protected $codes = []; public function getMessageId(): int @@ -34,11 +38,17 @@ public function setMessageId(int $messageId): self return $this; } + /** + * @return IntList + */ public function getCodes(): array { return $this->codes; } + /** + * @param IntList $codes + */ public function setCodes(array $codes): self { $this->codes = $codes; diff --git a/src/Packet/Pack.php b/src/Packet/Pack.php index 0dd0e61..ca04977 100644 --- a/src/Packet/Pack.php +++ b/src/Packet/Pack.php @@ -17,8 +17,14 @@ use Simps\MQTT\Protocol\Types; use Simps\MQTT\Tools\PackTool; +/** + * @phpstan-import-type PacketData from \Simps\MQTT\PhpStanTypes + */ class Pack { + /** + * @param PacketData $array + */ public static function connect(array $array): string { $body = PackTool::string($array['protocol_name']) . chr($array['protocol_level']); @@ -65,6 +71,9 @@ public static function connect(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function connAck(array $array): string { $body = !empty($array['session_present']) ? chr(1) : chr(0); @@ -75,6 +84,9 @@ public static function connAck(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function publish(array $array): string { $body = PackTool::string($array['topic']); @@ -90,6 +102,9 @@ public static function publish(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function subscribe(array $array): string { $id = $array['message_id']; @@ -103,6 +118,9 @@ public static function subscribe(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function subAck(array $array): string { $body = PackTool::shortInt($array['message_id']) . call_user_func_array( @@ -114,6 +132,9 @@ public static function subAck(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function unSubscribe(array $array): string { $body = PackTool::shortInt($array['message_id']); diff --git a/src/Packet/PackV5.php b/src/Packet/PackV5.php index a962cd4..4953b41 100644 --- a/src/Packet/PackV5.php +++ b/src/Packet/PackV5.php @@ -17,8 +17,14 @@ use Simps\MQTT\Protocol\Types; use Simps\MQTT\Tools\PackTool; +/** + * @phpstan-import-type PacketData from \Simps\MQTT\PhpStanTypes + */ class PackV5 { + /** + * @param PacketData $array + */ public static function connect(array $array): string { $body = PackTool::string($array['protocol_name']) . chr($array['protocol_level']); @@ -68,6 +74,9 @@ public static function connect(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function connAck(array $array): string { $body = !empty($array['session_present']) ? chr(1) : chr(0); @@ -82,6 +91,9 @@ public static function connAck(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function publish(array $array): string { $body = PackTool::string($array['topic']); @@ -101,6 +113,9 @@ public static function publish(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function subscribe(array $array): string { $body = PackTool::shortInt($array['message_id']); @@ -132,6 +147,9 @@ public static function subscribe(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function subAck(array $array): string { $body = PackTool::shortInt($array['message_id']); @@ -148,6 +166,9 @@ public static function subAck(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function unSubscribe(array $array): string { $body = PackTool::shortInt($array['message_id']); @@ -163,6 +184,9 @@ public static function unSubscribe(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function unSubAck(array $array): string { $body = PackTool::shortInt($array['message_id']); @@ -179,6 +203,9 @@ public static function unSubAck(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function disconnect(array $array): string { $code = !empty($array['code']) ? $array['code'] : ReasonCode::NORMAL_DISCONNECTION; @@ -192,6 +219,9 @@ public static function disconnect(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function genReasonPhrase(array $array): string { $body = PackTool::shortInt($array['message_id']); @@ -210,6 +240,9 @@ public static function genReasonPhrase(array $array): string return $head . $body; } + /** + * @param PacketData $array + */ public static function auth(array $array): string { $code = !empty($array['code']) ? $array['code'] : ReasonCode::SUCCESS; diff --git a/src/Packet/UnPack.php b/src/Packet/UnPack.php index 302b1cf..8e8d2b9 100644 --- a/src/Packet/UnPack.php +++ b/src/Packet/UnPack.php @@ -15,8 +15,14 @@ use Simps\MQTT\Protocol\Types; use Simps\MQTT\Tools\UnPackTool; +/** + * @phpstan-import-type PacketData from \Simps\MQTT\PhpStanTypes + */ class UnPack { + /** + * @return PacketData + */ public static function connect(string $remaining): array { $protocolName = UnPackTool::string($remaining); @@ -66,11 +72,17 @@ public static function connect(string $remaining): array return $package; } + /** + * @return PacketData + */ public static function connAck(string $remaining): array { return ['type' => Types::CONNACK, 'session_present' => ord($remaining[0]) & 0x01, 'code' => ord($remaining[1])]; } + /** + * @return PacketData + */ public static function publish(int $dup, int $qos, int $retain, string $remaining): array { $topic = UnPackTool::string($remaining); @@ -92,6 +104,9 @@ public static function publish(int $dup, int $qos, int $retain, string $remainin return $package; } + /** + * @return PacketData + */ public static function subscribe(string $remaining): array { $messageId = UnPackTool::shortInt($remaining); @@ -105,6 +120,9 @@ public static function subscribe(string $remaining): array return ['type' => Types::SUBSCRIBE, 'message_id' => $messageId, 'topics' => $topics]; } + /** + * @return PacketData + */ public static function subAck(string $remaining): array { $messageId = UnPackTool::shortInt($remaining); @@ -113,6 +131,9 @@ public static function subAck(string $remaining): array return ['type' => Types::SUBACK, 'message_id' => $messageId, 'codes' => array_values($codes)]; } + /** + * @return PacketData + */ public static function unSubscribe(string $remaining): array { $messageId = UnPackTool::shortInt($remaining); diff --git a/src/Packet/UnPackV5.php b/src/Packet/UnPackV5.php index 74277e3..6799155 100644 --- a/src/Packet/UnPackV5.php +++ b/src/Packet/UnPackV5.php @@ -17,8 +17,14 @@ use Simps\MQTT\Protocol\Types; use Simps\MQTT\Tools\UnPackTool; +/** + * @phpstan-import-type PacketData from \Simps\MQTT\PhpStanTypes + */ class UnPackV5 { + /** + * @return PacketData + */ public static function connect(string $remaining): array { $protocolName = UnPackTool::string($remaining); @@ -88,6 +94,9 @@ public static function connect(string $remaining): array return $package; } + /** + * @return PacketData + */ public static function connAck(string $remaining): array { $sessionPresent = ord($remaining[0]) & 0x01; @@ -108,6 +117,9 @@ public static function connAck(string $remaining): array return $package; } + /** + * @return PacketData + */ public static function publish(int $dup, int $qos, int $retain, string $remaining): array { $topic = UnPackTool::string($remaining); @@ -134,6 +146,9 @@ public static function publish(int $dup, int $qos, int $retain, string $remainin return $package; } + /** + * @return PacketData + */ public static function subscribe(string $remaining): array { $messageId = UnPackTool::shortInt($remaining); @@ -165,6 +180,9 @@ public static function subscribe(string $remaining): array return $package; } + /** + * @return PacketData + */ public static function subAck(string $remaining): array { $messageId = UnPackTool::shortInt($remaining); @@ -185,6 +203,9 @@ public static function subAck(string $remaining): array return $package; } + /** + * @return PacketData + */ public static function unSubscribe(string $remaining): array { $messageId = UnPackTool::shortInt($remaining); @@ -209,6 +230,9 @@ public static function unSubscribe(string $remaining): array return $package; } + /** + * @return PacketData + */ public static function unSubAck(string $remaining): array { $messageId = UnPackTool::shortInt($remaining); @@ -229,6 +253,9 @@ public static function unSubAck(string $remaining): array return $package; } + /** + * @return PacketData + */ public static function disconnect(string $remaining): array { if (isset($remaining[0])) { @@ -253,6 +280,9 @@ public static function disconnect(string $remaining): array return $package; } + /** + * @return PacketData + */ public static function getReasonCode(int $type, string $remaining): array { $messageId = UnPackTool::shortInt($remaining); @@ -281,6 +311,9 @@ public static function getReasonCode(int $type, string $remaining): array return $package; } + /** + * @return PacketData + */ public static function auth(string $remaining): array { if (isset($remaining[0])) { diff --git a/src/PhpStanTypes.php b/src/PhpStanTypes.php new file mode 100644 index 0000000..1078614 --- /dev/null +++ b/src/PhpStanTypes.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, + * please view the LICENSE file that was distributed with this source code. + */ +namespace Simps\MQTT; + +/** + * @phpstan-type ArrayMap array + * @phpstan-type StringMap array + * @phpstan-type IntList list + * @phpstan-type IntStringMap array + * @phpstan-type MqttProperties ArrayMap + * @phpstan-type ConnectData ArrayMap + * @phpstan-type MessageData ArrayMap + * @phpstan-type PacketData ArrayMap + * @phpstan-type WillData array{ + * topic: string, + * message?: string, + * qos?: int, + * retain?: int, + * properties?: MqttProperties + * } + * @phpstan-type SubscribeOptions array{ + * qos?: int, + * no_local?: bool, + * retain_as_published?: bool, + * retain_handling?: int + * } + * @phpstan-type SubscribeTopics array + * @phpstan-type UnsubscribeTopics list + */ +final class PhpStanTypes +{ + private function __construct() + { + } +} diff --git a/src/Property/PackProperty.php b/src/Property/PackProperty.php index 4a4b221..ded0917 100644 --- a/src/Property/PackProperty.php +++ b/src/Property/PackProperty.php @@ -15,8 +15,14 @@ use Simps\MQTT\Hex\Property; use Simps\MQTT\Tools\PackTool; +/** + * @phpstan-import-type MqttProperties from \Simps\MQTT\PhpStanTypes + */ class PackProperty { + /** + * @param MqttProperties $data + */ public static function connect(array $data): string { $tmpBody = ''; @@ -53,6 +59,9 @@ public static function connect(array $data): string return PackTool::genProperties($tmpBody); } + /** + * @param MqttProperties $data + */ public static function willProperties(array $data): string { $tmpBody = ''; @@ -85,6 +94,9 @@ public static function willProperties(array $data): string return PackTool::genProperties($tmpBody); } + /** + * @param MqttProperties $data + */ public static function connAck(array $data): string { $tmpBody = ''; @@ -129,6 +141,9 @@ public static function connAck(array $data): string return PackTool::genProperties($tmpBody); } + /** + * @param MqttProperties $data + */ public static function publish(array $data): string { $tmpBody = ''; @@ -166,6 +181,9 @@ public static function publish(array $data): string return PackTool::genProperties($tmpBody); } + /** + * @param MqttProperties $data + */ public static function pubAndSub(array $data): string { $tmpBody = ''; @@ -189,6 +207,9 @@ public static function pubAndSub(array $data): string return PackTool::genProperties($tmpBody); } + /** + * @param MqttProperties $data + */ public static function subscribe(array $data): string { $tmpBody = ''; @@ -212,6 +233,9 @@ public static function subscribe(array $data): string return PackTool::genProperties($tmpBody); } + /** + * @param MqttProperties $data + */ public static function unSubscribe(array $data): string { $tmpBody = ''; @@ -225,6 +249,9 @@ public static function unSubscribe(array $data): string return PackTool::genProperties($tmpBody); } + /** + * @param MqttProperties $data + */ public static function disConnect(array $data): string { $tmpBody = ''; @@ -252,6 +279,9 @@ public static function disConnect(array $data): string return PackTool::genProperties($tmpBody); } + /** + * @param MqttProperties $data + */ public static function auth(array $data): string { $tmpBody = ''; diff --git a/src/Property/UnPackProperty.php b/src/Property/UnPackProperty.php index ffec78b..59ab599 100644 --- a/src/Property/UnPackProperty.php +++ b/src/Property/UnPackProperty.php @@ -16,8 +16,14 @@ use Simps\MQTT\Hex\Property; use Simps\MQTT\Tools\UnPackTool; +/** + * @phpstan-import-type MqttProperties from \Simps\MQTT\PhpStanTypes + */ class UnPackProperty { + /** + * @return MqttProperties + */ public static function connect(int $length, string &$remaining): array { $properties = []; @@ -66,6 +72,9 @@ public static function connect(int $length, string &$remaining): array return $properties; } + /** + * @return MqttProperties + */ public static function willProperties(int $length, string &$remaining): array { $properties = []; @@ -109,6 +118,9 @@ public static function willProperties(int $length, string &$remaining): array return $properties; } + /** + * @return MqttProperties + */ public static function connAck(int $length, string &$remaining): array { $properties = []; @@ -165,6 +177,9 @@ public static function connAck(int $length, string &$remaining): array return $properties; } + /** + * @return MqttProperties + */ public static function publish(int $length, string &$remaining): array { $properties = []; @@ -216,6 +231,9 @@ public static function publish(int $length, string &$remaining): array return $properties; } + /** + * @return MqttProperties + */ public static function pubAndSub(int $length, string &$remaining): array { $properties = []; @@ -248,6 +266,9 @@ public static function pubAndSub(int $length, string &$remaining): array return $properties; } + /** + * @return MqttProperties + */ public static function subscribe(int $length, string &$remaining): array { $properties = []; @@ -280,6 +301,9 @@ public static function subscribe(int $length, string &$remaining): array return $properties; } + /** + * @return MqttProperties + */ public static function unSubscribe(int $length, string &$remaining): array { $properties = []; @@ -306,6 +330,9 @@ public static function unSubscribe(int $length, string &$remaining): array return $properties; } + /** + * @return MqttProperties + */ public static function disConnect(int $length, string &$remaining): array { $properties = []; @@ -343,6 +370,9 @@ public static function disConnect(int $length, string &$remaining): array return $properties; } + /** + * @return MqttProperties + */ public static function auth(int $length, string &$remaining): array { $properties = []; diff --git a/src/Protocol/ProtocolInterface.php b/src/Protocol/ProtocolInterface.php index b652f28..07cf10c 100644 --- a/src/Protocol/ProtocolInterface.php +++ b/src/Protocol/ProtocolInterface.php @@ -12,6 +12,9 @@ */ namespace Simps\MQTT\Protocol; +/** + * @phpstan-import-type PacketData from \Simps\MQTT\PhpStanTypes + */ interface ProtocolInterface { public const MQTT_PROTOCOL_LEVEL_3_1 = 3; @@ -44,7 +47,13 @@ interface ProtocolInterface public const MQTT_SESSION_PRESENT_1 = 1; + /** + * @param PacketData $array + */ public static function pack(array $array): string; + /** + * @return PacketData + */ public static function unpack(string $data): array; } diff --git a/src/Protocol/Types.php b/src/Protocol/Types.php index 3676c40..891a547 100644 --- a/src/Protocol/Types.php +++ b/src/Protocol/Types.php @@ -12,6 +12,9 @@ */ namespace Simps\MQTT\Protocol; +/** + * @phpstan-import-type IntStringMap from \Simps\MQTT\PhpStanTypes + */ class Types { public const CONNECT = 1; // Client request to connect to Server @@ -44,7 +47,7 @@ class Types public const AUTH = 15; // Authentication exchange - /** @var array */ + /** @var IntStringMap */ protected static $types = [ self::CONNECT => 'connect', self::CONNACK => 'connack', @@ -62,6 +65,9 @@ class Types self::AUTH => 'auth', ]; + /** + * @return IntStringMap + */ public static function getTypes(): array { return static::$types; diff --git a/src/Protocol/V3.php b/src/Protocol/V3.php index 9979221..b4c1e82 100644 --- a/src/Protocol/V3.php +++ b/src/Protocol/V3.php @@ -21,8 +21,14 @@ use Throwable; use TypeError; +/** + * @phpstan-import-type PacketData from \Simps\MQTT\PhpStanTypes + */ class V3 implements ProtocolInterface { + /** + * @param PacketData $array + */ public static function pack(array $array): string { try { @@ -76,6 +82,9 @@ public static function pack(array $array): string return $package; } + /** + * @return PacketData + */ public static function unpack(string $data): array { try { diff --git a/src/Protocol/V5.php b/src/Protocol/V5.php index b80c6de..4c217c8 100644 --- a/src/Protocol/V5.php +++ b/src/Protocol/V5.php @@ -18,8 +18,14 @@ use Simps\MQTT\Tools\PackTool; use Simps\MQTT\Tools\UnPackTool; +/** + * @phpstan-import-type PacketData from \Simps\MQTT\PhpStanTypes + */ class V5 implements ProtocolInterface { + /** + * @param PacketData $array + */ public static function pack(array $array): string { $type = $array['type']; @@ -68,6 +74,9 @@ public static function pack(array $array): string return $package; } + /** + * @return PacketData + */ public static function unpack(string $data): array { $type = UnPackTool::getType($data); diff --git a/tests/Unit/ClientTest.php b/tests/Unit/ClientTest.php index 37f3a24..5543039 100644 --- a/tests/Unit/ClientTest.php +++ b/tests/Unit/ClientTest.php @@ -40,19 +40,20 @@ public function testBase64() { $topic = 'simps-mqtt/test/base64'; $base64 = base64_encode(file_get_contents(TESTS_DIR . '/files/wechat.jpg')); - $config = getTestConnectConfig(); - $config->setSwooleConfig(['read_timeout' => 10.0]); - $client = new MQTTClient('test.mosquitto.org', SIMPS_MQTT_PORT, $config); + $client = new MQTTClient(SIMPS_MQTT_REMOTE_HOST, SIMPS_MQTT_PORT, getTestConnectConfig()); $client->connect(false); $client->subscribe([$topic => 0]); Coroutine::create(function () use ($topic, $base64) { - $client = new MQTTClient('test.mosquitto.org', SIMPS_MQTT_PORT, getTestConnectConfig()); + $client = new MQTTClient(SIMPS_MQTT_REMOTE_HOST, SIMPS_MQTT_PORT, getTestConnectConfig()); $client->connect(); $client->publish($topic, $base64); }); $buffer = $client->recv(); + if (empty($buffer)) { + $buffer = $client->recv(); + } $this->assertSame(Types::PUBLISH, $buffer['type']); $this->assertSame($topic, $buffer['topic']); $this->assertSame(strlen($base64), strlen($buffer['message'])); diff --git a/tests/Unit/MessageTest.php b/tests/Unit/MessageTest.php index 428b08b..f1178b5 100644 --- a/tests/Unit/MessageTest.php +++ b/tests/Unit/MessageTest.php @@ -40,7 +40,6 @@ public function testPublishMessage() 'The results of getContents and toString should be the same' ); $this->assertIsArray($message->getContents(true)); - $this->assertIsArray($message->toArray()); $this->assertEquals( $message->toArray(), $message->getContents(true), @@ -58,7 +57,6 @@ public function testPingRespMessage() ); $this->assertIsArray($message->getContents(true)); $this->assertEquals(Types::PINGRESP, $message->getContents(true)['type']); - $this->assertIsArray($message->toArray()); $this->assertEquals( $message->toArray(), $message->getContents(true), @@ -74,7 +72,6 @@ public function testWillMessage() ->setRetain(ProtocolInterface::MQTT_RETAIN_0) ->setMessage('this is content'); $this->assertIsArray($message->getContents(true)); - $this->assertIsArray($message->toArray()); $this->assertEquals( $message->toArray(), $message->getContents(true),