Hoje em dia eu estou envolvido com o AWS da Amazon, e já que estou migrando meus backends para Lumen, eu vou brincar um pouco com AWS e Lumen. Hoje eu quero criar um servidor Lumen simples para manusear notificações SNS. Um endpoint para ouvir SNS e outro para emitir notificações. Eu também quero registrar logs no CloudWatch. Vamos começar.
Primeiro, o servidor Lumen.
use Laravel\Lumen\Application; require __DIR__ . '/../vendor/autoload.php'; (new Dotenv\Dotenv(__DIR__ . "/../env"))->load(); $app = new Application(); $app->register(App\Providers\LogServiceProvider::class); $app->register(App\Providers\AwsServiceProvider::class); $app->group(['namespace' => 'App\Http\Controllers'], function (Application $app) { $app->get("/push", "SnsController@push"); $app->post("/read", "SnsController@read"); }); $app->run();
Como podemos ver, há uma rota para enviar notificações e outra para ler mensagens. Para trabalhar com SNS, criarei um provedor de serviços simples.
namespace App\Providers; use Illuminate\Support\ServiceProvider; use Aws\Sns\SnsClient; class AwsServiceProvider extends ServiceProvider { public function register() { $awsCredentials = [ 'region' => getenv('AWS_REGION'), 'version' => getenv('AWS_VERSION'), 'credentials' => [ 'key' => getenv('AWS_CREDENTIALS_KEY'), 'secret' => getenv('AWS_CREDENTIALS_SECRET'), ], ]; $this->app->instance(SnsClient::class, new SnsClient($awsCredentials)); } }
Agora podemos criar as rotas em SnsController. O Sns possui um mecanismo de confirmação para validar os endpoints. Isso está bem explicado aqui.
namespace App\Http\Controllers; use Aws\Sns\SnsClient; use Illuminate\Http\Request; use Laravel\Lumen\Routing\Controller; use Monolog\Logger; class SnsController extends Controller { private $request; private $logger; public function __construct(Request $request, Logger $logger) { $this->request = $request; $this->logger = $logger; } public function push(SnsClient $snsClient) { $snsClient->publish([ 'TopicArn' => getenv('AWS_SNS_TOPIC1'), 'Message' => 'hi', 'Subject' => 'Subject', ]); return ['push']; } public function read(SnsClient $snsClient) { $data = $this->request->json()->all(); if ($this->request->headers->get('X-Amz-Sns-Message-Type') == 'SubscriptionConfirmation') { $this->logger->notice("sns:confirmSubscription"); $snsClient->confirmSubscription([ 'TopicArn' => getenv('AWS_SNS_TOPIC1'), 'Token' => $data['Token'], ]); } else { $this->logger->warn("read", [ 'Subject' => $data['Subject'], 'Message' => $data['Message'], 'Timestamp' => $data['Timestamp'], ]); } return "OK"; } }
Finalmente eu quero usar o CloudWatch para configurar o Monolog com outro provedor de serviços. Isso também está bem explicado aqui:
namespace App\Providers; use Aws\CloudWatchLogs\CloudWatchLogsClient; use Illuminate\Support\ServiceProvider; use Maxbanton\Cwh\Handler\CloudWatch; use Monolog\Formatter\LineFormatter; use Monolog\Logger; class LogServiceProvider extends ServiceProvider { public function register() { $awsCredentials = [ 'region' => getenv('AWS_REGION'), 'version' => getenv('AWS_VERSION'), 'credentials' => [ 'key' => getenv('AWS_CREDENTIALS_KEY'), 'secret' => getenv('AWS_CREDENTIALS_SECRET'), ], ]; $cwClient = new CloudWatchLogsClient($awsCredentials); $cwRetentionDays = getenv('CW_RETENTIONDAYS'); $cwGroupName = getenv('CW_GROUPNAME'); $cwStreamNameInstance = getenv('CW_STREAMNAMEINSTANCE'); $loggerName = getenv('CF_LOGGERNAME'); $logger = new Logger($loggerName); $handler = new CloudWatch($cwClient, $cwGroupName, $cwStreamNameInstance, $cwRetentionDays); $handler->setFormatter(new LineFormatter(null, null, false, true)); $logger->pushHandler($handler); $this->app->instance(Logger::class, $logger); } }
Depurar esse tipo de webhooks com uma instância EC2 às vezes é um pouco difícil. Mas podemos facilmente expor nosso servidor web local à Internet com o ngrok.
Nós só precisamos iniciar o nosso servidor local.
php -S 0.0.0.0:8080 -t www
E criar um túnel com ngrok.
ngrok http 8080
E é isso. Lumen e SNS estão prontos e funcionando.
Código disponível no meu Github.
***
Gonzalo Ayuso faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela Redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://gonzalo123.com/2018/01/22/handling-amazon-sns-messages-with-php-lumen-and-cloudwatch/