diff --git a/app/realtime.php b/app/realtime.php index a125118654..6d94b2cc4a 100644 --- a/app/realtime.php +++ b/app/realtime.php @@ -1,336 +1,13 @@ set([ +$config = [ 'package_max_length' => 64000 // Default maximum Package Size (64kb) -]); +]; -$subscriptions = []; -$connections = []; - -$stats = new Table(4096, 1); -$stats->column('projectId', Table::TYPE_STRING, 64); -$stats->column('connections', Table::TYPE_INT); -$stats->column('connectionsTotal', Table::TYPE_INT); -$stats->column('messages', Table::TYPE_INT); -$stats->create(); - -/** - * Sends usage stats every 10 seconds. - */ -Timer::tick(10000, function () use (&$stats) { - /** @var Table $stats */ - foreach ($stats as $projectId => $value) { - if (empty($value['connections']) && empty($value['messages'])) { - continue; - } - - $connections = $value['connections']; - $messages = $value['messages']; - - $usage = new Event('v1-usage', 'UsageV1'); - $usage - ->setParam('projectId', $projectId) - ->setParam('realtimeConnections', $connections) - ->setParam('realtimeMessages', $messages) - ->setParam('networkRequestSize', 0) - ->setParam('networkResponseSize', 0); - - $stats->set($projectId, [ - 'projectId' => $projectId, - 'messages' => 0, - 'connections' => 0 - ]); - - if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { - $usage->trigger(); - } - } -}); - -$server->on('workerStart', function ($server, $workerId) use (&$subscriptions, &$register, &$stats) { - Console::success('Worker ' . $workerId . ' started succefully'); - - $attempts = 0; - $start = time(); - $redisPool = $register->get('redisPool'); - - /** - * Sending current connections to project channels on the console project every 5 seconds. - */ - $server->tick(5000, function () use (&$server, &$subscriptions, &$stats) { - if ( - array_key_exists('console', $subscriptions) - && array_key_exists('role:member', $subscriptions['console']) - && array_key_exists('project', $subscriptions['console']['role:member']) - ) { - $payload = []; - foreach ($stats as $projectId => $value) { - $payload[$projectId] = $value['connectionsTotal']; - } - foreach ($subscriptions['console']['role:member']['project'] as $connection => $value) { - $server->push( - $connection, - json_encode([ - 'event' => 'stats.connections', - 'channels' => ['project'], - 'timestamp' => time(), - 'payload' => $payload - ]), - SWOOLE_WEBSOCKET_OPCODE_TEXT, - SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS - ); - } - } - }); - - while ($attempts < 300) { - try { - if ($attempts > 0) { - Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . '). - Attempting restart in 5 seconds (attempt #' . $attempts . ')'); - sleep(5); // 5 sec delay between connection attempts - } - - /** @var Swoole\Coroutine\Redis $redis */ - $redis = $redisPool->get(); - - if ($redis->ping(true)) { - $attempts = 0; - Console::success('Pub/sub connection established (worker: ' . $workerId . ')'); - } else { - Console::error('Pub/sub failed (worker: ' . $workerId . ')'); - } - - $redis->subscribe(['realtime'], function ($redis, $channel, $payload) use ($server, $workerId, &$subscriptions, &$stats) { - /** - * Supported Resources: - * - Collection - * - Document - * - File - * - Account - * - Session - * - Team? (not implemented yet) - * - Membership? (not implemented yet) - * - Function - * - Execution - */ - $event = json_decode($payload, true); - - $receivers = Realtime::identifyReceivers($event, $subscriptions); - - - // Temporarily print debug logs by default for Alpha testing. - // if (App::isDevelopment() && !empty($receivers)) { - if (!empty($receivers)) { - Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers)); - Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers)); - Console::log("[Debug][Worker {$workerId}] Event: " . $payload); - } - - foreach ($receivers as $receiver) { - if ($server->exist($receiver) && $server->isEstablished($receiver)) { - $server->push( - $receiver, - json_encode($event['data']), - SWOOLE_WEBSOCKET_OPCODE_TEXT, - SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS - ); - } else { - $server->close($receiver); - } - } - if (($num = count($receivers)) > 0) { - $stats->incr($event['project'], 'messages', $num); - } - }); - } catch (\Throwable $th) { - Console::error('Pub/sub error: ' . $th->getMessage()); - $redisPool->put($redis); - $attempts++; - continue; - } - - $attempts++; - } - - Console::error('Failed to restart pub/sub...'); -}); - -$server->on('start', function (Server $server) { - Console::success('Server started succefully'); - - Console::info("Master pid {$server->master_pid}, manager pid {$server->manager_pid}"); - - // listen ctrl + c - Process::signal(2, function () use ($server) { - Console::log('Stop by Ctrl+C'); - $server->shutdown(); - }); -}); - -$server->on('open', function (Server $server, Request $request) use (&$connections, &$subscriptions, &$register, &$stats) { - $app = new App('UTC'); - $connection = $request->fd; - $request = new SwooleRequest($request); - - $db = $register->get('dbPool')->get(); - $redis = $register->get('redisPool')->get(); - - $register->set('db', function () use (&$db) { - return $db; - }); - - $register->set('cache', function () use (&$redis) { // Register cache connection - return $redis; - }); - - Console::info("Connection open (user: {$connection}, worker: {$server->getWorkerId()})"); - - App::setResource('request', function () use ($request) { - return $request; - }); - - App::setResource('response', function () { - return new Response(new SwooleResponse()); - }); - - try { - /** @var Appwrite\Database\Document $user */ - $user = $app->getResource('user'); - - /** @var Appwrite\Database\Document $project */ - $project = $app->getResource('project'); - - /** @var Appwrite\Database\Document $console */ - $console = $app->getResource('console'); - - /* - * Project Check - */ - if (empty($project->getId())) { - throw new Exception('Missing or unknown project ID', 1008); - } - - /* - * Abuse Check - * - * Abuse limits are connecting 128 times per minute and ip address. - */ - $timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, function () use ($db) { - return $db; - }); - $timeLimit - ->setNamespace('app_' . $project->getId()) - ->setParam('{ip}', $request->getIP()) - ->setParam('{url}', $request->getURI()); - - $abuse = new Abuse($timeLimit); - - if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') { - throw new Exception('Too many requests', 1013); - } - - /* - * Validate Client Domain - Check to avoid CSRF attack. - * Adding Appwrite API domains to allow XDOMAIN communication. - * Skip this check for non-web platforms which are not required to send an origin header. - */ - $origin = $request->getOrigin(); - $originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', []))); - - if (!$originValidator->isValid($origin) && $project->getId() !== 'console') { - throw new Exception($originValidator->getDescription(), 1008); - } - - Realtime::setUser($user); - - $roles = Realtime::getRoles(); - $channels = Realtime::parseChannels($request->getQuery('channels', [])); - - /** - * Channels Check - */ - if (empty($channels)) { - throw new Exception('Missing channels', 1008); - } - - Realtime::subscribe($project->getId(), $connection, $roles, $subscriptions, $connections, $channels); - - $server->push($connection, json_encode($channels)); - - $stats->incr($project->getId(), 'connections'); - $stats->incr($project->getId(), 'connectionsTotal'); - } catch (\Throwable $th) { - $response = [ - 'code' => $th->getCode(), - 'message' => $th->getMessage() - ]; - // Temporarily print debug logs by default for Alpha testing. - //if (App::isDevelopment()) { - Console::error("[Error] Connection Error"); - Console::error("[Error] Code: " . $response['code']); - Console::error("[Error] Message: " . $response['message']); - //} - $server->push($connection, json_encode($response)); - $server->close($connection); - } - /** - * Put used PDO and Redis Connections back into their pools. - */ - /** @var PDOPool $dbPool */ - $dbPool = $register->get('dbPool'); - $dbPool->put($db); - - /** @var RedisPool $redisPool */ - $redisPool = $register->get('redisPool'); - $redisPool->put($redis); -}); - -$server->on('message', function (Server $server, Frame $frame) { - $server->push($frame->fd, 'Sending messages is not allowed.'); - $server->close($frame->fd); -}); - -$server->on('close', function (Server $server, int $connection) use (&$connections, &$subscriptions, &$stats) { - if (array_key_exists($connection, $connections)) { - $stats->decr($connections[$connection]['projectId'], 'connectionsTotal'); - } - Realtime::unsubscribe($connection, $subscriptions, $connections); - Console::info('Connection close: ' . $connection); -}); - -$server->start(); +$realtimeServer = new Server($register, config: $config); diff --git a/src/Appwrite/Realtime/Realtime.php b/src/Appwrite/Realtime/Parser.php similarity index 99% rename from src/Appwrite/Realtime/Realtime.php rename to src/Appwrite/Realtime/Parser.php index f0f893f267..f99e7bfbe9 100644 --- a/src/Appwrite/Realtime/Realtime.php +++ b/src/Appwrite/Realtime/Parser.php @@ -5,7 +5,7 @@ namespace Appwrite\Realtime; use Appwrite\Auth\Auth; use Appwrite\Database\Document; -class Realtime +class Parser { /** * @var Document $user diff --git a/src/Appwrite/Realtime/Server.php b/src/Appwrite/Realtime/Server.php new file mode 100644 index 0000000000..0eed3f24b4 --- /dev/null +++ b/src/Appwrite/Realtime/Server.php @@ -0,0 +1,393 @@ +subscriptions = []; + $this->connections = []; + $this->register = $register; + + $this->stats = new Table(4096, 1); + $this->stats->column('projectId', Table::TYPE_STRING, 64); + $this->stats->column('connections', Table::TYPE_INT); + $this->stats->column('connectionsTotal', Table::TYPE_INT); + $this->stats->column('messages', Table::TYPE_INT); + $this->stats->create(); + + $this->server = new SwooleServer($host, $port, SWOOLE_PROCESS); + $this->server->set($config); + $this->server->on('start', [$this, 'onStart']); + $this->server->on('workerStart', [$this, 'onWorkerStart']); + $this->server->on('open', [$this, 'onOpen']); + $this->server->on('message', [$this, 'onMessage']); + $this->server->on('close', [$this, 'onClose']); + $this->server->start(); + } + + /** + * This is executed when the Realtime server starts. + * @param SwooleServer $server + * @return void + */ + public function onStart(SwooleServer $server): void + { + Console::success('Server started succefully'); + Console::info("Master pid {$server->master_pid}, manager pid {$server->manager_pid}"); + + Timer::tick(10000, function () { + /** @var Table $stats */ + foreach ($this->stats as $projectId => $value) { + if (empty($value['connections']) && empty($value['messages'])) { + continue; + } + + $connections = $value['connections']; + $messages = $value['messages']; + + $usage = new Event('v1-usage', 'UsageV1'); + $usage + ->setParam('projectId', $projectId) + ->setParam('realtimeConnections', $connections) + ->setParam('realtimeMessages', $messages) + ->setParam('networkRequestSize', 0) + ->setParam('networkResponseSize', 0); + + $this->stats->set($projectId, [ + 'projectId' => $projectId, + 'messages' => 0, + 'connections' => 0 + ]); + + if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') { + $usage->trigger(); + } + } + }); + + Process::signal(2, function () use ($server) { + Console::log('Stop by Ctrl+C'); + $server->shutdown(); + }); + } + + /** + * This is executed when a WebSocket worker process starts. + * @param SwooleServer $server + * @param int $workerId + * @return void + * @throws Exception + */ + public function onWorkerStart(SwooleServer $server, int $workerId): void + { + Console::success('Worker ' . $workerId . ' started succefully'); + + $attempts = 0; + $start = time(); + $redisPool = $this->register->get('redisPool'); + + /** + * Sending current connections to project channels on the console project every 5 seconds. + */ + $server->tick(5000, function () use (&$server) { + $this->tickSendProjectUsage($server); + }); + + while ($attempts < 300) { + try { + if ($attempts > 0) { + Console::error('Pub/sub connection lost (lasted ' . (time() - $start) . ' seconds, worker: ' . $workerId . '). + Attempting restart in 5 seconds (attempt #' . $attempts . ')'); + sleep(5); // 5 sec delay between connection attempts + } + + /** @var Swoole\Coroutine\Redis $redis */ + $redis = $redisPool->get(); + + if ($redis->ping(true)) { + $attempts = 0; + Console::success('Pub/sub connection established (worker: ' . $workerId . ')'); + } else { + Console::error('Pub/sub failed (worker: ' . $workerId . ')'); + } + + $redis->subscribe(['realtime'], function ($redis, $channel, $payload) use ($server, $workerId) { + $this->onRedisPublish($payload, $server, $workerId); + }); + } catch (\Throwable $th) { + Console::error('Pub/sub error: ' . $th->getMessage()); + $redisPool->put($redis); + $attempts++; + continue; + } + + $attempts++; + } + + Console::error('Failed to restart pub/sub...'); + } + + /** + * This is executed when a new Realtime connection is established. + * @param SwooleServer $server + * @param Request $request + * @return void + * @throws Exception + * @throws UtopiaException + */ + public function onOpen(SwooleServer $server, Request $request): void + { + $app = new App('UTC'); + $connection = $request->fd; + $request = new SwooleRequest($request); + + $db = $this->register->get('dbPool')->get(); + $redis = $this->register->get('redisPool')->get(); + + $this->register->set('db', function () use (&$db) { + return $db; + }); + + $this->register->set('cache', function () use (&$redis) { // Register cache connection + return $redis; + }); + + Console::info("Connection open (user: {$connection}, worker: {$server->getWorkerId()})"); + + App::setResource('request', function () use ($request) { + return $request; + }); + + App::setResource('response', function () { + return new Response(new SwooleResponse()); + }); + + try { + /** @var \Appwrite\Database\Document $user */ + $user = $app->getResource('user'); + + /** @var \Appwrite\Database\Document $project */ + $project = $app->getResource('project'); + + /** @var \Appwrite\Database\Document $console */ + $console = $app->getResource('console'); + + /* + * Project Check + */ + if (empty($project->getId())) { + throw new Exception('Missing or unknown project ID', 1008); + } + + /* + * Abuse Check + * + * Abuse limits are connecting 128 times per minute and ip address. + */ + $timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, function () use ($db) { + return $db; + }); + $timeLimit + ->setNamespace('app_' . $project->getId()) + ->setParam('{ip}', $request->getIP()) + ->setParam('{url}', $request->getURI()); + + $abuse = new Abuse($timeLimit); + + if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') { + throw new Exception('Too many requests', 1013); + } + + /* + * Validate Client Domain - Check to avoid CSRF attack. + * Adding Appwrite API domains to allow XDOMAIN communication. + * Skip this check for non-web platforms which are not required to send an origin header. + */ + $origin = $request->getOrigin(); + $originValidator = new Origin(\array_merge($project->getAttribute('platforms', []), $console->getAttribute('platforms', []))); + + if (!$originValidator->isValid($origin) && $project->getId() !== 'console') { + throw new Exception($originValidator->getDescription(), 1008); + } + + Parser::setUser($user); + + $roles = Parser::getRoles(); + $channels = Parser::parseChannels($request->getQuery('channels', [])); + + /** + * Channels Check + */ + if (empty($channels)) { + throw new Exception('Missing channels', 1008); + } + + Parser::subscribe($project->getId(), $connection, $roles, $this->subscriptions, $this->connections, $channels); + + $server->push($connection, json_encode($channels)); + + $this->stats->incr($project->getId(), 'connections'); + $this->stats->incr($project->getId(), 'connectionsTotal'); + } catch (\Throwable $th) { + $response = [ + 'code' => $th->getCode(), + 'message' => $th->getMessage() + ]; + // Temporarily print debug logs by default for Alpha testing. + //if (App::isDevelopment()) { + Console::error("[Error] Connection Error"); + Console::error("[Error] Code: " . $response['code']); + Console::error("[Error] Message: " . $response['message']); + //} + $server->push($connection, json_encode($response)); + $server->close($connection); + } + /** + * Put used PDO and Redis Connections back into their pools. + */ + /** @var PDOPool $dbPool */ + $dbPool = $this->register->get('dbPool'); + $dbPool->put($db); + + /** @var RedisPool $redisPool */ + $redisPool = $this->register->get('redisPool'); + $redisPool->put($redis); + } + + /** + * This is executed when a message is received by the Realtime server. + * @param SwooleServer $server + * @param Frame $frame + * @return void + */ + public function onMessage(SwooleServer $server, Frame $frame) + { + $server->push($frame->fd, 'Sending messages is not allowed.'); + $server->close($frame->fd); + } + + /** + * This is executed when a Realtime connection is closed. + * @param SwooleServer $server + * @param int $connection + * @return void + */ + public function onClose(SwooleServer $server, int $connection) + { + if (array_key_exists($connection, $this->connections)) { + $this->stats->decr($this->connections[$connection]['projectId'], 'connectionsTotal'); + } + Parser::unsubscribe($connection, $this->subscriptions, $this->connections); + Console::info('Connection close: ' . $connection); + } + + /** + * This is executed when an event is published on realtime channel in Redis. + * @param string $payload + * @param SwooleServer $server + * @param int $workerId + * @return void + */ + public function onRedisPublish(string $payload, SwooleServer &$server, int $workerId) + { + /** + * Supported Resources: + * - Collection + * - Document + * - File + * - Account + * - Session + * - Team? (not implemented yet) + * - Membership? (not implemented yet) + * - Function + * - Execution + */ + $event = json_decode($payload, true); + + $receivers = Parser::identifyReceivers($event, $this->subscriptions); + + // Temporarily print debug logs by default for Alpha testing. + // if (App::isDevelopment() && !empty($receivers)) { + if (!empty($receivers)) { + Console::log("[Debug][Worker {$workerId}] Receivers: " . count($receivers)); + Console::log("[Debug][Worker {$workerId}] Receivers Connection IDs: " . json_encode($receivers)); + Console::log("[Debug][Worker {$workerId}] Event: " . $payload); + } + + foreach ($receivers as $receiver) { + if ($server->exist($receiver) && $server->isEstablished($receiver)) { + $server->push( + $receiver, + json_encode($event['data']), + SWOOLE_WEBSOCKET_OPCODE_TEXT, + SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS + ); + } else { + $server->close($receiver); + } + } + if (($num = count($receivers)) > 0) { + $this->stats->incr($event['project'], 'messages', $num); + } + } + + /** + * This sends the usage to the `console` channel. + * @param SwooleServer $server + * @return void + */ + public function tickSendProjectUsage(SwooleServer &$server) + { + if ( + array_key_exists('console', $this->subscriptions) + && array_key_exists('role:member', $this->subscriptions['console']) + && array_key_exists('project', $this->subscriptions['console']['role:member']) + ) { + $payload = []; + foreach ($this->stats as $projectId => $value) { + $payload[$projectId] = $value['connectionsTotal']; + } + foreach ($this->subscriptions['console']['role:member']['project'] as $connection => $value) { + $server->push( + $connection, + json_encode([ + 'event' => 'stats.connections', + 'channels' => ['project'], + 'timestamp' => time(), + 'payload' => $payload + ]), + SWOOLE_WEBSOCKET_OPCODE_TEXT, + SWOOLE_WEBSOCKET_FLAG_FIN | SWOOLE_WEBSOCKET_FLAG_COMPRESS + ); + } + } + } +} diff --git a/tests/unit/Realtime/RealtimeChannelsTest.php b/tests/unit/Realtime/RealtimeChannelsTest.php index 5145acb2c4..923a38325e 100644 --- a/tests/unit/Realtime/RealtimeChannelsTest.php +++ b/tests/unit/Realtime/RealtimeChannelsTest.php @@ -3,7 +3,7 @@ namespace Appwrite\Tests; use Appwrite\Database\Document; -use Appwrite\Realtime\Realtime; +use Appwrite\Realtime; use PHPUnit\Framework\TestCase; class RealtimeChannelsTest extends TestCase @@ -46,7 +46,7 @@ class RealtimeChannelsTest extends TestCase */ for ($i = 0; $i < $this->connectionsPerChannel; $i++) { foreach ($this->allChannels as $index => $channel) { - Realtime::setUser(new Document([ + Realtime\Parser::setUser(new Document([ '$id' => 'user' . $this->connectionsCount, 'memberships' => [ [ @@ -57,10 +57,10 @@ class RealtimeChannelsTest extends TestCase ] ] ])); - $roles = Realtime::getRoles(); - $parsedChannels = Realtime::parseChannels([0 => $channel]); + $roles = Realtime\Parser::getRoles(); + $parsedChannels = Realtime\Parser::parseChannels([0 => $channel]); - Realtime::subscribe( + Realtime\Parser::subscribe( '1', $this->connectionsCount, $roles, @@ -78,14 +78,14 @@ class RealtimeChannelsTest extends TestCase */ for ($i = 0; $i < $this->connectionsPerChannel; $i++) { foreach ($this->allChannels as $index => $channel) { - Realtime::setUser(new Document([ + Realtime\Parser::setUser(new Document([ '$id' => '' ])); - $roles = Realtime::getRoles(); - $parsedChannels = Realtime::parseChannels([0 => $channel]); + $roles = Realtime\Parser::getRoles(); + $parsedChannels = Realtime\Parser::parseChannels([0 => $channel]); - Realtime::subscribe( + Realtime\Parser::subscribe( '1', $this->connectionsCount, $roles, @@ -130,13 +130,13 @@ class RealtimeChannelsTest extends TestCase */ $this->assertCount($this->connectionsTotal, $this->connections); - Realtime::unsubscribe(-1, $this->subscriptions, $this->connections); + Realtime\Parser::unsubscribe(-1, $this->subscriptions, $this->connections); $this->assertCount($this->connectionsTotal, $this->connections); $this->assertCount(($this->connectionsAuthenticated + (3 * $this->connectionsPerChannel) + 2), $this->subscriptions['1']); for ($i = 0; $i < $this->connectionsCount; $i++) { - Realtime::unsubscribe($i, $this->subscriptions, $this->connections); + Realtime\Parser::unsubscribe($i, $this->subscriptions, $this->connections); $this->assertCount(($this->connectionsCount - $i - 1), $this->connections); } @@ -161,7 +161,7 @@ class RealtimeChannelsTest extends TestCase ] ]; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -197,7 +197,7 @@ class RealtimeChannelsTest extends TestCase ] ]; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -234,7 +234,7 @@ class RealtimeChannelsTest extends TestCase ] ]; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -271,7 +271,7 @@ class RealtimeChannelsTest extends TestCase ] ]; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -300,7 +300,7 @@ class RealtimeChannelsTest extends TestCase ] ]; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); diff --git a/tests/unit/Realtime/RealtimeGuestTest.php b/tests/unit/Realtime/RealtimeGuestTest.php index b8cd68f8a9..01e43d7308 100644 --- a/tests/unit/Realtime/RealtimeGuestTest.php +++ b/tests/unit/Realtime/RealtimeGuestTest.php @@ -3,7 +3,7 @@ namespace Appwrite\Tests; use Appwrite\Database\Document; -use Appwrite\Realtime\Realtime; +use Appwrite\Realtime; use PHPUnit\Framework\TestCase; class RealtimeGuestTest extends TestCase @@ -13,11 +13,11 @@ class RealtimeGuestTest extends TestCase public function testGuest() { - Realtime::setUser(new Document([ + Realtime\Parser::setUser(new Document([ '$id' => '' ])); - $roles = Realtime::getRoles(); + $roles = Realtime\Parser::getRoles(); $this->assertCount(1, $roles); $this->assertContains('role:guest', $roles); @@ -29,7 +29,7 @@ class RealtimeGuestTest extends TestCase 4 => 'account.456' ]; - $channels = Realtime::parseChannels($channels); + $channels = Realtime\Parser::parseChannels($channels); $this->assertCount(3, $channels); $this->assertArrayHasKey('files', $channels); $this->assertArrayHasKey('documents', $channels); @@ -37,7 +37,7 @@ class RealtimeGuestTest extends TestCase $this->assertArrayNotHasKey('account', $channels); $this->assertArrayNotHasKey('account.456', $channels); - Realtime::subscribe('1', 1, $roles, $this->subscriptions, $this->connections, $channels); + Realtime\Parser::subscribe('1', 1, $roles, $this->subscriptions, $this->connections, $channels); $event = [ 'project' => '1', @@ -50,7 +50,7 @@ class RealtimeGuestTest extends TestCase ] ]; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -60,7 +60,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['role:guest']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -70,7 +70,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['role:member']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -79,7 +79,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['user:123']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -88,7 +88,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['team:abc']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -97,7 +97,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['team:abc/administrator']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -106,7 +106,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['team:abc/god']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -115,7 +115,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['team:def']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -124,7 +124,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['team:def/guest']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -133,7 +133,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['user:456']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -142,7 +142,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['team:def/member']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -152,7 +152,7 @@ class RealtimeGuestTest extends TestCase $event['permissions'] = ['*']; $event['data']['channels'] = ['documents.123']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -161,7 +161,7 @@ class RealtimeGuestTest extends TestCase $event['data']['channels'] = ['documents.789']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -171,19 +171,19 @@ class RealtimeGuestTest extends TestCase $event['project'] = '2'; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); $this->assertEmpty($receivers); - Realtime::unsubscribe(2, $this->subscriptions, $this->connections); + Realtime\Parser::unsubscribe(2, $this->subscriptions, $this->connections); $this->assertCount(1, $this->connections); $this->assertCount(1, $this->subscriptions['1']); - Realtime::unsubscribe(1, $this->subscriptions, $this->connections); + Realtime\Parser::unsubscribe(1, $this->subscriptions, $this->connections); $this->assertEmpty($this->connections); $this->assertEmpty($this->subscriptions); diff --git a/tests/unit/Realtime/RealtimeTest.php b/tests/unit/Realtime/RealtimeTest.php index a819f4cb72..a722bea10d 100644 --- a/tests/unit/Realtime/RealtimeTest.php +++ b/tests/unit/Realtime/RealtimeTest.php @@ -3,7 +3,7 @@ namespace Appwrite\Tests; use Appwrite\Database\Document; -use Appwrite\Realtime\Realtime; +use Appwrite\Realtime; use PHPUnit\Framework\TestCase; class RealtimeTest extends TestCase @@ -21,7 +21,7 @@ class RealtimeTest extends TestCase public function testUser() { - Realtime::setUser(new Document([ + Realtime\Parser::setUser(new Document([ '$id' => '123', 'memberships' => [ [ @@ -40,7 +40,7 @@ class RealtimeTest extends TestCase ] ])); - $roles = Realtime::getRoles(); + $roles = Realtime\Parser::getRoles(); $this->assertCount(7, $roles); $this->assertContains('user:123', $roles); @@ -59,7 +59,7 @@ class RealtimeTest extends TestCase 4 => 'account.456' ]; - $channels = Realtime::parseChannels($channels); + $channels = Realtime\Parser::parseChannels($channels); $this->assertCount(4, $channels); $this->assertArrayHasKey('files', $channels); @@ -69,7 +69,7 @@ class RealtimeTest extends TestCase $this->assertArrayNotHasKey('account', $channels); $this->assertArrayNotHasKey('account.456', $channels); - Realtime::subscribe('1', 1, $roles, $this->subscriptions, $this->connections, $channels); + Realtime\Parser::subscribe('1', 1, $roles, $this->subscriptions, $this->connections, $channels); $event = [ 'project' => '1', @@ -81,7 +81,7 @@ class RealtimeTest extends TestCase ] ]; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -91,7 +91,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['role:member']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -101,7 +101,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['user:123']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -111,7 +111,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['team:abc']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -121,7 +121,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['team:abc/administrator']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -131,7 +131,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['team:abc/god']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -141,7 +141,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['team:def']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -151,7 +151,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['team:def/guest']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -161,7 +161,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['user:456']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -170,7 +170,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['team:def/member']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -180,7 +180,7 @@ class RealtimeTest extends TestCase $event['permissions'] = ['*']; $event['data']['channels'] = ['documents.123']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -189,7 +189,7 @@ class RealtimeTest extends TestCase $event['data']['channels'] = ['documents.789']; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); @@ -199,20 +199,20 @@ class RealtimeTest extends TestCase $event['project'] = '2'; - $receivers = Realtime::identifyReceivers( + $receivers = Realtime\Parser::identifyReceivers( $event, $this->subscriptions ); $this->assertEmpty($receivers); - Realtime::unsubscribe(2, $this->subscriptions, $this->connections); + Realtime\Parser::unsubscribe(2, $this->subscriptions, $this->connections); $this->assertCount(1, $this->connections); $this->assertCount(7, $this->subscriptions['1']); - Realtime::unsubscribe(1, $this->subscriptions, $this->connections); + Realtime\Parser::unsubscribe(1, $this->subscriptions, $this->connections); $this->assertEmpty($this->connections); $this->assertEmpty($this->subscriptions);