closed) { return; } if ($this->net === null) { // opened at the first poll: the window is drawn before a desktop connection's TLS handshake $this->net = Network::connect($this->url, ['transport' => 'ws']); } foreach ($this->net->poll() as $event) { switch ($event->type) { case Event::OPEN: $this->net->joinRoom(self::ROOM); break; case Event::ROOM: if (!$this->open) { $this->open = true; $this->emit('open'); } break; case Event::MESSAGE: $this->emit('data', [$event->data]); break; case Event::ERROR: $info = $event->info(); $this->emit('error', [(string)($info['message'] ?? $info['code'] ?? 'network error')]); break; case Event::CLOSE: $this->finish('closed'); return; } } if ($this->net->state() === Connection::CLOSED) { $this->finish('closed'); } } public function write(string $bytes): void { if ($this->open && $this->net !== null) { $this->net->send($bytes, 0); } } public function close(): void { $this->net?->close(); $this->finish('closed'); } private function finish(string $why): void { if ($this->closed) { return; } $this->closed = true; $this->open = false; $this->emit('close', [$why]); } }