Esqueci de adicionar nos commits anteriores
This commit is contained in:
parent
4461772ebf
commit
b610ec20e1
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue