Compare commits

19 Commits

Author SHA1 Message Date
9607f69e24 Merge branch 'release/1.2.2' 2025-05-15 20:01:42 +08:00
6d3709da51 1.2.2 2025-05-15 20:01:31 +08:00
1456b21f34 加入错误码 2025-05-15 20:01:03 +08:00
7343267d3c Merge branch 'release/1.2.1' 2025-05-15 17:53:37 +08:00
430af8aede Merge tag '1.2.1' into develop 2025-05-15 17:53:37 +08:00
9028a8c59d 1.2.1 2025-05-15 17:53:26 +08:00
daefbe884c 增加用户的过期时间 2025-05-15 17:52:55 +08:00
9ad385e044 Merge branch 'release/1.1.2' 2025-05-15 16:34:04 +08:00
9b926634cf Merge tag '1.1.2' into develop 2025-05-15 16:34:04 +08:00
320739411a 1.1.2 2025-05-15 16:33:52 +08:00
cffc90dfc9 更新创建和修改参数 2025-05-15 16:32:42 +08:00
5b84406652 Merge branch 'release/1.1.1' 2025-05-13 23:49:39 +08:00
3c5020b80b Merge tag '1.1.1' into develop 2025-05-13 23:49:39 +08:00
e50eed84a2 1.1.1 2025-05-13 23:49:29 +08:00
41da8f6aee 增加回调地址设置 2025-05-13 23:48:58 +08:00
d9cf1f12b4 Merge tag '1.1.0' into develop 2025-05-13 22:00:09 +08:00
d37f452946 Merge branch 'release/1.1.0' 2025-05-13 22:00:08 +08:00
ef5eddbc8d 1.1.0 2025-05-13 21:59:57 +08:00
9939ee4c8b 使用标准日志接口 2025-05-13 21:59:28 +08:00
9 changed files with 193 additions and 49 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@ composer.lock
.idea/ .idea/
vendor/ vendor/
tests/prikey.pem tests/prikey.pem
demo.php

View File

@@ -2,7 +2,7 @@
"name": "maiyoule/mqttclient_author", "name": "maiyoule/mqttclient_author",
"type": "library", "type": "library",
"description": "MQTT管理模块操作库", "description": "MQTT管理模块操作库",
"version": "1.0.3", "version": "1.2.2",
"license": "MIT", "license": "MIT",
"authors": [ "authors": [
{ {
@@ -15,7 +15,8 @@
"php": ">=8.0", "php": ">=8.0",
"guzzlehttp/guzzle": "^7.0", "guzzlehttp/guzzle": "^7.0",
"phpseclib/phpseclib": "~3.0", "phpseclib/phpseclib": "~3.0",
"workerman/mqtt": "^2.2" "workerman/mqtt": "^2.2",
"psr/log": "^3.0"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^11.0" "phpunit/phpunit": "^11.0"

View File

@@ -3,6 +3,7 @@
namespace cn\com\maiyoule\mqttclient; namespace cn\com\maiyoule\mqttclient;
use cn\com\maiyoule\mqttclient\biz\client\SendMQTTMessage; use cn\com\maiyoule\mqttclient\biz\client\SendMQTTMessage;
use Psr\Log\LoggerInterface;
use Workerman\Mqtt\Client; use Workerman\Mqtt\Client;
use Workerman\Worker; use Workerman\Worker;
@@ -22,7 +23,7 @@ class AuthorAppMQTTClient
} }
private string $appid = ''; private string $appid = '';
private string $server = ''; private string $server = 'mqtt://mqttauthor.maiyoule.com.cn';
private int $port = 1883; private int $port = 1883;
private string $clientId = ''; private string $clientId = '';
private string $username = ''; private string $username = '';
@@ -99,6 +100,19 @@ class AuthorAppMQTTClient
} }
private LoggerInterface $logger;
public function getLogger(): LoggerInterface
{
return $this->logger;
}
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
/** /**
* @throws \Exception * @throws \Exception
*/ */
@@ -121,16 +135,18 @@ class AuthorAppMQTTClient
$this->worker = new Worker(); $this->worker = new Worker();
$this->worker->onWorkerStart = function () { $this->worker->onWorkerStart = function () {
$this->logger->info('Worker 启动');
$this->__startWorker(); $this->__startWorker();
}; };
$this->worker->onMessage = function ($conn, $data) { $this->worker->onMessage = function ($conn, $data) {
print_r($data); $this->logger->debug($data);
}; };
$this->worker->onWorkerStop = function () { $this->worker->onWorkerStop = function () {
$this->logger->info('Worker 停止');
$this->__stopWorker(); $this->__stopWorker();
}; };
$this->worker->onError = function () { $this->worker->onError = function () {
print_r('遇到错误'); $this->logger->error('Worker启动遇到错误');
}; };
if (!Worker::isRunning()) { if (!Worker::isRunning()) {
Worker::runAll(); Worker::runAll();
@@ -163,6 +179,9 @@ class AuthorAppMQTTClient
$this->client->disconnect(); $this->client->disconnect();
} }
/**
* @throws \Exception
*/
private function __startWorker(): void private function __startWorker(): void
{ {
//参考 https://www.workerman.net/doc/workerman/components/workerman-mqtt.html //参考 https://www.workerman.net/doc/workerman/components/workerman-mqtt.html
@@ -170,39 +189,49 @@ class AuthorAppMQTTClient
'keepalive' => 29, 'keepalive' => 29,
'client_id' => $this->getClientId(), 'client_id' => $this->getClientId(),
'protocol_name' => 'MQTT', 'protocol_name' => 'MQTT',
'protocol_level' => 4, 'protocol_level' => 5,
'clean_session' => true, 'clean_session' => true,
'reconnect_period' => 2, 'reconnect_period' => 2,
'connect_timeout' => 10, 'connect_timeout' => 10,
'username' => $this->getUsername(), 'username' => $this->getUsername(),
'password' => $this->getPassword(), 'password' => $this->getPassword(),
'resubscribe' => true 'resubscribe' => true,
'debug' => false
]; ];
$address = sprintf('mqtt://%s:%d', $this->getServer(), $this->getPort()); $address = sprintf('mqtt://%s:%d', $this->getServer(), $this->getPort());
try { $this->logger->debug('建立MQTT连接到' . $address);
$this->client = new Client($address, $option);
//连接回调
$this->client->onConnect = function (Client $connection) {
$topic = sprintf('biz/%s/#', $this->getAppid());
$connection->subscribe($topic, ['qos' => 0]);
$this->callEvent(self::EVENT_CONNECT, $connection); $this->client = new Client($address, $option);
}; //连接回调
$this->client->onClose = function () { $this->client->onConnect = function (Client $connection) {
$this->callEvent(self::EVENT_CLOSE); $this->logger->debug('MQTT 连接成功');
}; $topic = sprintf('biz/%s/#', $this->getAppid());
$this->client->onMessage = function (string $topic, string $data, Client $client) { $connection->subscribe($topic, ['qos' => 0], function (\Exception|null $exception, array $granted) {
//收到消息
$this->callEvent(self::EVENT_MESSAGE, $topic, $data, $client); if (!is_null($exception)) {
}; $this->logger->error($exception->getMessage());
//遇到错误 }
$this->client->onError = function (\Exception $err) { $this->logger->debug('主题订阅:' . json_encode($granted));
$this->callEvent(self::EVENT_ERROR, $err); });
};
$this->client->connect(); $this->callEvent(self::EVENT_CONNECT, $connection);
} catch (\Exception $e) { };
$this->client->onClose = function () {
$this->logger->debug('MQTT 连接断开');
$this->callEvent(self::EVENT_CLOSE);
};
$this->client->onMessage = function (string $topic, string $data, Client $client) {
//收到消息
$this->logger->debug(sprintf('MQTT 收到消息 Topic:%s Data:%s', $topic, $data));
$this->callEvent(self::EVENT_MESSAGE, $topic, $data, $client);
};
//遇到错误
$this->client->onError = function (\Exception $err) {
$this->logger->error('MQTT 遇到错误' . $err->getMessage());
$this->callEvent(self::EVENT_ERROR, $err);
};
$this->client->connect();
}
} }
const EVENT_CONNECT = 'connect'; const EVENT_CONNECT = 'connect';

View File

@@ -162,7 +162,7 @@ class AuthorServerClient
return new BizResponse(); return new BizResponse();
} }
$data = json_decode($content, true); $data = json_decode($content, true);
return new BizResponse($data['code'] ?? 0, $data['message'] ?? '', $data['data'] ?? []); return new BizResponse($data['code'] ?? 0, $data['message'] ?? '', $data['data'] ?? [], $data['err'] ?? '');
} catch (ClientException $e) { } catch (ClientException $e) {
$body = $e->getResponse()->getBody()->getContents(); $body = $e->getResponse()->getBody()->getContents();

View File

@@ -0,0 +1,37 @@
<?php
namespace cn\com\maiyoule\mqttclient\biz;
use cn\com\maiyoule\mqttclient\IRequest;
class AppUpdateCallbackRequest extends IRequest
{
public function path(): string
{
return 'app/callback/update';
}
public function body(): array
{
return [
'url' => $this->getUrl()
];
}
private string $url;
/**
* @return string
*/
public function getUrl(): string
{
return $this->url;
}
public function setUrl(string $url): void
{
$this->url = $url;
}
}

View File

@@ -18,25 +18,60 @@ class AppUserCreateRequest extends IRequest
'password' => $this->getPassword(), 'password' => $this->getPassword(),
'fettle' => $this->getFettle(), 'fettle' => $this->getFettle(),
'role' => $this->getRole(), 'role' => $this->getRole(),
'biz' => join(',', $this->getBiz()) 'publish' => join(',', $this->getPublish()),
'subscribe' => join(',', $this->getSubscribe()),
'expire' => $this->expireAt
]; ];
} }
private array $biz = []; private array $subscribe = [];
public function getBiz(): array public function getSubscribe(): array
{ {
return $this->biz; return $this->subscribe;
} }
public function setBiz(array|string $biz): void public function setSubscribe(array|string $subscribe): void
{ {
if (is_string($biz)) { if (is_string($subscribe)) {
$biz = [$biz]; $subscribe = [$subscribe];
} }
$this->biz = $biz; $this->subscribe = $subscribe;
} }
/**
* @var string 过期时间
*/
private string $expireAt = '';
public function getExpireAt(): string
{
return $this->expireAt;
}
public function setExpireAt(string $expireAt): void
{
$this->expireAt = $expireAt;
}
private array $publish = [];
public function getPublish(): array
{
return $this->publish;
}
public function setPublish(array|string $publish): void
{
if (is_string($publish)) {
$publish = [$publish];
}
$this->publish = $publish;
}
private string $password = ''; private string $password = '';
private string $fettle = ''; private string $fettle = '';
private string $role = 'user'; private string $role = 'user';

View File

@@ -29,23 +29,37 @@ class AppUserUpdateRequest extends IRequest
if (!is_null($this->fettle)) { if (!is_null($this->fettle)) {
$data['fettle'] = $this->fettle; $data['fettle'] = $this->fettle;
} }
if (!is_null($this->biz)) { if (!empty($this->publish)) {
$data['biz'] = join(',', $this->biz); $data['publish'] = join(',', $this->getPublish());
}
if (!empty($this->subscribe)) {
$data['subscribe'] = join(',', $this->getSubscribe());
} }
return $data; return $data;
} }
private ?array $biz = null; private array $subscribe = [];
public function getBiz(): array public function getSubscribe(): array
{ {
return $this->biz; return $this->subscribe;
} }
public function setBiz(array $biz): void public function setSubscribe(array|string $subscribe): void
{ {
$this->biz = $biz; if (is_string($subscribe)) {
$subscribe = [$subscribe];
}
$this->subscribe = $subscribe;
}
private array $publish = [];
public function getPublish(): array
{
return $this->publish;
} }
private string $username; private string $username;

View File

@@ -6,19 +6,22 @@ class BizResponse
{ {
private int $code; private int $code;
private string $message; private string $message;
private $data; private mixed $data;
private string $errCode;
/** /**
* @param int $code * @param int $code
* @param string $message * @param string $message
* @param $data * @param array $data
* @param string $errCode
*/ */
public function __construct(int $code = -1, string $message = '', $data = []) public function __construct(int $code = -1, string $message = '', mixed $data = [], string $errCode = '')
{ {
$this->code = $code; $this->code = $code;
$this->message = $message; $this->message = $message;
$this->data = $data; $this->data = $data;
$this->errCode = $errCode;
} }
public function isSuccess(): bool public function isSuccess(): bool
@@ -49,7 +52,7 @@ class BizResponse
/** /**
* @return mixed * @return mixed
*/ */
public function getData() public function getData(): mixed
{ {
return $this->data; return $this->data;
} }
@@ -62,5 +65,15 @@ class BizResponse
$this->data = $data; $this->data = $data;
} }
public function getErrCode(): string
{
return $this->errCode;
}
public function setErrCode(string $errCode): void
{
$this->errCode = $errCode;
}
} }

View File

@@ -2,11 +2,13 @@
namespace cn\com\maiyoule\mqttclient\test; namespace cn\com\maiyoule\mqttclient\test;
use cn\com\maiyoule\mqttclient\biz\AppUpdateCallbackRequest;
use cn\com\maiyoule\mqttclient\biz\AppUserCreateRequest; use cn\com\maiyoule\mqttclient\biz\AppUserCreateRequest;
use cn\com\maiyoule\mqttclient\biz\AppUserDeleteRequest; use cn\com\maiyoule\mqttclient\biz\AppUserDeleteRequest;
use cn\com\maiyoule\mqttclient\biz\AppUserUpdateRequest; use cn\com\maiyoule\mqttclient\biz\AppUserUpdateRequest;
use cn\com\maiyoule\mqttclient\exception\ApiException; use cn\com\maiyoule\mqttclient\exception\ApiException;
use cn\com\maiyoule\mqttclient\AuthorServerClient; use cn\com\maiyoule\mqttclient\AuthorServerClient;
use GuzzleHttp\Exception\GuzzleException;
use PHPUnit\Framework\Assert; use PHPUnit\Framework\Assert;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@@ -80,4 +82,16 @@ class AppManagerTest extends TestCase
} }
} }
public function testUpdateAppUrl()
{
$request = new AppUpdateCallbackRequest();
$request->setUrl('http://202.200.18.46:8000/api.php');
try {
$biz = $this->manager->exec($request);
$this->assertTrue($biz->isSuccess(), $biz->getMessage());
} catch (GuzzleException|ApiException $e) {
$this->fail($e->getMessage());
}
}
} }