Files
pitiupi/docs/documentation/09_sistema_de_plugins.md
T
Gabriel Felipe Souza SantosandCursor 112b6edaeb feat(screencast,chat): roteamento read-only, avisos de sessão e TCP privado
SessionNoticeMessage encerra abas de recebimento; abas ↑/↓; chat unifica bucket peer e conexão TCP.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-27 18:48:16 -03:00

4.4 KiB

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).

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 na shell: painel na aba, peer actions, rede
createPlugin(ConnectionManager, GuiManager) Legado — adapter na carga; não usar em plugins novos
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.

Carregamento de plugins

O PluginManager.loadPlugins() (chamado pela MainShellFrame):

  1. Lista arquivos .jar em PITIUPI_HOME/plugins (ver 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.

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.