Skip to content

Commit

Permalink
Add Psalm and fix issues
Browse files Browse the repository at this point in the history
  • Loading branch information
trowski committed Jun 24, 2020
1 parent 35d9a31 commit 8674d70
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 17 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Expand Up @@ -23,6 +23,7 @@ install:
script:
- php -dzend.assertions=1 -dassert.exception=1 vendor/bin/phpunit --coverage-text --verbose --coverage-clover build/logs/clover.xml
- PHP_CS_FIXER_IGNORE_ENV=1 php vendor/bin/php-cs-fixer --diff --dry-run -v fix
- vendor/bin/psalm

after_script:
- wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.2.0/php-coveralls.phar
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -38,7 +38,8 @@
"require-dev": {
"phpunit/phpunit": "^8 || ^7",
"amphp/phpunit-util": "^1.1.2",
"amphp/php-cs-fixer-config": "dev-master"
"amphp/php-cs-fixer-config": "dev-master",
"vimeo/psalm": "^3.11@dev"
},
"suggest": {
"ext-zlib": "Required for compression"
Expand Down
15 changes: 15 additions & 0 deletions psalm.xml
@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<psalm
errorLevel="2"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src"/>
<ignoreFiles>
<directory name="vendor"/>
</ignoreFiles>
</projectFiles>
</psalm>
4 changes: 2 additions & 2 deletions src/Client.php
Expand Up @@ -142,8 +142,8 @@ public function getInfo(): ClientMetadata;
* @param int $code
* @param string $reason
*
* @return Promise<[int, string]> Resolves with an array containing the close code used and the close reason.
* These may differ from those provided if the connection was closed prior.
* @return Promise<array> Resolves with an array containing the close code at key 0 and the close reason at key 1.
* These may differ from those provided if the connection was closed prior.
*/
public function close(int $code = Code::NORMAL_CLOSE, string $reason = ''): Promise;

Expand Down
30 changes: 28 additions & 2 deletions src/ClientMetadata.php
Expand Up @@ -23,23 +23,49 @@ final class ClientMetadata
/** @var string|null */
public $closeReason;

// Timestamps of when the event occurred.
/** @var int */
public $connectedAt = 0;

/** @var int */
public $closedAt = 0;

/** @var int */
public $lastReadAt = 0;

/** @var int */
public $lastSentAt = 0;

/** @var int */
public $lastDataReadAt = 0;

/** @var int */
public $lastDataSentAt = 0;

/** @var int */
public $lastHeartbeatAt = 0;

// Simple counters.
/** @var int */
public $bytesRead = 0;

/** @var int */
public $bytesSent = 0;

/** @var int */
public $framesRead = 0;

/** @var int */
public $framesSent = 0;

/** @var int */
public $messagesRead = 0;

/** @var int */
public $messagesSent = 0;

/** @var int */
public $pingCount = 0;

/** @var int */
public $pongCount = 0;

/** @var bool */
Expand Down
2 changes: 1 addition & 1 deletion src/Message.php
Expand Up @@ -7,7 +7,7 @@
use Amp\Promise;

/**
* This class allows streamed and buffered access to the websocket message by extending Payload.
* This class allows streamed and buffered access to the websocket message.
*/
final class Message implements InputStream
{
Expand Down
25 changes: 25 additions & 0 deletions src/Options.php
Expand Up @@ -4,18 +4,43 @@

final class Options
{
/** @var int */
private $streamThreshold = 32768; // 32KB

/** @var int */
private $frameSplitThreshold = 32768; // 32KB

/** @var int */
private $bytesPerSecondLimit = 1048576; // 1MB

/** @var int */
private $framesPerSecondLimit = 100;

/** @var int */
private $frameSizeLimit = 2097152; // 2MB

/** @var int */
private $messageSizeLimit = 10485760; // 10MB

/** @var bool */
private $textOnly = false;

/** @var bool */
private $validateUtf8 = true;

/** @var int */
private $closePeriod = 3;

/** @var bool */
private $compressionEnabled = false;

/** @var bool */
private $heartbeatEnabled = true;

/** @var int */
private $heartbeatPeriod = 10;

/** @var int */
private $queuedPingLimit = 3;

/**
Expand Down
28 changes: 19 additions & 9 deletions src/Rfc6455Client.php
Expand Up @@ -36,7 +36,7 @@ final class Rfc6455Client implements Client
/** @var string|null */
private static $watcher;

/** @var LRUCache Least-recently-used cache of next ping (heartbeat) times. */
/** @var LRUCache&\IteratorAggregate Least-recently-used cache of next ping (heartbeat) times. */
private static $heartbeatTimeouts;

/** @var int Cached current time. */
Expand Down Expand Up @@ -115,6 +115,7 @@ public function getIterator(): \Iterator
self::$framesReadInLastSecond = [];

if (!empty(self::$rateDeferreds)) {
/** @psalm-suppress PossiblyNullArgument */
Loop::unreference(self::$watcher);

$rateDeferreds = self::$rateDeferreds;
Expand All @@ -131,7 +132,6 @@ public function getIterator(): \Iterator
}

$client = self::$clients[$clientId];
\assert($client instanceof self);
self::$heartbeatTimeouts->put($clientId, self::$now + $client->options->getHeartbeatPeriod());

if ($client->getUnansweredPingCount() > $client->options->getQueuedPingLimit()) {
Expand Down Expand Up @@ -210,7 +210,7 @@ public function getTlsInfo(): ?TlsInfo

public function getCloseCode(): int
{
if (!$this->metadata->closedAt) {
if ($this->metadata->closeCode === null) {
throw new \Error('The client has not closed');
}

Expand All @@ -219,7 +219,7 @@ public function getCloseCode(): int

public function getCloseReason(): string
{
if (!$this->metadata->closedAt) {
if ($this->metadata->closeReason === null) {
throw new \Error('The client has not closed');
}

Expand Down Expand Up @@ -274,6 +274,7 @@ private function read(): \Generator

if ((self::$framesReadInLastSecond[$this->metadata->id] ?? 0) >= $maxFramesPerSecond
|| self::$bytesReadInLastSecond[$this->metadata->id] >= $maxBytesPerSecond) {
/** @psalm-suppress PossiblyNullArgument */
Loop::reference(self::$watcher); // Reference watcher to keep loop running until rate limit released.
self::$rateDeferreds[$this->metadata->id] = $deferred = new Deferred;
yield $deferred->promise();
Expand Down Expand Up @@ -438,7 +439,7 @@ private function onError(int $code, string $reason): void

public function send(string $data): Promise
{
\assert(\preg_match('//u', $data), 'Text data must be UTF-8');
\assert((bool) \preg_match('//u', $data), 'Text data must be UTF-8');
return $this->lastWrite = new Coroutine($this->sendData($data, Opcode::TEXT));
}

Expand Down Expand Up @@ -495,6 +496,7 @@ private function sendData(string $data, int $opcode): \Generator
$data = (string) \substr($data, $length);

if ($compress) {
/** @psalm-suppress PossiblyNullReference */
$chunk = $this->compressionContext->compress($chunk, false);
}

Expand All @@ -505,6 +507,7 @@ private function sendData(string $data, int $opcode): \Generator
}

if ($compress) {
/** @psalm-suppress PossiblyNullReference */
$data = $this->compressionContext->compress($data, true);
}

Expand Down Expand Up @@ -551,6 +554,7 @@ private function sendStream(InputStream $stream, int $opcode): \Generator
}

if ($compress) {
/** @psalm-suppress PossiblyNullReference */
$buffer = $this->compressionContext->compress($buffer, false);
}

Expand All @@ -562,6 +566,7 @@ private function sendStream(InputStream $stream, int $opcode): \Generator
}

if ($compress) {
/** @psalm-suppress PossiblyNullReference */
$buffer = $this->compressionContext->compress($buffer, true);
}

Expand Down Expand Up @@ -595,7 +600,7 @@ private function write(string $data, int $opcode, int $rsv = 0, bool $isFinal =
private function compile(string $data, int $opcode, int $rsv, bool $isFinal): string
{
$length = \strlen($data);
$w = \chr(($isFinal << 7) | ($rsv << 4) | $opcode);
$w = \chr(((int) $isFinal << 7) | ($rsv << 4) | $opcode);

$maskFlag = $this->masked ? 0x80 : 0;

Expand Down Expand Up @@ -677,14 +682,17 @@ public function close(int $code = Code::NORMAL_CLOSE, string $reason = ''): Prom
$onClose = $this->onClose;
$this->onClose = null;

foreach ($onClose as $callback) {
Promise\rethrow(call($callback, $this, $code, $reason));
if ($onClose !== null) {
foreach ($onClose as $callback) {
Promise\rethrow(call($callback, $this, $code, $reason));
}
}

unset(self::$clients[$this->metadata->id]);
self::$heartbeatTimeouts->remove($this->metadata->id);

if (empty(self::$clients)) {
/** @psalm-suppress PossiblyNullArgument */
Loop::cancel(self::$watcher);
self::$watcher = null;
self::$heartbeatTimeouts = null;
Expand Down Expand Up @@ -747,7 +755,7 @@ private function parser(): \Generator
$rsv = ($firstByte & 0b01110000) >> 4;
$opcode = $firstByte & 0b00001111;
$isMasked = (bool) ($secondByte & 0b10000000);
$maskingKey = null;
$maskingKey = '';
$frameLength = $secondByte & 0b01111111;

if ($opcode >= 3 && $opcode <= 7) {
Expand Down Expand Up @@ -914,6 +922,7 @@ private function parser(): \Generator
}

if ($compressed) {
/** @psalm-suppress PossiblyNullReference */
$payload = $compressionContext->decompress($payload, $final);

if ($payload === null) { // Decompression failed.
Expand All @@ -939,6 +948,7 @@ private function parser(): \Generator
}
}

/** @psalm-suppress PossiblyUndefinedVariable Defined in either condition above. */
if (!$valid) {
$this->onError(
Code::INCONSISTENT_FRAME_DATA_TYPE,
Expand Down
4 changes: 2 additions & 2 deletions src/Rfc7692Compression.php
Expand Up @@ -134,9 +134,9 @@ private static function fromHeader(bool $isServer, string $headerIn, ?string &$h
private $deflate;
/** @var resource */
private $inflate;
/** @var bool */
/** @var int */
private $sendingFlushMode;
/** @var bool */
/** @var int */
private $receivingFlushMode;

private function __construct(
Expand Down

0 comments on commit 8674d70

Please sign in to comment.