2022-06-09 01:57:34 +12:00
|
|
|
<?php
|
|
|
|
|
|
|
|
use Appwrite\Resque\Worker;
|
|
|
|
use Utopia\CLI\Console;
|
2023-09-21 00:08:29 +12:00
|
|
|
use Utopia\Database\Database;
|
|
|
|
use Utopia\Database\DateTime;
|
2023-09-06 05:10:48 +12:00
|
|
|
use Utopia\Database\Document;
|
2023-09-21 00:08:29 +12:00
|
|
|
use Utopia\Database\Query;
|
2023-08-22 04:45:15 +12:00
|
|
|
use Utopia\Messaging\Adapters\SMS as SMSAdapter;
|
2023-09-06 05:10:48 +12:00
|
|
|
use Utopia\Messaging\Adapters\SMS\Mock;
|
2022-11-18 21:51:28 +13:00
|
|
|
use Utopia\Messaging\Adapters\SMS\Msg91;
|
|
|
|
use Utopia\Messaging\Adapters\SMS\Telesign;
|
|
|
|
use Utopia\Messaging\Adapters\SMS\TextMagic;
|
|
|
|
use Utopia\Messaging\Adapters\SMS\Twilio;
|
|
|
|
use Utopia\Messaging\Adapters\SMS\Vonage;
|
2023-08-24 08:23:52 +12:00
|
|
|
use Utopia\Messaging\Adapters\Push as PushAdapter;
|
|
|
|
use Utopia\Messaging\Adapters\Push\APNS;
|
|
|
|
use Utopia\Messaging\Adapters\Push\FCM;
|
|
|
|
use Utopia\Messaging\Adapters\Email as EmailAdapter;
|
|
|
|
use Utopia\Messaging\Adapters\Email\Mailgun;
|
|
|
|
use Utopia\Messaging\Adapters\Email\SendGrid;
|
2023-09-06 05:10:48 +12:00
|
|
|
use Utopia\Messaging\Messages\Email;
|
|
|
|
use Utopia\Messaging\Messages\Push;
|
|
|
|
use Utopia\Messaging\Messages\SMS;
|
2023-10-04 23:45:59 +13:00
|
|
|
use Appwrite\Extend\Exception;
|
|
|
|
|
|
|
|
use function Swoole\Coroutine\batch;
|
2023-08-22 04:45:15 +12:00
|
|
|
|
2023-08-24 08:23:52 +12:00
|
|
|
require_once __DIR__ . '/../init.php';
|
2022-06-09 01:57:34 +12:00
|
|
|
|
|
|
|
Console::title('Messaging V1 Worker');
|
2023-08-24 08:23:52 +12:00
|
|
|
Console::success(APP_NAME . ' messaging worker v1 has started' . "\n");
|
2022-06-09 01:57:34 +12:00
|
|
|
|
|
|
|
class MessagingV1 extends Worker
|
|
|
|
{
|
2023-08-22 04:45:15 +12:00
|
|
|
protected ?SMSAdapter $sms = null;
|
|
|
|
protected ?PushAdapter $push = null;
|
2023-08-24 05:12:43 +12:00
|
|
|
protected ?EmailAdapter $email = null;
|
2023-08-23 00:51:30 +12:00
|
|
|
|
2023-09-21 00:08:29 +12:00
|
|
|
protected ?Database $dbForProject = null;
|
2023-08-24 08:23:52 +12:00
|
|
|
|
2022-06-09 01:57:34 +12:00
|
|
|
|
|
|
|
public function getName(): string
|
|
|
|
{
|
2023-10-04 23:45:59 +13:00
|
|
|
return "messaging";
|
2023-08-22 04:45:15 +12:00
|
|
|
}
|
|
|
|
|
2022-06-29 01:32:59 +12:00
|
|
|
|
2023-08-22 04:45:15 +12:00
|
|
|
public function init(): void
|
|
|
|
{
|
2022-06-09 01:57:34 +12:00
|
|
|
}
|
|
|
|
|
|
|
|
public function run(): void
|
|
|
|
{
|
2023-09-06 05:10:48 +12:00
|
|
|
$project = new Document($this->args['project']);
|
2023-09-21 00:08:29 +12:00
|
|
|
$this->dbForProject = $this->getProjectDB($project);
|
2023-09-06 05:10:48 +12:00
|
|
|
|
2023-10-04 23:45:59 +13:00
|
|
|
$message = $this->dbForProject->getDocument('messages', $this->args['messageId']);
|
2023-09-06 05:10:48 +12:00
|
|
|
|
2023-10-04 23:45:59 +13:00
|
|
|
$provider = $this->dbForProject->getDocument('providers', $message->getAttribute('providerId'));
|
2023-08-22 04:45:15 +12:00
|
|
|
|
2023-10-04 23:45:59 +13:00
|
|
|
$this->processMessage($message, $provider);
|
2023-09-21 00:08:29 +12:00
|
|
|
}
|
|
|
|
|
2023-10-07 02:53:46 +13:00
|
|
|
private function processMessage(Document $message, Document $provider): void
|
2023-09-21 00:08:29 +12:00
|
|
|
{
|
2023-10-07 02:53:46 +13:00
|
|
|
$adapter = match ($provider->getAttribute('type')) {
|
|
|
|
'sms' => $this->sms($provider),
|
|
|
|
'push' => $this->push($provider),
|
|
|
|
'email' => $this->email($provider),
|
2023-10-04 23:45:59 +13:00
|
|
|
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
2023-08-23 00:51:30 +12:00
|
|
|
};
|
2023-08-22 04:45:15 +12:00
|
|
|
|
2023-10-07 02:53:46 +13:00
|
|
|
$recipientsId = $message->getAttribute('to');
|
2023-09-21 00:08:29 +12:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var Document[] $recipients
|
|
|
|
*/
|
|
|
|
$recipients = [];
|
|
|
|
|
|
|
|
$topics = $this->dbForProject->find('topics', [Query::equal('$id', $recipientsId)]);
|
|
|
|
foreach ($topics as $topic) {
|
|
|
|
$recipients = \array_merge($recipients, $topic->getAttribute('targets'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$users = $this->dbForProject->find('users', [Query::equal('$id', $recipientsId)]);
|
|
|
|
foreach ($users as $user) {
|
|
|
|
$recipients = \array_merge($recipients, $user->getAttribute('targets'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$targets = $this->dbForProject->find('targets', [Query::equal('$id', $recipientsId)]);
|
2023-09-21 03:21:03 +12:00
|
|
|
$recipients = \array_merge($recipients, $targets);
|
2023-10-07 02:53:46 +13:00
|
|
|
$recipients = \array_filter($recipients, function (Document $recipient) use ($provider) {
|
|
|
|
return $recipient->getAttribute('providerId') === $provider->getId();
|
|
|
|
});
|
2023-09-21 00:08:29 +12:00
|
|
|
|
|
|
|
$identifiers = \array_map(function (Document $recipient) {
|
|
|
|
return $recipient->getAttribute('identifier');
|
|
|
|
}, $recipients);
|
|
|
|
|
2023-10-07 02:53:46 +13:00
|
|
|
$maxBatchSize = $adapter->getMaxMessagesPerRequest();
|
2023-09-21 00:08:29 +12:00
|
|
|
$batches = \array_chunk($identifiers, $maxBatchSize);
|
2023-10-12 19:18:26 +13:00
|
|
|
$batchIndex = 0;
|
2023-09-21 00:08:29 +12:00
|
|
|
|
2023-10-12 19:18:26 +13:00
|
|
|
$results = batch(\array_map(function ($batch) use ($message, $provider, $adapter, $batchIndex) {
|
|
|
|
return function () use ($batch, $message, $provider, $adapter, $batchIndex) {
|
2023-10-04 23:45:59 +13:00
|
|
|
$deliveredTo = 0;
|
|
|
|
$deliveryErrors = [];
|
2023-10-07 02:53:46 +13:00
|
|
|
$messageData = clone $message;
|
2023-10-04 23:45:59 +13:00
|
|
|
$messageData->setAttribute('to', $batch);
|
2023-10-07 02:53:46 +13:00
|
|
|
$data = match ($provider->getAttribute('type')) {
|
|
|
|
'sms' => $this->buildSMSMessage($messageData, $provider),
|
2023-10-05 00:58:38 +13:00
|
|
|
'push' => $this->buildPushMessage($messageData),
|
2023-10-07 02:53:46 +13:00
|
|
|
'email' => $this->buildEmailMessage($messageData, $provider),
|
2023-10-04 23:45:59 +13:00
|
|
|
default => throw new Exception(Exception::PROVIDER_INCORRECT_TYPE)
|
|
|
|
};
|
|
|
|
try {
|
2023-10-07 02:53:46 +13:00
|
|
|
$adapter->send($data);
|
2023-10-04 23:45:59 +13:00
|
|
|
$deliveredTo += \count($batch);
|
2023-10-05 00:58:38 +13:00
|
|
|
} catch (\Exception $e) {
|
2023-10-12 19:18:26 +13:00
|
|
|
$deliveryErrors[] = 'Failed sending to targets ' . $batchIndex + 1 . '-' . \count($batch) . ' with error: ' . $e->getMessage();
|
2023-10-04 23:45:59 +13:00
|
|
|
} finally {
|
2023-10-12 19:18:26 +13:00
|
|
|
$batchIndex++;
|
2023-10-04 23:45:59 +13:00
|
|
|
return [
|
2023-10-06 00:27:48 +13:00
|
|
|
'deliveredTo' => $deliveredTo,
|
|
|
|
'deliveryErrors' => $deliveryErrors,
|
2023-10-04 23:45:59 +13:00
|
|
|
];
|
2023-09-21 00:08:29 +12:00
|
|
|
}
|
2023-10-04 23:45:59 +13:00
|
|
|
};
|
|
|
|
}, $batches));
|
|
|
|
|
|
|
|
$deliveredTo = 0;
|
|
|
|
$deliveryErrors = [];
|
|
|
|
foreach ($results as $result) {
|
|
|
|
$deliveredTo += $result['deliveredTo'];
|
|
|
|
$deliveryErrors = \array_merge($deliveryErrors, $result['deliveryErrors']);
|
2023-09-21 00:08:29 +12:00
|
|
|
}
|
2023-10-07 02:53:46 +13:00
|
|
|
$message->setAttribute('deliveryErrors', $deliveryErrors);
|
2023-09-21 00:08:29 +12:00
|
|
|
|
2023-10-07 02:53:46 +13:00
|
|
|
if (\count($message->getAttribute('deliveryErrors')) > 0) {
|
|
|
|
$message->setAttribute('status', 'failed');
|
2023-09-21 00:08:29 +12:00
|
|
|
} else {
|
2023-10-07 02:53:46 +13:00
|
|
|
$message->setAttribute('status', 'sent');
|
2023-09-21 00:08:29 +12:00
|
|
|
}
|
2023-10-07 02:53:46 +13:00
|
|
|
$message->setAttribute('to', $recipientsId);
|
|
|
|
$message->setAttribute('deliveredTo', $deliveredTo);
|
|
|
|
$message->setAttribute('deliveredAt', DateTime::now());
|
2023-09-21 00:08:29 +12:00
|
|
|
|
2023-10-07 02:53:46 +13:00
|
|
|
$this->dbForProject->updateDocument('messages', $message->getId(), $message);
|
2022-06-09 01:57:34 +12:00
|
|
|
}
|
|
|
|
|
2023-08-23 04:47:32 +12:00
|
|
|
public function shutdown(): void
|
2022-06-09 01:57:34 +12:00
|
|
|
{
|
|
|
|
}
|
2023-08-24 00:49:32 +12:00
|
|
|
|
2023-10-07 02:53:46 +13:00
|
|
|
private function sms(Document $provider): ?SMSAdapter
|
2023-10-04 23:45:59 +13:00
|
|
|
{
|
2023-10-07 02:53:46 +13:00
|
|
|
$credentials = $provider->getAttribute('credentials');
|
|
|
|
return match ($provider->getAttribute('provider')) {
|
2023-10-04 23:45:59 +13:00
|
|
|
'mock' => new Mock('username', 'password'),
|
|
|
|
'twilio' => new Twilio($credentials['accountSid'], $credentials['authToken']),
|
|
|
|
'text-magic' => new TextMagic($credentials['username'], $credentials['apiKey']),
|
|
|
|
'telesign' => new Telesign($credentials['username'], $credentials['password']),
|
|
|
|
'msg91' => new Msg91($credentials['senderId'], $credentials['authKey']),
|
|
|
|
'vonage' => new Vonage($credentials['apiKey'], $credentials['apiSecret']),
|
|
|
|
default => null
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-10-07 02:53:46 +13:00
|
|
|
private function push(Document $provider): ?PushAdapter
|
2023-10-04 23:45:59 +13:00
|
|
|
{
|
2023-10-07 02:53:46 +13:00
|
|
|
$credentials = $provider->getAttribute('credentials');
|
|
|
|
return match ($provider->getAttribute('provider')) {
|
2023-10-04 23:45:59 +13:00
|
|
|
'apns' => new APNS(
|
|
|
|
$credentials['authKey'],
|
|
|
|
$credentials['authKeyId'],
|
|
|
|
$credentials['teamId'],
|
|
|
|
$credentials['bundleId'],
|
|
|
|
$credentials['endpoint']
|
|
|
|
),
|
|
|
|
'fcm' => new FCM($credentials['serverKey']),
|
|
|
|
default => null
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-10-07 02:53:46 +13:00
|
|
|
private function email(Document $provider): ?EmailAdapter
|
2023-10-04 23:45:59 +13:00
|
|
|
{
|
2023-10-07 02:53:46 +13:00
|
|
|
$credentials = $provider->getAttribute('credentials');
|
|
|
|
return match ($provider->getAttribute('provider')) {
|
2023-10-04 23:45:59 +13:00
|
|
|
'mailgun' => new Mailgun($credentials['apiKey'], $credentials['domain'], $credentials['isEuRegion']),
|
|
|
|
'sendgrid' => new SendGrid($credentials['apiKey']),
|
|
|
|
default => null
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildEmailMessage(Document $message, Document $provider): Email
|
2023-08-24 00:49:32 +12:00
|
|
|
{
|
2023-09-28 02:28:00 +13:00
|
|
|
$from = $provider['options']['from'];
|
|
|
|
$to = $message['to'];
|
|
|
|
$subject = $message['data']['subject'];
|
|
|
|
$content = $message['data']['content'];
|
|
|
|
$html = $message['data']['html'];
|
2023-10-04 23:45:59 +13:00
|
|
|
|
|
|
|
return new Email($to, $subject, $content, $from, null, $html);
|
2023-08-24 00:49:32 +12:00
|
|
|
}
|
|
|
|
|
2023-10-04 23:45:59 +13:00
|
|
|
private function buildSMSMessage(Document $message, Document $provider): SMS
|
2023-08-24 00:49:32 +12:00
|
|
|
{
|
2023-09-28 02:28:00 +13:00
|
|
|
$to = $message['to'];
|
|
|
|
$content = $message['data']['content'];
|
|
|
|
$from = $provider['options']['from'];
|
2023-08-24 00:49:32 +12:00
|
|
|
|
2023-09-06 05:10:48 +12:00
|
|
|
return new SMS($to, $content, $from);
|
2023-08-24 00:49:32 +12:00
|
|
|
}
|
|
|
|
|
2023-10-04 23:45:59 +13:00
|
|
|
private function buildPushMessage(Document $message): Push
|
2023-08-24 00:49:32 +12:00
|
|
|
{
|
2023-09-28 02:28:00 +13:00
|
|
|
$to = $message['to'];
|
|
|
|
$title = $message['data']['title'];
|
|
|
|
$body = $message['data']['body'];
|
|
|
|
$data = $message['data']['data'];
|
|
|
|
$action = $message['data']['action'];
|
|
|
|
$sound = $message['data']['sound'];
|
|
|
|
$icon = $message['data']['icon'];
|
|
|
|
$color = $message['data']['color'];
|
|
|
|
$tag = $message['data']['tag'];
|
|
|
|
$badge = $message['data']['badge'];
|
2023-10-04 23:45:59 +13:00
|
|
|
|
2023-09-06 05:10:48 +12:00
|
|
|
return new Push($to, $title, $body, $data, $action, $sound, $icon, $color, $tag, $badge);
|
2023-08-24 00:49:32 +12:00
|
|
|
}
|
2022-06-09 01:57:34 +12:00
|
|
|
}
|