src/Server/Config/Socket.php
<?php
declare(strict_types=1);
namespace K911\Swoole\Server\Config;
use Assert\Assertion;
use InvalidArgumentException;
final class Socket
{
private const CONSTANT_SWOOLE_SSL_IS_NOT_DEFINED_ERROR_MESSAGE = 'Constant SWOOLE_SSL is not defined. Please compile swoole extension with SSL support enabled.';
private const SWOOLE_SOCKET_TYPE = [
'tcp' => \SWOOLE_SOCK_TCP,
'tcp_ipv6' => \SWOOLE_SOCK_TCP6,
'udp' => \SWOOLE_SOCK_UDP,
'udp_ipv6' => \SWOOLE_SOCK_UDP6,
'unix_dgram' => \SWOOLE_SOCK_UNIX_DGRAM,
'unix_stream' => \SWOOLE_SOCK_UNIX_STREAM,
];
/**
* @var string
*/
private $host;
/**
* @var int
*/
private $port;
/**
* @var string
*/
private $type;
/**
* @var bool
*/
private $ssl;
/**
* @throws \Assert\AssertionFailedException
*/
public function __construct(string $host = '0.0.0.0', int $port = 9501, string $type = 'tcp', bool $ssl = false)
{
$this->setHost($host);
$this->setPort($port);
if ($ssl) {
Assertion::defined('SWOOLE_SSL', self::CONSTANT_SWOOLE_SSL_IS_NOT_DEFINED_ERROR_MESSAGE);
}
$this->type = $type;
$this->ssl = $ssl;
}
/**
* @throws \Assert\AssertionFailedException
*
* @return Socket
*/
public static function fromAddressPort(string $addressPort = '127.0.0.1:9501', string $socketType = 'tcp', bool $enableSsl = false): self
{
[$host, $port] = self::splitAddressPort($addressPort);
return new self($host, $port, $socketType, $enableSsl);
}
public function addressPort(): string
{
return \sprintf('%s:%d', $this->host, $this->port);
}
public function host(): string
{
return $this->host;
}
public function port(): int
{
return $this->port;
}
public function type(): int
{
$resolvedSocketType = self::SWOOLE_SOCKET_TYPE[$this->type];
if ($this->ssl) {
if (!\defined('SWOOLE_SSL')) {
throw new InvalidArgumentException(self::CONSTANT_SWOOLE_SSL_IS_NOT_DEFINED_ERROR_MESSAGE);
}
$resolvedSocketType |= \SWOOLE_SSL;
}
return $resolvedSocketType;
}
public function ssl(): bool
{
return $this->ssl;
}
public function withPort(int $port): self
{
$self = clone $this;
$self->setPort($port);
$self->port = $port;
return $self;
}
public function withHost(string $host): self
{
$self = clone $this;
$self->setHost($host);
return $self;
}
/**
* @return array values:
* - string host
* - int port
*/
private static function splitAddressPort(string $addressPort): array
{
$pos = \mb_strrpos($addressPort, ':');
if (false !== $pos) {
$host = \mb_substr($addressPort, 0, $pos);
if ('*' === $host) {
$host = '0.0.0.0';
}
$port = \mb_substr($addressPort, $pos + 1);
} elseif (\ctype_digit($addressPort)) {
$host = '127.0.0.1';
$port = $addressPort;
} else {
$host = $addressPort;
$port = 9501;
}
return [$host, (int) $port];
}
private function setPort(int $port): void
{
Assertion::between($port, 0, 65535, 'Port must be an integer between 0 and 65535');
$this->port = $port;
}
private function setHost(string $host): void
{
$this->host = $host;
}
}