2]; /** * Protocol identifier. * * @var class-string */ protected string $protocol = AbridgedStream::class; /** * Transport identifier. * * @var class-string */ protected string $transport = DefaultStream::class; /** * Proxy identifiers. * * @var array, array> */ protected array $proxy = []; /** * Whether to use the obfuscated protocol. */ protected bool $obfuscated = false; /** * Whether we're in test mode. */ protected bool $testMode = false; /** * Whether to use ipv6. */ protected bool $ipv6; /** * Connection timeout. */ protected int $timeout = 2; /** * Whether to retry connection. */ protected bool $retry = true; /** * Whether to use DNS over HTTPS. */ protected bool $useDoH = true; /** * Bind on specific address and port. */ private ?string $bindTo = null; /** * Subdomains of web.telegram.org for https protocol. */ protected array $sslSubdomains = [ 1 => 'pluto', 2 => 'venus', 3 => 'aurora', 4 => 'vesta', 5 => 'flora', ]; public function mergeArray(array $settings): void { if (isset($settings['connection']['ssl_subdomains'])) { $this->setSslSubdomains($settings['connection']['ssl_subdomains']); } $settings = $settings['connection_settings'] ?? []; if (isset($settings['media_socket_count']['min'])) { $this->setMinMediaSocketCount($settings['media_socket_count']['min']); } if (isset($settings['media_socket_count']['max'])) { $this->setMaxMediaSocketCount($settings['media_socket_count']['max']); } foreach (self::toCamel([ 'robin_period', 'default_dc', 'pfs' ]) as $object => $array) { if (isset($settings[$array])) { $this->{$object}($settings[$array]); } } $settings = $settings['all'] ?? []; foreach (self::toCamel([ 'test_mode', 'ipv6', 'timeout', 'obfuscated', ]) as $object => $array) { if (isset($settings[$array])) { $this->{$object}($settings[$array]); } } if (isset($settings['do_not_retry'])) { $this->setRetry(false); } if (isset($settings['proxy'])) { $isProxyArray = \is_iterable($settings['proxy']); foreach ($isProxyArray ? $settings['proxy'] : [$settings['proxy']] as $key => $proxy) { if ($proxy === '\\Socket') { $proxy = DefaultStream::class; } elseif ($proxy === '\\SocksProxy') { $proxy = SocksProxy::class; } elseif ($proxy === '\\HttpProxy') { $proxy = HttpProxy::class; } elseif ($proxy === '\\MTProxySocket') { $proxy = ObfuscatedStream::class; } if ($proxy !== DefaultStream::class) { $this->addProxy($proxy, $isProxyArray ? $settings['proxy_extra'][$key] : $settings['proxy_extra']); } } } if (isset($settings['transport'])) { $transport = $settings['transport']; if ($transport === 'tcp') { $transport = DefaultStream::class; } elseif ($transport === 'ws') { $transport = WsStream::class; } elseif ($transport === 'wss') { $transport = WssStream::class; } $this->setTransport($transport); } if (isset($settings['protocol'])) { $protocol = $settings['protocol']; switch ($protocol) { case 'abridged': case 'tcp_abridged': $protocol = AbridgedStream::class; break; case 'intermediate': case 'tcp_intermediate': $protocol = AbridgedStream::class; break; case 'obfuscated2': $this->setObfuscated(true); // no break case 'intermediate_padded': case 'tcp_intermediate_padded': $protocol = IntermediatePaddedStream::class; break; case 'full': case 'tcp_full': $protocol = FullStream::class; break; case 'http': $protocol = HttpStream::class; break; case 'https': $protocol = HttpsStream::class; break; case 'udp': $protocol = UdpBufferedStream::class; break; } $this->setProtocol($protocol); } } public function __construct() { $this->init(); } public function __wakeup() { $this->init(); } public function init(): void { Magic::classExists(true); if (Magic::$altervista) { $this->addProxy(HttpProxy::class, ['address' => 'localhost', 'port' => 80]); } } /** * Get protocol identifier. * * @return string */ public function getProtocol(): string { return $this->protocol; } /** * Set protocol identifier. * * @param class-string $protocol Protocol identifier * * @return self */ public function setProtocol(string $protocol): self { if (!isset(\class_implements($protocol)[MTProtoBufferInterface::class])) { throw new Exception("An invalid protocol was specified!"); } $this->protocol = $protocol; return $this; } /** * Get whether to use ipv6. * * @return bool */ public function getIpv6(): bool { return $this->ipv6 ?? Magic::$ipv6; } /** * Set whether to use ipv6. * * @param bool $ipv6 Whether to use ipv6 * * @return self */ public function setIpv6(bool $ipv6): self { $this->ipv6 = $ipv6; return $this; } /** * Get subdomains of web.telegram.org for https protocol. * * @return array */ public function getSslSubdomains(): array { return $this->sslSubdomains; } /** * Set subdomains of web.telegram.org for https protocol. * * @param array $sslSubdomains Subdomains of web.telegram.org for https protocol. * * @return self */ public function setSslSubdomains(array $sslSubdomains): self { $this->sslSubdomains = $sslSubdomains; return $this; } /** * Get minimum media socket count. * * @return int */ public function getMinMediaSocketCount(): int { return $this->minMediaSocketCount; } /** * Set minimum media socket count. * * @param int $minMediaSocketCount Minimum media socket count. * * @return self */ public function setMinMediaSocketCount(int $minMediaSocketCount): self { $this->minMediaSocketCount = $minMediaSocketCount; return $this; } /** * Get maximum media socket count. * * @return int */ public function getMaxMediaSocketCount(): int { return $this->maxMediaSocketCount; } /** * Set maximum media socket count. * * @param int $maxMediaSocketCount Maximum media socket count. * * @return self */ public function setMaxMediaSocketCount(int $maxMediaSocketCount): self { $this->maxMediaSocketCount = $maxMediaSocketCount; return $this; } /** * Get robin period (seconds). * * @return int */ public function getRobinPeriod(): int { return $this->robinPeriod; } /** * Set robin period (seconds). * * @param int $robinPeriod Robin period (seconds). * * @return self */ public function setRobinPeriod(int $robinPeriod): self { $this->robinPeriod = $robinPeriod; return $this; } /** * Get default DC ID. * * @return int */ public function getDefaultDc(): int { return $this->defaultDc; } /** * Get default DC params. * * @return array */ public function getDefaultDcParams(): array { return $this->defaultDcParams; } /** * Set default DC ID. * * @param int $defaultDc Default DC ID. * * @return self */ public function setDefaultDc(int $defaultDc): self { $this->defaultDc = $defaultDc; $this->defaultDcParams = ['datacenter' => $defaultDc]; return $this; } /** * Get proxy identifiers. * * @return array, array> */ public function getProxies(): array { return $this->proxy; } /** * Add proxy identifier to list. * * @param class-string $proxy Proxy identifier * @param array $extra Extra * * @return self */ public function addProxy(string $proxy, array $extra = []): self { if (!isset(\class_implements($proxy)[StreamInterface::class])) { throw new Exception("An invalid proxy class was specified!"); } if (!isset($this->proxy[$proxy])) { $this->proxy[$proxy] = []; } $this->proxy[$proxy][] = $extra; return $this; } /** * Set proxies. * * @param array $proxies Proxies * * @return self */ public function setProxy(array $proxies): self { $this->proxy = $proxies; return $this; } /** * Clear proxies. * * @return self */ public function clearProxies(): self { $this->proxy = []; return $this; } /** * Remove specific proxy pair. * * @param string $proxy * @param array $extra * * @return self */ public function removeProxy(string $proxy, array $extra): self { if (!isset($this->proxy[$proxy])) { return $this; } if (false === $index = \array_search($extra, $this->proxy[$proxy])) { return $this; } unset($this->proxy[$proxy][$index]); if (empty($this->proxy[$proxy])) { unset($this->proxy[$proxy]); } return $this; } /** * Get whether to use the obfuscated protocol. * * @return bool */ public function getObfuscated(): bool { return $this->obfuscated; } /** * Set whether to use the obfuscated protocol. * * @param bool $obfuscated Whether to use the obfuscated protocol. * * @return self */ public function setObfuscated(bool $obfuscated): self { $this->obfuscated = $obfuscated; return $this; } /** * Get whether we're in test mode. * * @return bool */ public function getTestMode(): bool { return $this->testMode; } /** * Set whether we're in test mode. * * @param bool $testMode Whether we're in test mode. * * @return self */ public function setTestMode(bool $testMode): self { $this->testMode = $testMode; return $this; } /** * Get transport identifier. * * @return class-string */ public function getTransport(): string { return $this->transport; } /** * Set transport identifier. * * @param class-string $transport Transport identifier. * * @return self */ public function setTransport(string $transport): self { if (!isset(\class_implements($transport)[RawStreamInterface::class])) { throw new Exception("An invalid transport was specified!"); } $this->transport = $transport; return $this; } /** * Get whether to retry connection. * * @return bool */ public function getRetry(): bool { return $this->retry; } /** * Set whether to retry connection. * * @param bool $retry Whether to retry connection. * * @return self */ public function setRetry(bool $retry): self { $this->retry = $retry; return $this; } /** * Get connection timeout. * * @return int */ public function getTimeout(): int { return $this->timeout; } /** * Set connection timeout. * * @param int $timeout Connection timeout. * * @return self */ public function setTimeout(int $timeout): self { $this->timeout = $timeout; return $this; } /** * Get whether to use DNS over HTTPS. * * @return bool */ public function getUseDoH(): bool { return $this->useDoH; } /** * Set whether to use DNS over HTTPS. * * @param bool $useDoH Whether to use DNS over HTTPS * * @return self */ public function setUseDoH(bool $useDoH): self { $this->useDoH = $useDoH; return $this; } /** * Get bind on specific address and port. * * @return ?string */ public function getBindTo(): ?string { return $this->bindTo; } /** * Set bind on specific address and port. * * @param ?string $bindTo Bind on specific address and port. * * @return self */ public function setBindTo(?string $bindTo): self { $this->bindTo = $bindTo; return $this; } }