From 70c98b0cfc93fa8342e329369df2b76e1e30f276 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Wed, 8 Jun 2022 15:57:34 +0200 Subject: [PATCH] feat: messaging worker --- Dockerfile | 1 + app/controllers/api/account.php | 16 +++++-- app/init.php | 2 + app/workers/messaging.php | 68 ++++++++++++++++++++++++++++ bin/worker-messaging | 10 +++++ docker-compose.yml | 26 +++++++++++ src/Appwrite/Event/Event.php | 3 ++ src/Appwrite/Event/Phone.php | 80 +++++++++++++++++++++++++++++++++ 8 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 app/workers/messaging.php create mode 100644 bin/worker-messaging create mode 100644 src/Appwrite/Event/Phone.php diff --git a/Dockerfile b/Dockerfile index 0dd0a8f6e..55d328bab 100755 --- a/Dockerfile +++ b/Dockerfile @@ -301,6 +301,7 @@ RUN chmod +x /usr/local/bin/doctor && \ chmod +x /usr/local/bin/worker-functions && \ chmod +x /usr/local/bin/worker-builds && \ chmod +x /usr/local/bin/worker-mails && \ + chmod +x /usr/local/bin/worker-messaging && \ chmod +x /usr/local/bin/worker-webhooks # Letsencrypt Permissions diff --git a/app/controllers/api/account.php b/app/controllers/api/account.php index 27d7db7d7..6746fe75c 100644 --- a/app/controllers/api/account.php +++ b/app/controllers/api/account.php @@ -21,6 +21,7 @@ use Appwrite\Utopia\Database\Validator\CustomId; use MaxMind\Db\Reader; use Utopia\App; use Appwrite\Event\Audit; +use Appwrite\Event\Phone as EventPhone; use Utopia\Audit\Audit as EventAudit; use Utopia\Config\Config; use Utopia\Database\Database; @@ -848,8 +849,9 @@ App::post('/v1/account/sessions/phone') ->inject('dbForProject') ->inject('audits') ->inject('events') + ->inject('messaging') ->inject('phone') - ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Audit $audits, Event $events, Phone $phone) { + ->action(function (string $userId, string $number, Request $request, Response $response, Document $project, Database $dbForProject, Audit $audits, Event $events, EventPhone $messaging, Phone $phone) { if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) { throw new Exception('Phone Disabled', 503, Exception::GENERAL_SMTP_DISABLED); } @@ -916,7 +918,10 @@ App::post('/v1/account/sessions/phone') $dbForProject->deleteCachedDocument('users', $user->getId()); - $phone->send(APP::getEnv('_APP_PHONE_FROM'), $number, $secret); + $messaging + ->setRecipient($number) + ->setMessage($secret) + ->trigger(); $events->setPayload( $response->output( @@ -2245,7 +2250,8 @@ App::post('/v1/account/verification/phone') ->inject('audits') ->inject('events') ->inject('usage') - ->action(function (Request $request, Response $response, Phone $phone, Document $user, Database $dbForProject, Audit $audits, Event $events, Stats $usage) { + ->inject('messaging') + ->action(function (Request $request, Response $response, Phone $phone, Document $user, Database $dbForProject, Audit $audits, Event $events, Stats $usage, EventPhone $messaging) { if (empty(App::getEnv('_APP_SMTP_HOST'))) { throw new Exception('SMTP Disabled', 503, Exception::GENERAL_SMTP_DISABLED); @@ -2282,7 +2288,9 @@ App::post('/v1/account/verification/phone') $dbForProject->deleteCachedDocument('users', $user->getId()); - $phone->send(APP::getEnv('_APP_PHONE_FROM'), $user->getAttribute('phone'), $secret); + $messaging + ->setRecipient($user->getAttribute('phone')) + ->setMessage($secret); $events ->setParam('userId', $user->getId()) diff --git a/app/init.php b/app/init.php index 574d009e3..1782e884a 100644 --- a/app/init.php +++ b/app/init.php @@ -32,6 +32,7 @@ use Appwrite\Event\Database as EventDatabase; use Appwrite\Event\Delete; use Appwrite\Event\Event; use Appwrite\Event\Mail; +use Appwrite\Event\Phone; use Appwrite\Network\Validator\Email; use Appwrite\Network\Validator\IP; use Appwrite\Network\Validator\URL; @@ -691,6 +692,7 @@ App::setResource('audits', fn() => new Audit()); App::setResource('mails', fn() => new Mail()); App::setResource('deletes', fn() => new Delete()); App::setResource('database', fn() => new EventDatabase()); +App::setResource('messaging', fn() => new Phone()); App::setResource('usage', function ($register) { return new Stats($register->get('statsd')); }, ['register']); diff --git a/app/workers/messaging.php b/app/workers/messaging.php new file mode 100644 index 000000000..45a72a375 --- /dev/null +++ b/app/workers/messaging.php @@ -0,0 +1,68 @@ +from = App::getEnv('_APP_PHONE_FROM'); + $this->phone = match ($provider) { + 'mock' => new Mock('', ''), // used for tests + 'twilio' => new Twilio($user, $secret), + 'text-magic' => new TextMagic($user, $secret), + 'telesign' => new Telesign($user, $secret), + default => null + }; + } + + public function run(): void + { + if (empty(App::getEnv('_APP_PHONE_PROVIDER'))) { + Console::info('Skipped sms processing. No Phone provider has been set.'); + return; + } + + $recipient = $this->args['recipient']; + $message = $this->args['message']; + + try { + $this->phone->send($this->from, $recipient, $message); + } catch (\Exception $error) { + throw new Exception('Error sending message: ' . $error->getMessage(), 500); + } + } + + public function shutdown(): void + { + } +} diff --git a/bin/worker-messaging b/bin/worker-messaging new file mode 100644 index 000000000..51057bc5a --- /dev/null +++ b/bin/worker-messaging @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ -z "$_APP_REDIS_USER" ] && [ -z "$_APP_REDIS_PASS" ] +then + REDIS_BACKEND="${_APP_REDIS_HOST}:${_APP_REDIS_PORT}" +else + REDIS_BACKEND="redis://${_APP_REDIS_USER}:${_APP_REDIS_PASS}@${_APP_REDIS_HOST}:${_APP_REDIS_PORT}" +fi + +INTERVAL=1 QUEUE='v1-messaging' APP_INCLUDE='/usr/src/code/app/workers/messaging.php' php /usr/src/code/vendor/bin/resque -dopcache.preload=opcache.preload=/usr/src/code/app/preload.php \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index dca7d01dc..e390fc469 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -528,6 +528,32 @@ services: - _APP_LOGGING_PROVIDER - _APP_LOGGING_CONFIG + appwrite-worker-messaging: + entrypoint: worker-messaging + <<: *x-logging + container_name: appwrite-worker-messaging + build: + context: . + networks: + - appwrite + volumes: + - ./app:/usr/src/code/app + - ./src:/usr/src/code/src + depends_on: + - redis + environment: + - _APP_ENV + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_PHONE_PROVIDER + - _APP_PHONE_USER + - _APP_PHONE_SECRET + - _APP_PHONE_FROM + - _APP_LOGGING_PROVIDER + - _APP_LOGGING_CONFIG + appwrite-maintenance: entrypoint: maintenance <<: *x-logging diff --git a/src/Appwrite/Event/Event.php b/src/Appwrite/Event/Event.php index 629a058fe..d8778fa04 100644 --- a/src/Appwrite/Event/Event.php +++ b/src/Appwrite/Event/Event.php @@ -32,6 +32,9 @@ class Event public const BUILDS_QUEUE_NAME = 'v1-builds'; public const BUILDS_CLASS_NAME = 'BuildsV1'; + public const MESSAGING_QUEUE_NAME = 'v1-messaging'; + public const MESSAGING_CLASS_NAME = 'MessagingV1'; + protected string $queue = ''; protected string $class = ''; protected string $event = ''; diff --git a/src/Appwrite/Event/Phone.php b/src/Appwrite/Event/Phone.php new file mode 100644 index 000000000..8baa5120c --- /dev/null +++ b/src/Appwrite/Event/Phone.php @@ -0,0 +1,80 @@ +recipient = $recipient; + + return $this; + } + + /** + * Returns set recipient for this messaging event. + * + * @return string + */ + public function getRecipient(): string + { + return $this->recipient; + } + + /** + * Sets url for the messaging event. + * + * @param string $message + * @return self + */ + public function setMessage(string $message): self + { + $this->message = $message; + + return $this; + } + + /** + * Returns set url for the messaging event. + * + * @return string + */ + public function getMessage(): string + { + return $this->message; + } + + /** + * Executes the event and sends it to the messaging worker. + * + * @return string|bool + * @throws \InvalidArgumentException + */ + public function trigger(): string|bool + { + return Resque::enqueue($this->queue, $this->class, [ + 'project' => $this->project, + 'user' => $this->user, + 'payload' => $this->payload, + 'recipient' => $this->recipient, + 'message' => $this->message, + 'events' => Event::generateEvents($this->getEvent(), $this->getParams()) + ]); + } +}