, other: ?string, offerer: bool}> */ private array $peers = []; /** @var list */ private array $listeners = []; /** @var list> */ private array $queue = []; public function name(): string { return 'simulated'; } public function isSupported(): bool { return true; } public function send(array $command): void { $id = (string)($command['id'] ?? ''); switch ($command['op'] ?? '') { case 'peer': $this->peers[$id] = ['channels' => [], 'other' => null, 'offerer' => false]; $this->queue[] = ['ev' => 'state', 'id' => $id, 'state' => 'new']; break; case 'channel': if (isset($this->peers[$id])) { $this->peers[$id]['channels'][] = (string)$command['label']; } break; case 'offer': if (isset($this->peers[$id])) { $this->peers[$id]['offerer'] = true; $this->queue[] = ['ev' => 'state', 'id' => $id, 'state' => 'connecting']; $this->queue[] = ['ev' => 'offer', 'id' => $id, 'sdp' => 'sim:' . $id]; $this->queue[] = ['ev' => 'ice', 'id' => $id, 'candidate' => 'candidate:1 1 UDP 1 127.0.0.1 9 typ host', 'mline' => 0]; } break; case 'remote': $this->remote($id, (string)$command['type'], (string)$command['sdp']); break; case 'send': $other = $this->peers[$id]['other'] ?? null; if ($other !== null && isset($this->peers[$other])) { $event = ['ev' => 'message', 'id' => $other, 'label' => (string)$command['label']]; $this->queue[] = $event + (isset($command['b64']) ? ['b64' => (string)$command['b64']] : ['text' => (string)($command['text'] ?? '')]); } break; case 'close': $other = $this->peers[$id]['other'] ?? null; unset($this->peers[$id]); if ($other !== null && isset($this->peers[$other])) { $this->peers[$other]['other'] = null; $this->queue[] = ['ev' => 'state', 'id' => $other, 'state' => 'disconnected']; } break; } } public function listen(callable $listener): void { $this->listeners[] = $listener; } public function poll(): void { foreach (array_splice($this->queue, 0) as $event) { foreach ($this->listeners as $fn) { $fn($event); } } } private function remote(string $id, string $type, string $sdp): void { $other = substr($sdp, 0, 4) === 'sim:' ? substr($sdp, 4) : ''; if (!isset($this->peers[$id], $this->peers[$other])) { $this->queue[] = ['ev' => 'error', 'id' => $id, 'message' => 'the simulated WebRTC only joins peers of this game']; return; } $this->peers[$id]['other'] = $other; if ($type === 'offer') { $this->queue[] = ['ev' => 'state', 'id' => $id, 'state' => 'connecting']; $this->queue[] = ['ev' => 'answer', 'id' => $id, 'sdp' => 'sim:' . $id]; return; } // the offerer got the answer: both sides are connected, the offerer's channels open on both foreach ([$id, $other] as $p) { $this->queue[] = ['ev' => 'state', 'id' => $p, 'state' => 'connected']; foreach ($this->peers[$id]['channels'] as $label) { $this->queue[] = ['ev' => 'open', 'id' => $p, 'label' => $label]; } } } }