diff --git a/pitiupi/src/pitiupi/GUI/MainWindow.java b/pitiupi/src/pitiupi/GUI/MainWindow.java index 3f40ab9..cc72db4 100644 --- a/pitiupi/src/pitiupi/GUI/MainWindow.java +++ b/pitiupi/src/pitiupi/GUI/MainWindow.java @@ -5,8 +5,8 @@ */ package pitiupi.GUI; -import pitiupi.net.SocketTCP; -import pitiupi.net.SocketUDP; +import pitiupi.net.tcp.SocketTCP; +import pitiupi.net.udp.SocketUDP; import java.util.ArrayList; import java.util.List; import javax.swing.JMenu; @@ -44,7 +44,9 @@ public class MainWindow extends javax.swing.JFrame { private SocketTCP socketTCP; private String userName; - private int port; + private int port; + + private String pitiupiIdentifier; private PluginLoader pluginManager; private final List plugins; @@ -58,6 +60,7 @@ public class MainWindow extends javax.swing.JFrame { public MainWindow(String userName, int port) { this.userName = userName; this.port = port; + this.pitiupiIdentifier = "Pitiupi.Alice.2026"; this.menuBar = new MenuBar(this); this.plugins = new ArrayList<>(); this.initComponents(); @@ -126,6 +129,10 @@ public class MainWindow extends javax.swing.JFrame { public String getUserName(){ return this.userName; } + + public String getIdentifier(){ + return this.pitiupiIdentifier; + } public void addMenu(JMenu menu) { this.menuBar.addPlugin(menu); diff --git a/pitiupi/src/pitiupi/net/HeartbeatMessage.java b/pitiupi/src/pitiupi/net/HeartbeatMessage.java index 5a07ec8..5476e0e 100644 --- a/pitiupi/src/pitiupi/net/HeartbeatMessage.java +++ b/pitiupi/src/pitiupi/net/HeartbeatMessage.java @@ -1,4 +1,5 @@ package pitiupi.net; + /** * Mensagem utilizada para sinalizar a presença de um usuário na rede. * diff --git a/pitiupi/src/pitiupi/net/SocketTCP.java b/pitiupi/src/pitiupi/net/SocketTCP.java deleted file mode 100644 index 04b5ac6..0000000 --- a/pitiupi/src/pitiupi/net/SocketTCP.java +++ /dev/null @@ -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. - * - *

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.

- * - *

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.

- * - *

As conexões são associadas aos endereços dos peers e podem ser - * encerradas quando um peer deixa de estar ativo.

- * - * @author Gustavo - */ -public class SocketTCP extends Thread implements PeerListener { - private final ExecutorService connectionExecutor = Executors.newCachedThreadPool(); - private final Map connections; - private ServerSocket serverSocket; - private InetAddress address; - - private final MainWindow main; - - private volatile boolean running = true; - - /** - * Cria o servidor TCP da aplicação. - * - *

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.

- * - * @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. - * - *

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.

- * - * @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. - * - *

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.

- */ - 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. - * - *

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.

- * - *

Cada mensagem recebida é encaminhada aos plugins da aplicação.

- * - * @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. - * - *

As conexões existentes são encerradas e o servidor deixa - * de aceitar novas conexões.

- */ - 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. - * - *

Conexões associadas a peers que não estão mais ativos são encerradas - * e removidas.

- * - * @param peers lista atualizada de peers ativos. - */ - @Override - public void onPeersChanged(List peers) { - Set 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) { - - } - } - } - } - } -} - diff --git a/pitiupi/src/pitiupi/net/TcpConnection.java b/pitiupi/src/pitiupi/net/TcpConnection.java deleted file mode 100644 index 4921ad8..0000000 --- a/pitiupi/src/pitiupi/net/TcpConnection.java +++ /dev/null @@ -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. - * - *

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.

- * - * @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. - * - *

A mensagem é precedida por seu tamanho para permitir que o receptor - * identifique o limite entre mensagens transmitidas pela mesma conexão.

- * - * @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. - * - *

O tamanho da mensagem é lido primeiro e, em seguida, os dados - * correspondentes são recebidos.

- * - * @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(); - } -} diff --git a/pitiupi/src/pitiupi/net/SocketUDP.java b/pitiupi/src/pitiupi/net/udp/SocketUDP.java similarity index 99% rename from pitiupi/src/pitiupi/net/SocketUDP.java rename to pitiupi/src/pitiupi/net/udp/SocketUDP.java index 285e314..8a76c6b 100644 --- a/pitiupi/src/pitiupi/net/SocketUDP.java +++ b/pitiupi/src/pitiupi/net/udp/SocketUDP.java @@ -3,7 +3,7 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package pitiupi.net; +package pitiupi.net.udp; import pitiupi.GUI.MainWindow; import java.io.ByteArrayInputStream; @@ -13,6 +13,8 @@ import java.io.ObjectInputStream; import java.net.*; import java.util.logging.Level; import java.util.logging.Logger; + +import pitiupi.net.HeartbeatMessage; import pitiupi.plugin.Plugin; /** diff --git a/pitiupi/src/pitiupi/plugin/Plugin.java b/pitiupi/src/pitiupi/plugin/Plugin.java index a52bdc5..6159842 100644 --- a/pitiupi/src/pitiupi/plugin/Plugin.java +++ b/pitiupi/src/pitiupi/plugin/Plugin.java @@ -4,9 +4,9 @@ */ package pitiupi.plugin; -import javax.swing.JMenu; import pitiupi.GUI.MainWindow; import pitiupi.net.Message; +import pitiupi.net.tcp.TcpConnection; /** * Interface base para plugins da aplicação. @@ -21,6 +21,7 @@ public interface Plugin { public String getName(); public String getAuthor(); public String getVersion(); + public String getIdentifier(); /** * Inicializa o plugin. @@ -46,5 +47,6 @@ public interface Plugin { * * @param message mensagem serializada recebida. */ - public void receiveMessage(byte[] message); + public void receiveMessage(Message message); + } \ No newline at end of file