feat(messaging): PluginKind.PING no catálogo de transporte

Alinha núcleo com plugin Ping didático e evita NoSuchFieldError ao carregar ping.jar novo.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Gabriel Felipe Souza SantosandCursor committed 2026-10-27 20:13:22 -03:00
1 parent fc9739a998
commit 7c8a476253
4 files changed
+35 -22

No files matched your search

+1 -1
View File
@@ -38,6 +38,6 @@ Os plugins de referência são **exemplos de sala de aula**, não produtos compl
| --- | --- | --- |
| **chat** | texto, sala geral, unicast/multicast/TCP, TCP privado básico | imagens, moderação, histórico persistente, criptografia |
| **screencast** | stream read-only, avisos de sessão | controle remoto do mouse/teclado, áudio |
| **ping** (exercício do aluno) | RTT, ping uma vez/contínuo, parar e avisar o peer | ICMP do SO, gráficos, SLA |
| **ping** (exercício do aluno) | chrome de sessão v1 (`PluginRoutingPanel`, abas ↑/↓), RTT, UDP apenas | TCP privado, ICMP do SO, gráficos, SLA |
Para evoluir: copie o padrão (`Plugin` + mensagens + painel na aba) e acrescente features no **seu** JAR — sem inflar o núcleo.
+16 -19
View File
@@ -78,19 +78,18 @@ Use `PeerIpv4` e `LocalNetworkInfo.bestLocalIpv4()` para IP legível no Windows.
## Passo 5 — `PingPanel` (UI)
`JPanel` com:
Siga o mesmo chrome do screencast: `PluginSessionWorkspace` + `PluginRoutingPanel` (`PluginKind.PING`, sem TCP privado).
- `SessionTabBar` — aba fixa **Todos** + `addTabIfAbsent` quando chega tráfego de um peer (**sem** mudar a aba ativa da shell).
- **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`: sala `Todos ↑`; peers que você abre `Nome ↑`; recebimento passivo `Nome ↓` (`view:<ip>`).
- `+ Nova` / `PeerDraftPanel` para IP manual.
- `JTextArea` monoespaçada por aba; linhas como `[HH:mm:ss] pong ← Alice · RTT 42 ms`.
- Botão **Parar todos os pings contínuos** chamando o controller.
- Abas **↓**: `bindReceiveSession` — controles de envio desabilitados.
**Não** use `JFrame`. No `PingPlugin`:
**Não** use `JFrame`. No `PingPlugin`: `bindShellWorkspaceContent(panel)`.
```java
bindShellWorkspaceContent(panel);
```
A aba só abre quando o usuário clicar na galeria **Plugins** ou numa peer action.
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`
@@ -107,14 +106,12 @@ A aba só abre quando o usuário clicar na galeria **Plugins** ou numa peer acti
**Peer actions sugeridas:**
| id | Label | Alvo |
| --- | --- | --- |
| `ping.once` | Ping uma vez | um peer |
| `ping.continuous` | Ping contínuo | um peer |
| `ping.stop` | Parar ping | um peer |
| `ping.all.once` | Ping para todos (uma vez) | Todos → `MULTICAST_UDP` |
| 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 |
Em cada ação de peer único: `workspace.openOrFocusTab(getIdentifier(), getDisplayName())` e chame o controller.
O envio fica nos botões do painel.
`receiveMessage`: despache para o controller com `SwingUtilities.invokeLater`.
@@ -126,8 +123,8 @@ Em cada ação de peer único: `workspace.openOrFocusTab(getIdentifier(), getDis
2. Aba **Configurações** → **Instalar JAR…** (ou copie para `~/pitiupi/plugins/`).
3. **Reinicie** o Pitiupi (obrigatório após mudar plugins).
4. Dois processos no mesmo PC: portas **5000** e **5001**, nomes diferentes.
5. Peer action **Ping uma vez** → veja RTT no log.
6. **Ping contínuo** → linhas a cada ~1 s; **Parar ping** → o outro vê “parou o ping contínuo”.
5. Lista lateral → **Enviar ping para esta pessoa** → aba `↑` com IP; clique **Enviar ping** → RTT no log.
6. Toggle **Ping contínuo** na aba `↑` → linhas a cada ~1 s; desligar o toggle → o outro vê “parou o ping contínuo” na aba `↓`.
7. 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.
@@ -141,7 +138,7 @@ O chat usa a mesma ideia de abas de sessão, mas adiciona roteamento TCP privado
- [ ] SPI e `getIdentifier` únicos
- [ ] Três mensagens registradas
- [ ] RTT calculado no `Pong`
- [ ] Aba passiva ao receber ping de peer novo
- [ ] Aba passiva `↓` ao receber ping de peer novo (sem roubar foco da shell)
- [ ] Contínuo + parar com aviso ao peer
- [ ] Reinício após instalar JAR
- [ ] Teste com segundo usuário (5001 ou outro PC)
@@ -9,7 +9,8 @@ public final class PluginTransportCatalog {
public enum PluginKind {
CHAT,
SCREEN_CAST
SCREEN_CAST,
PING
}
private PluginTransportCatalog() {
@@ -22,7 +23,7 @@ public final class PluginTransportCatalog {
TransportMode.UNICAST_UDP,
TransportMode.TCP
);
case SCREEN_CAST -> List.of(
case SCREEN_CAST, PING -> List.of(
TransportMode.MULTICAST_UDP,
TransportMode.UNICAST_UDP
);
@@ -35,6 +36,7 @@ public final class PluginTransportCatalog {
TransportMode.UNICAST_UDP,
TransportMode.TCP
);
case PING -> List.of(TransportMode.UNICAST_UDP);
};
}
}
@@ -13,4 +13,18 @@ class PluginTransportCatalogTest {
assertTrue(modes.contains(TransportMode.MULTICAST_UDP));
assertFalse(modes.contains(TransportMode.TCP));
}
@Test
void pingBroadcastExcludesTcp() {
var modes = PluginTransportCatalog.forBroadcast(PluginTransportCatalog.PluginKind.PING);
assertTrue(modes.contains(TransportMode.MULTICAST_UDP));
assertFalse(modes.contains(TransportMode.TCP));
}
@Test
void pingSinglePeerIsUdpOnly() {
var modes = PluginTransportCatalog.forSinglePeer(PluginTransportCatalog.PluginKind.PING);
assertTrue(modes.contains(TransportMode.UNICAST_UDP));
assertFalse(modes.contains(TransportMode.TCP));
}
}