Skip to content

Commit

Permalink
Improve ease of use without threads, get rid of ServerEventSource
Browse files Browse the repository at this point in the history
this leaves the responsibility of reading packets and ticking the server up to the user, which allows for more dynamic ticking, custom sleep mechanisms (perhaps RakLib is to share a thread with something else), and easier API use when used without threads.
  • Loading branch information
dktapps committed Apr 23, 2024
1 parent abbb8ed commit 68227b1
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 62 deletions.
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.

0 comments on commit 68227b1

Please sign in to comment.