Files
Gabriel Felipe Souza SantosandCursor 8338936251 docs: reescreve o manual e registra o JAR instalado no catálogo
O texto explica o núcleo, a rede e o tutorial do ping como o código está hoje. Instalar ou remover um JAR atualiza plugins.registry.json para o próximo run não perder o plugin.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-04 14:14:18 -03:00

5.4 KiB

Mapa do núcleo

O código do programa está em pitiupi/src/pitiupi. Um plugin não precisa abrir essas pastas para funcionar: o contrato de chamada está em nucleo-para-plugins.md. Este capítulo é para quem vai ler o código ou alterar o núcleo.

Pastas

Pacote O que faz
Main Garante .pitiupi/, pede nome e porta no LoginDialog e abre MainShellFrame
control.ConnectionManager Fachada da rede: porta, nome, envio UDP e TCP, presença, lista de ações
control.HeartbeatManager Anúncio periódico e timeout de quem sumiu
control.plugins.PluginManager Lê os JARs, acha as classes pelo SPI e entrega receiveMessage
net.udp.SocketUDP O MulticastSocket do grupo 224.0.0.3
net.tcp ServerSocket, uma TcpConnection por IP, framing de 4 bytes + N bytes
application.messaging MessageDispatcher, SendTarget, TransportMode, combo de transporte
application.presence A lista Usuários nesta rede (PresenceService, UserPeerView)
application.peeractions O menu que aparece ao clicar numa pessoa
application.session Aviso de início ou fim de uma atividade (SessionNoticeMessage)
application.invites Convite de sessão. O núcleo recebe e pode chamar onInviteAccepted. Nenhum plugin de referência envia convite, e a janela não mostra uma caixa de convite
application.activity Contagem de atividade por pessoa. A lista lateral não desenha selo
presentation.shell Janela, abas, galeria, configurações, painéis que o plugin reutiliza
models Plugin, Message e as mensagens do próprio núcleo
plugins.store Copia o JAR para .pitiupi/plugins e, no clone, grava plugins.registry.json
platform Onde fica .pitiupi (PitiupiHome) e config.properties de layout
errors.ErrorCode Quatro textos em português: falha ao instalar, ao remover, ao carregar, caminho inválido

Nome, porta, TTL e saída de rede ficam nas preferências do Java (NetworkPreferences), não nesse config.properties.

Caminho de um datagrama UDP

SocketUDP.receive lê o pacote e tenta desserializar com o classloader do núcleo.

  1. HeartbeatMessage vai para ConnectionManager.receiveHeartbeat. Não chega no plugin.
  2. GoodbyeMessage vai para receiveGoodbye. Não chega no plugin.
  3. SessionInviteMessage vai para receiveSessionInvite. Não chega em receiveMessage.
  4. Qualquer outro byte vai para PluginManager.handleMessage. Cada JAR tenta desserializar com o próprio classloader. Se a classe está em getMessages() (ou receiveAllTypes() é verdadeiro e a mensagem é pública), o núcleo chama receiveMessage.

Por isso heartbeat e goodbye não entram na lista do plugin. Se entrarem, o classloader do JAR não é o dono dessas classes.

Caminho de um frame TCP

TcpConnection lê um int e depois exatamente essa quantidade de bytes. Na abertura, o núcleo troca um HandshakeMessage (classe interna de net.tcp, invisível ao plugin) com o remetente, o destinatário e a marca de conexão privada.

  • Conexão pública: o frame, se for uma Message, segue o mesmo PluginManager.handleMessage do UDP.
  • Conexão privada cujo destinatário é um getIdentifier() de plugin: PluginManager.handleConnection chama receivePrivateConnection. Se o plugin devolve true, os frames seguintes vão para receiveBytes, e o fechamento chama onSocketClosed.
  • Destinatário que nenhum plugin aceita: o núcleo manda um InfoMessage de receptor não encontrado e não entrega os bytes.

O prazo de 5 segundos para abrir o socket está em rede.md.

Mensagens que o núcleo define

Classe Quem cria Quem consome
HeartbeatMessage HeartbeatManager, em multicast SocketUDP → presença. Fora do plugin
GoodbyeMessage Fechamento da janela ou troca de porta SocketUDP → tira a pessoa da lista. Fora do plugin
InfoMessage Núcleo, em conexões TCP de controle O próprio TCP (erro, fechamento, plugin ausente). Não é texto de chat
HandshakeMessage Abertura TCP, pacote net.tcp Só o núcleo. Não declare no plugin
SessionNoticeMessage Um plugin, em geral o screencast ao parar Outro plugin que listar a classe em getMessages()
SessionInviteMessage Quem chamar o envio InviteInboxService. A interface atual não mostra o convite

SessionNoticeMessage carrega o id do plugin, a fase (START ou END), o canal (SCREEN_CAST hoje), o nome e o IP de quem enviou, o escopo (BROADCAST ou DIRECT) e o TransportMode. O screencast manda END no canal SCREEN_CAST quando o compartilhamento para. Quem recebe e registrou o tipo fecha a aba de recebimento.

Onde alterar o núcleo

Mudança Onde
Novo tipo só do seu plugin Classe no JAR, extends Message, entrada em getMessages(). O núcleo não muda
Novo transporte no combo da interface Valor em PluginTransportCatalog.PluginKind. Hoje existem CHAT, SCREEN_CAST e PING
Mensagem de infraestrutura (todo mundo precisa entender sem ter o JAR) models.Messages e o filtro em SocketUDP.tryParseCoreUdpMessage
Nova ação na lista de pessoas Não é mudança de núcleo: PeerAction no plugin
Texto de erro de instalação errors.ErrorCode

O grupo multicast, a porta única e o framing TCP estão decididos em decision-register.md. O comportamento na rede está em rede.md.