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/




