Mantém só visão da disciplina e tutorial Ping em docs/tp/; documentação técnica sem tabelas de verificação para entrega. Co-authored-by: Cursor <cursoragent@cursor.com>
6.6 KiB
Tutorial de aula — plugin Ping
Exercício para montar o plugin mais simples do Pitiupi: medir RTT (tempo de ida e volta) com mensagens Ping / Pong na rede, igual a um ping de laboratório — mas usando o mesmo mecanismo de plugins do chat e do screencast.
A solução completa não entra no repositório público: o exercício é montado em plugins/ping/ na máquina local (fora do gate CI). Este tutorial descreve escopo, trechos e passos — o restante é implementado em sala.
Índice TP: README.md · Plugins de referência: 11_plugins_referencia.md.
O que você vai aprender
| Componente do núcleo | Para que serve no Ping |
|---|---|
Plugin + SPI |
O Pitiupi descobre seu JAR e chama createPlugin |
Message serializável |
PingMessage, PongMessage, PingStopMessage |
getMessages() / receiveMessage |
O núcleo entrega só os tipos que você registrou |
MessageDispatcher |
Envia UDP unicast/multicast sem montar socket manual |
PluginWorkspace |
Galeria e peer actions abrem a aba central |
PeerAction |
Menu ao clicar em um usuário na lista lateral |
SessionTabBar |
Abas por peer (passivas ao receber, como no chat) |
Limitações didáticas (de propósito)
- Não é ICMP do sistema operacional — são mensagens Java na LAN.
- Sem gráficos nem histórico em arquivo.
- Transporte padrão: UDP unicast para um peer; multicast só no “ping para todos (uma vez)”.
- Não há moderação, login extra nem criptografia.
Pré-requisitos
- Pitiupi abrindo com login (nome + porta).
09_sistema_de_plugins.md.- JDK 17 + Ant.
- Núcleo compilado:
pitiupi/dist/pitiupi.jar.
Passo 1 — Projeto Ant
- Copie
plugins/chatparaplugins/ping(somente na sua máquina). - Renomeie o projeto para
pitiupi.pinge o JAR de saída paradist/pitiupi.ping.jar. - Classpath de compilação:
../../pitiupi/dist/pitiupi.jar.
Passo 2 — SPI
Arquivo src/META-INF/services/pitiupi.models.Plugin:
pitiupi.ping.plugin.PingPlugin
Passo 3 — Mensagens
Três classes em pitiupi.ping.net, todas estendendo pitiupi.models.Messages.Message:
PingMessage— campos:pingId(UUID),sentAtMillis,senderName,senderIp,mode(ONCEouCONTINUOUS_TICK),sessionId(para série contínua).PongMessage—pingId,echoSentAtMillis(copiado do ping),responderName,responderIp.PingStopMessage—sessionId,senderName,senderIp(avisa que o contínuo parou).
Registre em PingPlugin.getMessages():
return List.of(PingMessage.class, PongMessage.class, PingStopMessage.class);
Por quê: o núcleo só desserializa tipos declarados; evita que outro plugin receba seus bytes por engano.
Passo 4 — PingController (lógica)
Classe em pitiupi.ping.control sem Swing:
- Ao enviar ping: grave
pendingByPingId.put(pingId, sentAtMillis)e useMessageDispatcher.send(..., UNICAST_UDP). - Ao receber
PingMessage: responda comPongMessage(eco dosentAtMillis). - Ao receber
PongMessage:rtt = now - pending.remove(pingId)e notifique a UI. - Contínuo:
javax.swing.Timera cada 1 s enviaCONTINUOUS_TICKcom o mesmosessionId. - Parar: cancele o timer local e envie
PingStopMessageao peer.
Use PeerIpv4 e LocalNetworkInfo.bestLocalIpv4() para IP legível no Windows.
Passo 5 — PingPanel (UI)
Siga o mesmo chrome do screencast: PluginSessionWorkspace + PluginRoutingPanel (PluginKind.PING, sem TCP privado).
- Destino e transporte no topo (IP, forma de envio, banner da sessão).
- Toolbar: Enviar ping (uma vez) e Ping contínuo (toggle só em abas de peer ↑; na sala Todos só o envio único).
SessionTabBar: salaTodos ↑; peers que você abreNome ↑; recebimento passivoNome ↓(view:<ip>).+ Nova/PeerDraftPanelpara IP manual.JTextAreamonoespaçada por aba; linhas como[HH:mm:ss] pong ← Alice · RTT 42 ms.- Abas ↓:
bindReceiveSession— controles de envio desabilitados.
Não use JFrame. No PingPlugin: bindShellWorkspaceContent(panel).
A aba da shell só abre quando o usuário clicar na galeria Plugins ou numa peer action (sem enviar ping automaticamente).
Passo 6 — PingPlugin
| Método | Valor |
|---|---|
getIdentifier() |
pitiupi.ping (único na sala) |
getDisplayName() |
Ping na rede |
createPlugin(ConnectionManager, PluginWorkspace):
- Crie
PingControllerePingPanel. bindShellWorkspaceContent(panel).installPeerActions(workspace.peerActions()).
Peer actions sugeridas:
| id | Label | Alvo | Comportamento |
|---|---|---|---|
ping.peer |
Enviar ping para esta pessoa | um peer | Abre/foca o plugin e a aba ↑ com o IP — sem disparar ping |
ping.room |
Abrir ping na sala (Todos) | Todos | Abre a aba sala — sem disparar ping |
O envio fica nos botões do painel.
receiveMessage: despache para o controller com SwingUtilities.invokeLater.
onShellTabClosed: pare todos os timers contínuos.
Passo 7 — Instalar e testar
ant jar→dist/pitiupi.ping.jar.- Aba Configurações → Instalar JAR… (ou copie para
~/pitiupi/plugins/). - Reinicie o Pitiupi (obrigatório após mudar plugins).
- Dois processos no mesmo PC: portas 5000 e 5001, nomes diferentes.
- Lista lateral → Enviar ping para esta pessoa → aba
↑com IP; clique Enviar ping → RTT no log. - Toggle Ping contínuo na aba
↑→ linhas a cada ~1 s; desligar o toggle → o outro vê “parou o ping contínuo” na aba↓. - Com colega na LAN: mesma porta, JAR instalado nos dois.
Instalação usa o mesmo PluginStore da aba Configurações (installFromFile + reinício). O núcleo expõe pitiupi.tools.PluginStoreCli para testes sem interface gráfica.
Passo 8 — Comparar com o chat
O chat usa a mesma ideia de abas de sessão, mas adiciona roteamento TCP privado e HTML. No Ping mantenha só UDP e texto em JTextArea — ideal para entender o fluxo antes de copiar padrões para um plugin novo.
Problemas comuns (Ping)
| Sintoma | Diagnóstico |
|---|---|
| RTT não aparece | Pong sem pingId correspondente em pendingByPingId |
| Peer não recebe | Tipo não listado em getMessages() ou UDP bloqueado |
ClassCastException |
Versões diferentes do JAR entre PCs |
| Aba não abre | Esqueceu bindShellWorkspaceContent ou peer action só abre UI (envio é no painel) |
Mais geral: 10_tutorial_plugin.md.