mirror of
https://gitee.com/hyperf/hyperf.git
synced 2024-11-29 18:27:44 +08:00
Optimized code of Hyperf\SocketIOServer\Parser\Decoder::decode(). (#6455)
Co-authored-by: 李铭昕 <715557344@qq.com>
This commit is contained in:
parent
0a0d1e6ac6
commit
b8d6f7529a
@ -1,4 +1,10 @@
|
||||
# v3.0.47 - TBD
|
||||
# v3.0.48 - TBD
|
||||
|
||||
# v3.0.47 - 2024-01-11
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#6455](https://github.com/hyperf/hyperf/pull/6455) Optimized code of Hyperf\SocketIOServer\Parser\Decoder::decode().
|
||||
|
||||
# v3.0.46 - 2023-11-30
|
||||
|
||||
|
@ -67,7 +67,7 @@
|
||||
"php-amqplib/php-amqplib": "^3.5",
|
||||
"php-di/phpdoc-reader": "^2.2",
|
||||
"phpspec/prophecy-phpunit": "^2.0",
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"phpstan/phpstan": "1.10.47",
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"predis/predis": "^1.1",
|
||||
"promphp/prometheus_client_php": "2.2.*",
|
||||
|
@ -1,5 +1,11 @@
|
||||
# Changelogs
|
||||
|
||||
# v3.0.47 - 2024-01-11
|
||||
|
||||
## Optimized
|
||||
|
||||
- [#6455](https://github.com/hyperf/hyperf/pull/6455) Optimized code of Hyperf\SocketIOServer\Parser\Decoder::decode().
|
||||
|
||||
# v3.0.46 - 2023-11-30
|
||||
|
||||
## Fixed
|
||||
|
@ -1,5 +1,11 @@
|
||||
# 版本更新记录
|
||||
|
||||
# v3.0.47 - 2024-01-11
|
||||
|
||||
## 优化
|
||||
|
||||
- [#6455](https://github.com/hyperf/hyperf/pull/6455) 优化 `Hyperf\SocketIOServer\Parser\Decoder::decode()` 的代码实现。
|
||||
|
||||
# v3.0.46 - 2023-11-30
|
||||
|
||||
## Fixed
|
||||
|
@ -11,49 +11,80 @@ declare(strict_types=1);
|
||||
*/
|
||||
namespace Hyperf\SocketIOServer\Parser;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
class Decoder
|
||||
{
|
||||
public function decode($payload): Packet
|
||||
/**
|
||||
* @param string $payload such as `2/ws?foo=xxx,2["event","hellohyperf"]`
|
||||
*/
|
||||
public function decode(string $payload): Packet
|
||||
{
|
||||
// type
|
||||
$i = 0;
|
||||
$type = $payload[$i];
|
||||
if (! $payload) {
|
||||
throw new InvalidArgumentException('Empty packet');
|
||||
}
|
||||
|
||||
$length = strlen($payload);
|
||||
$type = $payload[0];
|
||||
if (! in_array($type, [Packet::OPEN, Packet::CLOSE, Packet::EVENT, Packet::ACK], true)) {
|
||||
throw new InvalidArgumentException('Unknown packet type ' . $type);
|
||||
}
|
||||
|
||||
if ($length === 1) {
|
||||
return $this->makePacket($type);
|
||||
}
|
||||
|
||||
$nsp = '/';
|
||||
$query = [];
|
||||
++$i;
|
||||
|
||||
// TODO: Support attachment
|
||||
$payload = substr($payload, 1);
|
||||
if ($payload[0] === '/') {
|
||||
// parse url
|
||||
$exploded = explode(',', $payload, 2);
|
||||
$parsedUrl = parse_url($exploded[0]);
|
||||
$nsp = $parsedUrl['path'];
|
||||
if (! empty($parsedUrl['query'])) {
|
||||
parse_str($parsedUrl['query'], $query);
|
||||
}
|
||||
|
||||
// namespace
|
||||
if (isset($payload[$i]) && $payload[$i] === '/') {
|
||||
++$i;
|
||||
while ($payload[$i] !== ',' && $payload[$i] !== '?') {
|
||||
$nsp .= $payload[$i];
|
||||
++$i;
|
||||
}
|
||||
if ($payload[$i] === '?') {
|
||||
++$i;
|
||||
$query = '';
|
||||
while ($payload[$i] !== ',') {
|
||||
$query .= $payload[$i];
|
||||
++$i;
|
||||
}
|
||||
$result = [];
|
||||
parse_str($query, $result);
|
||||
$query = $result;
|
||||
}
|
||||
++$i;
|
||||
$payload = $exploded[1] ?? null;
|
||||
}
|
||||
|
||||
// id
|
||||
$id = '';
|
||||
while (mb_strlen($payload) > $i && filter_var($payload[$i], FILTER_VALIDATE_INT) !== false) {
|
||||
$id .= $payload[$i];
|
||||
++$i;
|
||||
if (! $payload) {
|
||||
return $this->makePacket($type, $nsp, $query);
|
||||
}
|
||||
|
||||
// data
|
||||
$data = json_decode(mb_substr($payload, $i), true) ?? [];
|
||||
$offset = 0;
|
||||
while (true) {
|
||||
$char = $payload[$offset] ?? null;
|
||||
if ($char === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_numeric($char)) {
|
||||
++$offset;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$id = substr($payload, 0, $offset);
|
||||
$payload = substr($payload, $offset);
|
||||
$data = [];
|
||||
if ($payload) {
|
||||
try {
|
||||
$data = json_decode($payload, true, flags: JSON_THROW_ON_ERROR);
|
||||
} catch (Throwable $exception) {
|
||||
throw new InvalidArgumentException('Invalid data', (int) $exception->getCode(), $exception);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->makePacket($type, $nsp, $query, $id, $data);
|
||||
}
|
||||
|
||||
public function makePacket(string $type, string $nsp = '/', array $query = [], string $id = '', array $data = []): Packet
|
||||
{
|
||||
return Packet::create([
|
||||
'type' => $type,
|
||||
'nsp' => $nsp,
|
||||
|
@ -12,6 +12,8 @@ declare(strict_types=1);
|
||||
namespace HyperfTest\SocketIOServer\Cases;
|
||||
|
||||
use Hyperf\SocketIOServer\Parser\Decoder;
|
||||
use InvalidArgumentException;
|
||||
use PHPUnit\Framework\Attributes\CoversNothing;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -57,5 +59,38 @@ class DecoderTest extends AbstractTestCase
|
||||
$this->assertEquals('1', $packet['type']);
|
||||
$this->assertEquals('/ws', $packet['nsp']);
|
||||
$this->assertEquals(['foo' => 'bar', 'baz' => '1'], $packet['query']);
|
||||
$result = $decoder->decode('2/1');
|
||||
$this->assertEquals(2, $result->type);
|
||||
$this->assertEquals('/1', $result->nsp);
|
||||
$result = $decoder->decode('2/1,2["event","hellohyperf"]');
|
||||
$this->assertEquals(2, $result->type);
|
||||
$this->assertEquals('/1', $result->nsp);
|
||||
$this->assertEquals('2', $result->id);
|
||||
$this->assertEquals([
|
||||
], $result->query);
|
||||
$result = $decoder->decode('2/1?foo=xxx,2["event","hellohyperf"]');
|
||||
$this->assertEquals(2, $result->type);
|
||||
$this->assertEquals('/1', $result->nsp);
|
||||
$this->assertEquals('2', $result->id);
|
||||
$this->assertEquals([
|
||||
'foo' => 'xxx',
|
||||
], $result->query);
|
||||
$this->assertEquals(json_decode('["event","hellohyperf"]', true), $result->data);
|
||||
|
||||
$result = $decoder->decode('2/1?foo=xxx,2{"event": "JOIN"}');
|
||||
$this->assertEquals(2, $result->type);
|
||||
$this->assertEquals('/1', $result->nsp);
|
||||
$this->assertEquals('2', $result->id);
|
||||
$this->assertEquals([
|
||||
'foo' => 'xxx',
|
||||
], $result->query);
|
||||
$this->assertEquals(['event' => 'JOIN'], $result->data);
|
||||
|
||||
try {
|
||||
$decoder->decode('2/1?2["event","hellohyperf"]');
|
||||
$this->assertTrue(false);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$this->assertEquals('Invalid data', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user