Esqueci de adicionar nos commits anteriores

This commit is contained in:
GustavoHMDS 2026-09-08 01:30:23 -03:00
parent 4461772ebf
commit b610ec20e1
6 changed files with 18 additions and 338 deletions

View File

@ -5,8 +5,8 @@
*/ */
package pitiupi.GUI; package pitiupi.GUI;
import pitiupi.net.SocketTCP; import pitiupi.net.tcp.SocketTCP;
import pitiupi.net.SocketUDP; import pitiupi.net.udp.SocketUDP;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.JMenu; import javax.swing.JMenu;
@ -44,7 +44,9 @@ public class MainWindow extends javax.swing.JFrame {
private SocketTCP socketTCP; private SocketTCP socketTCP;
private String userName; private String userName;
private int port; private int port;
private String pitiupiIdentifier;
private PluginLoader pluginManager; private PluginLoader pluginManager;
private final List<Plugin> plugins; private final List<Plugin> plugins;
@ -58,6 +60,7 @@ public class MainWindow extends javax.swing.JFrame {
public MainWindow(String userName, int port) { public MainWindow(String userName, int port) {
this.userName = userName; this.userName = userName;
this.port = port; this.port = port;
this.pitiupiIdentifier = "Pitiupi.Alice.2026";
this.menuBar = new MenuBar(this); this.menuBar = new MenuBar(this);
this.plugins = new ArrayList<>(); this.plugins = new ArrayList<>();
this.initComponents(); this.initComponents();
@ -127,6 +130,10 @@ public class MainWindow extends javax.swing.JFrame {
return this.userName; return this.userName;
} }
public String getIdentifier(){
return this.pitiupiIdentifier;
}
public void addMenu(JMenu menu) { public void addMenu(JMenu menu) {
this.menuBar.addPlugin(menu); this.menuBar.addPlugin(menu);
} }

View File

@ -1,4 +1,5 @@
package pitiupi.net; package pitiupi.net;
/** /**
* Mensagem utilizada para sinalizar a presença de um usuário na rede. * Mensagem utilizada para sinalizar a presença de um usuário na rede.
* *

View File

@ -1,244 +0,0 @@
package pitiupi.net;
import pitiupi.GUI.MainWindow;
import pitiupi.control.PeerInfo;
import pitiupi.control.PeerListener;
import pitiupi.plugin.Plugin;
import java.io.*;
import java.net.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/**
* Gerencia a comunicação TCP da aplicação.
*
* <p>Mantém conexões persistentes com os peers e reutiliza essas conexões
* para o envio de mensagens. As mensagens recebidas são encaminhadas aos
* plugins, que são responsáveis por interpretá-las.</p>
*
* <p>Novas conexões são aceitas pelo servidor e cada conexão possui uma
* tarefa própria para receber mensagens, permitindo que múltiplas conexões
* sejam mantidas simultaneamente.</p>
*
* <p>As conexões são associadas aos endereços dos peers e podem ser
* encerradas quando um peer deixa de estar ativo.</p>
*
* @author Gustavo
*/
public class SocketTCP extends Thread implements PeerListener {
private final ExecutorService connectionExecutor = Executors.newCachedThreadPool();
private final Map<InetAddress, TcpConnection> connections;
private ServerSocket serverSocket;
private InetAddress address;
private final MainWindow main;
private volatile boolean running = true;
/**
* Cria o servidor TCP da aplicação.
*
* <p>O servidor utiliza a porta definida pela aplicação e inicia sem
* estabelecer conexões com os peers. As conexões são criadas conforme
* necessário durante o envio ou recebidas de outros peers.</p>
*
* @param main janela principal da aplicação.
*/
public SocketTCP(MainWindow main) {
this.main = main;
connections = new ConcurrentHashMap<>();
try {
serverSocket = new ServerSocket(main.getPort());
address = InetAddress.getByName(InetAddress.getLocalHost().getHostAddress());
} catch (IOException ex) {
System.out.println("There is no socket connection. Sorry.");
System.out.println(ex);
}
}
/**
* Envia uma mensagem TCP para um peer.
*
* <p>Uma conexão existente com o peer é reutilizada. Caso não exista uma
* conexão válida, uma nova conexão é criada e adicionada ao conjunto de
* conexões ativas.</p>
*
* @param msg mensagem serializada a ser enviada.
* @param destinationAddress endereço IP do peer destinatário.
*/
public void send(byte[] msg, InetAddress destinationAddress) {
try {
if (destinationAddress.equals(address)) {
throw new IllegalArgumentException("Destination address cannot be the same as the original address.");
}
TcpConnection connec tion;
synchronized (connections) {
connection = connections.get(destinationAddress);
if (connection == null || connection.isClosed()) {
Socket socket = new Socket(destinationAddress, main.getPort());
connection = new TcpConnection(socket);
connections.put(destinationAddress, connection);
startReceiver(destinationAddress, connection);
}
}
connection.send(msg);
} catch (IOException ex) {
System.out.println("Could not send TCP message.");
System.out.println(ex);
}
}
/**
* Aguarda e aceita novas conexões TCP.
*
* <p>Cada conexão aceita é associada ao endereço do peer e registrada para
* que possa ser utilizada tanto para recepção quanto para envio de
* mensagens.</p>
*/
private void receive() {
while (running) {
try {
Socket socket = serverSocket.accept();
InetAddress address = socket.getInetAddress();
TcpConnection connection = new TcpConnection(socket);
TcpConnection oldConnection = connections.put(address, connection);
if (oldConnection != null) {
oldConnection.close();
}
startReceiver(address, connection);
} catch (IOException ex) {
if (!running) {
break;
}
System.out.println("Error accepting TCP connection.");
System.out.println(ex);
}
}
}
/**
* Inicia a recepção de mensagens de uma conexão TCP.
*
* <p>A recepção é executada de forma independente para que uma conexão
* não impeça a aceitação ou o processamento de outras conexões.</p>
*
* <p>Cada mensagem recebida é encaminhada aos plugins da aplicação.</p>
*
* @param address endereço do peer associado à conexão.
* @param connection conexão TCP utilizada para a comunicação.
*/
private void startReceiver(InetAddress address, TcpConnection connection) {
connectionExecutor.submit(() -> {
try {
while (running) {
byte[] message = connection.receive();
for (Plugin plugin : main.getPlugins()) {
plugin.receiveMessage(message);
}
}
} catch (IOException ex) {
System.out.println(
"Connection with " + address.getHostAddress() + " closed."
);
} finally {
connections.remove(address, connection);
try {
connection.close();
} catch (IOException ignored) {
}
}
});
}
/**
* Inicia o processo de recepção de conexões TCP.
*/
@Override
public void run() {
receive();
}
/**
* Encerra o servidor TCP e as conexões associadas.
*
* <p>As conexões existentes são encerradas e o servidor deixa
* de aceitar novas conexões.</p>
*/
public void close() {
running = false;
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException _) {
}
}
for (TcpConnection connection : connections.values()) {
try {
connection.close();
} catch (IOException _) {
}
}
connections.clear();
connectionExecutor.shutdownNow();
}
/**
* Atualiza as conexões de acordo com os peers atualmente ativos.
*
* <p>Conexões associadas a peers que não estão mais ativos são encerradas
* e removidas.</p>
*
* @param peers lista atualizada de peers ativos.
*/
@Override
public void onPeersChanged(List<PeerInfo> peers) {
Set<InetAddress> activePeers = peers.stream()
.map(PeerInfo::getAddress)
.collect(Collectors.toSet());
for (InetAddress address : connections.keySet()) {
if (!activePeers.contains(address)) {
TcpConnection connection = connections.remove(address);
if (connection != null) {
try {
connection.close();
} catch (IOException e) {
}
}
}
}
}
}

View File

@ -1,88 +0,0 @@
package pitiupi.net;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
/**
* Representa uma conexão TCP persistente com um peer.
*
* <p>Encapsula o socket e os streams utilizados para enviar e receber
* mensagens. Também é responsável pelo framing das mensagens, permitindo
* que várias mensagens sejam transmitidas pela mesma conexão.</p>
*
* @author Gustavo
*/
class TcpConnection {
private final Socket socket;
private final DataInputStream input;
private final DataOutputStream output;
/**
* Cria uma conexão a partir de um socket existente.
*
* @param socket socket TCP utilizado pela conexão.
* @throws IOException caso não seja possível obter os streams do socket.
*/
public TcpConnection(Socket socket) throws IOException {
this.socket = socket;
this.input = new DataInputStream(socket.getInputStream());
this.output = new DataOutputStream(socket.getOutputStream());
}
/**
* Envia uma mensagem pela conexão.
*
* <p>A mensagem é precedida por seu tamanho para permitir que o receptor
* identifique o limite entre mensagens transmitidas pela mesma conexão.</p>
*
* @param message mensagem serializada a ser enviada.
* @throws IOException caso ocorra um erro durante o envio.
*/
public void send(byte[] message) throws IOException {
synchronized (output) {
output.writeInt(message.length);
output.write(message);
output.flush();
}
}
/**
* Recebe uma mensagem completa da conexão.
*
* <p>O tamanho da mensagem é lido primeiro e, em seguida, os dados
* correspondentes são recebidos.</p>
*
* @return mensagem recebida.
* @throws IOException caso ocorra um erro durante a recepção.
*/
public byte[] receive() throws IOException {
int length = input.readInt();
if (length < 0) {
throw new IOException("Invalid message length.");
}
return input.readNBytes(length);
}
/**
* Verifica se o socket da conexão está fechado.
*
* @return {@code true} caso o socket esteja fechado.
*/
public boolean isClosed() {
return socket.isClosed();
}
/**
* Encerra a conexão TCP.
*
* @throws IOException caso ocorra um erro ao fechar o socket.
*/
public void close() throws IOException {
socket.close();
}
}

View File

@ -3,7 +3,7 @@
* To change this template file, choose Tools | Templates * To change this template file, choose Tools | Templates
* and open the template in the editor. * and open the template in the editor.
*/ */
package pitiupi.net; package pitiupi.net.udp;
import pitiupi.GUI.MainWindow; import pitiupi.GUI.MainWindow;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -13,6 +13,8 @@ import java.io.ObjectInputStream;
import java.net.*; import java.net.*;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import pitiupi.net.HeartbeatMessage;
import pitiupi.plugin.Plugin; import pitiupi.plugin.Plugin;
/** /**

View File

@ -4,9 +4,9 @@
*/ */
package pitiupi.plugin; package pitiupi.plugin;
import javax.swing.JMenu;
import pitiupi.GUI.MainWindow; import pitiupi.GUI.MainWindow;
import pitiupi.net.Message; import pitiupi.net.Message;
import pitiupi.net.tcp.TcpConnection;
/** /**
* Interface base para plugins da aplicação. * Interface base para plugins da aplicação.
@ -21,6 +21,7 @@ public interface Plugin {
public String getName(); public String getName();
public String getAuthor(); public String getAuthor();
public String getVersion(); public String getVersion();
public String getIdentifier();
/** /**
* Inicializa o plugin. * Inicializa o plugin.
@ -46,5 +47,6 @@ public interface Plugin {
* *
* @param message mensagem serializada recebida. * @param message mensagem serializada recebida.
*/ */
public void receiveMessage(byte[] message); public void receiveMessage(Message message);
} }