1
0
Fork 0
mirror of synced 2024-06-03 03:14:50 +12:00

fix realtime

This commit is contained in:
Torsten Dittmann 2021-09-30 13:18:50 +02:00
parent aa5d4cfc9b
commit 80e0df8a69
9 changed files with 159 additions and 185 deletions

View file

@ -1,10 +1,6 @@
<?php <?php
use Appwrite\Auth\Auth; use Appwrite\Auth\Auth;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Database;
use Appwrite\Database\Validator\Authorization;
use Appwrite\Event\Event; use Appwrite\Event\Event;
use Appwrite\Messaging\Adapter\Realtime; use Appwrite\Messaging\Adapter\Realtime;
use Appwrite\Network\Validator\Origin; use Appwrite\Network\Validator\Origin;
@ -18,7 +14,10 @@ use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit; use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\App; use Utopia\App;
use Utopia\CLI\Console; use Utopia\CLI\Console;
use Utopia\Config\Config; use Utopia\Database\Database;
use Utopia\Cache\Adapter\Redis as RedisCache;
use Utopia\Cache\Cache;
use Utopia\Database\Adapter\MariaDB;
use Utopia\Swoole\Request; use Utopia\Swoole\Request;
use Utopia\WebSocket\Server; use Utopia\WebSocket\Server;
use Utopia\WebSocket\Adapter; use Utopia\WebSocket\Adapter;
@ -51,116 +50,114 @@ $server = new Server($adapter);
$server->onStart(function () use ($stats, $register, $containerId, &$documentId) { $server->onStart(function () use ($stats, $register, $containerId, &$documentId) {
Console::success('Server started succefully'); Console::success('Server started succefully');
$getConsoleDb = function () use ($register) { // $getConsoleDb = function () use ($register) {
$db = $register->get('dbPool')->get(); // $db = $register->get('dbPool')->get();
$cache = $register->get('redisPool')->get(); // $cache = $register->get('redisPool')->get();
$consoleDb = new Database(); // $cache = new Cache(new RedisCache($cache));
$consoleDb->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache)); // $database = new Database(new MariaDB($db), $cache);
$consoleDb->setNamespace('app_console');
$consoleDb->setMocks(Config::getParam('collections', []));
return [ // return [
$consoleDb, // $database,
function () use ($register, $db, $cache) { // function () use ($register, $db, $cache) {
$register->get('dbPool')->put($db); // $register->get('dbPool')->put($db);
$register->get('redisPool')->put($cache); // $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 ($getConsoleDb, $containerId, &$documentId) {
try { // try {
[$consoleDb, $returnConsoleDb] = call_user_func($getConsoleDb); // [$consoleDb, $returnConsoleDb] = call_user_func($getConsoleDb);
$document = [ // // $document = [
'$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS, // // '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS,
'$permissions' => [ // // '$permissions' => [
'read' => ['*'], // // 'read' => ['*'],
'write' => ['*'], // // 'write' => ['*'],
], // // ],
'container' => $containerId, // // 'container' => $containerId,
'timestamp' => time(), // // 'timestamp' => time(),
'value' => '{}' // // 'value' => '{}'
]; // // ];
Authorization::disable(); // // Authorization::disable();
$document = $consoleDb->createDocument($document); // // $document = $consoleDb->createDocument($document);
Authorization::enable(); // // Authorization::enable();
$documentId = $document->getId(); // // $documentId = $document->getId();
} catch (\Throwable $th) { // } catch (\Throwable $th) {
Console::error('[Error] Type: ' . get_class($th)); // Console::error('[Error] Type: ' . get_class($th));
Console::error('[Error] Message: ' . $th->getMessage()); // Console::error('[Error] Message: ' . $th->getMessage());
Console::error('[Error] File: ' . $th->getFile()); // Console::error('[Error] File: ' . $th->getFile());
Console::error('[Error] Line: ' . $th->getLine()); // Console::error('[Error] Line: ' . $th->getLine());
} finally { // } finally {
call_user_func($returnConsoleDb); // 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 ($stats, $getConsoleDb, $containerId, &$documentId) {
foreach ($stats as $projectId => $value) { // foreach ($stats as $projectId => $value) {
if (empty($value['connections']) && empty($value['messages'])) { // if (empty($value['connections']) && empty($value['messages'])) {
continue; // 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)) {
return; // return;
} // }
try { // try {
[$consoleDb, $returnConsoleDb] = call_user_func($getConsoleDb); // [$consoleDb, $returnConsoleDb] = call_user_func($getConsoleDb);
$consoleDb->updateDocument([ // // $consoleDb->updateDocument([
'$id' => $documentId, // // '$id' => $documentId,
'$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS, // // '$collection' => Database::SYSTEM_COLLECTION_CONNECTIONS,
'$permissions' => [ // // '$permissions' => [
'read' => ['*'], // // 'read' => ['*'],
'write' => ['*'], // // 'write' => ['*'],
], // // ],
'container' => $containerId, // // 'container' => $containerId,
'timestamp' => time(), // // 'timestamp' => time(),
'value' => json_encode($payload) // // 'value' => json_encode($payload)
]); // // ]);
} catch (\Throwable $th) { // } catch (\Throwable $th) {
Console::error('[Error] Type: ' . get_class($th)); // Console::error('[Error] Type: ' . get_class($th));
Console::error('[Error] Message: ' . $th->getMessage()); // Console::error('[Error] Message: ' . $th->getMessage());
Console::error('[Error] File: ' . $th->getFile()); // Console::error('[Error] File: ' . $th->getFile());
Console::error('[Error] Line: ' . $th->getLine()); // Console::error('[Error] Line: ' . $th->getLine());
} finally { // } finally {
call_user_func($returnConsoleDb); // call_user_func($returnConsoleDb);
} // }
}); // });
}); });
$server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime) { $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats, $realtime) {
@ -175,20 +172,20 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
*/ */
if ($realtime->hasSubscriber('console', 'role:member', 'project')) { if ($realtime->hasSubscriber('console', 'role:member', 'project')) {
$db = $register->get('dbPool')->get(); $db = $register->get('dbPool')->get();
$cache = $register->get('redisPool')->get(); $redis = $register->get('redisPool')->get();
$consoleDb = new Database(); $cache = new Cache(new RedisCache($redis));
$consoleDb->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache)); $database = new Database(new MariaDB($db), $cache);
$consoleDb->setNamespace('app_console'); $database->setNamespace('project_console_internal');
$consoleDb->setMocks(Config::getParam('collections', []));
$payload = []; $payload = [];
$list = $consoleDb->getCollection([ $list = [];
'filters' => [ // $list = $consoleDb->getCollection([
'$collection=' . Database::SYSTEM_COLLECTION_CONNECTIONS, // 'filters' => [
'timestamp>' . (time() - 15) // '$collection=' . Database::SYSTEM_COLLECTION_CONNECTIONS,
], // 'timestamp>' . (time() - 15)
]); // ],
// ]);
/** /**
* Aggregate stats across containers. * Aggregate stats across containers.
@ -228,7 +225,7 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
} }
$register->get('dbPool')->put($db); $register->get('dbPool')->put($db);
$register->get('redisPool')->put($cache); $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.
@ -290,12 +287,11 @@ $server->onWorkerStart(function (int $workerId) use ($server, $register, $stats,
$db = $register->get('dbPool')->get(); $db = $register->get('dbPool')->get();
$cache = $register->get('redisPool')->get(); $cache = $register->get('redisPool')->get();
$projectDB = new Database(); $cache = new Cache(new RedisCache($cache));
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache)); $database = new Database(new MariaDB($db), $cache);
$projectDB->setNamespace('app_' . $projectId); $database->setNamespace('project_' . $projectId .'_internal');
$projectDB->setMocks(Config::getParam('collections', []));
$user = $projectDB->getDocument($userId); $user = $database->getDocument('users', $userId);
$roles = Auth::getRoles($user); $roles = Auth::getRoles($user);
@ -367,15 +363,19 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
}); });
try { try {
/** @var \Appwrite\Database\Document $user */ /** @var \Utopia\Database\Document $user */
$user = $app->getResource('user'); $user = $app->getResource('user');
/** @var \Appwrite\Database\Document $project */ /** @var \Utopia\Database\Document $project */
$project = $app->getResource('project'); $project = $app->getResource('project');
/** @var \Appwrite\Database\Document $console */ /** @var \Utopia\Database\Document $console */
$console = $app->getResource('console'); $console = $app->getResource('console');
$cache = new Cache(new RedisCache($redis));
$database = new Database(new MariaDB($db), $cache);
$database->setNamespace('project_' . $project->getId() .'_internal');
/* /*
* Project Check * Project Check
*/ */
@ -388,17 +388,17 @@ $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, $db); // $timeLimit = new TimeLimit('url:{url},ip:{ip}', 128, 60, $database);
$timeLimit // $timeLimit
->setNamespace('app_' . $project->getId()) // ->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,6 +457,7 @@ $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) {
@ -477,27 +478,26 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
$db = $register->get('dbPool')->get(); $db = $register->get('dbPool')->get();
$cache = $register->get('redisPool')->get(); $cache = $register->get('redisPool')->get();
$projectDB = new Database(); $cache = new Cache(new RedisCache($cache));
$projectDB->setAdapter(new RedisAdapter(new MySQLAdapter($db, $cache), $cache)); $database = new Database(new MariaDB($db), $cache);
$projectDB->setNamespace('app_' . $realtime->connections[$connection]['projectId']); $database->setNamespace('project_' . $realtime->connections[$connection]['projectId'] .'_internal');
$projectDB->setMocks(Config::getParam('collections', []));
/* /*
* 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, $db); // $timeLimit = new TimeLimit('url:{url},conection:{connection}', 32, 60, $database);
$timeLimit // $timeLimit
->setNamespace('app_' . $realtime->connections[$connection]['projectId']) // ->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);
@ -518,11 +518,10 @@ $server->onMessage(function (int $connection, string $message) use ($server, $re
Auth::$unique = $session['id']; Auth::$unique = $session['id'];
Auth::$secret = $session['secret']; Auth::$secret = $session['secret'];
$user = $projectDB->getDocument(Auth::$unique); $user = $database->getDocument('users', Auth::$unique);
if ( if (
empty($user->getId()) // Check a document has been found in the DB empty($user->getId()) // Check a document has been found in the DB
|| Database::SYSTEM_COLLECTION_USERS !== $user->getCollection() // Validate returned document is really a user document
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret) // Validate user has valid login token || !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret) // Validate user has valid login token
) { ) {
// cookie not valid // cookie not valid

View file

@ -12,8 +12,6 @@ Console::success(APP_NAME.' database worker v1 has started'."\n");
class DatabaseV1 extends Worker class DatabaseV1 extends Worker
{ {
public $args = [];
public function init(): void public function init(): void
{ {
} }

View file

@ -18,11 +18,6 @@ Console::success(APP_NAME . ' deletes worker v1 has started' . "\n");
class DeletesV1 extends Worker class DeletesV1 extends Worker
{ {
/**
* @var array
*/
public $args = [];
/** /**
* @var Database * @var Database
*/ */

View file

@ -170,32 +170,6 @@ services:
- _APP_DB_PASS - _APP_DB_PASS
- _APP_USAGE_STATS - _APP_USAGE_STATS
appwrite-worker-usage:
entrypoint: worker-usage
container_name: appwrite-worker-usage
build:
context: .
networks:
- appwrite
volumes:
- ./app:/usr/src/code/app
- ./src:/usr/src/code/src
depends_on:
- redis
- telegraf
environment:
- _APP_ENV
- _APP_REDIS_HOST
- _APP_REDIS_PORT
- _APP_REDIS_USER
- _APP_REDIS_PASS
- _APP_STATSD_HOST
- _APP_STATSD_PORT
- _APP_MAINTENANCE_INTERVAL
- _APP_MAINTENANCE_RETENTION_EXECUTION
- _APP_MAINTENANCE_RETENTION_ABUSE
- _APP_MAINTENANCE_RETENTION_AUDIT
appwrite-worker-audits: appwrite-worker-audits:
entrypoint: worker-audits entrypoint: worker-audits
container_name: appwrite-worker-audits container_name: appwrite-worker-audits

View file

@ -11,7 +11,8 @@ this.realtime.socket=new WebSocket(this.config.endpointRealtime+'/realtime?'+cha
this.realtime.socket.addEventListener('close',event=>{var _a,_b,_c;if(((_b=(_a=this.realtime)===null||_a===void 0?void 0:_a.lastMessage)===null||_b===void 0?void 0:_b.type)==='error'&&((_c=this.realtime)===null||_c===void 0?void 0:_c.lastMessage.data).code===1008){return;} this.realtime.socket.addEventListener('close',event=>{var _a,_b,_c;if(((_b=(_a=this.realtime)===null||_a===void 0?void 0:_a.lastMessage)===null||_b===void 0?void 0:_b.type)==='error'&&((_c=this.realtime)===null||_c===void 0?void 0:_c.lastMessage.data).code===1008){return;}
console.error('Realtime got disconnected. Reconnect will be attempted in 1 second.',event.reason);setTimeout(()=>{this.realtime.createSocket();},1000);});},authenticate:(event)=>{var _a,_b,_c;const message=JSON.parse(event.data);if(message.type==='connected'&&((_a=this.realtime.socket)===null||_a===void 0?void 0:_a.readyState)===WebSocket.OPEN){const cookie=JSON.parse((_b=window.localStorage.getItem('cookieFallback'))!==null&&_b!==void 0?_b:"{}");const session=cookie===null||cookie===void 0?void 0:cookie[`a_session_${this.config.project}`];const data=message.data;if(session&&!data.user){(_c=this.realtime.socket)===null||_c===void 0?void 0:_c.send(JSON.stringify({type:"authentication",data:{session}}));}}},onMessage:(channel,callback)=>(event)=>{try{const message=JSON.parse(event.data);this.realtime.lastMessage=message;if(message.type==='event'){let data=message.data;if(data.channels&&data.channels.includes(channel)){callback(data);}} console.error('Realtime got disconnected. Reconnect will be attempted in 1 second.',event.reason);setTimeout(()=>{this.realtime.createSocket();},1000);});},authenticate:(event)=>{var _a,_b,_c;const message=JSON.parse(event.data);if(message.type==='connected'&&((_a=this.realtime.socket)===null||_a===void 0?void 0:_a.readyState)===WebSocket.OPEN){const cookie=JSON.parse((_b=window.localStorage.getItem('cookieFallback'))!==null&&_b!==void 0?_b:"{}");const session=cookie===null||cookie===void 0?void 0:cookie[`a_session_${this.config.project}`];const data=message.data;if(session&&!data.user){(_c=this.realtime.socket)===null||_c===void 0?void 0:_c.send(JSON.stringify({type:"authentication",data:{session}}));}}},onMessage:(channel,callback)=>(event)=>{try{const message=JSON.parse(event.data);this.realtime.lastMessage=message;if(message.type==='event'){let data=message.data;if(data.channels&&data.channels.includes(channel)){callback(data);}}
else if(message.type==='error'){throw message.data;}} else if(message.type==='error'){throw message.data;}}
catch(e){console.error(e);}}};this.account={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/account';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(email,password,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');} catch(e){console.error(e);}}};this.account={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/account';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(userId,email,password,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');} if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
let path='/account';let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;} let path='/account';let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;}
if(typeof email!=='undefined'){payload['email']=email;} if(typeof email!=='undefined'){payload['email']=email;}
@ -2353,7 +2354,10 @@ return $value;}).add("platformsLimit",function($value){return $value;}).add("lim
return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');}).add("runtimeName",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].name;} return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');}).add("runtimeName",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].name;}
return'';}).add("runtimeLogo",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].logo;} return'';}).add("runtimeLogo",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].logo;}
return'';}).add("runtimeVersion",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].version;} return'';}).add("runtimeVersion",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].version;}
return'';}).add("accessProject",function($value,router){return($value&&$value.hasOwnProperty(router.params.project))?$value[router.params.project]:0;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} return'';}).add("indexAttributes",function($value){let output='';for(let i=0;i<$value.attributes.length;i++){output+=$value.attributes[i]+' ('+$value.orders[i]+'), '}
return output.slice(0,-2);}).add("collectionAttributes",function($value){if(!Array.isArray($value)){return[];}
$value.unshift({$id:'$id'});return $value;}).add("documentAttribute",function($value,attribute){if($value[attribute.key]){return $value[attribute.key];}
return null;}).add("accessProject",function($value,router){return($value&&$value.hasOwnProperty(router.params.project))?$value[router.params.project]:0;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);}
let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";} let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";}
return annotate(number,maxPlaces,forcePlaces,abbr);} return annotate(number,maxPlaces,forcePlaces,abbr);}
function annotate(number,maxPlaces,forcePlaces,abbr){let rounded=0;switch(abbr){case"T":rounded=number/1e12;break;case"B":rounded=number/1e9;break;case"M":rounded=number/1e6;break;case"K":rounded=number/1e3;break;case"":rounded=number;break;} function annotate(number,maxPlaces,forcePlaces,abbr){let rounded=0;switch(abbr){case"T":rounded=number/1e12;break;case"B":rounded=number/1e9;break;case"M":rounded=number/1e6;break;case"K":rounded=number/1e3;break;case"":rounded=number;break;}

View file

@ -11,7 +11,8 @@ this.realtime.socket=new WebSocket(this.config.endpointRealtime+'/realtime?'+cha
this.realtime.socket.addEventListener('close',event=>{var _a,_b,_c;if(((_b=(_a=this.realtime)===null||_a===void 0?void 0:_a.lastMessage)===null||_b===void 0?void 0:_b.type)==='error'&&((_c=this.realtime)===null||_c===void 0?void 0:_c.lastMessage.data).code===1008){return;} this.realtime.socket.addEventListener('close',event=>{var _a,_b,_c;if(((_b=(_a=this.realtime)===null||_a===void 0?void 0:_a.lastMessage)===null||_b===void 0?void 0:_b.type)==='error'&&((_c=this.realtime)===null||_c===void 0?void 0:_c.lastMessage.data).code===1008){return;}
console.error('Realtime got disconnected. Reconnect will be attempted in 1 second.',event.reason);setTimeout(()=>{this.realtime.createSocket();},1000);});},authenticate:(event)=>{var _a,_b,_c;const message=JSON.parse(event.data);if(message.type==='connected'&&((_a=this.realtime.socket)===null||_a===void 0?void 0:_a.readyState)===WebSocket.OPEN){const cookie=JSON.parse((_b=window.localStorage.getItem('cookieFallback'))!==null&&_b!==void 0?_b:"{}");const session=cookie===null||cookie===void 0?void 0:cookie[`a_session_${this.config.project}`];const data=message.data;if(session&&!data.user){(_c=this.realtime.socket)===null||_c===void 0?void 0:_c.send(JSON.stringify({type:"authentication",data:{session}}));}}},onMessage:(channel,callback)=>(event)=>{try{const message=JSON.parse(event.data);this.realtime.lastMessage=message;if(message.type==='event'){let data=message.data;if(data.channels&&data.channels.includes(channel)){callback(data);}} console.error('Realtime got disconnected. Reconnect will be attempted in 1 second.',event.reason);setTimeout(()=>{this.realtime.createSocket();},1000);});},authenticate:(event)=>{var _a,_b,_c;const message=JSON.parse(event.data);if(message.type==='connected'&&((_a=this.realtime.socket)===null||_a===void 0?void 0:_a.readyState)===WebSocket.OPEN){const cookie=JSON.parse((_b=window.localStorage.getItem('cookieFallback'))!==null&&_b!==void 0?_b:"{}");const session=cookie===null||cookie===void 0?void 0:cookie[`a_session_${this.config.project}`];const data=message.data;if(session&&!data.user){(_c=this.realtime.socket)===null||_c===void 0?void 0:_c.send(JSON.stringify({type:"authentication",data:{session}}));}}},onMessage:(channel,callback)=>(event)=>{try{const message=JSON.parse(event.data);this.realtime.lastMessage=message;if(message.type==='event'){let data=message.data;if(data.channels&&data.channels.includes(channel)){callback(data);}}
else if(message.type==='error'){throw message.data;}} else if(message.type==='error'){throw message.data;}}
catch(e){console.error(e);}}};this.account={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/account';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(email,password,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');} catch(e){console.error(e);}}};this.account={get:()=>__awaiter(this,void 0,void 0,function*(){let path='/account';let payload={};const uri=new URL(this.config.endpoint+path);return yield this.call('get',uri,{'content-type':'application/json',},payload);}),create:(userId,email,password,name)=>__awaiter(this,void 0,void 0,function*(){if(typeof userId==='undefined'){throw new AppwriteException('Missing required parameter: "userId"');}
if(typeof email==='undefined'){throw new AppwriteException('Missing required parameter: "email"');}
if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');} if(typeof password==='undefined'){throw new AppwriteException('Missing required parameter: "password"');}
let path='/account';let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;} let path='/account';let payload={};if(typeof userId!=='undefined'){payload['userId']=userId;}
if(typeof email!=='undefined'){payload['email']=email;} if(typeof email!=='undefined'){payload['email']=email;}

View file

@ -300,7 +300,10 @@ return $value;}).add("platformsLimit",function($value){return $value;}).add("lim
return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');}).add("runtimeName",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].name;} return $value.join(", ").replace(/,\s([^,]+)$/,' and $1');}).add("runtimeName",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].name;}
return'';}).add("runtimeLogo",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].logo;} return'';}).add("runtimeLogo",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].logo;}
return'';}).add("runtimeVersion",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].version;} return'';}).add("runtimeVersion",function($value,env){if(env&&env.RUNTIMES&&env.RUNTIMES[$value]){return env.RUNTIMES[$value].version;}
return'';}).add("accessProject",function($value,router){return($value&&$value.hasOwnProperty(router.params.project))?$value[router.params.project]:0;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);} return'';}).add("indexAttributes",function($value){let output='';for(let i=0;i<$value.attributes.length;i++){output+=$value.attributes[i]+' ('+$value.orders[i]+'), '}
return output.slice(0,-2);}).add("collectionAttributes",function($value){if(!Array.isArray($value)){return[];}
$value.unshift({$id:'$id'});return $value;}).add("documentAttribute",function($value,attribute){if($value[attribute.key]){return $value[attribute.key];}
return null;}).add("accessProject",function($value,router){return($value&&$value.hasOwnProperty(router.params.project))?$value[router.params.project]:0;});function abbreviate(number,maxPlaces,forcePlaces,forceLetter){number=Number(number);forceLetter=forceLetter||false;if(forceLetter!==false){return annotate(number,maxPlaces,forcePlaces,forceLetter);}
let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";} let abbr;if(number>=1e12){abbr="T";}else if(number>=1e9){abbr="B";}else if(number>=1e6){abbr="M";}else if(number>=1e3){abbr="K";}else{abbr="";}
return annotate(number,maxPlaces,forcePlaces,abbr);} return annotate(number,maxPlaces,forcePlaces,abbr);}
function annotate(number,maxPlaces,forcePlaces,abbr){let rounded=0;switch(abbr){case"T":rounded=number/1e12;break;case"B":rounded=number/1e9;break;case"M":rounded=number/1e6;break;case"K":rounded=number/1e3;break;case"":rounded=number;break;} function annotate(number,maxPlaces,forcePlaces,abbr){let rounded=0;switch(abbr){case"T":rounded=number/1e12;break;case"B":rounded=number/1e9;break;case"M":rounded=number/1e6;break;case"K":rounded=number/1e3;break;case"":rounded=number;break;}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long