Adds a Dictionary type for safer array creation in a similar fashion as C#
parent
792c3939ab
commit
6dd2118267
|
@ -7,27 +7,29 @@ use Emulator\Messages\Incoming\ClientMessage;
|
||||||
use Emulator\Messages\Incoming\Handshake\ReleaseVersionMessageEvent;
|
use Emulator\Messages\Incoming\Handshake\ReleaseVersionMessageEvent;
|
||||||
use Emulator\Messages\Incoming\Handshake\SecurityTicketMessageEvent;
|
use Emulator\Messages\Incoming\Handshake\SecurityTicketMessageEvent;
|
||||||
use Emulator\Messages\Incoming\Header;
|
use Emulator\Messages\Incoming\Header;
|
||||||
|
use Emulator\Messages\Incoming\IMessageEvent;
|
||||||
use Emulator\Network\Game\Sessions\Session;
|
use Emulator\Network\Game\Sessions\Session;
|
||||||
|
use Emulator\Utilities\Dictionary;
|
||||||
use SplObjectStorage;
|
use SplObjectStorage;
|
||||||
|
|
||||||
class MessageHandler {
|
class MessageHandler {
|
||||||
private SplObjectStorage $handlers;
|
private Dictionary $handlers;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->handlers = new SplObjectStorage();
|
$this->handlers = new Dictionary(IMessageEvent::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function initialize(): void {
|
public function initialize(): void {
|
||||||
$this->handlers[Header::ReleaseVersion] = new ReleaseVersionMessageEvent();
|
$this->handlers->add(Header::ReleaseVersion, new ReleaseVersionMessageEvent());
|
||||||
$this->handlers[Header::SecurityTicket] = new SecurityTicketMessageEvent();
|
$this->handlers->add(Header::SecurityTicket, new SecurityTicketMessageEvent());
|
||||||
|
|
||||||
Logger::info("Loaded " . count($this->handlers) . " message handlers");
|
Logger::info("Loaded {$this->handlers->count()} message handlers");
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handlePacket(Session $session, ClientMessage $request): void {
|
public function handlePacket(Session $session, ClientMessage $request): void {
|
||||||
if (($header = Header::tryFrom($request->getHeader()))) {
|
if (($header = Header::tryFrom($request->getHeader()))) {
|
||||||
if ($this->handlers->contains($header)) {
|
if ($this->handlers->containsKey($header->value)) {
|
||||||
$this->handlers[$header]->handle($session, $request);
|
$this->handlers->get($header)->handle($session, $request);
|
||||||
} else {
|
} else {
|
||||||
Logger::warn("[{$request->getHeader()}] [$header->name] - Unregistered!");
|
Logger::warn("[{$request->getHeader()}] [$header->name] - Unregistered!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,7 @@ use Emulator\Messages\Outgoing\IMessageComposer;
|
||||||
use Emulator\Messages\Outgoing\ServerMessage;
|
use Emulator\Messages\Outgoing\ServerMessage;
|
||||||
use Override;
|
use Override;
|
||||||
|
|
||||||
class AuthenticatedComposer implements IMessageComposer
|
class AuthenticatedComposer implements IMessageComposer {
|
||||||
{
|
|
||||||
|
|
||||||
#[Override] function compose(ServerMessage $message): void {
|
#[Override] function compose(ServerMessage $message): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,14 +7,15 @@ use Emulator\Encoding\ByteEncoding;
|
||||||
use Emulator\Messages\Incoming\ClientMessage;
|
use Emulator\Messages\Incoming\ClientMessage;
|
||||||
use Emulator\Messages\MessageHandler;
|
use Emulator\Messages\MessageHandler;
|
||||||
use Emulator\Network\Game\Sessions\Session;
|
use Emulator\Network\Game\Sessions\Session;
|
||||||
|
use Emulator\Utilities\Dictionary;
|
||||||
use OpenSwoole\WebSocket\Server;
|
use OpenSwoole\WebSocket\Server;
|
||||||
use OpenSwoole\Http\Request;
|
use OpenSwoole\Http\Request;
|
||||||
use OpenSwoole\WebSocket\Frame;
|
use OpenSwoole\WebSocket\Frame;
|
||||||
|
|
||||||
class GameNetworkServer {
|
class GameNetworkServer {
|
||||||
private array $sessions;
|
private Dictionary $sessions;
|
||||||
public function __construct(private readonly MessageHandler $messageHandler) {
|
public function __construct(private readonly MessageHandler $messageHandler) {
|
||||||
$this->sessions = [];
|
$this->sessions = new Dictionary(Session::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function start(int $port): void {
|
public function start(int $port): void {
|
||||||
|
@ -32,17 +33,17 @@ class GameNetworkServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onOpen(Server $server, Request $request): void {
|
function onOpen(Server $server, Request $request): void {
|
||||||
$this->sessions[$request->fd] = new Session($server, $request);
|
$this->sessions->add($request->fd, new Session($server, $request));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onClose(Server $server, int $fd): void {
|
function onClose(Server $server, int $fd): void {
|
||||||
Logger::info("Connection #$fd has been closed");
|
Logger::info("Connection #$fd has been closed");
|
||||||
unset($this->sessions[$fd]);
|
$this->sessions->remove($fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDisconnect(Server $server, int $fd): void {
|
function onDisconnect(Server $server, int $fd): void {
|
||||||
Logger::info("Connection #$fd has disconnected");
|
Logger::info("Connection #$fd has disconnected");
|
||||||
unset($this->sessions[$fd]);
|
$this->sessions->remove($fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMessage(Server $server, Frame $frame): void {
|
function onMessage(Server $server, Frame $frame): void {
|
||||||
|
@ -52,7 +53,7 @@ class GameNetworkServer {
|
||||||
$length = ByteEncoding::getInt32(array_slice($data, 1, 4));
|
$length = ByteEncoding::getInt32(array_slice($data, 1, 4));
|
||||||
$packet = array_slice($data, 4, $length);
|
$packet = array_slice($data, 4, $length);
|
||||||
|
|
||||||
$this->messageHandler->handlePacket($this->sessions[$frame->fd], new ClientMessage($packet));
|
$this->messageHandler->handlePacket($this->sessions->get($frame->fd), new ClientMessage($packet));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Emulator\Utilities;
|
||||||
|
|
||||||
|
use InvalidArgumentException;
|
||||||
|
|
||||||
|
class Dictionary {
|
||||||
|
private array $arr;
|
||||||
|
public function __construct(private readonly string $valueType) {
|
||||||
|
$this->arr = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add(mixed $key, mixed $value): void {
|
||||||
|
if (!is_int($key) && !is_string($key) && !TypeChecker::isEnum($key)) {
|
||||||
|
throw new InvalidArgumentException('Key must be an integer, string or an enum');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$value instanceof $this->valueType) {
|
||||||
|
throw new InvalidArgumentException("Value must be an instance of {$this->valueType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TypeChecker::isEnum($key)) {
|
||||||
|
$key = $key->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists($key, $this->arr)) {
|
||||||
|
throw new InvalidArgumentException("Key $key already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->arr[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get($key): mixed {
|
||||||
|
if (TypeChecker::isEnum($key)) {
|
||||||
|
$key = $key->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->arr[$key] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function containsKey($key): bool {
|
||||||
|
if (TypeChecker::isEnum($key)) {
|
||||||
|
$key = $key->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_key_exists($key, $this->arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function count(): int {
|
||||||
|
return count($this->arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function remove($key): void {
|
||||||
|
if (TypeChecker::isEnum($key)) {
|
||||||
|
$key = $key->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($this->arr[$key]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Emulator\Utilities;
|
||||||
|
|
||||||
|
class TypeChecker {
|
||||||
|
public static function isEnum($var): bool {
|
||||||
|
return is_object($var) && enum_exists(get_class($var));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue