*/ class struct_subject/**/ { /** * @var int * @author Christian Fraß */ public $port; /** * @var function * @author Christian Fraß */ public $handler; /** * whether a global handler for the operating systems interrupt signal (SIGINT) shall be installed for stopping the * server gracfully * * @var boolean * @author Christian Fraß */ public $install_killhandler; /** * procedure to be executed on start * * @var function,void> * @author Christian Fraß */ public $on_starting; /** * procedure to be executed on stop * * @var function,void> * @author Christian Fraß */ public $on_stopping; /** * procedure to be executed on start * * @var function,void> * @author Christian Fraß */ public $on_started; /** * procedure to be executed on stop * * @var function,void> * @author Christian Fraß */ public $on_stopped; /** * @var any * @author Christian Fraß */ public $socket; /** * whether the server is supposed to shutdown * * @var boolean * @author Christian Fraß */ public $run; /** * @author Christian Fraß */ public function __construct( int $port, \Closure $handler, bool $install_killhandler, \Closure $on_starting, \Closure $on_stopping, \Closure $on_started, \Closure $on_stopped ) { $this->port = $port; $this->handler = $handler; $this->install_killhandler = $install_killhandler; $this->on_starting = $on_starting; $this->on_stopping = $on_stopping; $this->on_started = $on_started; $this->on_stopped = $on_stopped; $this->socket = null; $this->run = false; } } /** * @param int $port * @param function $handler * @param boolean $install_killhandler * @param function,void> [$on_starting] * @param function,void> [$on_stopping] * @param function,void> [$on_started] * @param function,void> [$on_stopped] * @return struct_subject * @author Christian Fraß */ function make( int $port, \Closure $handler, bool $install_killhandler = false, \Closure $on_starting = null, \Closure $on_stopping = null, \Closure $on_started = null, \Closure $on_stopped = null ) : struct_subject { if ($on_starting === null) { $on_starting = function () { \alveolata\log\info('starting server …'); }; } if ($on_stopping === null) { $on_stopping = function () { \alveolata\log\info('stopping server …'); }; } if ($on_started === null) { $on_started = function () { \alveolata\log\info('server started'); }; } if ($on_stopped === null) { $on_stopped = function () { \alveolata\log\info('server stopped'); }; } return ( new struct_subject( $port, $handler, $install_killhandler, $on_starting, $on_stopping, $on_started, $on_stopped ) ); } /** * @param struct_subject $subject * @author Christian Fraß */ function killhandler( struct_subject/**/ $subject ) : void { \alveolata\log\warning( 'killhandler for server won\'t work' ); /* \pcntl_signal( SIGINT, function ($signo) use (&$subject) {stop($subject);} ); */ } /** * @param struct_subject $subject * @author Christian Fraß */ function stop/**/( struct_subject/**/ $subject ) : void { ($subject->on_stopping)(); if (! ($subject->socket === null)) { \socket_shutdown($subject->socket); } $subject->run = false; } /** * @param struct_subject $subject * @author Christian Fraß */ function start/**/( struct_subject/**/ $subject ) : void { $conf = [ 'host' => 'localhost', 'max_connections' => 7, 'buffer_length' => 2048, ]; ($subject->on_starting)(); if ($subject->install_killhandler) { killhandler($subject); } $subject->run = true; $socket = \socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); // \socket_set_nonblock($socket); \socket_bind( $socket, $conf['host'], $subject->port ); \socket_listen( $socket, $conf['max_connections'] ); ($subject->on_started)(); while ($subject->run) { $subject->socket = $request = \socket_accept( $socket ); /*if ($request === false) { usleep(125000); } else {*/ $input = \socket_read( $request, $conf['buffer_length'] ); $output = ($subject->handler)($input); $bytes = \socket_write( $request, $output, strlen($output) ); $successful = ($bytes !== false); if (! $successful) { \error_log('could not write to socket; shutting down server'); break; } /*}*/ } \socket_close( $request ); \socket_close( $socket ); ($subject->on_stopped)(); } ?>