|
@@ -84,33 +84,57 @@
|
|
|
$this->fire('open', $this);
|
|
|
return $this;
|
|
|
}
|
|
|
- public function handle(){
|
|
|
+ public function handle(int $length = 2048, bool $binary = false){
|
|
|
if(!$this->open){
|
|
|
$this->open();
|
|
|
}
|
|
|
+ socket_set_nonblock($this->socket);
|
|
|
if($this->socket_type == static::SERVER){
|
|
|
- socket_set_nonblock($this->socket);
|
|
|
+ $regex = $binary ? '/\0/' : '/[\n\r]/';
|
|
|
+ $type = $binary ? PHP_BINARY_READ : PHP_NORMAL_READ;
|
|
|
do{
|
|
|
- $client = socket_accept($this->socket);
|
|
|
- if($client === false){
|
|
|
- $this->open = $this->error !== 'A non-blocking socket operation could not be completed immediately.';
|
|
|
- }elseif(!is_null($client)){
|
|
|
- socket_set_nonblock($client);
|
|
|
- $this->client = $client;
|
|
|
- $this->fire('connect', $this);
|
|
|
- while($this->open && $this->read() !== false){};
|
|
|
- socket_set_block($client);
|
|
|
- socket_close($client);
|
|
|
- $this->client = null;
|
|
|
- $this->fire('disconnect', $this);
|
|
|
+ $socket = socket_accept($this->socket);
|
|
|
+ if($socket === false){
|
|
|
+ usleep(100);
|
|
|
+ }elseif($socket > 0){
|
|
|
+ socket_set_nonblock($socket);
|
|
|
+ $client = [$socket, ''];
|
|
|
+ $this->clients[] = $client;
|
|
|
+ $this->fire('connect', $this, $client);
|
|
|
+ }else{
|
|
|
+ $error = trim(socket_strerror($socket));
|
|
|
+ if($error !== 'A non-blocking socket operation could not be completed immediately.'){
|
|
|
+ $this->fire('error', $this, new \Exception($error));
|
|
|
+ $this->open = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $this->fire('tick', $this);
|
|
|
+ if($this->open){
|
|
|
+ foreach($this->clients as $client){
|
|
|
+ $data = socket_read($client[0], $length, $type);
|
|
|
+ if($data === false){
|
|
|
+ $this->drop($client);
|
|
|
+ }else{
|
|
|
+ if(strlen($data) > 0 && $this->fire('data', $this, $data, $client) !== false){
|
|
|
+ $client[1] .= $data;
|
|
|
+ }
|
|
|
+ $pos = preg_match($regex, $data, $matches, PREG_OFFSET_CAPTURE) == 1 ? $matches[0][1] : false;
|
|
|
+ if($pos === strlen($data) - 1){
|
|
|
+ $this->fire('read', $this, substr($client[1], 0, -1), $client);
|
|
|
+ $client[1] = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ $this->fire('tick', $this);
|
|
|
+ if($this->open === false){
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}while($this->open);
|
|
|
- socket_set_block($this->socket);
|
|
|
}elseif($this->socket_type == static::CLIENT){
|
|
|
- socket_set_nonblock($this->client);
|
|
|
- while($this->open && $this->read() !== false){};
|
|
|
- socket_set_block($this->client);
|
|
|
+ while($this->open && $this->read($length, $binary) !== false){};
|
|
|
}
|
|
|
+ socket_set_block($this->socket);
|
|
|
$this->close(true);
|
|
|
return $this;
|
|
|
}
|
|
@@ -129,31 +153,45 @@
|
|
|
return false;
|
|
|
}
|
|
|
$regex = $binary ? '/\0/' : '/[\n\r]/';
|
|
|
+ $type = $binary ? PHP_BINARY_READ : PHP_NORMAL_READ;
|
|
|
$line = '';
|
|
|
do{
|
|
|
- $data = socket_read($this->socket, $length, $binary ? PHP_BINARY_READ : PHP_NORMAL_READ);
|
|
|
+ $data = socket_read($this->socket, $length, $type);
|
|
|
if($data === false){
|
|
|
$this->open = false;
|
|
|
}elseif(strlen($data) > 0 && $this->fire('data', $this, $data) !== false){
|
|
|
$line .= $data;
|
|
|
}
|
|
|
$pos = preg_match($regex, $data, $matches, PREG_OFFSET_CAPTURE) == 1 ? $matches[0][1] : false;
|
|
|
- $this->fire('tick', $this);
|
|
|
}while($pos !== strlen($data) - 1 && $this->open !== false);
|
|
|
$line = substr($line, 0, -1);
|
|
|
$this->fire('read', $this, $line);
|
|
|
return $line;
|
|
|
}
|
|
|
+ public function client_write(array $client, $data, bool $binary = false){
|
|
|
+ if(!$this->open){
|
|
|
+ throw new \Exception("You can't write to a socket that isn't open");
|
|
|
+ }
|
|
|
+ $stop = $binary ? "\0" : "\n";
|
|
|
+ if($this->fire('write', $this, $data) !== false){
|
|
|
+ $this->throw_if(socket_write($client[0], $data.$stop));
|
|
|
+ }
|
|
|
+ return $this;
|
|
|
+ }
|
|
|
public function close(bool $event = false){
|
|
|
- $this->drop();
|
|
|
+ foreach($this->clients as $client){
|
|
|
+ $this->drop($client);
|
|
|
+ }
|
|
|
socket_close($this->socket);
|
|
|
$this->open = false;
|
|
|
$this->fire('close', $this);
|
|
|
return $this;
|
|
|
}
|
|
|
public function drop($client){
|
|
|
- if(!is_null($client)){
|
|
|
- socket_close($client);
|
|
|
+ socket_close($client[0]);
|
|
|
+ if(in_array($client, $this->clients)){
|
|
|
+ array_splice($this->clients, array_search($client, $this->clients), 1);
|
|
|
+ $this->fire('disconnect', $this, $client);
|
|
|
}
|
|
|
}
|
|
|
}
|