/** * Connect to ARI. * * @param string $address Example ws://localhost:8088/ari/events?api_key=username:password&app=stasis_app_name */ public function connect($address) { $components = parse_url($address); $host = $components['host']; $port = $components['port']; $path = $components['path']; $query = $components['query']; $queryParts = []; parse_str($query, $queryParts); $this->stasisApplicationName = $queryParts['app']; $apiKey = $queryParts['api_key']; list($username, $password) = explode(':', $apiKey); $this->endpoint = new PestJSON('http://' . $host . ':' . $port . dirname($path)); $this->endpoint->setupAuth($username, $password, 'basic'); $this->wsClient = new WebSocket($address, $this->eventLoop, $this->logger); $this->wsClient->on("message", function (WebSocketMessage $rawMessage) { $message = new Message($rawMessage->getData()); $eventType = '\\phparia\\Events\\' . $message->getType(); if (class_exists($eventType)) { $event = new $eventType($this, $rawMessage->getData()); } else { $this->logger->warn("Event: '{$eventType}' not implemented"); // @todo Create a generic event for any that are not implemented return; } // Emit the specific event (just to get it back to where it came from) if ($event instanceof IdentifiableEventInterface) { $this->logger->notice("Emitting ID event: {$event->getEventId()}"); $this->wsClient->emit($event->getEventId(), array('event' => $event)); } // Emit the general event $this->logger->notice("Emitting event: {$message->getType()}"); $this->wsClient->emit($message->getType(), array('event' => $event)); }); }
public function receive(callable $callback, callable $error) { $should_close = false; $this->client->on('request', function () { $this->logger->notice('Request object created!'); }); $this->client->on('handshake', function () { $this->logger->notice('Handshake received!'); }); $this->client->on('connect', function () { $this->logger->notice('Connected!'); }); $this->client->on('error', function () use($error) { // Call the error callback. $error(); // Reopen the connection. $this->client->close(); $this->client->open(self::TIMEOUT); }); $this->client->on('close', function () use($should_close) { // Reopen the connection. if (!$should_close) { $this->client->open(self::TIMEOUT); } }); $this->client->on('message', function (WebSocketMessageInterface $message) use($callback, &$should_close) { // Wait for the message to be finalized. if (!$message->isFinalised()) { return; } // Get the contents. $contents = json_decode($message->getData(), true); if (!$contents) { return; } // Handle the contents. $value = $this->handleContents($contents); // Call the callback with the value. $result = $callback($value); // If the callback returns true, close the connection. if ($result === true) { $should_close = true; $this->client->close(); } }); }
public function __construct($server, LoggerInterface $logger) { $this->server = $server; $this->logger = $logger; $this->handlers = new \SplObjectStorage(); $this->membership = new \SplObjectStorage(); /** * @var $membership \SplObjectStorage|WebSocketUriHandlerInterface[] */ $membership = $this->membership; $that = $this; $server->on("connect", function (WebSocketTransportInterface $client) use($that, $logger, $membership) { $handler = $that->matchConnection($client); if ($handler) { $logger->notice("Added client {$client->getId()} to " . get_class($handler)); $membership->attach($client, $handler); $handler->emit("connect", array("client" => $client)); $handler->addConnection($client); } else { $logger->err("Cannot route {$client->getId()} with request uri {$client->getHandshakeRequest()->getUriString()}"); } }); $server->on('disconnect', function (WebSocketTransportInterface $client) use($that, $logger, $membership) { if ($membership->contains($client)) { $handler = $membership[$client]; $membership->detach($client); $logger->notice("Removed client {$client->getId()} from" . get_class($handler)); $handler->removeConnection($client); $handler->emit("disconnect", array("client" => $client)); } else { $logger->warn("Client {$client->getId()} not attached to any handler, so cannot remove it!"); } }); $server->on("message", function (WebSocketTransportInterface $client, WebSocketMessageInterface $message) use($that, $logger, $membership) { if ($membership->contains($client)) { $handler = $membership[$client]; $handler->emit("message", compact('client', 'message')); } else { $logger->warn("Client {$client->getId()} not attached to any handler, so cannot forward the message!"); } }); }
/** * Start the server */ public function bind() { $err = $errno = 0; $this->flashPolicyFile = str_replace('to-ports="*', 'to-ports="' . $this->uri->getPort() ?: 80, $this->flashPolicyFile); $serverSocket = stream_socket_server($this->uri->toString(), $errno, $err, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $this->context); $this->logger->notice(sprintf("phpws listening on %s", $this->uri->toString())); if ($serverSocket == false) { $this->logger->err("Error: {$err}"); return; } $timeOut =& $this->purgeUserTimeOut; $sockets = $this->streams; $that = $this; $logger = $this->logger; $this->loop->addReadStream($serverSocket, function ($serverSocket) use($that, $logger, $sockets) { $newSocket = stream_socket_accept($serverSocket); if (false === $newSocket) { return; } stream_set_blocking($newSocket, 0); $client = new WebSocketConnection($newSocket, $that->loop, $logger); $sockets->attach($client); $client->on("handshake", function (Handshake $request) use($that, $client) { $that->emit("handshake", [$client->getTransport(), $request]); }); $client->on("connect", function () use($that, $client, $logger) { $con = $client->getTransport(); $that->getConnections()->attach($con); $that->emit("connect", ["client" => $con]); }); $client->on("message", function ($message) use($that, $client, $logger) { $connection = $client->getTransport(); $that->emit("message", ["client" => $connection, "message" => $message]); }); $client->on("close", function () use($that, $client, $logger, &$sockets, $client) { $sockets->detach($client); $connection = $client->getTransport(); if ($connection) { $that->getConnections()->detach($connection); $that->emit("disconnect", ["client" => $connection]); } }); $client->on("flashXmlRequest", function () use($that, $client) { $client->getTransport()->sendString($that->flashPolicyFile); $client->close(); }); }); $this->loop->addPeriodicTimer(5, function () use($timeOut, $sockets, $that) { # Lets send some pings foreach ($that->getConnections() as $c) { if ($c instanceof WebSocketTransportHybi) { $c->sendFrame(WebSocketFrame::create(WebSocketOpcode::PING_FRAME)); } } $currentTime = time(); if ($timeOut == null) { return; } foreach ($sockets as $s) { if ($currentTime - $s->getLastChanged() > $timeOut) { $s->close(); } } }); }
/** * Logs a message using the logger. * * @param string $message */ public function log($message) { if (isset($this->logger)) { $this->logger->notice($message); } }