Files
pitiupi/docs/documentation/09_sistema_de_plugins.md
T
Gabriel Felipe Souza SantosandCursor aa75cebaaa docs: separar material de TP em docs/tp/
documentation/ fica neutra (produto); visão TP, tutorial Ping e
checklists de entrega movem para docs/tp/ sem link reverso.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-27 21:37:03 -03:00

94 lines
5.1 KiB
Markdown

# Sistema de plugins
O sistema de plugins permite extensão modular sem alterar o núcleo. O contrato está em `pitiupi.models.Plugin` (classe abstrata).
**Breaking change (pós-v1):** plugins devem implementar apenas `createPlugin(ConnectionManager, PluginWorkspace)`. A API antiga com `GuiManager` e menus por categoria foi removida.
## Interface Plugin
Métodos obrigatórios:
| Método | Função |
| --- | --- |
| `getName()`, `getAuthor()`, `getVersion()`, `getIdentifier()` | Identificação (o `identifier` distingue plugins em conexões TCP dedicadas) |
| `getDisplayName()` | Texto na galeria e título de aba (padrão: `getName()`) |
| `createPlugin(ConnectionManager, PluginWorkspace)` | Inicialização: `bindShellWorkspaceContent`, `installPeerActions`, rede |
| `getMessages()` | Lista de classes `Message` que o plugin desserializa |
| `receiveMessage(Message)` | Processamento após o `PluginManager` identificar o tipo |
Métodos opcionais (ciclo de vida e TCP avançado):
| Método | Função |
| --- | --- |
| `onShellTabClosed()` | Usuário fechou a aba do plugin no topo; liberar timers, captura, envio contínuo |
| `receiveAllTypes()` | Receber todas as mensagens públicas |
| `receivePrivateConnection(TcpConnection)` | Aceitar conexão TCP direcionada ao plugin |
| `receiveBytes(TcpConnection, byte[])` | Ler payload bruto na conexão privada |
| `onSocketClosed(TcpConnection)` | Limpar estado ao fechar socket |
### Descoberta de plugins
Para serem reconhecidos, os plugins devem possuir os arquivos de configuração
do Java Service Provider Interface (SPI):
```
MeusPlugins
|
+---META-INF
|
+---services
|
+---pitiupi.models.Plugin
```
O arquivo `pitiupi.models.Plugin` deve conter o nome completo das classes que
implementam a interface Plugin:
```
MeusPlugins.plugins.NomeDaClasse
```
Para serem carregados, os plugins devem estar empacotados como arquivos JAR
e colocados no diretório plugins da aplicação.
O catálogo de build (`plugins.registry.json`) cobre **chat** e **screencast** no gate de CI. Outros módulos podem ser buildados localmente e instalados via JAR em `PITIUPI_HOME/plugins` sem entrar no catálogo.
### Carregamento de plugins
O `PluginManager.loadPlugins()` (chamado pela `MainShellFrame`):
1. Lista arquivos `.jar` em `PITIUPI_HOME/plugins` (ver [00_quickstart.md](00_quickstart.md); symlinks de dev via `./scripts/pitiupi.sh link`).
2. Para cada JAR, cria um `URLClassLoader` e usa `ServiceLoader.load(Plugin.class, classLoader)`.
3. Chama `createPlugin(connectionManager, pluginWorkspace)` em cada instância (`ShellPluginWorkspace`).
4. Na recepção UDP/TCP, tenta desserializar com `PluginObjectInputStream` e despacha para plugins que declararam o tipo em `getMessages()`.
Ao fechar uma aba dinâmica de plugin, `TabWorkspacePanel` notifica `PluginManager.notifyShellTabClosed(pluginId)` **antes** de remover o conteúdo, para o plugin encerrar trabalho em segundo plano.
Implementação: `pitiupi/src/pitiupi/control/plugins/PluginManager.java`.
## Shell e abas (PluginWorkspace)
Na `MainShellFrame`, `createPlugin(ConnectionManager, PluginWorkspace)` registra o painel com `bindShellWorkspaceContent(JPanel)` **sem** abrir aba no boot. A galeria **Plugins** e as peer actions abrem a aba sob demanda.
## Peer actions na lista lateral
`PeerActionBroker.getAllActionsFor(target)` agrupa ações de **todos** os plugins (submenu por `getDisplayName()`). Destinos: `SINGLE_PEER` (um usuário) ou `ALL_PEERS` (linha **Todos**).
## Envio didático (núcleo)
`PluginRoutingPanel` (núcleo) padroniza destino, forma de envio e dica embaixo para chat, screencast e futuros plugins.
`MessageDispatcher` envia com `TransportMode` e `SendTarget`. `PluginTransportCatalog` define quais transportes cada plugin mostra na UI (sala geral vs um IP). Os combos usam textos didáticos (`describeForUi`) com o termo técnico entre parênteses (multicast UDP, UDP unicast, TCP). Na sala geral o campo IP fica desativado; um resumo **“Como esta mensagem vai”** (chat) deixa explícito o transporte escolhido — na sala pode ser multicast ou cópias unicast/TCP para cada pessoa, conforme o plugin. Para um peer use o IP manualmente ou a peer action na lista lateral.
Em abas de **recebimento** (ex. screencast `view:`), `PluginRoutingPanel.bindReceiveSession` deixa IP e forma de envio somente leitura, refletindo o que o remetente usou.
## Segurança e plugins de terceiros
- Instale apenas JARs de fontes confiáveis (`PITIUPI_HOME/plugins` ou aba Configurações).
- O núcleo desserializa mensagens de rede com classloader por plugin; mensagens malformadas devem ser ignoradas, mas **não** há sandbox — um JAR malicioso tem o mesmo poder de um programa local.
- Não há atualização automática de plugins pelo núcleo na v1.
### Avisos de sessão (D24)
`SessionNoticeMessage` (núcleo) sinaliza fases `START` / `END` por `pluginId` e canal (`SessionNoticeChannel`, ex. `screen_cast`). Plugins registram o tipo em `getMessages()` e reagem na UI (ex. fechar aba de recebimento ao `END` de compartilhamento). Campos incluem remetente, escopo (broadcast/direto) e `TransportMode` observado.