Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ease of use without threads, get rid of ServerEventSource #230

Open
wants to merge 2 commits into
base: major-next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 28 additions & 40 deletions src/server/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@

class Server implements ServerInterface{

private const RAKLIB_TPS = 100;
private const RAKLIB_TIME_PER_TICK = 1 / self::RAKLIB_TPS;
public const RAKLIB_TPS = 100;
public const RAKLIB_TIME_PER_TICK = 1 / self::RAKLIB_TPS;

protected int $receiveBytes = 0;
protected int $sendBytes = 0;
Expand Down Expand Up @@ -87,7 +87,6 @@ public function __construct(
protected ServerSocket $socket,
protected int $maxMtuSize,
ProtocolAcceptor $protocolAcceptor,
private ServerEventSource $eventSource,
private ServerEventListener $eventListener,
private ExceptionTraceCleaner $traceCleaner,
private int $recvMaxSplitParts = ServerSession::DEFAULT_MAX_SPLIT_PART_COUNT,
Expand All @@ -113,58 +112,40 @@ public function getLogger() : \Logger{
return $this->logger;
}

public function tickProcessor() : void{
$start = microtime(true);

/*
* The below code is designed to allow co-op between sending and receiving to avoid slowing down either one
* when high traffic is coming either way. Yielding will occur after 100 messages.
*/
do{
$stream = !$this->shutdown;
for($i = 0; $i < 100 && $stream && !$this->shutdown; ++$i){ //if we received a shutdown event, we don't care about any more messages from the event source
$stream = $this->eventSource->process($this);
}

$socket = true;
for($i = 0; $i < 100 && $socket; ++$i){
$socket = $this->receivePacket();
}
}while($stream || $socket);

$this->tick();

$time = microtime(true) - $start;
if($time < self::RAKLIB_TIME_PER_TICK){
@time_sleep_until(microtime(true) + self::RAKLIB_TIME_PER_TICK - $time);
}
}

/**
* Disconnects all sessions and blocks until everything has been shut down properly.
*/
public function waitShutdown() : void{
$this->shutdown = true;

while($this->eventSource->process($this)){
//Ensure that any late messages are processed before we start initiating server disconnects, so that if the
//server implementation used a custom disconnect mechanism (e.g. a server transfer), we don't break it in
//race conditions.
}

foreach($this->sessions as $session){
$session->initiateDisconnect(DisconnectReason::SERVER_SHUTDOWN);
}

while(count($this->sessions) > 0){
$this->tickProcessor();
$start = microtime(true);

while($this->receivePacket()){
//NOOP
}
$this->tick();

$time = microtime(true) - $start;
if($time < self::RAKLIB_TIME_PER_TICK && count($this->sessions) > 0){
@time_sleep_until(microtime(true) + self::RAKLIB_TIME_PER_TICK - $time);
}
}

$this->socket->close();
$this->logger->debug("Graceful shutdown complete");
}

private function tick() : void{
/**
* Ticks sessions, updates bandwidth stats and IP bans, and other heartbeat tasks.
* This should be called once per 10ms. It must be called in regular intervals.
* @see self::RAKLIB_TIME_PER_TICK
*/
public function tick() : void{
$time = microtime(true);
foreach($this->sessions as $session){
$session->update($time);
Expand Down Expand Up @@ -198,8 +179,15 @@ private function tick() : void{
++$this->ticks;
}

/** @phpstan-impure */
private function receivePacket() : bool{
/**
* Reads a packet from the socket and processes it.
*
* This should be called in a loop until it returns false. However, it may be desirable to break out of the loop
* to do other tasks even if there are packets left to process, to ensure high traffic doesn't starve other tasks.
*
* @phpstan-impure
*/
public function receivePacket() : bool{
try{
$buffer = $this->socket->readPacket($addressIp, $addressPort);
}catch(SocketException $e){
Expand Down
22 changes: 0 additions & 22 deletions src/server/ServerEventSource.php

This file was deleted.