1. Pub/sub: o coração
Por baixo de "enviar uma mensagem e ela chegar a todos" há um padrão clássico: publicar / assinar (pub/sub).
- Os interessados se inscrevem dando uma função (um callback).
- Quando alguém publica uma mensagem, todas as funções inscritas são chamadas com essa mensagem.
Quem publica não sabe quem está ouvindo; apenas emite. Isso desacopla emissor e receptores.
const subs = [];
function inscrever(fn) { subs.push(fn); }
function enviar(msg) { subs.forEach((fn) => fn(msg)); }
2. Salas (rooms)
Um chat não é um único canal: ele tem salas. Uma sala agrupa as pessoas
que devem receber as mesmas mensagens ("general", "random", um DM...). No
Socket.io é socket.join("general") e io.to("general").emit(...).
Conceitualmente, uma sala é um pub/sub com sua própria lista de inscritos: publicar em "general" só notifica quem está inscrito em "general".
3. Presença (quem está conectado)
A presença responde a "quem está aqui agora?". Quando alguém se
conecta, ela é adicionada à lista; quando sai (ou a conexão cai), ela é
removida. Um Set é perfeito: evita duplicatas se você se reconectar e permite
perguntar "fulano está aqui?" em O(1).
const conectados = new Set();
conectados.add("ana"); // entra
conectados.delete("ana"); // sai
[...conectados]; // lista atual
Com essas três peças —pub/sub, salas e presença— você tem o modelo mental completo de um chat em tempo real. Vamos construí-las.
Exemplos
Pub/sub mínimo em ação
const subs = [];
const inscrever = (fn) => subs.push(fn);
const enviar = (m) => subs.forEach((fn) => fn(m));
inscrever((m) => console.log("A recebe:", m));
inscrever((m) => console.log("B recebe:", m));
enviar("oi");