/**
  * Returns true if the underlying socket is open, false if it has been closed.
  *
  * @return bool
  */
 public function isOpen() : bool
 {
     return $this->socket->isOpen();
 }
Example #2
0
 /**
  * Services requests for a connected client.
  *
  * Manages the server-side state for the remote client and interprets client commands.
  */
 private function handleClient(Socket $socket) : Generator
 {
     yield from log()->log(Log::INFO, 'Accepted client from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort());
     // Create a new context object for this client.
     $context = new ClientContext($socket, $this->encoder, $this->accessLayer);
     try {
         // Send a welcome message.
         $welcome = new Response(200, 'Ready');
         yield from $context->writeResponse($welcome);
         // Command loop
         while ($socket->isOpen()) {
             // Parse incoming commands.
             $command = (yield from $context->readCommand());
             // Determine the command name and choose how to handle it.
             $handler = null;
             switch ($command->name()) {
                 // Mandatory commands
                 case 'CAPABILITIES':
                     $handler = $this->getHandler(handlers\CapabilitiesHandler::class);
                     break;
                 case 'HEAD':
                     $handler = $this->getHandler(handlers\HeadHandler::class);
                     break;
                 case 'HELP':
                     $handler = $this->getHandler(handlers\HelpHandler::class);
                     break;
                     // We don't advertise MODE support, but some readers need it
                 // We don't advertise MODE support, but some readers need it
                 case 'MODE':
                     $handler = $this->getHandler(handlers\ModeHandler::class);
                     break;
                 case 'STAT':
                     $handler = $this->getHandler(handlers\StatHandler::class);
                     break;
                 case 'QUIT':
                     yield from $context->writeResponse(new Response(205, 'Closing connection'));
                     break 2;
                     // stop command loop
                     // LIST commands
                 // stop command loop
                 // LIST commands
                 case 'LIST':
                     $handler = $this->getHandler(handlers\ListHandler::class);
                     break;
                     // NEWNEWS commands
                 // NEWNEWS commands
                 case 'NEWNEWS':
                     $handler = $this->getHandler(handlers\NewNewsHandler::class);
                     break;
                     // POST commands
                 // POST commands
                 case 'POST':
                     $handler = $this->getHandler(handlers\PostHandler::class);
                     break;
                     // READER commands
                 // READER commands
                 case 'ARTICLE':
                     $handler = $this->getHandler(handlers\ArticleHandler::class);
                     break;
                 case 'BODY':
                     $handler = $this->getHandler(handlers\BodyHandler::class);
                     break;
                 case 'DATE':
                     $handler = $this->getHandler(handlers\DateHandler::class);
                     break;
                 case 'GROUP':
                     $handler = $this->getHandler(handlers\GroupHandler::class);
                     break;
                 case 'LAST':
                     $handler = $this->getHandler(handlers\LastHandler::class);
                     break;
                 case 'LISTGROUP':
                     $handler = $this->getHandler(handlers\ListGroupHandler::class);
                     break;
                 case 'NEWGROUPS':
                     $handler = $this->getHandler(handlers\NewGroupsHandler::class);
                     break;
                 case 'NEXT':
                     $handler = $this->getHandler(handlers\NextHandler::class);
                     break;
             }
             // Unknown command
             if (!$handler) {
                 yield from $context->writeResponse(new Response(500, 'Unknown command'));
             } else {
                 // Execute the selected command handler.
                 try {
                     yield from $handler->handle($command, $context);
                 } catch (\Throwable $e) {
                     yield from log()->log(Log::ERROR, 'Error handling command: ' . $e);
                     yield from $context->writeResponse(new Response(502, 'Server error'));
                 }
             }
         }
     } catch (UnreadableException $e) {
         // Client disconnected.
     } catch (UnwritableException $e) {
         // Client disconnected.
     } catch (ClosedException $e) {
         // Client disconnected.
     }
     yield from log()->log(Log::INFO, 'Disconnected client from %s:%d on %s:%d', $socket->getRemoteAddress(), $socket->getRemotePort(), $socket->getLocalAddress(), $socket->getLocalPort());
     // Close the connection to the client.
     if ($socket->isOpen()) {
         $socket->close();
     }
 }