1
0
Fork 0
mirror of synced 2024-05-19 12:12:36 +12:00
appwrite/src/Appwrite/Event/Realtime.php
2021-06-28 16:34:28 +02:00

265 lines
7.3 KiB
PHP

<?php
namespace Appwrite\Event;
use Appwrite\Database\Document;
use Utopia\App;
class Realtime
{
/**
* @var string
*/
protected $project = '';
/**
* @var string
*/
protected $event = '';
/**
* @var string
*/
protected $userId = '';
/**
* @var array
*/
protected $channels = [];
/**
* @var array
*/
protected $permissions = [];
/**
* @var false
*/
protected $permissionsChanged = false;
/**
* @var Document
*/
protected $payload;
/**
* Event constructor.
*
* @param string $project
* @param string $event
* @param array $payload
*/
public function __construct(string $project, string $event, array $payload)
{
$this->project = $project;
$this->event = $event;
$this->payload = new Document($payload);
}
/**
* @param string $project
* return $this
*/
public function setProject(string $project): self
{
$this->project = $project;
return $this;
}
/**
* @param string $userId
* return $this
*/
public function setUserId(string $userId): self
{
$this->userId = $userId;
return $this;
}
/**
* @return string
*/
public function getProject(): string
{
return $this->project;
}
/**
* @param string $event
* return $this
*/
public function setEvent(string $event): self
{
$this->event = $event;
return $this;
}
/**
* @return string
*/
public function getEvent(): string
{
return $this->event;
}
/**
* @param array $payload
* @return $this
*/
public function setPayload(array $payload): self
{
$this->payload = new Document($payload);
return $this;
}
/**
* @return Document
*/
public function getPayload(): Document
{
return $this->payload;
}
/**
* Converts the channels from the Query Params into an array.
* Also renames the account channel to account.USER_ID and removes all illegal account channel variations.
* @param array $channels
* @param Document $user
* @return array
*/
public static function convertChannels(array $channels, Document $user): array
{
$channels = array_flip($channels);
foreach ($channels as $key => $value) {
switch (true) {
case strpos($key, 'account.') === 0:
unset($channels[$key]);
break;
case $key === 'account':
if (!empty($user->getId())) {
$channels['account.' . $user->getId()] = $value;
}
unset($channels['account']);
break;
}
}
if (\array_key_exists('account', $channels)) {
if ($user->getId()) {
$channels['account.' . $user->getId()] = $channels['account'];
}
unset($channels['account']);
}
return $channels;
}
/**
* Populate channels array based on the event name and payload.
*
* @return void
*/
private function prepareChannels(): void
{
switch (true) {
case strpos($this->event, 'account.recovery.') === 0:
case strpos($this->event, 'account.sessions.') === 0:
case strpos($this->event, 'account.verification.') === 0:
$this->channels[] = 'account.' . $this->payload->getAttribute('userId');
$this->permissions = ['user:' . $this->payload->getAttribute('userId')];
break;
case strpos($this->event, 'account.') === 0:
$this->channels[] = 'account.' . $this->payload->getId();
$this->permissions = ['user:' . $this->payload->getId()];
break;
case strpos($this->event, 'teams.memberships') === 0:
$this->permissionsChanged = in_array($this->event, ['teams.memberships.update', 'teams.memberships.delete', 'teams.memberships.update.status']);
$this->channels[] = 'memberships';
$this->channels[] = 'memberships.' . $this->payload->getId();
$this->permissions = ['team:' . $this->payload->getAttribute('teamId')];
break;
case strpos($this->event, 'teams.') === 0:
$this->permissionsChanged = $this->event === 'teams.create';
$this->channels[] = 'teams';
$this->channels[] = 'teams.' . $this->payload->getId();
$this->permissions = ['team:' . $this->payload->getId()];
break;
case strpos($this->event, 'database.collections.') === 0:
$this->channels[] = 'collections';
$this->channels[] = 'collections.' . $this->payload->getId();
$this->permissions = $this->payload->getAttribute('$permissions.read');
break;
case strpos($this->event, 'database.documents.') === 0:
$this->channels[] = 'documents';
$this->channels[] = 'collections.' . $this->payload->getAttribute('$collection') . '.documents';
$this->channels[] = 'documents.' . $this->payload->getId();
$this->permissions = $this->payload->getAttribute('$permissions.read');
break;
case strpos($this->event, 'storage.') === 0:
$this->channels[] = 'files';
$this->channels[] = 'files.' . $this->payload->getId();
$this->permissions = $this->payload->getAttribute('$permissions.read');
break;
case strpos($this->event, 'functions.executions.') === 0:
if (!empty($this->payload->getAttribute('$permissions.read'))) {
$this->channels[] = 'executions';
$this->channels[] = 'executions.' . $this->payload->getId();
$this->channels[] = 'functions.' . $this->payload->getAttribute('functionId');
$this->permissions = $this->payload->getAttribute('$permissions.read');
}
break;
}
}
/**
* Execute Event.
*
* @return void
*/
public function trigger(): void
{
$this->prepareChannels();
if (empty($this->channels)) return;
$redis = new \Redis();
$redis->connect(App::getEnv('_APP_REDIS_HOST', ''), App::getEnv('_APP_REDIS_PORT', ''));
$redis->publish('realtime', json_encode([
'project' => $this->project,
'permissions' => $this->permissions,
'permissionsChanged' => $this->permissionsChanged,
'userId' => $this->userId,
'data' => [
'event' => $this->event,
'channels' => $this->channels,
'timestamp' => time(),
'payload' => $this->payload->getArrayCopy()
]
]));
$this->reset();
}
/**
* Resets this event and unpopulates all data.
*
* @return $this
*/
public function reset(): self
{
$this->event = '';
$this->payload = $this->channels = [];
return $this;
}
}