fix realtime with db refactor
This commit is contained in:
parent
42414e8841
commit
a585a9090a
|
@ -2282,7 +2282,56 @@ $collections = [
|
||||||
'orders' => [Database::ORDER_DESC],
|
'orders' => [Database::ORDER_DESC],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
]
|
],
|
||||||
|
'realtime' => [
|
||||||
|
'$collection' => Database::METADATA,
|
||||||
|
'$id' => 'realtime',
|
||||||
|
'name' => 'Realtime Connections',
|
||||||
|
'attributes' => [
|
||||||
|
[
|
||||||
|
'$id' => 'container',
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => Database::LENGTH_KEY,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => true,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$id' => 'timestamp',
|
||||||
|
'type' => Database::VAR_INTEGER,
|
||||||
|
'format' => '',
|
||||||
|
'size' => 0,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => false,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'$id' => 'value',
|
||||||
|
'type' => Database::VAR_STRING,
|
||||||
|
'format' => '',
|
||||||
|
'size' => 16384,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => true,
|
||||||
|
'default' => null,
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [], //TODO: use json filter
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'indexes' => [
|
||||||
|
[
|
||||||
|
'$id' => '_key_timestamp',
|
||||||
|
'type' => Database::INDEX_KEY,
|
||||||
|
'attributes' => ['timestamp'],
|
||||||
|
'lengths' => [],
|
||||||
|
'orders' => [Database::ORDER_DESC],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
return $collections;
|
return $collections;
|
|
@ -699,10 +699,10 @@ App::post('/v1/functions/:functionId/executions')
|
||||||
]));
|
]));
|
||||||
|
|
||||||
Authorization::reset();
|
Authorization::reset();
|
||||||
|
|
||||||
$jwt = ''; // initialize
|
$jwt = ''; // initialize
|
||||||
if (!$user->isEmpty()) { // If userId exists, generate a JWT for function
|
if (!$user->isEmpty()) { // If userId exists, generate a JWT for function
|
||||||
|
|
||||||
$sessions = $user->getAttribute('sessions', []);
|
$sessions = $user->getAttribute('sessions', []);
|
||||||
$current = new Document();
|
$current = new Document();
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Appwrite\Auth\Auth;
|
use Appwrite\Auth\Auth;
|
||||||
use Appwrite\Database\Document;
|
|
||||||
use Appwrite\Database\Validator\Authorization;
|
use Appwrite\Database\Validator\Authorization;
|
||||||
use Appwrite\Messaging\Adapter\Realtime;
|
use Appwrite\Messaging\Adapter\Realtime;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\Exception;
|
use Utopia\Exception;
|
||||||
use Utopia\Abuse\Abuse;
|
use Utopia\Abuse\Abuse;
|
||||||
use Utopia\Abuse\Adapters\TimeLimit;
|
use Utopia\Abuse\Adapters\TimeLimit;
|
||||||
|
use Utopia\Database\Document;
|
||||||
use Utopia\Storage\Device\Local;
|
use Utopia\Storage\Device\Local;
|
||||||
use Utopia\Storage\Storage;
|
use Utopia\Storage\Storage;
|
||||||
|
|
||||||
|
@ -209,11 +209,11 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
||||||
$target = Realtime::fromPayload($events->getParam('event'), $payload);
|
$target = Realtime::fromPayload($events->getParam('event'), $payload);
|
||||||
|
|
||||||
Realtime::send(
|
Realtime::send(
|
||||||
$project->getId(),
|
$project->getId(),
|
||||||
$response->getPayload(),
|
$response->getPayload(),
|
||||||
$events->getParam('event'),
|
$events->getParam('event'),
|
||||||
$target['channels'],
|
$target['channels'],
|
||||||
$target['roles'],
|
$target['roles'],
|
||||||
[
|
[
|
||||||
'permissionsChanged' => $target['permissionsChanged'],
|
'permissionsChanged' => $target['permissionsChanged'],
|
||||||
'userId' => $events->getParam('userId')
|
'userId' => $events->getParam('userId')
|
||||||
|
@ -221,11 +221,11 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($audits->getParam('event'))) {
|
if (!empty($audits->getParam('event'))) {
|
||||||
$audits->trigger();
|
$audits->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($deletes->getParam('type')) && !empty($deletes->getParam('document'))) {
|
if (!empty($deletes->getParam('type')) && !empty($deletes->getParam('document'))) {
|
||||||
$deletes->trigger();
|
$deletes->trigger();
|
||||||
}
|
}
|
||||||
|
@ -233,13 +233,13 @@ App::shutdown(function ($utopia, $request, $response, $project, $events, $audits
|
||||||
if (!empty($database->getParam('type')) && !empty($database->getParam('document'))) {
|
if (!empty($database->getParam('type')) && !empty($database->getParam('document'))) {
|
||||||
$database->trigger();
|
$database->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
$route = $utopia->match($request);
|
$route = $utopia->match($request);
|
||||||
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
|
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
|
||||||
&& $project->getId()
|
&& $project->getId()
|
||||||
&& $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin
|
&& $mode !== APP_MODE_ADMIN // TODO: add check to make sure user is admin
|
||||||
&& !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage on admin mode
|
&& !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage on admin mode
|
||||||
|
|
||||||
$usage
|
$usage
|
||||||
->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage'))
|
->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage'))
|
||||||
->setParam('networkResponseSize', $response->getSize())
|
->setParam('networkResponseSize', $response->getSize())
|
||||||
|
|
|
@ -131,7 +131,6 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$dbForConsole->createCollection($key, $attributes, $indexes);
|
$dbForConsole->createCollection($key, $attributes, $indexes);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Console::success('[Setup] - Server database init completed...');
|
Console::success('[Setup] - Server database init completed...');
|
||||||
|
|
|
@ -28,11 +28,9 @@ use Appwrite\Event\Event;
|
||||||
use Appwrite\Network\Validator\Email;
|
use Appwrite\Network\Validator\Email;
|
||||||
use Appwrite\Network\Validator\IP;
|
use Appwrite\Network\Validator\IP;
|
||||||
use Appwrite\Network\Validator\URL;
|
use Appwrite\Network\Validator\URL;
|
||||||
use Appwrite\Event\Realtime;
|
|
||||||
use Appwrite\OpenSSL\OpenSSL;
|
use Appwrite\OpenSSL\OpenSSL;
|
||||||
use Appwrite\Stats\Stats;
|
use Appwrite\Stats\Stats;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\CLI\Console;
|
|
||||||
use Utopia\View;
|
use Utopia\View;
|
||||||
use Utopia\Config\Config;
|
use Utopia\Config\Config;
|
||||||
use Utopia\Locale\Locale;
|
use Utopia\Locale\Locale;
|
||||||
|
|
284
app/realtime.php
284
app/realtime.php
|
@ -18,6 +18,10 @@ use Utopia\Database\Database;
|
||||||
use Utopia\Cache\Adapter\Redis as RedisCache;
|
use Utopia\Cache\Adapter\Redis as RedisCache;
|
||||||
use Utopia\Cache\Cache;
|
use Utopia\Cache\Cache;
|
||||||
use Utopia\Database\Adapter\MariaDB;
|
use Utopia\Database\Adapter\MariaDB;
|
||||||
|
use Utopia\Database\Document;
|
||||||
|
use Utopia\Database\Query;
|
||||||
|
use Utopia\Database\Validator\Authorization;
|
||||||
|
use Utopia\Registry\Registry;
|
||||||
use Utopia\Swoole\Request;
|
use Utopia\Swoole\Request;
|
||||||
use Utopia\WebSocket\Server;
|
use Utopia\WebSocket\Server;
|
||||||
use Utopia\WebSocket\Adapter;
|
use Utopia\WebSocket\Adapter;
|
||||||
|
@ -40,124 +44,121 @@ $stats->column('messages', Table::TYPE_INT);
|
||||||
$stats->create();
|
$stats->create();
|
||||||
|
|
||||||
$containerId = uniqid();
|
$containerId = uniqid();
|
||||||
$documentId = null;
|
$statsDocument = null;
|
||||||
|
|
||||||
$adapter = new Adapter\Swoole(port: App::getEnv('PORT', 80));
|
$adapter = new Adapter\Swoole(port: App::getEnv('PORT', 80));
|
||||||
$adapter->setPackageMaxLength(64000); // Default maximum Package Size (64kb)
|
$adapter->setPackageMaxLength(64000); // Default maximum Package Size (64kb)
|
||||||
|
|
||||||
$server = new Server($adapter);
|
$server = new Server($adapter);
|
||||||
|
|
||||||
$server->onStart(function () use ($stats, $register, $containerId, &$documentId) {
|
function getDatabase(Registry &$register, string $namespace)
|
||||||
|
{
|
||||||
|
$db = $register->get('dbPool')->get();
|
||||||
|
$redis = $register->get('redisPool')->get();
|
||||||
|
|
||||||
|
$cache = new Cache(new RedisCache($redis));
|
||||||
|
$database = new Database(new MariaDB($db), $cache);
|
||||||
|
$database->setNamespace($namespace);
|
||||||
|
|
||||||
|
return [
|
||||||
|
$database,
|
||||||
|
function () use ($register, $db, $redis) {
|
||||||
|
$register->get('dbPool')->put($db);
|
||||||
|
$register->get('redisPool')->put($redis);
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
$server->onStart(function () use ($stats, $register, $containerId, &$statsDocument) {
|
||||||
Console::success('Server started succefully');
|
Console::success('Server started succefully');
|
||||||
|
|
||||||
// $getConsoleDb = function () use ($register) {
|
|
||||||
// $db = $register->get('dbPool')->get();
|
|
||||||
// $cache = $register->get('redisPool')->get();
|
|
||||||
|
|
||||||
// $cache = new Cache(new RedisCache($cache));
|
|
||||||
// $database = new Database(new MariaDB($db), $cache);
|
|
||||||
|
|
||||||
// return [
|
|
||||||
// $database,
|
|
||||||
// function () use ($register, $db, $cache) {
|
|
||||||
// $register->get('dbPool')->put($db);
|
|
||||||
// $register->get('redisPool')->put($cache);
|
|
||||||
// }
|
|
||||||
// ];
|
|
||||||
// };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create document for this worker to share stats across Containers.
|
* Create document for this worker to share stats across Containers.
|
||||||
*/
|
*/
|
||||||
// go(function () use ($getConsoleDb, $containerId, &$documentId) {
|
go(function () use ($register, $containerId, &$statsDocument) {
|
||||||
// try {
|
try {
|
||||||
// [$consoleDb, $returnConsoleDb] = call_user_func($getConsoleDb);
|
[$database, $returnDatabase] = getDatabase($register, 'project_console_internal');
|
||||||
// // $document = [
|
$document = new Document([
|
||||||
// // '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS,
|
'$id' => $database->getId(),
|
||||||
// // '$permissions' => [
|
'$collection' => 'realtime',
|
||||||
// // 'read' => ['*'],
|
'$read' => [],
|
||||||
// // 'write' => ['*'],
|
'$write' => [],
|
||||||
// // ],
|
'container' => $containerId,
|
||||||
// // 'container' => $containerId,
|
'timestamp' => time(),
|
||||||
// // 'timestamp' => time(),
|
'value' => '{}'
|
||||||
// // 'value' => '{}'
|
]);
|
||||||
// // ];
|
$statsDocument = Authorization::skip(function () use ($database, $document) {
|
||||||
// // Authorization::disable();
|
return $database->createDocument('realtime', $document);
|
||||||
// // $document = $consoleDb->createDocument($document);
|
});
|
||||||
// // Authorization::enable();
|
} catch (\Throwable $th) {
|
||||||
// // $documentId = $document->getId();
|
Console::error('[Error] Type: ' . get_class($th));
|
||||||
// } catch (\Throwable $th) {
|
Console::error('[Error] Message: ' . $th->getMessage());
|
||||||
// Console::error('[Error] Type: ' . get_class($th));
|
Console::error('[Error] File: ' . $th->getFile());
|
||||||
// Console::error('[Error] Message: ' . $th->getMessage());
|
Console::error('[Error] Line: ' . $th->getLine());
|
||||||
// Console::error('[Error] File: ' . $th->getFile());
|
} finally {
|
||||||
// Console::error('[Error] Line: ' . $th->getLine());
|
call_user_func($returnDatabase);
|
||||||
// } finally {
|
}
|
||||||
// call_user_func($returnConsoleDb);
|
});
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * Save current connections to the Database every 5 seconds.
|
* Save current connections to the Database every 5 seconds.
|
||||||
// */
|
*/
|
||||||
// Timer::tick(5000, function () use ($stats, $getConsoleDb, $containerId, &$documentId) {
|
Timer::tick(5000, function () use ($register, $stats, $containerId, &$statsDocument) {
|
||||||
// foreach ($stats as $projectId => $value) {
|
/** @var Document $statsDocument */
|
||||||
// if (empty($value['connections']) && empty($value['messages'])) {
|
foreach ($stats as $projectId => $value) {
|
||||||
// continue;
|
if (empty($value['connections']) && empty($value['messages'])) {
|
||||||
// }
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// $connections = $stats->get($projectId, 'connections');
|
$connections = $stats->get($projectId, 'connections');
|
||||||
// $messages = $stats->get($projectId, 'messages');
|
$messages = $stats->get($projectId, 'messages');
|
||||||
|
|
||||||
// $usage = new Event('v1-usage', 'UsageV1');
|
$usage = new Event('v1-usage', 'UsageV1');
|
||||||
// $usage
|
$usage
|
||||||
// ->setParam('projectId', $projectId)
|
->setParam('projectId', $projectId)
|
||||||
// ->setParam('realtimeConnections', $connections)
|
->setParam('realtimeConnections', $connections)
|
||||||
// ->setParam('realtimeMessages', $messages)
|
->setParam('realtimeMessages', $messages)
|
||||||
// ->setParam('networkRequestSize', 0)
|
->setParam('networkRequestSize', 0)
|
||||||
// ->setParam('networkResponseSize', 0);
|
->setParam('networkResponseSize', 0);
|
||||||
|
|
||||||
// $stats->set($projectId, [
|
$stats->set($projectId, [
|
||||||
// 'messages' => 0,
|
'messages' => 0,
|
||||||
// 'connections' => 0
|
'connections' => 0
|
||||||
// ]);
|
]);
|
||||||
|
|
||||||
// if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
|
||||||
// $usage->trigger();
|
$usage->trigger();
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// $payload = [];
|
$payload = [];
|
||||||
// foreach ($stats as $projectId => $value) {
|
foreach ($stats as $projectId => $value) {
|
||||||
// if (!empty($value['connectionsTotal'])) {
|
if (!empty($value['connectionsTotal'])) {
|
||||||
// $payload[$projectId] = $stats->get($projectId, 'connectionsTotal');
|
$payload[$projectId] = $stats->get($projectId, 'connectionsTotal');
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// if (empty($payload)) {
|
if (empty($payload) || empty($statsDocument)) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// try {
|
try {
|
||||||
// [$consoleDb, $returnConsoleDb] = call_user_func($getConsoleDb);
|
[$database, $returnDatabase] = getDatabase($register, 'project_console_internal');
|
||||||
|
|
||||||
// // $consoleDb->updateDocument([
|
$statsDocument
|
||||||
// // '$id' => $documentId,
|
->setAttribute('timestamp', time())
|
||||||
// // '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS,
|
->setAttribute('value', json_encode($payload));
|
||||||
// // '$permissions' => [
|
|
||||||
// // 'read' => ['*'],
|
Authorization::skip(function () use ($database, $statsDocument) {
|
||||||
// // 'write' => ['*'],
|
$database->updateDocument('realtime', $statsDocument->getId(), $statsDocument);
|
||||||
// // ],
|
});
|
||||||
// // 'container' => $containerId,
|
} catch (\Throwable $th) {
|
||||||
// // 'timestamp' => time(),
|
Console::error('[Error] Type: ' . get_class($th));
|
||||||
// // 'value' => json_encode($payload)
|
Console::error('[Error] Message: ' . $th->getMessage());
|
||||||
// // ]);
|
Console::error('[Error] File: ' . $th->getFile());
|
||||||
// } catch (\Throwable $th) {
|
Console::error('[Error] Line: ' . $th->getLine());
|
||||||
// Console::error('[Error] Type: ' . get_class($th));
|
} finally {
|
||||||
// Console::error('[Error] Message: ' . $th->getMessage());
|
call_user_func($returnDatabase);
|
||||||
// Console::error('[Error] File: ' . $th->getFile());
|
}
|
||||||
// Console::error('[Error] Line: ' . $th->getLine());
|
});
|
||||||
// } finally {
|
|
||||||
// call_user_func($returnConsoleDb);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime) {
|
$server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime) {
|
||||||
|
@ -171,21 +172,16 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||||
* Sending current connections to project channels on the console project every 5 seconds.
|
* Sending current connections to project channels on the console project every 5 seconds.
|
||||||
*/
|
*/
|
||||||
if ($realtime->hasSubscriber('console', 'role:member', 'project')) {
|
if ($realtime->hasSubscriber('console', 'role:member', 'project')) {
|
||||||
$db = $register->get('dbPool')->get();
|
|
||||||
$redis = $register->get('redisPool')->get();
|
|
||||||
|
|
||||||
$cache = new Cache(new RedisCache($redis));
|
[$database, $returnDatabase] = getDatabase($register, 'project_console_internal');
|
||||||
$database = new Database(new MariaDB($db), $cache);
|
|
||||||
$database->setNamespace('project_console_internal');
|
|
||||||
|
|
||||||
$payload = [];
|
$payload = [];
|
||||||
$list = [];
|
|
||||||
// $list = $consoleDb->getCollection([
|
$list = Authorization::skip(function () use ($database) {
|
||||||
// 'filters' => [
|
return $database->find('realtime', [
|
||||||
// '$collection=' . Database::SYSTEM_COLLECTION_CONNECTIONS,
|
new Query('timestamp', Query::TYPE_GREATER, [(time() - 15)])
|
||||||
// 'timestamp>' . (time() - 15)
|
]);
|
||||||
// ],
|
});
|
||||||
// ]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregate stats across containers.
|
* Aggregate stats across containers.
|
||||||
|
@ -224,8 +220,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
$register->get('dbPool')->put($db);
|
call_user_func($returnDatabase);
|
||||||
$register->get('redisPool')->put($redis);
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Sending test message for SDK E2E tests every 5 seconds.
|
* Sending test message for SDK E2E tests every 5 seconds.
|
||||||
|
@ -284,12 +279,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$db = $register->get('dbPool')->get();
|
[$database, $returnDatabase] = getDatabase($register, 'project_' . $projectId . '_internal');
|
||||||
$cache = $register->get('redisPool')->get();
|
|
||||||
|
|
||||||
$cache = new Cache(new RedisCache($cache));
|
|
||||||
$database = new Database(new MariaDB($db), $cache);
|
|
||||||
$database->setNamespace('project_' . $projectId .'_internal');
|
|
||||||
|
|
||||||
$user = $database->getDocument('users', $userId);
|
$user = $database->getDocument('users', $userId);
|
||||||
|
|
||||||
|
@ -297,8 +287,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
|
||||||
|
|
||||||
$realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']);
|
$realtime->subscribe($projectId, $connection, $roles, $realtime->connections[$connection]['channels']);
|
||||||
|
|
||||||
$register->get('dbPool')->put($db);
|
call_user_func($returnDatabase);
|
||||||
$register->get('redisPool')->put($cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$receivers = $realtime->getSubscribers($event);
|
$receivers = $realtime->getSubscribers($event);
|
||||||
|
@ -374,7 +363,7 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||||
|
|
||||||
$cache = new Cache(new RedisCache($redis));
|
$cache = new Cache(new RedisCache($redis));
|
||||||
$database = new Database(new MariaDB($db), $cache);
|
$database = new Database(new MariaDB($db), $cache);
|
||||||
$database->setNamespace('project_' . $project->getId() .'_internal');
|
$database->setNamespace('project_' . $project->getId() . '_internal');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Project Check
|
* Project Check
|
||||||
|
@ -388,17 +377,16 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||||
*
|
*
|
||||||
* Abuse limits are connecting 128 times per minute and ip address.
|
* Abuse limits are connecting 128 times per minute and ip address.
|
||||||
*/
|
*/
|
||||||
// $timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $database);
|
$timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $database);
|
||||||
// $timeLimit
|
$timeLimit
|
||||||
// ->setParam('{ip}', $request->getIP())
|
->setParam('{ip}', $request->getIP())
|
||||||
// ->setParam('{url}', $request->getURI())
|
->setParam('{url}', $request->getURI());
|
||||||
// ->setup();
|
|
||||||
|
|
||||||
// $abuse = new Abuse($timeLimit);
|
$abuse = new Abuse($timeLimit);
|
||||||
|
|
||||||
// if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||||
// throw new Exception('Too many requests', 1013);
|
throw new Exception('Too many requests', 1013);
|
||||||
// }
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Validate Client Domain - Check to avoid CSRF attack.
|
* Validate Client Domain - Check to avoid CSRF attack.
|
||||||
|
@ -457,7 +445,6 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
|
||||||
Console::error('[Error] Connection Error');
|
Console::error('[Error] Connection Error');
|
||||||
Console::error('[Error] Code: ' . $response['data']['code']);
|
Console::error('[Error] Code: ' . $response['data']['code']);
|
||||||
Console::error('[Error] Message: ' . $response['data']['message']);
|
Console::error('[Error] Message: ' . $response['data']['message']);
|
||||||
var_dump($th->getFile(), $th->getLine(), $th->getTraceAsString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($th instanceof PDOException) {
|
if ($th instanceof PDOException) {
|
||||||
|
@ -476,28 +463,27 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||||
try {
|
try {
|
||||||
$response = new Response(new SwooleResponse());
|
$response = new Response(new SwooleResponse());
|
||||||
$db = $register->get('dbPool')->get();
|
$db = $register->get('dbPool')->get();
|
||||||
$cache = $register->get('redisPool')->get();
|
$redis = $register->get('redisPool')->get();
|
||||||
|
|
||||||
$cache = new Cache(new RedisCache($cache));
|
$cache = new Cache(new RedisCache($redis));
|
||||||
$database = new Database(new MariaDB($db), $cache);
|
$database = new Database(new MariaDB($db), $cache);
|
||||||
$database->setNamespace('project_' . $realtime->connections[$connection]['projectId'] .'_internal');
|
$database->setNamespace('project_' . $realtime->connections[$connection]['projectId'] . '_internal');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Abuse Check
|
* Abuse Check
|
||||||
*
|
*
|
||||||
* Abuse limits are sending 32 times per minute and connection.
|
* Abuse limits are sending 32 times per minute and connection.
|
||||||
*/
|
*/
|
||||||
// $timeLimit = new TimeLimit('url:{url},conection:{connection}', 32, 60, $database);
|
$timeLimit = new TimeLimit('url:{url},conection:{connection}', 32, 60, $database);
|
||||||
// $timeLimit
|
$timeLimit
|
||||||
// ->setParam('{connection}', $connection)
|
->setParam('{connection}', $connection)
|
||||||
// ->setParam('{container}', $containerId)
|
->setParam('{container}', $containerId);
|
||||||
// ->setup();
|
|
||||||
|
|
||||||
// $abuse = new Abuse($timeLimit);
|
$abuse = new Abuse($timeLimit);
|
||||||
|
|
||||||
// if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
if ($abuse->check() && App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') === 'enabled') {
|
||||||
// throw new Exception('Too many messages', 1013);
|
throw new Exception('Too many messages', 1013);
|
||||||
// }
|
}
|
||||||
|
|
||||||
$message = json_decode($message, true);
|
$message = json_decode($message, true);
|
||||||
|
|
||||||
|
@ -506,7 +492,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||||
}
|
}
|
||||||
|
|
||||||
switch ($message['type']) {
|
switch ($message['type']) {
|
||||||
/**
|
/**
|
||||||
* This type is used to authenticate.
|
* This type is used to authenticate.
|
||||||
*/
|
*/
|
||||||
case 'authentication':
|
case 'authentication':
|
||||||
|
@ -515,8 +501,8 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||||
}
|
}
|
||||||
|
|
||||||
$session = Auth::decodeSession($message['data']['session']);
|
$session = Auth::decodeSession($message['data']['session']);
|
||||||
Auth::$unique = $session['id'];
|
Auth::$unique = $session['id'] ?? '';
|
||||||
Auth::$secret = $session['secret'];
|
Auth::$secret = $session['secret'] ?? '';
|
||||||
|
|
||||||
$user = $database->getDocument('users', Auth::$unique);
|
$user = $database->getDocument('users', Auth::$unique);
|
||||||
|
|
||||||
|
@ -564,7 +550,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
$register->get('dbPool')->put($db);
|
$register->get('dbPool')->put($db);
|
||||||
$register->get('redisPool')->put($cache);
|
$register->get('redisPool')->put($redis);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,7 @@ class Realtime extends Adapter
|
||||||
*/
|
*/
|
||||||
if (
|
if (
|
||||||
\array_key_exists($channel, $this->subscriptions[$event['project']][$role])
|
\array_key_exists($channel, $this->subscriptions[$event['project']][$role])
|
||||||
&& (\in_array($role, $event['roles']) || \in_array('*', $event['roles']))
|
&& (\in_array($role, $event['roles']) || \in_array('role:all', $event['roles']))
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Saving all connections that are allowed to receive this event.
|
* Saving all connections that are allowed to receive this event.
|
||||||
|
@ -277,28 +277,29 @@ class Realtime extends Adapter
|
||||||
case strpos($event, 'database.collections.') === 0:
|
case strpos($event, 'database.collections.') === 0:
|
||||||
$channels[] = 'collections';
|
$channels[] = 'collections';
|
||||||
$channels[] = 'collections.' . $payload->getId();
|
$channels[] = 'collections.' . $payload->getId();
|
||||||
$roles = $payload->getAttribute('$permissions.read');
|
$roles = $payload->getRead();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case strpos($event, 'database.documents.') === 0:
|
case strpos($event, 'database.documents.') === 0:
|
||||||
$channels[] = 'documents';
|
$channels[] = 'documents';
|
||||||
$channels[] = 'collections.' . $payload->getAttribute('$collection') . '.documents';
|
$channels[] = 'collections.' . $payload->getAttribute('$collection') . '.documents';
|
||||||
$channels[] = 'documents.' . $payload->getId();
|
$channels[] = 'documents.' . $payload->getId();
|
||||||
$roles = $payload->getAttribute('$permissions.read');
|
$roles = $payload->getRead();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case strpos($event, 'storage.') === 0:
|
case strpos($event, 'storage.') === 0:
|
||||||
$channels[] = 'files';
|
$channels[] = 'files';
|
||||||
$channels[] = 'files.' . $payload->getId();
|
$channels[] = 'files.' . $payload->getId();
|
||||||
$roles = $payload->getAttribute('$permissions.read');
|
$roles = $payload->getRead();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case strpos($event, 'functions.executions.') === 0:
|
case strpos($event, 'functions.executions.') === 0:
|
||||||
if (!empty($payload->getAttribute('$permissions.read'))) {
|
\var_dump($payload->getArrayCopy());
|
||||||
|
if (!empty($payload->getRead())) {
|
||||||
$channels[] = 'executions';
|
$channels[] = 'executions';
|
||||||
$channels[] = 'executions.' . $payload->getId();
|
$channels[] = 'executions.' . $payload->getId();
|
||||||
$channels[] = 'functions.' . $payload->getAttribute('functionId');
|
$channels[] = 'functions.' . $payload->getAttribute('functionId');
|
||||||
$roles = $payload->getAttribute('$permissions.read');
|
$roles = $payload->getRead();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,12 @@ class Execution extends Model
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => '5e5ea5c16897e',
|
'example' => '5e5ea5c16897e',
|
||||||
])
|
])
|
||||||
->addRule('$permissions', [
|
->addRule('$read', [
|
||||||
'type' => Response::MODEL_PERMISSIONS,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'Execution permissions.',
|
'description' => 'Execution read permissions.',
|
||||||
'default' => new \stdClass,
|
'default' => '',
|
||||||
'example' => new \stdClass,
|
'example' => 'role:all',
|
||||||
'array' => false,
|
'array' => true,
|
||||||
])
|
])
|
||||||
->addRule('functionId', [
|
->addRule('functionId', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
|
|
|
@ -190,7 +190,6 @@ trait RealtimeBase
|
||||||
$user = $this->getUser();
|
$user = $this->getUser();
|
||||||
$userId = $user['$id'] ?? '';
|
$userId = $user['$id'] ?? '';
|
||||||
$session = $user['session'] ?? '';
|
$session = $user['session'] ?? '';
|
||||||
$projectId = $this->getProject()['$id'];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for SUCCESS
|
* Test for SUCCESS
|
||||||
|
@ -617,27 +616,11 @@ trait RealtimeBase
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||||
]), [
|
]), [
|
||||||
|
'collectionId' => 'unique()',
|
||||||
'name' => 'Actors',
|
'name' => 'Actors',
|
||||||
'read' => ['*'],
|
'read' => ['role:all'],
|
||||||
'write' => ['*'],
|
'write' => ['role:all'],
|
||||||
'rules' => [
|
'permission' => 'collection'
|
||||||
[
|
|
||||||
'label' => 'First Name',
|
|
||||||
'key' => 'firstName',
|
|
||||||
'type' => 'text',
|
|
||||||
'default' => '',
|
|
||||||
'required' => true,
|
|
||||||
'array' => false
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'label' => 'Last Name',
|
|
||||||
'key' => 'lastName',
|
|
||||||
'type' => 'text',
|
|
||||||
'default' => '',
|
|
||||||
'required' => true,
|
|
||||||
'array' => false
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = json_decode($client->receive(), true);
|
$response = json_decode($client->receive(), true);
|
||||||
|
@ -655,6 +638,24 @@ trait RealtimeBase
|
||||||
|
|
||||||
$data = ['actorsId' => $actors['body']['$id']];
|
$data = ['actorsId' => $actors['body']['$id']];
|
||||||
|
|
||||||
|
$name = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['actorsId'] . '/attributes/string', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
|
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||||
|
]), [
|
||||||
|
'attributeId' => 'name',
|
||||||
|
'size' => 256,
|
||||||
|
'required' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals($name['headers']['status-code'], 201);
|
||||||
|
$this->assertEquals($name['body']['key'], 'name');
|
||||||
|
$this->assertEquals($name['body']['type'], 'string');
|
||||||
|
$this->assertEquals($name['body']['size'], 256);
|
||||||
|
$this->assertEquals($name['body']['required'], true);
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test Document Create
|
* Test Document Create
|
||||||
*/
|
*/
|
||||||
|
@ -662,12 +663,12 @@ trait RealtimeBase
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()), [
|
], $this->getHeaders()), [
|
||||||
|
'documentId' => 'unique()',
|
||||||
'data' => [
|
'data' => [
|
||||||
'firstName' => 'Chris',
|
'name' => 'Chris Evans'
|
||||||
'lastName' => 'Evans',
|
|
||||||
],
|
],
|
||||||
'read' => ['*'],
|
'read' => ['role:all'],
|
||||||
'write' => ['*'],
|
'write' => ['role:all'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = json_decode($client->receive(), true);
|
$response = json_decode($client->receive(), true);
|
||||||
|
@ -683,6 +684,7 @@ trait RealtimeBase
|
||||||
$this->assertContains('collections.' . $actors['body']['$id'] . '.documents', $response['data']['channels']);
|
$this->assertContains('collections.' . $actors['body']['$id'] . '.documents', $response['data']['channels']);
|
||||||
$this->assertEquals('database.documents.create', $response['data']['event']);
|
$this->assertEquals('database.documents.create', $response['data']['event']);
|
||||||
$this->assertNotEmpty($response['data']['payload']);
|
$this->assertNotEmpty($response['data']['payload']);
|
||||||
|
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans');
|
||||||
|
|
||||||
$data['documentId'] = $document['body']['$id'];
|
$data['documentId'] = $document['body']['$id'];
|
||||||
|
|
||||||
|
@ -693,12 +695,12 @@ trait RealtimeBase
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()), [
|
], $this->getHeaders()), [
|
||||||
|
'documentId' => 'unique()',
|
||||||
'data' => [
|
'data' => [
|
||||||
'firstName' => 'Chris1',
|
'name' => 'Chris Evans 2'
|
||||||
'lastName' => 'Evans2',
|
|
||||||
],
|
],
|
||||||
'read' => ['*'],
|
'read' => ['role:all'],
|
||||||
'write' => ['*'],
|
'write' => ['role:all'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = json_decode($client->receive(), true);
|
$response = json_decode($client->receive(), true);
|
||||||
|
@ -715,8 +717,8 @@ trait RealtimeBase
|
||||||
$this->assertEquals('database.documents.update', $response['data']['event']);
|
$this->assertEquals('database.documents.update', $response['data']['event']);
|
||||||
$this->assertNotEmpty($response['data']['payload']);
|
$this->assertNotEmpty($response['data']['payload']);
|
||||||
|
|
||||||
$this->assertEquals($response['data']['payload']['firstName'], 'Chris1');
|
$this->assertEquals($response['data']['payload']['name'], 'Chris Evans 2');
|
||||||
$this->assertEquals($response['data']['payload']['lastName'], 'Evans2');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test Document Delete
|
* Test Document Delete
|
||||||
|
@ -725,13 +727,12 @@ trait RealtimeBase
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()), [
|
], $this->getHeaders()), [
|
||||||
|
'documentId' => 'unique()',
|
||||||
'data' => [
|
'data' => [
|
||||||
'firstName' => 'Bradly',
|
'name' => 'Bradley Cooper'
|
||||||
'lastName' => 'Cooper',
|
|
||||||
|
|
||||||
],
|
],
|
||||||
'read' => ['*'],
|
'read' => ['role:all'],
|
||||||
'write' => ['*'],
|
'write' => ['role:all'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$client->receive();
|
$client->receive();
|
||||||
|
@ -754,6 +755,7 @@ trait RealtimeBase
|
||||||
$this->assertContains('collections.' . $data['actorsId'] . '.documents', $response['data']['channels']);
|
$this->assertContains('collections.' . $data['actorsId'] . '.documents', $response['data']['channels']);
|
||||||
$this->assertEquals('database.documents.delete', $response['data']['event']);
|
$this->assertEquals('database.documents.delete', $response['data']['event']);
|
||||||
$this->assertNotEmpty($response['data']['payload']);
|
$this->assertNotEmpty($response['data']['payload']);
|
||||||
|
$this->assertEquals($response['data']['payload']['name'], 'Bradley Cooper');
|
||||||
|
|
||||||
$client->close();
|
$client->close();
|
||||||
}
|
}
|
||||||
|
@ -786,9 +788,10 @@ trait RealtimeBase
|
||||||
'content-type' => 'multipart/form-data',
|
'content-type' => 'multipart/form-data',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()), [
|
], $this->getHeaders()), [
|
||||||
|
'fileId' => 'unique()',
|
||||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||||
'read' => ['*'],
|
'read' => ['role:all'],
|
||||||
'write' => ['*'],
|
'write' => ['role:all'],
|
||||||
'folderId' => 'xyz',
|
'folderId' => 'xyz',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -814,8 +817,8 @@ trait RealtimeBase
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
], $this->getHeaders()), [
|
], $this->getHeaders()), [
|
||||||
'read' => ['*'],
|
'read' => ['role:all'],
|
||||||
'write' => ['*'],
|
'write' => ['role:all'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$response = json_decode($client->receive(), true);
|
$response = json_decode($client->receive(), true);
|
||||||
|
@ -878,16 +881,17 @@ trait RealtimeBase
|
||||||
$this->assertEquals($user['$id'], $response['data']['user']['$id']);
|
$this->assertEquals($user['$id'], $response['data']['user']['$id']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test File Create
|
* Test Functions Create
|
||||||
*/
|
*/
|
||||||
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
|
$function = $this->client->call(Client::METHOD_POST, '/functions', [
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $this->getProject()['$id'],
|
'x-appwrite-project' => $this->getProject()['$id'],
|
||||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||||
]), [
|
], [
|
||||||
|
'functionId' => 'unique()',
|
||||||
'name' => 'Test',
|
'name' => 'Test',
|
||||||
|
'execute' => ['role:member'],
|
||||||
'runtime' => 'php-8.0',
|
'runtime' => 'php-8.0',
|
||||||
'execute' => ['*'],
|
|
||||||
'timeout' => 10,
|
'timeout' => 10,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -988,6 +992,7 @@ trait RealtimeBase
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
'x-appwrite-project' => $projectId,
|
'x-appwrite-project' => $projectId,
|
||||||
], $this->getHeaders()), [
|
], $this->getHeaders()), [
|
||||||
|
'teamId' => 'unique()',
|
||||||
'name' => 'Arsenal'
|
'name' => 'Arsenal'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
namespace Appwrite\Tests;
|
namespace Appwrite\Tests;
|
||||||
|
|
||||||
use Appwrite\Auth\Auth;
|
use Appwrite\Auth\Auth;
|
||||||
use Appwrite\Database\Document;
|
use Utopia\Database\Document;
|
||||||
use Appwrite\Messaging\Adapter\Realtime;
|
use Appwrite\Messaging\Adapter\Realtime;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
@ -146,14 +146,14 @@ class MessagingChannelsTest extends TestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests Wildcard (*) Permissions on every channel.
|
* Tests Wildcard (role:all) Permissions on every channel.
|
||||||
*/
|
*/
|
||||||
public function testWildcardPermission()
|
public function testWildcardPermission()
|
||||||
{
|
{
|
||||||
foreach ($this->allChannels as $index => $channel) {
|
foreach ($this->allChannels as $index => $channel) {
|
||||||
$event = [
|
$event = [
|
||||||
'project' => '1',
|
'project' => '1',
|
||||||
'roles' => ['*'],
|
'roles' => ['role:all'],
|
||||||
'data' => [
|
'data' => [
|
||||||
'channels' => [
|
'channels' => [
|
||||||
0 => $channel,
|
0 => $channel,
|
||||||
|
|
|
@ -20,7 +20,7 @@ class MessagingGuestTest extends TestCase
|
||||||
|
|
||||||
$event = [
|
$event = [
|
||||||
'project' => '1',
|
'project' => '1',
|
||||||
'roles' => ['*'],
|
'roles' => ['role:all'],
|
||||||
'data' => [
|
'data' => [
|
||||||
'channels' => [
|
'channels' => [
|
||||||
0 => 'documents',
|
0 => 'documents',
|
||||||
|
@ -95,7 +95,7 @@ class MessagingGuestTest extends TestCase
|
||||||
|
|
||||||
$this->assertEmpty($receivers);
|
$this->assertEmpty($receivers);
|
||||||
|
|
||||||
$event['roles'] = ['*'];
|
$event['roles'] = ['role:all'];
|
||||||
$event['data']['channels'] = ['documents.123'];
|
$event['data']['channels'] = ['documents.123'];
|
||||||
|
|
||||||
$receivers = $realtime->getSubscribers($event);
|
$receivers = $realtime->getSubscribers($event);
|
||||||
|
|
|
@ -29,7 +29,7 @@ class MessagingTest extends TestCase
|
||||||
|
|
||||||
$event = [
|
$event = [
|
||||||
'project' => '1',
|
'project' => '1',
|
||||||
'roles' => ['*'],
|
'roles' => ['role:all'],
|
||||||
'data' => [
|
'data' => [
|
||||||
'channels' => [
|
'channels' => [
|
||||||
0 => 'account.123',
|
0 => 'account.123',
|
||||||
|
@ -103,7 +103,7 @@ class MessagingTest extends TestCase
|
||||||
|
|
||||||
$this->assertEmpty($receivers);
|
$this->assertEmpty($receivers);
|
||||||
|
|
||||||
$event['roles'] = ['*'];
|
$event['roles'] = ['role:all'];
|
||||||
$event['data']['channels'] = ['documents.123'];
|
$event['data']['channels'] = ['documents.123'];
|
||||||
|
|
||||||
$receivers = $realtime->getSubscribers($event);
|
$receivers = $realtime->getSubscribers($event);
|
||||||
|
|
Loading…
Reference in a new issue