2020-01-01 13:17:19 +08:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\VarDumper\Server ;
use Psr\Log\LoggerInterface ;
use Symfony\Component\VarDumper\Cloner\Data ;
use Symfony\Component\VarDumper\Cloner\Stub ;
/**
* A server collecting Data clones sent by a ServerDumper .
*
* @ author Maxime Steinhausser < maxime . steinhausser @ gmail . com >
*
* @ final
*/
class DumpServer
{
private $host ;
private $socket ;
private $logger ;
public function __construct ( string $host , LoggerInterface $logger = null )
{
2021-08-04 18:44:24 +08:00
if ( ! str_contains ( $host , '://' )) {
2020-01-01 13:17:19 +08:00
$host = 'tcp://' . $host ;
}
$this -> host = $host ;
$this -> logger = $logger ;
}
public function start () : void
{
if ( ! $this -> socket = stream_socket_server ( $this -> host , $errno , $errstr )) {
2020-06-19 16:30:27 +08:00
throw new \RuntimeException ( sprintf ( 'Server start failed on "%s": ' , $this -> host ) . $errstr . ' ' . $errno );
2020-01-01 13:17:19 +08:00
}
}
public function listen ( callable $callback ) : void
{
if ( null === $this -> socket ) {
$this -> start ();
}
foreach ( $this -> getMessages () as $clientId => $message ) {
$payload = @ unserialize ( base64_decode ( $message ), [ 'allowed_classes' => [ Data :: class , Stub :: class ]]);
// Impossible to decode the message, give up.
if ( false === $payload ) {
if ( $this -> logger ) {
$this -> logger -> warning ( 'Unable to decode a message from {clientId} client.' , [ 'clientId' => $clientId ]);
}
continue ;
}
if ( ! \is_array ( $payload ) || \count ( $payload ) < 2 || ! $payload [ 0 ] instanceof Data || ! \is_array ( $payload [ 1 ])) {
if ( $this -> logger ) {
$this -> logger -> warning ( 'Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)' , [ 'clientId' => $clientId ]);
}
continue ;
}
2021-01-30 17:47:18 +08:00
[ $data , $context ] = $payload ;
2020-01-01 13:17:19 +08:00
$callback ( $data , $context , $clientId );
}
}
public function getHost () : string
{
return $this -> host ;
}
private function getMessages () : iterable
{
$sockets = [( int ) $this -> socket => $this -> socket ];
$write = [];
while ( true ) {
$read = $sockets ;
stream_select ( $read , $write , $write , null );
foreach ( $read as $stream ) {
if ( $this -> socket === $stream ) {
$stream = stream_socket_accept ( $this -> socket );
$sockets [( int ) $stream ] = $stream ;
} elseif ( feof ( $stream )) {
unset ( $sockets [( int ) $stream ]);
fclose ( $stream );
} else {
yield ( int ) $stream => fgets ( $stream );
}
}
}
}
}