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>
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.
HeartbeatMessagevai paraConnectionManager.receiveHeartbeat. Não chega no plugin.GoodbyeMessagevai parareceiveGoodbye. Não chega no plugin.SessionInviteMessagevai parareceiveSessionInvite. Não chega emreceiveMessage.- Qualquer outro byte vai para
PluginManager.handleMessage. Cada JAR tenta desserializar com o próprio classloader. Se a classe está emgetMessages()(oureceiveAllTypes()é verdadeiro e a mensagem é pública), o núcleo chamareceiveMessage.
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 mesmoPluginManager.handleMessagedo UDP. - Conexão privada cujo destinatário é um
getIdentifier()de plugin:PluginManager.handleConnectionchamareceivePrivateConnection. Se o plugin devolvetrue, os frames seguintes vão parareceiveBytes, e o fechamento chamaonSocketClosed. - Destinatário que nenhum plugin aceita: o núcleo manda um
InfoMessagede 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.