Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Learn why MongoDB was selected as a leader in the 2024 Gartner® Magic Quadrant™
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Produtoschevron-right
MongoDBchevron-right

Adição de notificações em tempo real ao Ghost CMS usando MongoDB e eventos enviados pelo servidor

TQ
Tobias Quante7 min read • Published Aug 14, 2023 • Updated Aug 14, 2023
DockerFluxos de alteraçõesJavaScriptMongoDB
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty

Sobre o Ghost

Isso garante que o núcleo do sistema permaneça enxuto. Para integrar aplicativos de terceiros, você nem precisa instalar plugins. Em vez disso, o Ghost oferece um recurso chamado Webhooks, que é executado enquanto você trabalha em sua publicação.
Esses webhooks enviam itens específicos, como uma publicação ou uma página, para um endpoint HTTP definido por você e, assim, fornecem uma base ideal para nosso serviço em tempo real.

Eventos enviados pelo servidor

Você provavelmente está familiarizado com o conceito de sessão HTTP. Um cliente envia uma solicitação, o servidor responde e fecha a conexão. Ao usar eventos enviados pelo servidor (SSEs), essa conexão permanece aberta. Isso permite que o servidor continue gravando mensagens na resposta.
Um ciclo de vida HTTP padrão consiste em uma solicitação do cliente e uma resposta do servidor
Como os Websockets (WS), aplicativos e sites usam SSEs para comunicação em tempo real. Enquanto os WSs usam um protocolo dedicado e funcionam em ambas as direções, os SSEs são unidirecionais. Eles usam endpoints HTTP simples para escrever uma mensagem sempre que ocorre um evento no lado do servidor.
Os eventos MongoDB Server Sent são gravados em uma resposta de conexão já existente
Os clientes podem se inscrever nesses endpoints usando a API do navegadorEventSource :
1const subscription = new EventSource("https://example.io/subscribe")

MongoDB Change Streams

Agora que examinamos a borda do nosso aplicativo, é hora de apresentar seu núcleo. Usaremos o MongoDB para armazenar um subconjunto dos dados do webhook dohost recebidos. Além disso, usaremos o MongoDB Change Streams para assistir à nossa coleção de webhook.
Resumindo, o Change Streams registra os dados que fluem para nosso banco de dados. Podemos assinar esse fluxo de dados e React a ele. Reagir significa enviar mensagens SSE para clientes conectados sempre que um novo webhook é recebido e armazenado.
O código Javascript a seguir mostra uma assinatura simples do Change Stream.
1import {MongoClient} from 'mongodb';
2
3const client = new MongoClient("<mongodb-url>");
4const ghostDb = client.db('ghost');
5const ghostCollection = ghostDb.collection('webhooks');
6const ghostChangeStrem = ghostCollection.watch();
7
8ghostChangeStream.on('change', document => {
9 /* document is the MongoDB collection entry, e.g. our webhook */
10});
Sua natureza baseada em eventos combina perfeitamente com webhooks e SSEs. Podemos React a webhooks recém-chegados onde os dados são criados, garantindo a integridade dos dados em todo o nosso aplicativo.

Crie um endpoint em tempo real

Precisamos de uma camada extra de aplicativo para propagar essas alterações para clientes conectados. Decidi usar Typescript e Express, mas você pode usar qualquer outra framework do lado do servidor. Você também precisará de uma instância dedicada do MongoDB*. Para um início rápido, você pode se inscrever no MongoDB Atlas. Em seguida, crie um cluster gratuito e conecte-se a ele.
Vamos começar clonando o branch1-get-started deste repositório do Github:
1# ssh
2$ git clone git@github.com:tq-bit/mongodb-article-mongo-changestreams.git
3
4# HTTP(s)
5$ git clone https://github.com/tq-bit/mongodb-article-mongo-changestreams.git
6
7# Change to the starting branch
8$ git checkout 1-get-started
9
10# Install NPM dependencies
11$ npm install
12
13# Make a copy of .env.example
14$ cp .env.example .env
Certifique-se de preencher a variável de ambiente MONGO_HOST com sua connection string!
O Express e o cliente de banco de dados já estão implementados. Então, a seguir, vamos nos concentrar em adicionar MongoDB change stream e eventos enviados pelo servidor.
Depois que tudo estiver configurado, você poderá iniciar o servidor em http://localhost:3000 digitando
1npm run dev
O aplicativo usa dois endpoints importantes que estenderemos nas próximas seções:
  • /api/notification/subscribe <- Usado pelo EventSource para receber mensagens de eventos
  • /api/notification/article/create < - Usado como alvo de webhook peloGhost
* Se você não estiver usando o MongoDB Atlas, certifique-se de ter osconjuntos de replicação habilitados.

Adicionar eventos enviados pelo servidor

Abra o projeto clonado em seu editor de código favorito. Adicionaremos nossa lógica SSE em src/components/notification/notification.listener.ts.
Em resumo, a implementação de SSE requer três etapas:
  • Escreva um cabeçalho de status HTTP 200 .
  • Escreva uma mensagem de abertura.
  • Adicione manipuladores de mensagens de resposta baseados em eventos.
Começaremos a enviar uma mensagem estática e revisitaremos este módulo depois de adicionar ChangeStreams.
Você também pode git checkout 2-add-sse para ver o resultado final.

Escrever o cabeçalho HTTP

Escrever o cabeçalho HTTP informa os clientes sobre uma conexão bem-sucedida. Ele também propaga o tipo de conteúdo da resposta e garante que os eventos não sejam armazenados em cache.
Adicione o seguinte código à função subscribeToArticleNotification interna:
1// Replace
2// TODO: Add function to write the head
3// with
4console.log('Step 1: Write the response head and keep the connection open');
5res.writeHead(200, {
6 'Content-Type': 'text/event-stream',
7 'Cache-Control': 'no-cache',
8 Connection: 'keep-alive'
9});

Escreva uma mensagem de abertura

A primeira mensagem enviada deve ter um tipo de evento de "abrir". Não é obrigatório, mas ajuda a determinar se a inscrição foi bem-sucedida.
Acrescente o seguinte código à função subscribeToArticleNotification:
1// Replace
2// TODO: Add functionality to write the opening message
3// with
4console.log('Step 2: Write the opening event message');
5res.write('event: open\n');
6res.write('data: Connection opened!\n'); // Data can be any string
7res.write(`id: ${crypto.randomUUID()}\n\n`);

Adicionar manipuladores de mensagens de resposta

Podemos personalizar o conteúdo e o tempo de todas as outras mensagens enviadas. Vamos adicionar uma função de espaço reservado que envia mensagens a cada cinco segundos por enquanto. E já que estamos nisso, vamos também adicionar um manipulador para fechar a conexão do cliente:
Acrescente o seguinte código à função subscribeToArticleNotification:
1setInterval(() => {
2 console.log('Step 3: Send a message every five seconds');
3 res.write(`event: message\n`);
4 res.write(`data: ${JSON.stringify({ message: 'Five seconds have passed' })}\n`);
5 res.write(`id: ${crypto.randomUUID()}\n\n`);
6}, 5000);
7
8
9// Step 4: Handle request events such as client disconnect
10// Clean up the Change Stream connection and close the connection stream to the client
11req.on('close', () => {
12 console.log('Step 4: Handle request events such as client disconnect');
13 res.end();
14});
Para verificar se tudo está funcionando, visite http://localhost:3000/api/notification/subscribe.
o servidor enviou dados de eventos em uma tela do navegador

Adicione um endpoint POST para o Python

Vamos visitar src/components/notification/notification.model.ts a seguir. Adicionaremos um comandoinsertsimples para nosso banco de dados na função createNotificiation:
Você também pode git checkout 3-webhook-handler para ver o resultado final.
1// Replace
2// TODO: Add insert one functionality for DB
3// with
4return notificationCollection.insertOne(notification);
E para src/components/notification/notification.controller.ts. Para processar webhooks recebidos, adicionaremos uma função de manipulador a handleArticleCreationNotification:
1// Replace
2// TODO: ADD handleArticleCreationNotification
3// with
4const incomingWebhook: GhostWebhook = req.body;
5await NotificationModel.createNotificiation({
6 id: crypto.randomUUID(),
7 ghostId: incomingWebhook.post?.current?.id,
8 ghostOriginalUrl: incomingWebhook.post?.current?.url,
9 ghostTitle: incomingWebhook.post?.current?.title,
10 ghostVisibility: incomingWebhook.post?.current?.visibility,
11 type: NotificationEventType.PostPublished,
12});
13
14res.status(200).send('OK');
Esse manipulador pegará os dados do webhook de entrada e inserirá uma nova notificação.
1curl -X POST -d '{
2 "post": {
3 "current": {
4 "id": "sj7dj-lnhd1-kabah9-107gh-6hypo",
5 "url": "http://localhost:2368/how-to-create-realtime-notifications",
6 "title": "How to create realtime notifications",
7 "visibility": "public"
8 }
9 }
10}' http://localhost:3000/api/notification/article/create
Você também pode testar a funcionalidade de inserção usando o cliente Postman ou VSCode REST e, em seguida, verificar sua MongoDB collection.Para sua conveniência, há uma solicitação de exemplo em/test/notification.rest no diretório do projeto.

Disparar fluxos de alterações do MongoDB

Até agora, podemos enviar SSEs e inserir notificações do Ghost. Vamos colocar esses dois recursos juntos agora.
Anteriormente, adicionamos uma mensagem estática de servidor enviada a cada cinco segundos. Vamos revisar src/components/notification/notification.listener.ts e torná-lo mais dinâmico.
Primeiro, vamos nos livre de todo o setInterval e de sua chamada de resposta. Em vez disso, usaremos nosso notificationCollection e seu método interno watch. Este método retorna um ChangeStream.
Você pode criar um change stream adicionando o seguinte código acima do segmento de códigoexport default:
1const notificationStream = notificationCollection.watch();
O stream aciona um evento sempre que a coleção relacionada é alterada. Isso inclui o eventoinsert da seção anterior.
Podemos registrar funções de retorno de chamada para cada uma delas. O evento que é acionado quando um documento dentro da collection é alterado é "change":
1notificationStream.on('change', (next) => {
2 console.log('Step 3.1: Change in Database detected!');
3});
A variável passada para a função de retorno de chamada é um documento de fluxo de alterações. Inclui duas informações importantes para nós:
  • O documento inserido, atualizado ou excluído.
  • O tipo de operação na coleção.
Vamos atribuí-las a uma variável, cada uma dentro do callback:
1notificationStream.on('change', (next) => {
2 // ... previous code
3 const {
4 // @ts-ignore, fullDocument is not part of the next type (yet)
5 fullDocument /* The newly inserted fullDocument */,
6 operationType /* The MongoDB operation Type, e.g. insert */,
7 } = next;
8});
Vamos escrever a notificação para o cliente. Podemos fazer isso repetindo o método que usamos para a mensagem de abertura.
1notificationStream.on('change', (next) => {
2 // ... previous code
3 console.log('Step 3.2: Writing out response to connected clients');
4 res.write(`event: ${operationType}\n`);
5 res.write(`data: ${JSON.stringify(fullDocument)}\n`);
6 res.write(`id: ${crypto.randomUUID()}\n\n`);
7});
E é isso! Você pode testar se tudo está funcional por:
  1. Abrir seu navegador em http://localhost:3000/api/notification/subscribe.
  2. Usando o arquivo em test/notification.rest com o cliente HTTP do VSCode.
  3. Verificar se o seu navegador inclui uma abertura e uma notificação fantasma.
o servidor enviou dados do evento em uma tela do navegador após a implementação completa do change stream
Para uma implementação de webhook HTTP, você precisará de uma instância do Ghost em execução. Adicionei um dockerfile a este repositório para sua conveniência. Você também pode instalar o Ghost localmente.
Para iniciar o Ghost com o dockerfile, certifique-se de ter o Docker Engine ou o Docker Desktop com suporte para docker compose instalado.
Para uma instalação local e a primeira configuração, você deve seguir o guia oficial de instalação do Ghost.
Depois que a instância do Ghost estiver em funcionamento, abra o navegador em http://localhost:2368/ghost. Você pode configurar seu site como quiser, dar um nome a ele, inserir detalhes e assim por diante.
Configurar a implantação do Ghost
Para criar um webhook, você deve primeiro criar uma integração personalizada. Para fazer isso, navegue até as configurações do seu site e clique no ponto de menu “Integrations”. Clique em "Add Webhook, ", insira um nome e clique em "Create. "
Integrações personalizadas de terceiros dohost
Dentro da integração recém-criada, agora você pode configurar um webhook para apontar para seu aplicativo em http://<host>:<port>/api/notification/article/create*.
* Esse URL pode variar de acordo com a configuração local do Spark. Por exemplo, se você executar o Python em um contêiner, poderá encontrar o IP local da sua máquina usando o terminal e ifconfig no Linux ou ipconfig no Windows.
Aplicativo fantasma local em tempo real
E é isso. Agora, sempre que uma postagem for publicada, seu conteúdo será enviado para nosso endpoint em tempo real. Após ser inserido no MongoDB, uma mensagem de evento será enviada a todos os clientes conectados.

Assine os Change Streams do seu tema Ghost

Existem algumas maneiras de adicionar notificações em tempo real ao seu tema Ghost. Entrar em detalhes está além do escopo deste artigo. Eu preparei dois arquivos, um plugin.js e um arquivo plugin.cssque você pode injetar no tema Casper padrão.
Tente fazer isso iniciando uma instância local do Ghost usando o dockerfile fornecido.
Em seguida, você deve instruir seu aplicativo a exibir os ativos JS e CSS. Adicione o seguinte ao seu arquivoindex.ts:
1// ... other app.use hooks
2app.use(express.static('public'));
3// ... app.listen()
Por fim, navegue até Code Injection e adicione as duas entradas a seguir no 'Site Header':
1<script src="http://localhost:3000/js/plugin.js"></script>
2<link href="http://localhost:3000/css/plugin.css" rel="stylesheet">
A peça principal do plugin é a API do navegador EventSource. Você vai querer usá-lo ao integrar este aplicativo com outros temas.
Ao voltar para a publicação do Ghost, você deverá ver um pequeno ícone de sino no canto superior direito.
notificações de assinatura no Ghost

Seguindo em frente

Se você acompanhou, parabéns! Agora você tem um serviço de notificação em tempo real funcionando para o seu blog Ghost. E se ainda não, o que está esperando? Cadastre-se para uma conta gratuita no MongoDB Atlas e comece a construir. Você pode usar a ramificação final deste repositório para começar e explorar todo o poder do kit de ferramentas do MongoDB.

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Análise de moeda com coleções de séries temporais #2 — Cálculo da média móvel simples e da média móvel exponencial


May 16, 2022 | 7 min read
Tutorial

Explorando os recursos avançados do Atlas Search com o MongoDB Atlas Atlas Search


Aug 20, 2024 | 6 min read
Tutorial

Introdução ao MongoDB Kotlin Driver


Sep 09, 2024 | 9 min read
Início rápido

Pipelines de agregação complexos com Baunilha PHP e MongoDB


Sep 05, 2024 | 10 min read
Sumário