R controller

This commit is contained in:
a6a2f5842 2025-12-05 22:08:47 +01:00
parent ad0e8d556f
commit ae22264aea
1 changed files with 94 additions and 87 deletions

View File

@ -14,12 +14,23 @@ use Illuminate\Support\Facades\Log;
class Controller
{
protected bool $isMockConnection;
protected ?MockConnection $mockConnectionClone = null;
final public function __construct(
protected ConnectionInterface $connection,
protected PrivateChannel|Channel|PresenceChannel|null $channel,
protected string $event,
protected LocalChannelManager|RedisChannelManager $channelManager
) {}
) {
// Cache class check to avoid repeated get_class() calls (reflection is slow)
$this->isMockConnection = get_class($connection) === MockConnection::class;
// Pre-clone MockConnection once if needed (reuse across method calls)
if ($this->isMockConnection) {
$this->mockConnectionClone = clone $connection;
}
}
public static function controll_message(
ConnectionInterface $connection,
@ -28,15 +39,8 @@ class Controller
LocalChannelManager|RedisChannelManager $channelManager
) {
$event = self::get_event($message);
if (count($event) != 2) {
return $connection->send(json_encode([
'event' => $message['event'] . ':error',
'data' => [
'message' => 'Event unknown',
],
'channel' => $message['channel'],
]));
if (count($event) !== 2) {
return self::send_error($connection, $message, 'Event unknown');
}
try {
@ -44,43 +48,29 @@ class Controller
? implode('', array_map(fn($item) => ucfirst($item), explode('-', $event[0])))
: ucfirst($event[0]);
$vendorcontroller = '\BlaxSoftware\LaravelWebSockets\Websocket\Controllers\\' . $contr . 'Controller';
$appcontroller = '\App\Websocket\Controllers\\' . $contr . 'Controller';
$vendorcontroller = '\\BlaxSoftware\\LaravelWebSockets\\Websocket\\Controllers\\' . $contr . 'Controller';
$appcontroller = '\\App\\Websocket\\Controllers\\' . $contr . 'Controller';
$method = static::without_uniquifyer($event[1]);
$controller = class_exists($appcontroller)
$controllerClass = class_exists($appcontroller)
? $appcontroller
: $vendorcontroller;
: (class_exists($vendorcontroller) ? $vendorcontroller : null);
if (! $controller) {
return $connection->send(json_encode([
'event' => $message['event'] . ':error',
'data' => [
'message' => 'Event could not be associated',
],
'channel' => $message['channel'],
]));
if (! $controllerClass) {
return self::send_error($connection, $message, 'Event could not be associated');
}
if (! method_exists($controller, $method)) {
return $connection->send(json_encode([
'event' => $message['event'] . ':error',
'data' => [
'message' => 'Event could not be handled',
],
'channel' => $message['channel'],
]));
if (! method_exists($controllerClass, $method)) {
return self::send_error($connection, $message, 'Event could not be handled');
}
// Instantiate the controller
$controller = (new $controller(
$controller = new $controllerClass(
$connection,
$channel,
$message['event'],
$channelManager
));
);
// Return unauthorized if auth is required
if (($controller->need_auth ?? true) && ! $connection->user) {
return $controller->error('Unauthorized');
}
@ -91,11 +81,8 @@ class Controller
$message['channel']
);
if (
$payload === false
|| $payload === true
) {
return;
if ($payload === false || $payload === true) {
return null;
}
$connection->send(json_encode([
@ -115,25 +102,12 @@ class Controller
];
Log::error($e->getMessage(), $reload);
return $connection->send(json_encode([
'event' => $message['event'] . ':error',
'data' => [
'message' => $e->getMessage(),
'meta' => [
'reported' => true,
],
],
'channel' => $message['channel'],
]));
if (app()->bound('sentry')) {
app('sentry')->captureException($e);
}
return $connection->send(json_encode([
'event' => $message['event'] . ':error',
'data' => [
'message' => 'An unknown error occured',
],
'channel' => $message['channel'],
]));
return self::send_error($connection, $message, $e->getMessage(), true);
}
}
final public function progress(
@ -155,11 +129,13 @@ class Controller
$p['data'] = $payload['data'];
}
if (get_class($this->connection) === MockConnection::class) {
$connection = clone $this->connection;
$connection->send(json_encode($p));
// Pre-encode once (avoid repeated encoding)
$encoded = json_encode($p);
if ($this->isMockConnection) {
$this->mockConnectionClone->send($encoded);
} else {
$this->connection->send(json_encode($p));
$this->connection->send($encoded);
}
return true;
@ -184,11 +160,13 @@ class Controller
$p['data'] = $payload['data'];
}
if (get_class($this->connection) === MockConnection::class) {
$connection = clone $this->connection;
$connection->send(json_encode($p));
// Pre-encode once (avoid repeated encoding)
$encoded = json_encode($p);
if ($this->isMockConnection) {
$this->mockConnectionClone->send($encoded);
} else {
$this->connection->send(json_encode($p));
$this->connection->send($encoded);
}
return true;
@ -227,11 +205,13 @@ class Controller
Log::channel('websocket')->error('Send error: ' . @$p['data']['message'], $p);
if (get_class($this->connection) === MockConnection::class) {
$connection = clone $this->connection;
$connection->send(json_encode($p));
// Pre-encode once (avoid repeated encoding)
$encoded = json_encode($p);
if ($this->isMockConnection) {
$this->mockConnectionClone->send($encoded);
} else {
$this->connection->send(json_encode($p));
$this->connection->send($encoded);
}
return true;
@ -257,24 +237,26 @@ class Controller
'channel' => $channel,
];
if (get_class($this->connection) !== MockConnection::class) {
if (!$this->isMockConnection) {
if (! $channel) {
$this->error('Channel not found');
return;
}
// Pre-encode ONCE - massive improvement for 100+ connections
$encoded = json_encode($p);
foreach ($this->channel->getConnections() as $channel_conection) {
if ($channel_conection !== $this->connection) {
$channel_conection->send(json_encode($p));
$channel_conection->send($encoded);
}
if ($including_self) {
$this->connection->send(json_encode($p));
$this->connection->send($encoded);
}
}
} else {
$connection = clone $this->connection;
$connection->broadcast(
$this->mockConnectionClone->broadcast(
$p,
$channel,
$including_self
@ -302,20 +284,25 @@ class Controller
'channel' => $channel,
];
if (get_class($this->connection) !== MockConnection::class) {
if (!$this->isMockConnection) {
if (! $channel) {
$this->error('Channel not found');
return;
}
// Pre-encode ONCE for all matching sockets
$encoded = json_encode($p);
// Use array_flip for O(1) lookup instead of O(n) in_array
$socketIdLookup = array_flip($socketIds);
foreach ($this->channel->getConnections() as $channel_conection) {
if (in_array($channel_conection->socketId, $socketIds)) {
$channel_conection->send(json_encode($p));
if (isset($socketIdLookup[$channel_conection->socketId])) {
$channel_conection->send($encoded);
}
}
} else {
$connection = clone $this->connection;
$connection->whisper(
$this->mockConnectionClone->whisper(
$p,
$socketIds,
$channel
@ -323,6 +310,26 @@ class Controller
}
}
private static function send_error(
ConnectionInterface $connection,
array $message,
string $reason,
bool $reported = false
) {
$connection->send(json_encode([
'event' => ($message['event'] ?? 'unknown') . ':error',
'data' => [
'message' => $reason,
'meta' => [
'reported' => $reported,
],
],
'channel' => $message['channel'] ?? null,
]));
return null;
}
protected static function get_uniquifyer($event)
{
preg_match('/[\[].*[\]]/', $event, $matches);