Compare commits
12
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c9e61ce0f | ||
|
|
6538dac8af | ||
|
|
67813e4881 | ||
|
|
4cc07a3754 | ||
|
|
fa696194aa | ||
|
|
9fb4952f32 | ||
|
|
96b8faca5b | ||
|
|
cac549f1ee | ||
|
|
a86f4dbf82 | ||
|
|
7168431bcd | ||
|
|
0b7c67fef6 | ||
|
|
15ea8ac207 |
No files matched your search
@@ -1,4 +1,4 @@
|
||||
#Mon, 17 Aug 2026 14:26:26 -0300
|
||||
#Fri, 02 Oct 2026 20:11:21 -0300
|
||||
|
||||
|
||||
C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi.chat=
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../pitiupi/dist/pitiupi.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -4,28 +4,29 @@
|
||||
*/
|
||||
package pitiupi.chat.GUI;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.JMenu;
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastMenu;
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastSubMenu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author flavio
|
||||
*/
|
||||
public class ChatMenu extends JMenu {
|
||||
|
||||
private final ChatWindow chatWindow;
|
||||
private javax.swing.JMenuItem menuItem;
|
||||
public class ChatMenu extends MulticastSubMenu {
|
||||
ChatMulticastMenu chatMulticastMenu;
|
||||
|
||||
public ChatMenu(ChatWindow chatWindow) {
|
||||
this.chatWindow = chatWindow;
|
||||
this.setText("Chat");
|
||||
menuItem = new javax.swing.JMenuItem();
|
||||
menuItem.setText("Show Chat Window");
|
||||
menuItem.addActionListener(this::chatMenuActionPerformed);
|
||||
this.add(menuItem);
|
||||
this.chatMulticastMenu = new ChatMulticastMenu(chatWindow);
|
||||
}
|
||||
|
||||
private void chatMenuActionPerformed(ActionEvent ae) {
|
||||
this.chatWindow.setVisible(true);
|
||||
@Override
|
||||
public String getText() {
|
||||
return "Chat";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MulticastMenu> getMenus() {
|
||||
return List.of(chatMulticastMenu);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package pitiupi.chat.GUI;
|
||||
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastActionMenu;;
|
||||
|
||||
public class ChatMulticastMenu extends MulticastActionMenu {
|
||||
ChatWindow chatWindow;
|
||||
|
||||
public ChatMulticastMenu(ChatWindow chatWindow) {
|
||||
this.chatWindow = chatWindow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "Show Chat Window";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
chatWindow.setVisible(true);
|
||||
}
|
||||
}
|
||||
@@ -5,34 +5,33 @@
|
||||
*/
|
||||
package pitiupi.chat.GUI;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import pitiupi.chat.net.ChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.models.Messages.Message;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author flavio
|
||||
*/
|
||||
public class ChatWindow extends javax.swing.JDialog {
|
||||
public class ChatWindow extends JDialog {
|
||||
|
||||
private javax.swing.JButton jButton1;
|
||||
private javax.swing.JEditorPane jEditorPane1;
|
||||
private javax.swing.JPanel jPanel1;
|
||||
private javax.swing.JPanel jPanel2;
|
||||
private javax.swing.JScrollPane jScrollPane1;
|
||||
private javax.swing.JScrollPane jScrollPane2;
|
||||
private javax.swing.JSplitPane jSplitPane1;
|
||||
private javax.swing.JTextArea jTextArea1;
|
||||
private JButton jButton1;
|
||||
private JEditorPane jEditorPane1;
|
||||
private JPanel jPanel1;
|
||||
private JPanel jPanel2;
|
||||
private JScrollPane jScrollPane1;
|
||||
private JScrollPane jScrollPane2;
|
||||
private JSplitPane jSplitPane1;
|
||||
private JTextArea jTextArea1;
|
||||
|
||||
private final MainWindow mainWindow;
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
public ChatWindow(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
public ChatWindow(ConnectionManager connectionManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
initComponents();
|
||||
}
|
||||
|
||||
@@ -43,23 +42,23 @@ public class ChatWindow extends javax.swing.JDialog {
|
||||
*/
|
||||
private void initComponents() {
|
||||
|
||||
this.setDefaultCloseOperation(javax.swing.WindowConstants.HIDE_ON_CLOSE);
|
||||
this.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
|
||||
this.setTitle("Chat Window");
|
||||
this.setBounds(new java.awt.Rectangle(0, 0, 800, 600));
|
||||
this.getContentPane().setLayout(new java.awt.BorderLayout(5, 5));
|
||||
this.setPreferredSize(new java.awt.Dimension(800, 600));
|
||||
|
||||
jSplitPane1 = new javax.swing.JSplitPane();
|
||||
jScrollPane1 = new javax.swing.JScrollPane();
|
||||
jEditorPane1 = new javax.swing.JEditorPane();
|
||||
jPanel1 = new javax.swing.JPanel();
|
||||
jScrollPane2 = new javax.swing.JScrollPane();
|
||||
jTextArea1 = new javax.swing.JTextArea();
|
||||
jPanel2 = new javax.swing.JPanel();
|
||||
jButton1 = new javax.swing.JButton();
|
||||
jSplitPane1 = new JSplitPane();
|
||||
jScrollPane1 = new JScrollPane();
|
||||
jEditorPane1 = new JEditorPane();
|
||||
jPanel1 = new JPanel();
|
||||
jScrollPane2 = new JScrollPane();
|
||||
jTextArea1 = new JTextArea();
|
||||
jPanel2 = new JPanel();
|
||||
jButton1 = new JButton();
|
||||
|
||||
jSplitPane1.setDividerLocation(500);
|
||||
jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT);
|
||||
jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
|
||||
jEditorPane1.setContentType("text/html");
|
||||
jPanel1.setLayout(new java.awt.BorderLayout());
|
||||
jTextArea1.setColumns(20);
|
||||
@@ -94,17 +93,13 @@ public class ChatWindow extends javax.swing.JDialog {
|
||||
if (jTextArea1.getText().trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ChatMessage message = new ChatMessage(mainWindow.getUserName(), jTextArea1.getText());
|
||||
ChatMessage message = new ChatMessage(connectionManager.getUserName(), jTextArea1.getText());
|
||||
this.sendChatMessage(message);
|
||||
jTextArea1.setText("");
|
||||
}
|
||||
|
||||
public void sendChatMessage(Message message) {
|
||||
try {
|
||||
mainWindow.getSocketUDP().sendMulticast(message.toByteArray());
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
connectionManager.sendUdpMulticast(message);
|
||||
}
|
||||
|
||||
public void receiveChatMessage(ChatMessage message) {
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
package pitiupi.chat.net;
|
||||
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.net.Message;
|
||||
|
||||
import pitiupi.models.Messages.Message;
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -4,49 +4,44 @@
|
||||
*/
|
||||
package pitiupi.chat.plugin;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import pitiupi.chat.GUI.ChatMenu;
|
||||
import pitiupi.chat.GUI.ChatWindow;
|
||||
import pitiupi.chat.net.ChatMessage;
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.plugin.Plugin;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.GuiManager;
|
||||
import pitiupi.models.Menus.MenuCategory;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.models.Plugin;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author flavio
|
||||
*/
|
||||
public class ChatPlugin implements Plugin {
|
||||
public class ChatPlugin extends Plugin {
|
||||
|
||||
private ChatWindow chatWindow;
|
||||
private MainWindow mainWindow;
|
||||
|
||||
public ChatPlugin() {
|
||||
@Override
|
||||
public void createPlugin(ConnectionManager connectionManager, GuiManager guiManager) {
|
||||
this.chatWindow = new ChatWindow(connectionManager);
|
||||
guiManager.createMenu(MenuCategory.Social, new ChatMenu(chatWindow));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPlugin(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.chatWindow = new ChatWindow(mainWindow);
|
||||
this.mainWindow.addMenu(new ChatMenu(chatWindow));
|
||||
public List<Class<? extends Message>> getMessages() {
|
||||
return List.of(ChatMessage.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receiveMessage(byte[] message) {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(message);
|
||||
ObjectInputStream ois;
|
||||
try {
|
||||
ois = new ObjectInputStream(bis);
|
||||
if (ois.readObject() instanceof ChatMessage msg) {
|
||||
public void receiveMessage(Message message) {
|
||||
if (message instanceof ChatMessage msg) {
|
||||
this.chatWindow.receiveChatMessage(msg);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
System.out.println(ex.toString());
|
||||
} catch (ClassNotFoundException ex) {
|
||||
System.out.println(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,7 +60,9 @@ public class ChatPlugin implements Plugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessage() {
|
||||
return new ChatMessage();
|
||||
public String getIdentifier() {
|
||||
return "Pitiupi.Chat.Example";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
JAR = ../pitiupi/dist/pitiupi.jar
|
||||
OUT_DIR = out
|
||||
META-INF_DIR = src/META-INF
|
||||
DIST = dist/mpChat.jar
|
||||
|
||||
SOURCES = $(shell find -name "*.java")
|
||||
|
||||
all:
|
||||
mkdir -p "$(OUT_DIR)"
|
||||
mkdir -p "$(dir $(DIST))"
|
||||
javac -cp "$(JAR)" -d "$(OUT_DIR)" $(SOURCES)
|
||||
cp -r "$(META-INF_DIR)" "$(OUT_DIR)"
|
||||
jar cf "$(DIST)" -C "$(OUT_DIR)" .
|
||||
|
||||
clean:
|
||||
rm -rf "$(OUT_DIR)"/*
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1 @@
|
||||
plugin.MultiProtocolChat
|
||||
BIN
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
Binary file not shown.
File renamed without changes.
Binary file not shown.
File renamed without changes.
@@ -0,0 +1,40 @@
|
||||
package GUI;
|
||||
|
||||
import pitiupi.models.Menus.MenuCategory;
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastSubMenu;
|
||||
import plugin.MultiProtocolChat;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
|
||||
public class ChatMenu extends MulticastSubMenu {
|
||||
private final MultiProtocolChat multiProtocolChat;
|
||||
|
||||
public ChatMenu(MultiProtocolChat multiProtocolChat) {
|
||||
this.multiProtocolChat = multiProtocolChat;
|
||||
this.setText("MP-Chat");
|
||||
|
||||
JMenuItem startPrivateChat = new JMenuItem("start Private Chat");
|
||||
startPrivateChat.addActionListener(e -> showPrivateChatDialog());
|
||||
this.add(startPrivateChat);
|
||||
}
|
||||
|
||||
public void newMenuItem(JMenuItem newMenuItem, ChatWindow chatWindow) {
|
||||
newMenuItem.addActionListener(e -> chatWindow.setVisible(true));
|
||||
|
||||
this.add(newMenuItem);
|
||||
}
|
||||
|
||||
public void removeMenuItem(JMenuItem removeMenuItem) {
|
||||
this.remove(removeMenuItem);
|
||||
}
|
||||
|
||||
private void showPrivateChatDialog() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "MP-Chat";
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package GUI;
|
||||
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -10,13 +10,13 @@ import java.net.UnknownHostException;
|
||||
|
||||
public abstract class ChatWindow extends JFrame {
|
||||
|
||||
protected final MainWindow mainWindow;
|
||||
protected final ConnectionManager connectionManager;
|
||||
|
||||
private JTextArea receivedMessagesArea;
|
||||
protected JTextField messageField;
|
||||
|
||||
public ChatWindow(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
public ChatWindow(ConnectionManager connectionManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
initComponents();
|
||||
}
|
||||
|
||||
@@ -63,20 +63,20 @@ public abstract class ChatWindow extends JFrame {
|
||||
|
||||
protected abstract void initButtons(JPanel bottomPanel);
|
||||
|
||||
protected TestChatMessage createMessage(String tipoMensagem) {
|
||||
protected MpChatMessage createMessage(String tipoMensagem) {
|
||||
try {
|
||||
String nome = mainWindow.getUserName();
|
||||
String nome = connectionManager.getUserName();
|
||||
String ip = InetAddress.getLocalHost().getHostAddress();
|
||||
String message = messageField.getText();
|
||||
|
||||
return new TestChatMessage(nome, ip, tipoMensagem, message);
|
||||
return new MpChatMessage(nome, ip, tipoMensagem, message);
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveMessage(TestChatMessage msg) {
|
||||
public void receiveMessage(MpChatMessage msg) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
String mensagem = String.format(
|
||||
"[%s] %s (%s): %s%n",
|
||||
@@ -0,0 +1,38 @@
|
||||
package GUI;
|
||||
|
||||
import control.ChatController;
|
||||
import pitiupi.models.Menus.UnicastMenus.UnicastActionMenu;
|
||||
import pitiupi.models.User;
|
||||
import plugin.MultiProtocolChat;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class PrivateChatMenu extends UnicastActionMenu {
|
||||
PrivateChatWindow privateChatWindow;
|
||||
private final MultiProtocolChat multiProtocolChat;
|
||||
private final ChatController chatController;
|
||||
|
||||
public PrivateChatMenu(PrivateChatWindow PrivateChatWindow, MultiProtocolChat multiProtocolChat, ChatController chatController) {
|
||||
this.privateChatWindow = PrivateChatWindow;
|
||||
this.multiProtocolChat = multiProtocolChat;
|
||||
this.chatController = chatController;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(User user) {
|
||||
if (multiProtocolChat.openConnection(user.getAddress())
|
||||
else errorLabel.setVisible(true);
|
||||
|
||||
dialog.setContentPane(contentPanel);
|
||||
dialog.pack();
|
||||
dialog.setLocationRelativeTo(SwingUtilities.getWindowAncestor(privateChatWindow));
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "start Private Chat";
|
||||
}
|
||||
}
|
||||
+6
-9
@@ -1,7 +1,7 @@
|
||||
package GUI;
|
||||
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -13,10 +13,9 @@ public class PrivateChatWindow extends ChatWindow {
|
||||
|
||||
private final TcpConnection connection;
|
||||
|
||||
public PrivateChatWindow(MainWindow mainWindow, TcpConnection connection) {
|
||||
public PrivateChatWindow(ConnectionManager ConnectionManager, TcpConnection connection) {
|
||||
super(ConnectionManager);
|
||||
this.connection = connection;
|
||||
|
||||
super(mainWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -34,13 +33,11 @@ public class PrivateChatWindow extends ChatWindow {
|
||||
|
||||
private void sendTCP() {
|
||||
try {
|
||||
TestChatMessage msg = createMessage("TCP Private");
|
||||
MpChatMessage msg = createMessage("TCP Private");
|
||||
connection.send(msg.toByteArray());
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(
|
||||
PrivateChatWindow.class.getName()
|
||||
).log(Level.SEVERE, null, ex);
|
||||
Logger.getLogger(PrivateChatWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package GUI;
|
||||
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastActionMenu;
|
||||
|
||||
public class PublicChatMenu extends MulticastActionMenu {
|
||||
PublicChatWindow publicChatWindow;
|
||||
|
||||
PublicChatMenu(PublicChatWindow publicChatWindow) {
|
||||
this.publicChatWindow = publicChatWindow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
publicChatWindow.setVisible(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -1,7 +1,7 @@
|
||||
package GUI;
|
||||
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -13,8 +13,8 @@ public class PublicChatWindow extends ChatWindow {
|
||||
|
||||
private JTextField ipField;
|
||||
|
||||
public PublicChatWindow(MainWindow mainWindow) {
|
||||
super(mainWindow);
|
||||
public PublicChatWindow(ConnectionManager connectionManager) {
|
||||
super(connectionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,11 +56,11 @@ public class PublicChatWindow extends ChatWindow {
|
||||
|
||||
private void sendTCP() {
|
||||
try {
|
||||
TestChatMessage msg = createMessage("TCP Unicast");
|
||||
MpChatMessage msg = createMessage("TCP Unicast");
|
||||
|
||||
InetAddress ip = InetAddress.getByName(ipField.getText());
|
||||
|
||||
mainWindow.getSocketTCP().send(msg, ip);
|
||||
connectionManager.sendTcp(msg, ip);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(PublicChatWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
@@ -69,11 +69,11 @@ public class PublicChatWindow extends ChatWindow {
|
||||
|
||||
private void sendUDP() {
|
||||
try {
|
||||
TestChatMessage msg = createMessage("UDP Unicast");
|
||||
MpChatMessage msg = createMessage("UDP Unicast");
|
||||
|
||||
InetAddress ip = InetAddress.getByName(ipField.getText());
|
||||
|
||||
mainWindow.getSocketUDP().sendUnicast(msg, ip);
|
||||
connectionManager.sendUdpUnicast(msg, ip);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(PublicChatWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
@@ -82,9 +82,9 @@ public class PublicChatWindow extends ChatWindow {
|
||||
|
||||
private void sendMulticast() {
|
||||
try {
|
||||
TestChatMessage msg = createMessage("UDP Multicast");
|
||||
MpChatMessage msg = createMessage("UDP Multicast");
|
||||
|
||||
mainWindow.getSocketUDP().sendMulticast(msg);
|
||||
connectionManager.sendUdpMulticast(msg);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(PublicChatWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
@@ -0,0 +1 @@
|
||||
plugin.MultiProtocolChat
|
||||
+23
-11
@@ -4,25 +4,28 @@ import GUI.ChatMenu;
|
||||
import GUI.ChatWindow;
|
||||
import GUI.PrivateChatWindow;
|
||||
import GUI.PublicChatWindow;
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.PeerListener;
|
||||
import pitiupi.models.User;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.net.InetAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class ChatController {
|
||||
MainWindow mainWindow;
|
||||
public class ChatController implements PeerListener {
|
||||
ConnectionManager connectionManager;
|
||||
ChatMenu chatMenu;
|
||||
|
||||
PublicChatWindow publicChatWindow;
|
||||
|
||||
private final HashMap<TcpConnection, JMenuItem> chatMenus;
|
||||
private final HashMap<TcpConnection, ChatWindow> chatWindows;
|
||||
|
||||
public ChatController(MainWindow mainWindow, ChatMenu chatMenu) {
|
||||
this.mainWindow = mainWindow;
|
||||
publicChatWindow = new PublicChatWindow(mainWindow);
|
||||
public ChatController(ConnectionManager connectionManager, ChatMenu chatMenu) {
|
||||
this.connectionManager = connectionManager;
|
||||
publicChatWindow = new PublicChatWindow(connectionManager);
|
||||
|
||||
chatMenus = new HashMap<>();
|
||||
chatWindows = new HashMap<>();
|
||||
@@ -35,7 +38,7 @@ public class ChatController {
|
||||
public void addChatWindow(TcpConnection tcpConnection) {
|
||||
if (chatWindows.containsKey(tcpConnection)) return;
|
||||
|
||||
PrivateChatWindow newChat = new PrivateChatWindow(mainWindow, tcpConnection);
|
||||
PrivateChatWindow newChat = new PrivateChatWindow(connectionManager, tcpConnection);
|
||||
chatWindows.put(tcpConnection, newChat);
|
||||
JMenuItem newMenuItem = new JMenuItem();
|
||||
chatMenus.put(tcpConnection, newMenuItem);
|
||||
@@ -52,10 +55,19 @@ public class ChatController {
|
||||
removedWindow.dispose();
|
||||
}
|
||||
|
||||
public void receivePublic(TestChatMessage message) {
|
||||
public void receivePublic(MpChatMessage message) {
|
||||
publicChatWindow.receiveMessage(message);
|
||||
}
|
||||
public void receivePrivate(TcpConnection tcpConnection, TestChatMessage message) {
|
||||
public void receivePrivate(TcpConnection tcpConnection, MpChatMessage message) {
|
||||
chatWindows.get(tcpConnection).receiveMessage(message);
|
||||
}
|
||||
|
||||
public void openChatWindow(InetAddress address) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeersChanged(List<User> list) {
|
||||
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,21 +1,21 @@
|
||||
package net;
|
||||
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.models.Messages.Message;
|
||||
|
||||
public class TestChatMessage extends Message {
|
||||
public class MpChatMessage extends Message {
|
||||
private String nome;
|
||||
private String ip;
|
||||
private String tipoMensagem;
|
||||
private String message;
|
||||
|
||||
public TestChatMessage(String nome, String ip, String tipoMensagem, String message) {
|
||||
public MpChatMessage(String nome, String ip, String tipoMensagem, String message) {
|
||||
this.nome = nome;
|
||||
this.ip = ip;
|
||||
this.tipoMensagem = tipoMensagem;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public TestChatMessage(){}
|
||||
public MpChatMessage(){}
|
||||
|
||||
public String getNome() {
|
||||
return nome;
|
||||
+29
-24
@@ -2,11 +2,12 @@ package plugin;
|
||||
|
||||
import GUI.ChatMenu;
|
||||
import control.ChatController;
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.net.Message;
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.GuiManager;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
import pitiupi.plugin.PrivateConnectionPlugin;
|
||||
import pitiupi.models.Plugin;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -14,9 +15,10 @@ import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class TestChat implements PrivateConnectionPlugin{
|
||||
public class MultiProtocolChat extends Plugin {
|
||||
ChatController chatController;
|
||||
MainWindow mainWindow;
|
||||
ConnectionManager connectionManager;
|
||||
GuiManager guiManager;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -39,47 +41,50 @@ public class TestChat implements PrivateConnectionPlugin{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPlugin(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
public void createPlugin(ConnectionManager connectionManager, GuiManager guiManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
this.guiManager = guiManager;
|
||||
|
||||
ChatMenu chatMenu = new ChatMenu(this);
|
||||
chatController = new ChatController(mainWindow, chatMenu);
|
||||
mainWindow.addMenu(chatMenu);
|
||||
chatController = new ChatController(connectionManager, chatMenu);
|
||||
guiManager.addMulticastMenu(chatMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessage() {
|
||||
return new TestChatMessage();
|
||||
return new MpChatMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveMessage(byte[] message) {
|
||||
TestChatMessage testChatMessage = parseMessage(message);
|
||||
chatController.receivePublic(testChatMessage);
|
||||
MpChatMessage mpChatMessage = parseMessage(message);
|
||||
chatController.receivePublic(mpChatMessage);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receivePrivateConnection(TcpConnection tcpConnection) {
|
||||
public boolean receivePrivateConnection(TcpConnection connection) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
chatController.addChatWindow(tcpConnection);
|
||||
chatController.addChatWindow(connection);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveBytes(TcpConnection connection, byte[] bytes) {
|
||||
TestChatMessage testChatMessage = parseMessage(bytes);
|
||||
chatController.receivePrivate(connection, testChatMessage);
|
||||
public boolean receiveBytes(TcpConnection connection, byte[] bytes) {
|
||||
MpChatMessage mpChatMessage = parseMessage(bytes);
|
||||
chatController.receivePrivate(connection, mpChatMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSocketClosed(TcpConnection tcpConnection) {
|
||||
chatController.removeChatWindow(tcpConnection);
|
||||
public boolean onSocketClosed(TcpConnection connection) {
|
||||
chatController.removeChatWindow(connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean openConnection(String ip) {
|
||||
try {
|
||||
mainWindow.getSocketTCP().createPrivateConnection(InetAddress.getByName(ip), getIdentifier(), getIdentifier());
|
||||
connectionManager.connectPluginTcp(InetAddress.getByName(ip), getIdentifier(), getIdentifier());
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -88,12 +93,12 @@ public class TestChat implements PrivateConnectionPlugin{
|
||||
return false;
|
||||
}
|
||||
|
||||
private TestChatMessage parseMessage(byte[] bytes) {
|
||||
private MpChatMessage parseMessage(byte[] bytes) {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois;
|
||||
try {
|
||||
ois = new ObjectInputStream(bis);
|
||||
if (ois.readObject() instanceof TestChatMessage msg) {
|
||||
if (ois.readObject() instanceof MpChatMessage msg) {
|
||||
return msg;
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException ex) {
|
||||
Generated
+23
-31
@@ -5,24 +5,10 @@
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="083e72ce-fa9b-4ddf-a0ef-24105aa3eabb" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/../.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../.idea/misc.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../.idea/vcs.xml" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi.chat/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi.chat/.idea/misc.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi.chat/build/built-jar.properties" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi.chat/build/built-jar.properties" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi.chat/build/classes/pitiupi/chat/GUI/ChatWindow.class" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi.chat/build/classes/pitiupi/chat/GUI/ChatWindow.class" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi.chat/dist/pitiupi.chat.jar" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi.chat/pitiupi.chat.iml" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi.chat/pitiupi.chat.iml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi.chat/src/pitiupi/chat/GUI/ChatWindow.java" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi.chat/src/pitiupi/chat/GUI/ChatWindow.java" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/../pitiupi.testSocket/Makefile" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/build/built-jar.properties" beforeDir="false" afterPath="$PROJECT_DIR$/build/built-jar.properties" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/build/classes/pitiupi/screenCast/GUI/ScreenCastWindow.class" beforeDir="false" afterPath="$PROJECT_DIR$/build/classes/pitiupi/screenCast/GUI/ScreenCastWindow.class" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/dist/pitiupi.screenCast.jar" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/pitiupi/screenCast/GUI/ScreenCastWindow.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/pitiupi/screenCast/GUI/ScreenCastWindow.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi/plugins/pitiupi.chat.jar" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi/plugins/pitiupi.chat.jar" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi/plugins/pitiupi.screenCast.jar" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi/plugins/pitiupi.screenCast.jar" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi/src/pitiupi/GUI/MainWindow.java" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi/src/pitiupi/GUI/MainWindow.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi/src/pitiupi/control/HeartbeatManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi/src/pitiupi/control/HeartbeatManager.java" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi/.idea/misc.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/../pitiupi/src/pitiupi/net/tcp/ConnectionFactory.java" beforeDir="false" afterPath="$PROJECT_DIR$/../pitiupi/src/pitiupi/net/tcp/ConnectionFactory.java" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -46,10 +32,12 @@
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"git-widget-placeholder": "feature/unicast",
|
||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||
"codeWithMe.voiceChat.enabledByDefault": "false",
|
||||
"git-widget-placeholder": "feature/separacao-gerenciadores",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "C:/Users/extre/OneDrive/Documentos/Faculdade/2026_02/Monitoria/Pitiupi/pitiupi.screenCast",
|
||||
"last_opened_file_path": "C:/Users/Gustavo/OneDrive/Documentos/Faculdade/2026_2/Monitoria/pitiupi/pitiupi.screenCast",
|
||||
"project.structure.last.edited": "Modules",
|
||||
"project.structure.proportion": "0.15",
|
||||
"project.structure.side.proportion": "0.2",
|
||||
@@ -57,17 +45,6 @@
|
||||
}
|
||||
}]]></component>
|
||||
<component name="RunManager">
|
||||
<configuration default="true" type="JetRunConfigurationType">
|
||||
<module name="pitiupi.screenCast" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="KotlinStandaloneScriptRunConfigurationType">
|
||||
<module name="pitiupi.screenCast" />
|
||||
<option name="filePath" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration default="true" type="PythonConfigurationType" factoryName="Python">
|
||||
<module name="pitiupi.screenCast" />
|
||||
<option name="ENV_FILES" value="" />
|
||||
@@ -102,11 +79,23 @@
|
||||
<option name="ADD_SOURCE_ROOTS" value="true" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration default="true" type="JetRunConfigurationType">
|
||||
<module name="pitiupi.screenCast" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="KotlinStandaloneScriptRunConfigurationType">
|
||||
<module name="pitiupi.screenCast" />
|
||||
<option name="filePath" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-jdk-9823dce3aa75-bf35d07a577b-intellij.indexing.shared.core-IU-252.28539.54" />
|
||||
<option value="bundled-jdk-30f59d01ecdd-37e91769500f-intellij.indexing.shared.core-IU-261.26222.65" />
|
||||
<option value="bundled-js-predefined-d6986cc7102b-31caf2ab9e3c-JavaScript-IU-261.26222.65" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
@@ -120,4 +109,7 @@
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,6 +1,6 @@
|
||||
#Mon, 17 Aug 2026 14:35:40 -0300
|
||||
#Tue, 29 Sep 2026 11:04:58 -0300
|
||||
|
||||
|
||||
C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi.screenCast=
|
||||
C\:\\Users\\Gustavo\\OneDrive\\Documentos\\Faculdade\\2026_2\\Monitoria\\pitiupi\\pitiupi.screenCast=
|
||||
|
||||
C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi=
|
||||
C\:\\Users\\Gustavo\\OneDrive\\Documentos\\Faculdade\\2026_2\\Monitoria\\pitiupi\\pitiupi=
|
||||
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="module-library">
|
||||
<library>
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../../pitiupi/dist/pitiupi.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</orderEntry>
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
package pitiupi.screenCast.GUI;
|
||||
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.GuiManager;
|
||||
import pitiupi.screenCast.control.AlarmClock;
|
||||
import pitiupi.screenCast.control.ImageTransformation;
|
||||
import pitiupi.screenCast.control.ScreenShot;
|
||||
@@ -38,10 +40,13 @@ public class ScreenCastWindow extends javax.swing.JFrame {
|
||||
public final static int TIME = 1000;
|
||||
|
||||
private float compressRatio;
|
||||
private final MainWindow mainWindow;
|
||||
private final ConnectionManager connectionManager;
|
||||
private final GuiManager guiManager;
|
||||
|
||||
public ScreenCastWindow(ConnectionManager connectionManager, GuiManager guiManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
this.guiManager = guiManager;
|
||||
|
||||
public ScreenCastWindow(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.compressRatio = 0.5f;
|
||||
this.initComponents();
|
||||
}
|
||||
@@ -91,19 +96,12 @@ public class ScreenCastWindow extends javax.swing.JFrame {
|
||||
BufferedImage image = ScreenShot.takeAShot();
|
||||
BufferedImage rescaled = ImageTransformation.resize(image, 1024, 768);
|
||||
byte[] byteImage = ImageTransformation.compress(rescaled, compressRatio);
|
||||
ScreenCastMessage message = new ScreenCastMessage(this.mainWindow.getUserName(), byteImage);
|
||||
msg = message.toByteArray();
|
||||
ScreenCastMessage message = new ScreenCastMessage(this.connectionManager.getUserName(), byteImage);
|
||||
|
||||
if (!connectionManager.sendUdpMulticast(message)) this.compressRatio -= 0.1f;
|
||||
} catch (AWTException | IOException ex) {
|
||||
Logger.getLogger(AlarmClock.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
if (msg != null) {
|
||||
try {
|
||||
this.mainWindow.getSocketUDP().sendMulticast(msg);
|
||||
} catch (IOException ex) {
|
||||
System.out.println(ex.toString());
|
||||
this.compressRatio -= 0.1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveScreenCastMessage(ScreenCastMessage message) {
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.GuiManager;
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.plugin.Plugin;
|
||||
import pitiupi.screenCast.GUI.ScreenCastMenu;
|
||||
@@ -21,7 +23,6 @@ import pitiupi.screenCast.net.ScreenCastMessage;
|
||||
public class ScreenCastPlugin implements Plugin {
|
||||
|
||||
private ScreenCastWindow screenCastWindow;
|
||||
private MainWindow mainWindow;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@@ -39,10 +40,14 @@ public class ScreenCastPlugin implements Plugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPlugin(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.screenCastWindow = new ScreenCastWindow(mainWindow);
|
||||
this.mainWindow.addMenu(new ScreenCastMenu(screenCastWindow));
|
||||
public String getIdentifier() {
|
||||
return "Pitiupi.ScreenCast.Example";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPlugin(ConnectionManager connectionManager, GuiManager guiManager) {
|
||||
this.screenCastWindow = new ScreenCastWindow(connectionManager, guiManager);
|
||||
guiManager.addMenu(new ScreenCastMenu(screenCastWindow));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,9 +59,7 @@ public class ScreenCastPlugin implements Plugin {
|
||||
if (ois.readObject() instanceof ScreenCastMessage msg) {
|
||||
this.screenCastWindow.receiveScreenCastMessage(msg);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
System.out.println(ex.toString());
|
||||
} catch (ClassNotFoundException ex) {
|
||||
} catch (IOException | ClassNotFoundException ex) {
|
||||
System.out.println(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
plugin.TestChat
|
||||
Binary file not shown.
@@ -1,84 +0,0 @@
|
||||
package GUI;
|
||||
|
||||
import plugin.TestChat;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChatMenu extends JMenu {
|
||||
private final TestChat testChat;
|
||||
|
||||
public ChatMenu(TestChat testChat) {
|
||||
this.testChat = testChat;
|
||||
this.setText("MP-Chat");
|
||||
|
||||
JMenuItem startPrivateChat = new JMenuItem("start Private Chat");
|
||||
startPrivateChat.addActionListener(_ -> showPrivateChatDialog());
|
||||
this.add(startPrivateChat);
|
||||
}
|
||||
|
||||
public void newMenuItem(JMenuItem newMenuItem, ChatWindow chatWindow) {
|
||||
newMenuItem.addActionListener(_ -> chatWindow.setVisible(true));
|
||||
|
||||
this.add(newMenuItem);
|
||||
}
|
||||
|
||||
public void removeMenuItem(JMenuItem removeMenuItem) {
|
||||
this.remove(removeMenuItem);
|
||||
}
|
||||
|
||||
private void showPrivateChatDialog() {
|
||||
JDialog dialog = new JDialog(
|
||||
SwingUtilities.getWindowAncestor(this),
|
||||
"Novo chat privado",
|
||||
Dialog.ModalityType.APPLICATION_MODAL
|
||||
);
|
||||
|
||||
JTextField ipField = new JTextField();
|
||||
|
||||
JButton startButton = new JButton("Iniciar");
|
||||
JButton cancelButton = new JButton("Cancelar");
|
||||
|
||||
JPanel contentPanel = new JPanel(new BorderLayout(10, 10));
|
||||
contentPanel.setBorder(
|
||||
BorderFactory.createEmptyBorder(10, 10, 10, 10)
|
||||
);
|
||||
|
||||
JPanel ipPanel = new JPanel(new BorderLayout(5, 5));
|
||||
ipPanel.add(new JLabel("IP:"), BorderLayout.WEST);
|
||||
ipPanel.add(ipField, BorderLayout.CENTER);
|
||||
|
||||
JPanel buttonsPanel = new JPanel(
|
||||
new FlowLayout(FlowLayout.RIGHT)
|
||||
);
|
||||
|
||||
buttonsPanel.add(cancelButton);
|
||||
buttonsPanel.add(startButton);
|
||||
|
||||
JLabel errorLabel = new JLabel("Não foi possível estabelecer a conexão.");
|
||||
errorLabel.setForeground(Color.RED);
|
||||
errorLabel.setVisible(false);
|
||||
|
||||
contentPanel.add(errorLabel, BorderLayout.NORTH);
|
||||
contentPanel.add(ipPanel, BorderLayout.CENTER);
|
||||
contentPanel.add(buttonsPanel, BorderLayout.SOUTH);
|
||||
|
||||
cancelButton.addActionListener(e -> dialog.dispose());
|
||||
|
||||
startButton.addActionListener(e -> {
|
||||
String ip = ipField.getText();
|
||||
|
||||
if (testChat.openConnection(ip)) dialog.dispose();
|
||||
else errorLabel.setVisible(true);
|
||||
|
||||
});
|
||||
|
||||
dialog.setContentPane(contentPanel);
|
||||
dialog.pack();
|
||||
dialog.setLocationRelativeTo(SwingUtilities.getWindowAncestor(this));
|
||||
dialog.setVisible(true);
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
plugin.TestChat
|
||||
Generated
+1
-1
@@ -1,5 +1,5 @@
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="openjdk-26" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_26_PREVIEW" project-jdk-name="openjdk-26" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -468,10 +468,10 @@ MeusPlugins
|
||||
|
|
||||
+---services
|
||||
|
|
||||
+---pitiupi.plugin.Plugin
|
||||
+---pitiupi.models.Plugin
|
||||
```
|
||||
|
||||
O arquivo `pitiupi.plugin.Plugin` deve conter o nome completo das classes que
|
||||
O arquivo `pitiupi.models.Plugin` deve conter o nome completo das classes que
|
||||
implementam a interface Plugin:
|
||||
|
||||
```
|
||||
|
||||
@@ -46,8 +46,8 @@ javac.modulepath=
|
||||
javac.processormodulepath=
|
||||
javac.processorpath=\
|
||||
${javac.classpath}
|
||||
javac.source=25
|
||||
javac.target=25
|
||||
javac.source=17
|
||||
javac.target=17
|
||||
javac.test.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
*/
|
||||
package pitiupi.GUI;
|
||||
|
||||
import pitiupi.net.tcp.SocketTCP;
|
||||
import pitiupi.net.udp.SocketUDP;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JMenu;
|
||||
import pitiupi.control.PluginLoader;
|
||||
import pitiupi.plugin.Plugin;
|
||||
import pitiupi.control.HeartbeatManager;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.GuiManager;
|
||||
import pitiupi.control.plugins.PluginManager;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* Janela principal da aplicação.
|
||||
@@ -28,28 +27,15 @@ import pitiupi.control.HeartbeatManager;
|
||||
* @author tony
|
||||
* @author Gustavo
|
||||
*/
|
||||
public class MainWindow extends javax.swing.JFrame {
|
||||
public class MainWindow extends JFrame {
|
||||
|
||||
private final MenuBar menuBar;
|
||||
private javax.swing.JScrollPane jScrollPane1;
|
||||
private javax.swing.JLabel status;
|
||||
private javax.swing.JPanel statusPanel;
|
||||
private javax.swing.JTabbedPane tabbedPane;
|
||||
private MenuBar menuBar;
|
||||
private JLabel status;
|
||||
OnlineUsersPanel onlineUsersPanel;
|
||||
|
||||
private HeartbeatManager heartbeatManager;
|
||||
private OnlineUsersPanel onlineUsersPanel;
|
||||
|
||||
|
||||
private SocketUDP socketUDP;
|
||||
private SocketTCP socketTCP;
|
||||
|
||||
private String userName;
|
||||
private int port;
|
||||
|
||||
private String pitiupiIdentifier;
|
||||
|
||||
private PluginLoader pluginManager;
|
||||
private final List<Plugin> plugins;
|
||||
private final ConnectionManager connectionManager;
|
||||
private final PluginManager pluginManager;
|
||||
private final GuiManager guiManager;
|
||||
|
||||
/**
|
||||
* Cria a janela principal da aplicação.
|
||||
@@ -58,62 +44,53 @@ public class MainWindow extends javax.swing.JFrame {
|
||||
* @param port porta utilizada na comunicação multicast.
|
||||
*/
|
||||
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();
|
||||
}
|
||||
initMenu();
|
||||
|
||||
pluginManager = new PluginManager();
|
||||
connectionManager = new ConnectionManager(this, userName, pluginManager, port);
|
||||
|
||||
initUserPanel();
|
||||
initStatusPanel();
|
||||
|
||||
guiManager = new GuiManager(this, menuBar, onlineUsersPanel);
|
||||
|
||||
loadPlugins();
|
||||
|
||||
this.pack();
|
||||
|
||||
private void initComponents() {
|
||||
initGUI();
|
||||
initSocket();
|
||||
initHeartbeat();
|
||||
initPlugins();
|
||||
this.setSize(new java.awt.Dimension(1024, 768));
|
||||
}
|
||||
|
||||
private void initGUI() {
|
||||
private void initMenu() {
|
||||
menuBar = new MenuBar(this);
|
||||
|
||||
this.setJMenuBar(menuBar);
|
||||
this.setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
|
||||
this.setTitle("Share My Sheet");
|
||||
this.setTitle("Pitiupi");
|
||||
|
||||
jScrollPane1 = new javax.swing.JScrollPane();
|
||||
tabbedPane = new javax.swing.JTabbedPane();
|
||||
statusPanel = new javax.swing.JPanel();
|
||||
status = new javax.swing.JLabel();
|
||||
javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
|
||||
javax.swing.JTabbedPane tabbedPane = new javax.swing.JTabbedPane();
|
||||
|
||||
jScrollPane1.setViewportView(tabbedPane);
|
||||
statusPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));
|
||||
status.setText("Connected on port " + this.port + " name " + this.userName);
|
||||
statusPanel.add(status);
|
||||
|
||||
this.getContentPane().add(jScrollPane1, java.awt.BorderLayout.CENTER);
|
||||
this.getContentPane().add(statusPanel, java.awt.BorderLayout.PAGE_END);
|
||||
|
||||
this.pack();
|
||||
}
|
||||
|
||||
private void initSocket() {
|
||||
this.socketUDP = new SocketUDP(this);
|
||||
this.socketTCP = new SocketTCP(this);
|
||||
|
||||
this.socketUDP.start();
|
||||
this.socketTCP.start();
|
||||
private void initUserPanel() {
|
||||
onlineUsersPanel = new OnlineUsersPanel();
|
||||
this.connectionManager.addPeerListener(onlineUsersPanel);
|
||||
this.getContentPane().add(onlineUsersPanel, java.awt.BorderLayout.LINE_END);
|
||||
}
|
||||
|
||||
private void initHeartbeat() {
|
||||
this.heartbeatManager = new HeartbeatManager(this);
|
||||
this.onlineUsersPanel = new OnlineUsersPanel();
|
||||
this.heartbeatManager.addPeerListener(this.onlineUsersPanel);
|
||||
this.getContentPane().add(this.onlineUsersPanel, java.awt.BorderLayout.LINE_END);
|
||||
this.heartbeatManager.start();
|
||||
}
|
||||
private void initStatusPanel() {
|
||||
JPanel statusPanel = new JPanel();
|
||||
status = new JLabel();
|
||||
|
||||
private void initPlugins() {
|
||||
this.pluginManager = new PluginLoader(this);
|
||||
this.pluginManager.loadPlugins();
|
||||
statusPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||
updateStatus();
|
||||
statusPanel.add(status);
|
||||
|
||||
this.getContentPane().add(statusPanel, BorderLayout.PAGE_END);
|
||||
}
|
||||
|
||||
public void exit() {
|
||||
@@ -122,65 +99,21 @@ public class MainWindow extends javax.swing.JFrame {
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public HeartbeatManager getHeartbeatManager() {
|
||||
return heartbeatManager;
|
||||
public ConnectionManager getConnectionManager() {
|
||||
return connectionManager;
|
||||
}
|
||||
|
||||
public String getUserName(){
|
||||
return this.userName;
|
||||
}
|
||||
|
||||
public String getIdentifier(){
|
||||
return this.pitiupiIdentifier;
|
||||
}
|
||||
|
||||
public void addMenu(JMenu menu) {
|
||||
this.menuBar.addPlugin(menu);
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public SocketUDP getSocketUDP() {
|
||||
return this.socketUDP;
|
||||
}
|
||||
|
||||
public SocketTCP getSocketTCP() {
|
||||
return this.socketTCP;
|
||||
}
|
||||
|
||||
public List<Plugin> getPlugins() {
|
||||
return plugins;
|
||||
public void loadPlugins() {
|
||||
pluginManager.loadPlugins(connectionManager, guiManager);
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.userName = userName;
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
reconnect();
|
||||
connectionManager.setUserName(userName);
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
private void updateStatus() {
|
||||
this.status.setText("Connected on port " + this.port + " name " + this.userName);
|
||||
this.status.setText("Connected on port " + connectionManager.getPort() + " name " + connectionManager.getUserName());
|
||||
}
|
||||
|
||||
private void reconnect() {
|
||||
if (this.socketUDP != null) {
|
||||
this.socketUDP.close();
|
||||
}
|
||||
if (this.socketTCP != null) {
|
||||
this.socketTCP.close();
|
||||
}
|
||||
|
||||
this.socketUDP = new SocketUDP(this);
|
||||
this.socketTCP = new SocketTCP(this);
|
||||
|
||||
this.socketUDP.start();
|
||||
this.socketTCP.start();
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,14 @@
|
||||
*/
|
||||
package pitiupi.GUI;
|
||||
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import pitiupi.models.Menus.MenuCategory;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Barra de menus principal da aplicação.
|
||||
@@ -21,12 +27,14 @@ import javax.swing.JMenuBar;
|
||||
*/
|
||||
public class MenuBar extends JMenuBar {
|
||||
|
||||
private javax.swing.JMenuItem setupMenu;
|
||||
private javax.swing.JMenuItem aboutMenu;
|
||||
private javax.swing.JMenu fileMenu;
|
||||
private javax.swing.JMenu helpMenu;
|
||||
private javax.swing.JMenu pluginMenu;
|
||||
private javax.swing.JMenuItem exitMenu;
|
||||
private JMenuItem preferencesMenu;
|
||||
private JMenuItem aboutMenu;
|
||||
private JMenu fileMenu;
|
||||
private JMenu helpMenu;
|
||||
private JMenu pluginMenu;
|
||||
private Map<MenuCategory, JMenu> categories;
|
||||
|
||||
private JMenuItem exitMenu;
|
||||
private final MainWindow mainWindow;
|
||||
|
||||
/**
|
||||
@@ -40,63 +48,70 @@ public class MenuBar extends JMenuBar {
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
fileMenu = new javax.swing.JMenu();
|
||||
exitMenu = new javax.swing.JMenuItem();
|
||||
helpMenu = new javax.swing.JMenu();
|
||||
pluginMenu = new javax.swing.JMenu();
|
||||
setupMenu = new javax.swing.JMenuItem();
|
||||
aboutMenu = new javax.swing.JMenuItem();
|
||||
initFileMenu();
|
||||
initPluginMenu();
|
||||
initHelpMenu();
|
||||
}
|
||||
|
||||
fileMenu.setText("File");
|
||||
exitMenu.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.ALT_MASK));
|
||||
exitMenu.setText("Exit");
|
||||
private void initFileMenu() {
|
||||
fileMenu = new JMenu("File");
|
||||
exitMenu = new JMenuItem("Exit");
|
||||
|
||||
exitMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_DOWN_MASK));
|
||||
exitMenu.addActionListener(this::exitMenuActionPerformed);
|
||||
fileMenu.add(exitMenu);
|
||||
this.add(fileMenu);
|
||||
}
|
||||
|
||||
private void initPluginMenu() {
|
||||
pluginMenu = new JMenu("Plugin");
|
||||
categories = new HashMap<>();
|
||||
|
||||
for (MenuCategory category : MenuCategory.values()) {
|
||||
JMenu newCategoryMenu = new JMenu(category.toString());
|
||||
|
||||
pluginMenu.add(newCategoryMenu);
|
||||
categories.put(category, newCategoryMenu);
|
||||
}
|
||||
|
||||
pluginMenu.setText("Plugin");
|
||||
this.add(pluginMenu);
|
||||
}
|
||||
|
||||
helpMenu.setText("Help");
|
||||
private void initHelpMenu() {
|
||||
helpMenu = new JMenu("Help");
|
||||
preferencesMenu = new JMenuItem("Preferences");
|
||||
aboutMenu = new JMenuItem("About");
|
||||
|
||||
setupMenu.setText("Preferences");
|
||||
setupMenu.addActionListener(this::setupMenuActionPerformed);
|
||||
helpMenu.add(setupMenu);
|
||||
preferencesMenu.addActionListener(this::setupMenuActionPerformed);
|
||||
helpMenu.add(preferencesMenu);
|
||||
|
||||
aboutMenu.setText("About");
|
||||
aboutMenu.addActionListener(this::aboutMenuActionPerformed);
|
||||
helpMenu.add(aboutMenu);
|
||||
|
||||
this.add(helpMenu);
|
||||
}
|
||||
|
||||
private void exitMenuActionPerformed(java.awt.event.ActionEvent evt) {
|
||||
private void exitMenuActionPerformed(ActionEvent evt) {
|
||||
mainWindow.exit();
|
||||
}
|
||||
|
||||
|
||||
private void setupMenuActionPerformed(java.awt.event.ActionEvent evt) {
|
||||
private void setupMenuActionPerformed(ActionEvent evt) {
|
||||
Login login = new Login();
|
||||
login.setVisible(true);
|
||||
|
||||
mainWindow.setUserName(login.getName());
|
||||
mainWindow.setPort(login.getPort());
|
||||
mainWindow.getConnectionManager().setPort(login.getPort());
|
||||
|
||||
login.dispose();
|
||||
}
|
||||
|
||||
private void aboutMenuActionPerformed(java.awt.event.ActionEvent evt) {
|
||||
private void aboutMenuActionPerformed(ActionEvent evt) {
|
||||
About about = new About();
|
||||
about.setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adiciona um menu fornecido por um plugin à seção de plugins da barra
|
||||
* de menus.
|
||||
*
|
||||
* @param menu menu criado pelo plugin.
|
||||
*/
|
||||
public void addPlugin(JMenu menu){
|
||||
this.pluginMenu.add(menu);
|
||||
public void addPluginMenu(MenuCategory category, JMenuItem menu){
|
||||
System.out.println("addPluginMenu");
|
||||
categories.get(category).add(menu);
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,16 @@ package pitiupi.GUI;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import pitiupi.control.PeerInfo;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import javax.swing.*;
|
||||
|
||||
import pitiupi.models.Menus.MenuCategory;
|
||||
import pitiupi.models.User;
|
||||
import pitiupi.control.PeerListener;
|
||||
|
||||
/**
|
||||
@@ -20,10 +22,16 @@ import pitiupi.control.PeerListener;
|
||||
*/
|
||||
public class OnlineUsersPanel extends JPanel implements PeerListener {
|
||||
|
||||
private final DefaultListModel<String> listModel;
|
||||
private final JList<String> userList;
|
||||
private final DefaultListModel<User> listModel;
|
||||
private final JList<User> userList;
|
||||
JPopupMenu menu;
|
||||
private Map<MenuCategory, JMenu> categories;
|
||||
|
||||
public OnlineUsersPanel() {
|
||||
menu = new JPopupMenu();
|
||||
categories = new HashMap<>();
|
||||
initMenu();
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(BorderFactory.createTitledBorder("Online"));
|
||||
setPreferredSize(new Dimension(160, 0));
|
||||
@@ -31,6 +39,48 @@ public class OnlineUsersPanel extends JPanel implements PeerListener {
|
||||
listModel = new DefaultListModel<>();
|
||||
userList = new JList<>(listModel);
|
||||
add(new JScrollPane(userList), BorderLayout.CENTER);
|
||||
|
||||
setupUserListActions();
|
||||
}
|
||||
|
||||
private void initMenu() {
|
||||
for (MenuCategory category : MenuCategory.values()) {
|
||||
JMenu newCategory = new JMenu(category.toString());
|
||||
|
||||
menu.add(newCategory);
|
||||
categories.put(category, newCategory);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupUserListActions() {
|
||||
userList.addMouseListener(new MouseAdapter() {
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
int index = userList.locationToIndex(e.getPoint());
|
||||
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
userList.setSelectedIndex(index);
|
||||
menu.show(userList, e.getX(), e.getY());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void initUnicastMenu(JMenuItem menuItem, Consumer<User> action) {
|
||||
menuItem.addActionListener(e -> {
|
||||
User user = userList.getSelectedValue();
|
||||
|
||||
if (user != null) {
|
||||
action.accept(user);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addUnicastMenu(MenuCategory category, JMenuItem menuItem) {
|
||||
categories.get(category).add(menuItem);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -39,11 +89,11 @@ public class OnlineUsersPanel extends JPanel implements PeerListener {
|
||||
* @param peers lista atualizada de usuários ativos na rede.
|
||||
*/
|
||||
@Override
|
||||
public void onPeersChanged(List<PeerInfo> peers) {
|
||||
public void onPeersChanged(List<User> peers) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
listModel.clear();
|
||||
for (PeerInfo peer : peers) {
|
||||
listModel.addElement(peer.toString());
|
||||
for (User peer : peers) {
|
||||
listModel.addElement(peer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package pitiupi.control;
|
||||
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.control.plugins.PluginManager;
|
||||
import pitiupi.models.Messages.HeartbeatMessage;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.net.tcp.SocketTCP;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
import pitiupi.net.udp.SocketUDP;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class ConnectionManager {
|
||||
private final String pitiupiIdentifier;
|
||||
|
||||
private final PluginManager pluginManager;
|
||||
|
||||
private final HeartbeatManager heartbeatManager;
|
||||
|
||||
private SocketTCP socketTCP;
|
||||
private SocketUDP socketUDP;
|
||||
private String username;
|
||||
private int port;
|
||||
|
||||
public ConnectionManager(MainWindow main, String username, PluginManager pluginManager, int port) {
|
||||
this.pluginManager = pluginManager;
|
||||
|
||||
this.username = username;
|
||||
this.port = port;
|
||||
|
||||
pitiupiIdentifier = "Pitiupi.Alice.2026";
|
||||
|
||||
reconnect();
|
||||
|
||||
heartbeatManager = new HeartbeatManager(this);
|
||||
heartbeatManager.start();
|
||||
}
|
||||
|
||||
public TcpConnection connectPluginTcp(InetAddress destinationAdress, String senderId, String receiverId) {
|
||||
return socketTCP.createPrivateConnection(destinationAdress, senderId, receiverId);
|
||||
}
|
||||
|
||||
public boolean sendTcp(Message message, InetAddress destinationAddress) {
|
||||
return socketTCP.send(message, destinationAddress);
|
||||
}
|
||||
|
||||
public boolean sendUdpUnicast(Message message, InetAddress destinationAddress) {
|
||||
try {
|
||||
socketUDP.sendUnicast(message, destinationAddress);
|
||||
return true;
|
||||
} catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean sendUdpMulticast(Message message) {
|
||||
try {
|
||||
socketUDP.sendMulticast(message);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error sending UDP Multicast");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void broadcastLocal(byte[] message) {
|
||||
pluginManager.handleMessage(message);
|
||||
}
|
||||
|
||||
public void addPeerListener(PeerListener peerListener) {
|
||||
heartbeatManager.addPeerListener(peerListener);
|
||||
}
|
||||
|
||||
public void receiveHeartbeat(HeartbeatMessage message, InetAddress destinationAddress) {
|
||||
heartbeatManager.receiveHeartbeat(message, destinationAddress);
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
reconnect();
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getIdentifier(){
|
||||
return this.pitiupiIdentifier;
|
||||
}
|
||||
|
||||
private void reconnect() {
|
||||
if (this.socketUDP != null) {
|
||||
this.socketUDP.close();
|
||||
}
|
||||
if (this.socketTCP != null) {
|
||||
this.socketTCP.close();
|
||||
}
|
||||
|
||||
this.socketUDP = new SocketUDP(this, pluginManager);
|
||||
this.socketTCP = new SocketTCP(this, pluginManager);
|
||||
|
||||
this.socketUDP.start();
|
||||
this.socketTCP.start();
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return this.username;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.username = userName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package pitiupi.control;
|
||||
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.GUI.MenuBar;
|
||||
import pitiupi.GUI.OnlineUsersPanel;
|
||||
import pitiupi.models.Menus.*;
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastActionMenu;
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastMenu;
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastSubMenu;
|
||||
import pitiupi.models.Menus.UnicastMenus.UnicastActionMenu;
|
||||
import pitiupi.models.Menus.UnicastMenus.UnicastMenu;
|
||||
import pitiupi.models.Menus.UnicastMenus.UnicastSubMenu;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class GuiManager {
|
||||
private MainWindow mainWindow;
|
||||
private MenuBar menuBar;
|
||||
private OnlineUsersPanel onlineUsersPanel;
|
||||
|
||||
private Logger logger;
|
||||
|
||||
public GuiManager(MainWindow mainWindow, MenuBar menuBar, OnlineUsersPanel onlineUsersPanel) {
|
||||
this.mainWindow = mainWindow;
|
||||
this.menuBar = menuBar;
|
||||
this.onlineUsersPanel = onlineUsersPanel;
|
||||
this.logger = Logger.getLogger(GuiManager.class.getName());
|
||||
}
|
||||
|
||||
public void createMenu(MenuCategory category, Menu menu) {
|
||||
System.out.println(
|
||||
menu.getClass().getSuperclass().getSuperclass()
|
||||
);
|
||||
|
||||
System.out.println(
|
||||
MulticastMenu.class
|
||||
);
|
||||
|
||||
System.out.println(
|
||||
menu.getClass().getSuperclass().getSuperclass()
|
||||
== MulticastMenu.class
|
||||
);
|
||||
try {
|
||||
JMenuItem newMenu = buildMenu(menu);
|
||||
if (menu instanceof MulticastMenu) {
|
||||
menuBar.addPluginMenu(category, newMenu);
|
||||
}
|
||||
if (menu instanceof UnicastMenu) {
|
||||
onlineUsersPanel.addUnicastMenu(category, newMenu);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
logger.log(Level.WARNING, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private JMenuItem buildMenu(Menu menu) {
|
||||
if (menu instanceof MulticastSubMenu multicastSubMenu) {
|
||||
JMenu newMenu = new JMenu(menu.getText());
|
||||
|
||||
for (Menu child : multicastSubMenu.getMenus()) {
|
||||
newMenu.add(buildMenu(child));
|
||||
}
|
||||
|
||||
return newMenu;
|
||||
}
|
||||
|
||||
if (menu instanceof UnicastSubMenu unicastSubMenu) {
|
||||
JMenu newMenu = new JMenu(menu.getText());
|
||||
|
||||
for (Menu child : unicastSubMenu.getMenus()) {
|
||||
newMenu.add(buildMenu(child));
|
||||
}
|
||||
|
||||
return newMenu;
|
||||
}
|
||||
|
||||
if (menu instanceof MulticastActionMenu multicastActionMenu) {
|
||||
JMenuItem newMenu = new JMenuItem(menu.getText());
|
||||
newMenu.addActionListener(e -> multicastActionMenu.onClick());
|
||||
return newMenu;
|
||||
}
|
||||
|
||||
if (menu instanceof UnicastActionMenu unicastActionMenu) {
|
||||
JMenuItem newMenu = new JMenuItem(menu.getText());
|
||||
|
||||
onlineUsersPanel.initUnicastMenu(newMenu, unicastActionMenu::onClick);
|
||||
return newMenu;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Invalid menu type");
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package pitiupi.control;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -10,10 +9,9 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.net.HeartbeatMessage;
|
||||
|
||||
import pitiupi.models.User;
|
||||
import pitiupi.models.Messages.HeartbeatMessage;
|
||||
import java.util.UUID;
|
||||
/**
|
||||
* Gerencia o mecanismo de heartbeat da aplicação.
|
||||
@@ -28,9 +26,8 @@ public class HeartbeatManager {
|
||||
|
||||
private static final long HEARTBEAT_INTERVAL_MS = 5000;
|
||||
private static final long PEER_TIMEOUT_MS = 15000; // ~3 batimentos perdidos
|
||||
|
||||
private final MainWindow mainWindow;
|
||||
private final Map<String, PeerInfo> peers = new ConcurrentHashMap<>();
|
||||
private final ConnectionManager connectionManager;
|
||||
private final Map<String, User> peers = new ConcurrentHashMap<>();
|
||||
private final List<PeerListener> listeners = new CopyOnWriteArrayList<>();
|
||||
private ScheduledExecutorService scheduler;
|
||||
private final String instanceId = UUID.randomUUID().toString();
|
||||
@@ -38,11 +35,9 @@ public class HeartbeatManager {
|
||||
/**
|
||||
* Cria um gerenciador de heartbeat associado à janela principal da aplicação.
|
||||
*
|
||||
* @param mainWindow janela principal utilizada para obter o nome do usuário
|
||||
* e o socket de comunicação.
|
||||
*/
|
||||
public HeartbeatManager(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
public HeartbeatManager(ConnectionManager connectionManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,12 +59,8 @@ public class HeartbeatManager {
|
||||
}
|
||||
|
||||
private void announce() {
|
||||
try {
|
||||
HeartbeatMessage msg = new HeartbeatMessage(mainWindow.getUserName(), instanceId);
|
||||
mainWindow.getSocketUDP().sendMulticast(msg);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(HeartbeatManager.class.getName()).log(Level.WARNING, "Falha ao enviar heartbeat", ex);
|
||||
}
|
||||
HeartbeatMessage msg = new HeartbeatMessage(connectionManager.getUserName(), instanceId);
|
||||
connectionManager.sendUdpMulticast(msg);
|
||||
}
|
||||
|
||||
// Chamado pelo Socket quando um pacote é identificado como heartbeat
|
||||
@@ -94,7 +85,7 @@ public class HeartbeatManager {
|
||||
String key = msg.getInstanceId();
|
||||
boolean isNew = !peers.containsKey(key);
|
||||
|
||||
PeerInfo peer = peers.computeIfAbsent(key, k -> new PeerInfo(msg.getUserName(), from, msg.getTimestamp()));
|
||||
User peer = peers.computeIfAbsent(key, k -> new User(msg.getUserName(), from, msg.getTimestamp()));
|
||||
peer.touch(System.currentTimeMillis());
|
||||
|
||||
if (isNew) {
|
||||
@@ -111,7 +102,7 @@ public class HeartbeatManager {
|
||||
}
|
||||
|
||||
private void notifyListeners() {
|
||||
List<PeerInfo> snapshot = new ArrayList<>(peers.values());
|
||||
List<User> snapshot = new ArrayList<>(peers.values());
|
||||
for (PeerListener l : listeners) {
|
||||
l.onPeersChanged(snapshot);
|
||||
}
|
||||
@@ -144,7 +135,7 @@ public class HeartbeatManager {
|
||||
*
|
||||
* @return lista contendo os peers atualmente conhecidos.
|
||||
*/
|
||||
public List<PeerInfo> getPeers() {
|
||||
public List<User> getPeers() {
|
||||
return new ArrayList<>(peers.values());
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package pitiupi.control;
|
||||
|
||||
import pitiupi.models.User;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -17,5 +19,5 @@ public interface PeerListener {
|
||||
*
|
||||
* @param peers lista atualizada de usuários ativos.
|
||||
*/
|
||||
void onPeersChanged(List<PeerInfo> peers);
|
||||
void onPeersChanged(List<User> peers);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template
|
||||
*/
|
||||
package pitiupi.control;
|
||||
|
||||
import java.awt.List;
|
||||
import java.io.File;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Vector;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.Main;
|
||||
import pitiupi.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Responsável por localizar, carregar e registrar os plugins
|
||||
* presentes no diretório {@code plugins}.
|
||||
*
|
||||
* <p>Os plugins são descobertos utilizando {@link java.util.ServiceLoader}
|
||||
* e devem estar empacotados como arquivos JAR contendo a configuração
|
||||
* {@code META-INF/services} correspondente.</p>
|
||||
* @author flavio
|
||||
*/
|
||||
public class PluginLoader {
|
||||
|
||||
private final pitiupi.GUI.MainWindow mainWindow;
|
||||
|
||||
public PluginLoader(MainWindow main) {
|
||||
this.mainWindow = main;
|
||||
}
|
||||
|
||||
public void loadPlugins() {
|
||||
File pluginDir = new File("plugins");
|
||||
File[] jarFiles = pluginDir.listFiles((dir, name) -> name.endsWith(".jar"));
|
||||
|
||||
if (jarFiles == null || jarFiles.length == 0) {
|
||||
System.out.println("No plugins found in the " + pluginDir.getAbsolutePath() + " directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 2. Convert jar file paths into URLs
|
||||
ArrayList urls = new ArrayList();
|
||||
for (File file : jarFiles) {
|
||||
urls.add(file.toURI().toURL());
|
||||
System.out.println("Discovered plugin package: " + file.getName());
|
||||
}
|
||||
|
||||
// 3. Create a class loader isolated from the application's default loader
|
||||
URLClassLoader pluginClassLoader = new URLClassLoader(
|
||||
(URL[])urls.toArray(new URL[0]),
|
||||
Main.class.getClassLoader()
|
||||
);
|
||||
System.out.println(pluginClassLoader);
|
||||
|
||||
// 4. Locate and instantiate all classes implementing the Plugin interface
|
||||
ServiceLoader<Plugin> serviceLoader = ServiceLoader.load(Plugin.class, pluginClassLoader);
|
||||
|
||||
System.out.println("\n--- Executing Discovered Plugins ---" + serviceLoader.findFirst());
|
||||
for (Plugin plugin : serviceLoader) {
|
||||
System.out.println("Loading: " + plugin.getName());
|
||||
plugin.createPlugin(this.mainWindow);
|
||||
this.mainWindow.getPlugins().add(plugin);
|
||||
}
|
||||
|
||||
} catch (MalformedURLException e) {
|
||||
System.out.println(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package pitiupi.control.plugins;
|
||||
|
||||
import pitiupi.models.Plugin;
|
||||
|
||||
class LoadedPlugin {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public LoadedPlugin(Plugin plugin, ClassLoader classLoader) {
|
||||
this.plugin = plugin;
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public ClassLoader getClassLoader() {
|
||||
return classLoader;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package pitiupi.control.plugins;
|
||||
|
||||
import pitiupi.Main;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.GuiManager;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
import pitiupi.models.Plugin;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PluginManager {
|
||||
private final List<LoadedPlugin> loadedPlugins;
|
||||
private final HashSet<String> loadedJars;
|
||||
|
||||
private final Logger logger;
|
||||
|
||||
public PluginManager() {
|
||||
this.loadedPlugins = new ArrayList<>();
|
||||
this.loadedJars = new HashSet<>();
|
||||
|
||||
logger = Logger.getLogger(getClass().getName());
|
||||
}
|
||||
|
||||
public void handleMessage(byte[] msg) {
|
||||
Message message = null;
|
||||
|
||||
for (LoadedPlugin loadedPlugin : loadedPlugins) {
|
||||
message = deserialize(msg, loadedPlugin.getClassLoader());
|
||||
if (message != null) break;
|
||||
}
|
||||
if (message == null) return;
|
||||
|
||||
for (LoadedPlugin loadedPlugin : loadedPlugins) {
|
||||
Plugin plugin = loadedPlugin.getPlugin();
|
||||
|
||||
if (plugin.receiveAllTypes() && message.isPublic()) {
|
||||
plugin.receiveMessage(message);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Class<? extends Message> messageType : plugin.getMessages()) {
|
||||
if (messageType.isInstance(message)) {
|
||||
plugin.receiveMessage(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Plugin getPlugin(String pluginId) {
|
||||
for (LoadedPlugin loadedPlugin : loadedPlugins) {
|
||||
if (loadedPlugin.getPlugin().getIdentifier().equals(pluginId))
|
||||
return loadedPlugin.getPlugin();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void handleMessageFromConnection(TcpConnection connection, byte[] msg) {
|
||||
Plugin plugin = getPlugin(connection.getReceiver());
|
||||
if (plugin == null) return;
|
||||
|
||||
plugin.receiveBytes(connection, msg);
|
||||
}
|
||||
|
||||
public boolean handleConnection(TcpConnection connection, String receiverId) {
|
||||
Plugin plugin = getPlugin(receiverId);
|
||||
if (plugin == null) return false;
|
||||
|
||||
plugin.receivePrivateConnection(connection);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void handleDisconnection(TcpConnection connection, String receiverId) {
|
||||
Plugin plugin = getPlugin(receiverId);
|
||||
if (plugin == null) return;
|
||||
|
||||
plugin.onSocketClosed(connection);
|
||||
}
|
||||
|
||||
public void loadPlugins(ConnectionManager connectionManager, GuiManager guiManager) {
|
||||
File pluginDir = new File("plugins");
|
||||
File[] jarFiles = pluginDir.listFiles((dir, name) -> name.endsWith(".jar"));
|
||||
|
||||
if (jarFiles == null || jarFiles.length == 0) {
|
||||
System.out.println("No plugins found in the " + pluginDir.getAbsolutePath() + " directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : jarFiles) {
|
||||
|
||||
if (loadedJars.contains(file.getName())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
System.out.println("Discovered plugin package: " + file.getName());
|
||||
|
||||
try {
|
||||
URLClassLoader classLoader = new URLClassLoader(
|
||||
new URL[]{file.toURI().toURL()},
|
||||
Main.class.getClassLoader()
|
||||
);
|
||||
|
||||
ServiceLoader<Plugin> serviceLoader = ServiceLoader.load(Plugin.class, classLoader);
|
||||
|
||||
for (Plugin plugin : serviceLoader) {
|
||||
System.out.println("Loading: " + plugin.getName());
|
||||
LoadedPlugin loadedPlugin = new LoadedPlugin(plugin, classLoader);
|
||||
|
||||
plugin.createPlugin(connectionManager, guiManager);
|
||||
loadedPlugins.add(loadedPlugin);
|
||||
loadedJars.add(file.getName());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.WARNING, "Failed to load plugin " + file.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Message deserialize(byte[] data, ClassLoader classLoader) {
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(data);
|
||||
|
||||
PluginObjectInputStream objectInput = new PluginObjectInputStream(input, classLoader);
|
||||
|
||||
Object object = objectInput.readObject();
|
||||
|
||||
if (!(object instanceof Message)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (Message) object;
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
catch (IOException e) {
|
||||
logger.log(Level.SEVERE, "Failed to load plugin package", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package pitiupi.control.plugins;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
|
||||
public class PluginObjectInputStream extends ObjectInputStream {
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public PluginObjectInputStream(InputStream input, ClassLoader classLoader) throws IOException {
|
||||
super(input);
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> resolveClass(ObjectStreamClass description) throws ClassNotFoundException {
|
||||
return Class.forName(description.getName(), false, classLoader);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package pitiupi.models.Menus;
|
||||
|
||||
public abstract class Menu {
|
||||
public abstract String getText();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package pitiupi.models.Menus;
|
||||
|
||||
public enum MenuCategory {
|
||||
Jogos,
|
||||
Social,
|
||||
Streaming
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package pitiupi.models.Menus.MulticastMenus;
|
||||
|
||||
public abstract class MulticastActionMenu extends MulticastMenu{
|
||||
public abstract void onClick();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package pitiupi.models.Menus.MulticastMenus;
|
||||
|
||||
import pitiupi.models.Menus.Menu;
|
||||
|
||||
public abstract class MulticastMenu extends Menu {
|
||||
MulticastMenu() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package pitiupi.models.Menus.MulticastMenus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MulticastSubMenu extends MulticastMenu{
|
||||
public abstract List<MulticastMenu> getMenus();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package pitiupi.models.Menus.UnicastMenus;
|
||||
|
||||
import pitiupi.models.User;
|
||||
|
||||
public abstract class UnicastActionMenu extends UnicastMenu{
|
||||
public abstract void onClick(User user);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package pitiupi.models.Menus.UnicastMenus;
|
||||
|
||||
import pitiupi.models.Menus.Menu;
|
||||
import pitiupi.models.User;
|
||||
|
||||
public abstract class UnicastMenu extends Menu {
|
||||
UnicastMenu() {}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package pitiupi.models.Menus.UnicastMenus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class UnicastSubMenu extends UnicastMenu{
|
||||
public abstract List<UnicastMenu> getMenus();
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package pitiupi.net;
|
||||
package pitiupi.models.Messages;
|
||||
|
||||
/**
|
||||
* Mensagem utilizada para sinalizar a presença de um usuário na rede.
|
||||
+13
-14
@@ -1,6 +1,6 @@
|
||||
package pitiupi.net.tcp;
|
||||
package pitiupi.models.Messages;
|
||||
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -8,12 +8,11 @@ import java.io.ObjectInputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class SysInfoMessage extends Message {
|
||||
|
||||
private final SysInfoType type;
|
||||
public class InfoMessage extends Message {
|
||||
private final InfoType type;
|
||||
private final String message;
|
||||
|
||||
public SysInfoMessage(String message, SysInfoType type) {
|
||||
public InfoMessage(String message, InfoType type) {
|
||||
this.message = message;
|
||||
this.type = type;
|
||||
}
|
||||
@@ -22,29 +21,29 @@ public class SysInfoMessage extends Message {
|
||||
return message;
|
||||
}
|
||||
|
||||
public SysInfoType getType() {
|
||||
public InfoType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static void sendSystemInfo(TcpConnection connection, SysInfoType type, String description) {
|
||||
public static void sendSystemInfo(TcpConnection connection, InfoType type, String description) {
|
||||
try {
|
||||
SysInfoMessage error = new SysInfoMessage(description, type);
|
||||
InfoMessage error = new InfoMessage(description, type);
|
||||
connection.send(error.toByteArray());
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(SysInfoMessage.class.getName()).log(Level.WARNING, null, ex);
|
||||
Logger.getLogger(InfoMessage.class.getName()).log(Level.WARNING, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static SysInfoMessage parseSystemInfo(byte[] bytes) {
|
||||
public static InfoMessage parseSystemInfo(byte[] bytes) {
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(bis)) {
|
||||
|
||||
Object object = ois.readObject();
|
||||
if (object instanceof SysInfoMessage) {
|
||||
return (SysInfoMessage) object;
|
||||
if (object instanceof InfoMessage) {
|
||||
return (InfoMessage) object;
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException ex) {
|
||||
Logger.getLogger(SysInfoMessage.class.getName()).log(Level.WARNING, null, ex);
|
||||
Logger.getLogger(InfoMessage.class.getName()).log(Level.WARNING, null, ex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package pitiupi.net.tcp;
|
||||
package pitiupi.models.Messages;
|
||||
|
||||
public enum SysInfoType {
|
||||
public enum InfoType {
|
||||
CONNECTION_REJECTED,
|
||||
RECEIVER_NOT_FOUND,
|
||||
MESSAGE_REJECTED,
|
||||
+14
-1
@@ -3,7 +3,7 @@
|
||||
* To change this template file, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
package pitiupi.net;
|
||||
package pitiupi.models.Messages;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -24,6 +24,19 @@ import java.io.Serializable;
|
||||
* @author flavio
|
||||
*/
|
||||
public abstract class Message implements Serializable{
|
||||
private boolean isPublic;
|
||||
|
||||
protected Message(){
|
||||
isPublic = true;
|
||||
}
|
||||
|
||||
protected Message(boolean isPublic){
|
||||
this.isPublic = isPublic;
|
||||
}
|
||||
|
||||
public boolean isPublic(){
|
||||
return isPublic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializa a mensagem para um vetor de bytes.
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
|
||||
*/
|
||||
package pitiupi.models;
|
||||
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.GuiManager;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Interface base para plugins da aplicação.
|
||||
*
|
||||
* <p>Cada plugin deve implementar esta interface para ser carregado
|
||||
* pela aplicação e participar do sistema de comunicação por mensagens.</p>
|
||||
*
|
||||
* @author flavio
|
||||
*/
|
||||
public abstract class Plugin {
|
||||
public abstract String getName();
|
||||
public abstract String getAuthor();
|
||||
public abstract String getVersion();
|
||||
public abstract String getIdentifier();
|
||||
|
||||
/**
|
||||
* Inicializa o plugin.
|
||||
*
|
||||
* <p>Este método é chamado pela aplicação após o carregamento do plugin.</p>
|
||||
*
|
||||
* @param connectionManager interface com o sistema de conexões da aplicação.
|
||||
* @param guiManager interface com a janela principal da aplicação
|
||||
*/
|
||||
public abstract void createPlugin(ConnectionManager connectionManager, GuiManager guiManager);
|
||||
|
||||
/**
|
||||
* Retorna uma mensagem utilizada pelo plugin.
|
||||
*
|
||||
* @return mensagem criada pelo plugin.
|
||||
*/
|
||||
public abstract List<Class<? extends Message>> getMessages();
|
||||
|
||||
/**
|
||||
* Recebe uma mensagem enviada pela aplicação.
|
||||
*
|
||||
* <p>A mensagem é recebida em formato serializado. O plugin deve verificar
|
||||
* se a mensagem pertence ao seu tipo e realizar o processamento necessário.</p>
|
||||
*
|
||||
* @param message mensagem serializada recebida.
|
||||
*/
|
||||
public abstract void receiveMessage(Message message);
|
||||
|
||||
public boolean receiveAllTypes() {return false;}
|
||||
public boolean receivePrivateConnection(TcpConnection connection) {
|
||||
return false;
|
||||
}
|
||||
public boolean receiveBytes(TcpConnection connection, byte[] bytes) {
|
||||
return false;
|
||||
}
|
||||
public boolean onSocketClosed(TcpConnection connection) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package pitiupi.control;
|
||||
package pitiupi.models;
|
||||
|
||||
import java.net.InetAddress;
|
||||
/**
|
||||
@@ -10,13 +10,13 @@ import java.net.InetAddress;
|
||||
*
|
||||
* @author tony
|
||||
*/
|
||||
public class PeerInfo {
|
||||
public class User {
|
||||
|
||||
private final String userName;
|
||||
private final InetAddress address;
|
||||
private volatile long lastSeen;
|
||||
|
||||
public PeerInfo(String userName, InetAddress address, long lastSeen) {
|
||||
public User(String userName, InetAddress address, long lastSeen) {
|
||||
this.userName = userName;
|
||||
this.address = address;
|
||||
this.lastSeen = lastSeen;
|
||||
@@ -1,6 +1,8 @@
|
||||
package pitiupi.net.tcp;
|
||||
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.models.Messages.InfoMessage;
|
||||
import pitiupi.models.Messages.InfoType;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
@@ -24,7 +26,7 @@ import java.util.logging.Logger;
|
||||
* a utilizar o timeout padrão definido por {@link #STANDARD_TIMEOUT}.</p>
|
||||
*/
|
||||
public class ConnectionFactory {
|
||||
private static final int HANDSHAKE_TIMEOUT = 5000;
|
||||
private static final int HANDSHAKE_TIMEOUT = 1000;
|
||||
private static final int STANDARD_TIMEOUT = 300_000;
|
||||
|
||||
/**
|
||||
@@ -64,7 +66,9 @@ public class ConnectionFactory {
|
||||
connection.send(handshake.toByteArray());
|
||||
HandshakeMessage handshakeResponse = validateConnection(connection);
|
||||
|
||||
if (handshakeResponse == null) return null;
|
||||
if (handshakeResponse == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
connection.setTimeout(STANDARD_TIMEOUT);
|
||||
|
||||
@@ -102,7 +106,6 @@ public class ConnectionFactory {
|
||||
|
||||
if (handshake == null) return null;
|
||||
|
||||
|
||||
connection.send(handshake.createResponse().toByteArray());
|
||||
|
||||
connection.setSender(handshake.getSender());
|
||||
@@ -151,7 +154,7 @@ public class ConnectionFactory {
|
||||
Object object = ois.readObject();
|
||||
|
||||
if (object instanceof Message message) {
|
||||
SysInfoMessage sysInfo = SysInfoMessage.parseSystemInfo(bytes);
|
||||
InfoMessage sysInfo = InfoMessage.parseSystemInfo(bytes);
|
||||
if (sysInfo != null) return null;
|
||||
|
||||
|
||||
@@ -160,25 +163,25 @@ public class ConnectionFactory {
|
||||
}
|
||||
}
|
||||
|
||||
SysInfoMessage.sendSystemInfo(
|
||||
InfoMessage.sendSystemInfo(
|
||||
connection,
|
||||
SysInfoType.CONNECTION_REJECTED,
|
||||
InfoType.CONNECTION_REJECTED,
|
||||
"The message was not from an allowed type."
|
||||
);
|
||||
}
|
||||
catch (SocketTimeoutException ex) {
|
||||
SysInfoMessage.sendSystemInfo(
|
||||
InfoMessage.sendSystemInfo(
|
||||
connection,
|
||||
SysInfoType.CONNECTION_REJECTED,
|
||||
InfoType.CONNECTION_REJECTED,
|
||||
"No handshake was received within the allowed time."
|
||||
);
|
||||
}
|
||||
catch (ClassNotFoundException | IOException ex) {
|
||||
Logger.getLogger(ConnectionFactory.class.getName()).log(Level.SEVERE, null, ex);
|
||||
|
||||
SysInfoMessage.sendSystemInfo(
|
||||
InfoMessage.sendSystemInfo(
|
||||
connection,
|
||||
SysInfoType.INTERNAL_ERROR,
|
||||
InfoType.INTERNAL_ERROR,
|
||||
"The server could not process the handshake."
|
||||
);
|
||||
}
|
||||
@@ -205,17 +208,17 @@ public class ConnectionFactory {
|
||||
String receiver = handshake.getReceiver();
|
||||
|
||||
if (sender == null || sender.isBlank()) {
|
||||
SysInfoMessage.sendSystemInfo(
|
||||
InfoMessage.sendSystemInfo(
|
||||
connection,
|
||||
SysInfoType.CONNECTION_REJECTED,
|
||||
InfoType.CONNECTION_REJECTED,
|
||||
"Invalid Sender: " + sender + "."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (receiver == null || receiver.isBlank()) {
|
||||
SysInfoMessage.sendSystemInfo(
|
||||
InfoMessage.sendSystemInfo(
|
||||
connection,
|
||||
SysInfoType.CONNECTION_REJECTED,
|
||||
InfoType.CONNECTION_REJECTED,
|
||||
"Invalid Receiver: " + receiver + "."
|
||||
);
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package pitiupi.net.tcp;
|
||||
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.models.Messages.Message;
|
||||
|
||||
class HandshakeMessage extends Message {
|
||||
private final boolean isPrivate;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package pitiupi.net.tcp;
|
||||
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.plugin.Plugin;
|
||||
import pitiupi.plugin.PrivateConnectionPlugin;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.plugins.PluginManager;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.models.Messages.InfoMessage;
|
||||
import pitiupi.models.Messages.InfoType;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.Objects;
|
||||
@@ -37,11 +37,13 @@ public class SocketTCP extends Thread {
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
|
||||
private final PluginManager pluginManager;
|
||||
|
||||
private final TcpConnectionManager tcpConnectionManager;
|
||||
|
||||
private ServerSocket serverSocket;
|
||||
private InetAddress address;
|
||||
|
||||
private final MainWindow main;
|
||||
|
||||
private volatile boolean running = true;
|
||||
|
||||
/**
|
||||
@@ -51,15 +53,18 @@ public class SocketTCP extends Thread {
|
||||
* com os peers são estabelecidas sob demanda durante o envio ou aceitas
|
||||
* quando iniciadas por outros peers.</p>
|
||||
*
|
||||
* @param main janela principal da aplicação, usada para obter a porta,
|
||||
* @param connectionManager interface de conexão da aplicação, usada para obter a porta,
|
||||
* o identificador local e os plugins disponíveis.
|
||||
*/
|
||||
public SocketTCP(MainWindow main) {
|
||||
this.main = main;
|
||||
public SocketTCP(ConnectionManager connectionManager, PluginManager pluginManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
this.pluginManager = pluginManager;
|
||||
|
||||
logger = Logger.getLogger(getClass().getName());
|
||||
connectionManager = new ConnectionManager();
|
||||
tcpConnectionManager = new TcpConnectionManager();
|
||||
|
||||
try {
|
||||
serverSocket = new ServerSocket(main.getPort());
|
||||
serverSocket = new ServerSocket(connectionManager.getPort());
|
||||
address = InetAddress.getByName(InetAddress.getLocalHost().getHostAddress());
|
||||
} catch (IOException ex) {
|
||||
System.out.println("There is no socket connection. Sorry.");
|
||||
@@ -78,25 +83,32 @@ public class SocketTCP extends Thread {
|
||||
* @param msg mensagem que será enviada.
|
||||
* @param destinationAddress endereço IP do peer que receberá a mensagem.
|
||||
*/
|
||||
public void send(Message msg, InetAddress destinationAddress) {
|
||||
public boolean send(Message msg, InetAddress destinationAddress) {
|
||||
try {
|
||||
TcpConnection connection = getPublicConnection(destinationAddress, main.getIdentifier(), main.getIdentifier());
|
||||
TcpConnection connection = getPublicConnection(
|
||||
destinationAddress,
|
||||
connectionManager.getIdentifier(),
|
||||
connectionManager.getIdentifier()
|
||||
);
|
||||
|
||||
if (connection == null) {
|
||||
System.out.println("Could not establish TCP connection.");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
connection.send(msg.toByteArray());
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Could not send TCP message.");
|
||||
System.out.println(ex.toString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Estabelece uma conexão TCP privada com um plugin específico do peer de destino.
|
||||
*
|
||||
* <p>A conexão é criada como privada e passa a ser gerenciada pelo
|
||||
* {@link ConnectionManager}. O método também inicia a tarefa responsável
|
||||
* {@link TcpConnectionManager}. O método também inicia a tarefa responsável
|
||||
* por receber os dados dessa conexão.</p>
|
||||
*
|
||||
* @param destinationAddress endereço IP do peer de destino.
|
||||
@@ -115,11 +127,11 @@ public class SocketTCP extends Thread {
|
||||
* Obtém uma conexão TCP pública existente com o peer de destino ou estabelece
|
||||
* uma nova caso não exista uma conexão válida.
|
||||
*
|
||||
* <p>As conexões públicas são gerenciadas pelo {@link ConnectionManager}.
|
||||
* <p>As conexões públicas são gerenciadas pelo {@link TcpConnectionManager}.
|
||||
* O método primeiro verifica se já existe uma conexão pública registrada
|
||||
* para o endereço de destino e, caso ela exista e não esteja fechada,
|
||||
* reutiliza-a. Caso contrário, uma nova conexão pública é estabelecida,
|
||||
* registrada no {@link ConnectionManager} e disponibilizada para uso.</p>
|
||||
* registrada no {@link TcpConnectionManager} e disponibilizada para uso.</p>
|
||||
*
|
||||
* <p>O acesso ao método é sincronizado para evitar que múltiplas threads
|
||||
* estabeleçam simultaneamente conexões públicas para o mesmo peer.</p>
|
||||
@@ -133,7 +145,7 @@ public class SocketTCP extends Thread {
|
||||
private synchronized TcpConnection getPublicConnection(InetAddress destinationAddress, String senderId, String receiverId) {
|
||||
TcpConnection connection;
|
||||
|
||||
connection = connectionManager.getPublicConnection(destinationAddress);
|
||||
connection = tcpConnectionManager.getPublicConnection(destinationAddress);
|
||||
if (connection != null && !connection.isClosed()) return connection;
|
||||
|
||||
connection = establishOutgoingConnection(destinationAddress, senderId, receiverId, false);
|
||||
@@ -146,7 +158,7 @@ public class SocketTCP extends Thread {
|
||||
*
|
||||
* <p>Cada socket aceito é encaminhado para processamento assíncrono,
|
||||
* interpretado como uma {@link TcpConnection}, registrado pelo
|
||||
* {@link ConnectionManager} e associado ao receptor adequado.</p>
|
||||
* {@link TcpConnectionManager} e associado ao receptor adequado.</p>
|
||||
*/
|
||||
private void receive() {
|
||||
while (running) {
|
||||
@@ -188,7 +200,7 @@ public class SocketTCP extends Thread {
|
||||
throw new IllegalArgumentException("Connections to the local host are forbidden.");
|
||||
}
|
||||
|
||||
TcpConnection connection = ConnectionFactory.createConnection(destinationAddress, main.getPort(), sender, receiver, isPrivate);
|
||||
TcpConnection connection = ConnectionFactory.createConnection(destinationAddress, connectionManager.getPort(), sender, receiver, isPrivate);
|
||||
if (connection == null) return null;
|
||||
|
||||
saveConnection(connection);
|
||||
@@ -229,10 +241,10 @@ public class SocketTCP extends Thread {
|
||||
*/
|
||||
private void saveConnection(TcpConnection connection) {
|
||||
if (connection.isPrivate()) {
|
||||
connectionManager.addPrivateConnection(connection);
|
||||
tcpConnectionManager.addPrivateConnection(connection);
|
||||
}
|
||||
else {
|
||||
connectionManager.addPublicConnection(connection);
|
||||
tcpConnectionManager.addPublicConnection(connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,47 +266,21 @@ public class SocketTCP extends Thread {
|
||||
return;
|
||||
}
|
||||
|
||||
if (connection.getReceiver().equals(main.getIdentifier())) {
|
||||
if (connection.getReceiver().equals(connectionManager.getIdentifier())) {
|
||||
systemConnectionReceiver(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin receiver = findConnectionReceiver(connection);
|
||||
if (receiver instanceof PrivateConnectionPlugin plugin) {
|
||||
plugin.receivePrivateConnection(connection);
|
||||
|
||||
privateConnectionReceiver(connection, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Localiza o plugin responsável por receber uma conexão privada.
|
||||
*
|
||||
* <p>A busca é feita pelo identificador do destinatário informado na
|
||||
* própria conexão. Caso nenhum plugin correspondente seja encontrado,
|
||||
* uma mensagem de erro é enviada ao peer remoto.</p>
|
||||
*
|
||||
* @param connection conexão privada cujo destinatário será localizado.
|
||||
* @return o plugin com o identificador correspondente ao destinatário,
|
||||
* ou {@code null} se nenhum plugin for encontrado.
|
||||
*/
|
||||
private Plugin findConnectionReceiver(TcpConnection connection) {
|
||||
Plugin receiver = null;
|
||||
for(Plugin plugin : main.getPlugins()) {
|
||||
if (plugin.getIdentifier().equals(connection.getReceiver())) {
|
||||
receiver = plugin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (receiver == null) {
|
||||
SysInfoMessage.sendSystemInfo(
|
||||
if (pluginManager.handleConnection(connection, connection.getReceiver()))
|
||||
privateConnectionReceiver(connection);
|
||||
else {
|
||||
InfoMessage.sendSystemInfo(
|
||||
connection,
|
||||
SysInfoType.RECEIVER_NOT_FOUND,
|
||||
InfoType.RECEIVER_NOT_FOUND,
|
||||
"This peer does not have the plugin: " + connection.getReceiver()
|
||||
);
|
||||
}
|
||||
return receiver;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -306,7 +292,7 @@ public class SocketTCP extends Thread {
|
||||
* condição de erro.</p>
|
||||
*
|
||||
* <p>O método também trata timeouts e erros de I/O, removendo a conexão
|
||||
* do {@link ConnectionManager} quando ela deixa de ser utilizável.</p>
|
||||
* do {@link TcpConnectionManager} quando ela deixa de ser utilizável.</p>
|
||||
*
|
||||
* @param connection conexão pública da qual as mensagens serão recebidas.
|
||||
*/
|
||||
@@ -315,18 +301,16 @@ public class SocketTCP extends Thread {
|
||||
try {
|
||||
byte[] bytes = connection.receive();
|
||||
|
||||
SysInfoMessage sysMessage = SysInfoMessage.parseSystemInfo(bytes);
|
||||
InfoMessage sysMessage = InfoMessage.parseSystemInfo(bytes);
|
||||
|
||||
if (sysMessage == null) {
|
||||
for (Plugin plugin : main.getPlugins()) {
|
||||
plugin.receiveMessage(bytes);
|
||||
}
|
||||
pluginManager.handleMessage(bytes);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (sysMessage.getType()) {
|
||||
case CONNECTION_CLOSED, INTERNAL_ERROR -> {
|
||||
connectionManager.closeConnection(connection);
|
||||
tcpConnectionManager.closeConnection(connection);
|
||||
return;
|
||||
}
|
||||
case MESSAGE_REJECTED -> {
|
||||
@@ -337,12 +321,12 @@ public class SocketTCP extends Thread {
|
||||
}
|
||||
catch (SocketTimeoutException ex) {
|
||||
if (connection.hasTimedOut()) {
|
||||
connectionManager.closeConnection(connection, "Connection timeout");
|
||||
tcpConnectionManager.closeConnection(connection, "Connection timeout");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
connectionManager.closeConnection(connection);
|
||||
tcpConnectionManager.closeConnection(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,24 +341,22 @@ public class SocketTCP extends Thread {
|
||||
* do plugin e o fechamento da conexão.</p>
|
||||
*
|
||||
* @param connection conexão privada da qual os dados serão recebidos.
|
||||
* @param plugin plugin responsável pelo processamento dos dados recebidos.
|
||||
*/
|
||||
private void privateConnectionReceiver(TcpConnection connection, Plugin plugin) {
|
||||
if (plugin instanceof PrivateConnectionPlugin privatePlugin) {
|
||||
private void privateConnectionReceiver(TcpConnection connection) {
|
||||
while (running) {
|
||||
try {
|
||||
byte[] message = connection.receive();
|
||||
SysInfoMessage sysMessage = SysInfoMessage.parseSystemInfo(message);
|
||||
InfoMessage sysMessage = InfoMessage.parseSystemInfo(message);
|
||||
|
||||
if (sysMessage == null) {
|
||||
privatePlugin.receiveBytes(connection, message);
|
||||
pluginManager.handleMessageFromConnection(connection, message);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (sysMessage.getType()) {
|
||||
case CONNECTION_CLOSED, INTERNAL_ERROR -> {
|
||||
privatePlugin.onSocketClosed(connection);
|
||||
connectionManager.closeConnection(connection);
|
||||
pluginManager.handleDisconnection(connection, connection.getReceiver());
|
||||
tcpConnectionManager.closeConnection(connection);
|
||||
}
|
||||
default -> {
|
||||
continue;
|
||||
@@ -383,13 +365,12 @@ public class SocketTCP extends Thread {
|
||||
}
|
||||
catch (SocketTimeoutException ex) {
|
||||
if (connection.hasTimedOut()) {
|
||||
connectionManager.closeConnection(connection, "Connection timeout");
|
||||
tcpConnectionManager.closeConnection(connection, "Connection timeout");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
connectionManager.closeConnection(connection);
|
||||
}
|
||||
tcpConnectionManager.closeConnection(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -410,7 +391,7 @@ public class SocketTCP extends Thread {
|
||||
try (ByteArrayInputStream bis = new ByteArrayInputStream(message);
|
||||
ObjectInputStream ois = new ObjectInputStream(bis)) {
|
||||
|
||||
SysInfoMessage sysMessage = SysInfoMessage.parseSystemInfo(message);
|
||||
InfoMessage sysMessage = InfoMessage.parseSystemInfo(message);
|
||||
if (sysMessage != null) continue;
|
||||
|
||||
//TODO: Ainda não existem mensagens trocadas entre o sistema.
|
||||
@@ -421,7 +402,7 @@ public class SocketTCP extends Thread {
|
||||
if (connection.hasTimedOut()) return;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
connectionManager.closeConnection(connection);
|
||||
tcpConnectionManager.closeConnection(connection);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -430,19 +411,18 @@ public class SocketTCP extends Thread {
|
||||
* Encerra uma conexão TCP e registra o motivo informado.
|
||||
*
|
||||
* <p>Quando nenhuma descrição é fornecida, é utilizado um motivo padrão.
|
||||
* O fechamento efetivo da conexão é delegado ao {@link ConnectionManager}.</p>
|
||||
* O fechamento efetivo da conexão é delegado ao {@link TcpConnectionManager}.</p>
|
||||
*
|
||||
* @param connection conexão que será encerrada.
|
||||
* @param description motivo do encerramento; pode ser {@code null}.
|
||||
*/
|
||||
public void disconnect(TcpConnection connection, String description) {
|
||||
connectionManager.closeConnection(
|
||||
tcpConnectionManager.closeConnection(
|
||||
connection,
|
||||
Objects.requireNonNullElse(description, "No reason provided")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
receive();
|
||||
@@ -469,7 +449,7 @@ public class SocketTCP extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
connectionManager.closeAllConnections("The peer must have closed the application or changed ports");
|
||||
tcpConnectionManager.closeAllConnections("The peer must have closed the application or changed ports");
|
||||
|
||||
connectionExecutor.shutdownNow();
|
||||
}
|
||||
|
||||
+11
-9
@@ -1,7 +1,9 @@
|
||||
package pitiupi.net.tcp;
|
||||
|
||||
import pitiupi.control.PeerInfo;
|
||||
import pitiupi.models.Messages.InfoType;
|
||||
import pitiupi.models.User;
|
||||
import pitiupi.control.PeerListener;
|
||||
import pitiupi.models.Messages.InfoMessage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
@@ -27,7 +29,7 @@ import java.util.stream.Collectors;
|
||||
* peers ativos para encerrar conexões associadas a peers que deixaram de
|
||||
* estar disponíveis.</p>
|
||||
*/
|
||||
class ConnectionManager implements PeerListener {
|
||||
class TcpConnectionManager implements PeerListener {
|
||||
private final Logger logger;
|
||||
private final Map<InetAddress, TcpConnection> publicConnections;
|
||||
private final Map<InetAddress, List<TcpConnection>> privateConnections;
|
||||
@@ -35,7 +37,7 @@ class ConnectionManager implements PeerListener {
|
||||
/**
|
||||
* Cria um gerenciador de conexões TCP vazio.
|
||||
*/
|
||||
public ConnectionManager() {
|
||||
public TcpConnectionManager() {
|
||||
publicConnections = new ConcurrentHashMap<>();
|
||||
privateConnections = new ConcurrentHashMap<>();
|
||||
|
||||
@@ -65,7 +67,7 @@ class ConnectionManager implements PeerListener {
|
||||
*/
|
||||
public void addPrivateConnection(TcpConnection connection) {
|
||||
List<TcpConnection> connections =
|
||||
privateConnections.computeIfAbsent(connection.getAddress(), _ -> new ArrayList<>());
|
||||
privateConnections.computeIfAbsent(connection.getAddress(), e -> new ArrayList<>());
|
||||
|
||||
synchronized (connections) {
|
||||
connections.add(connection);
|
||||
@@ -99,7 +101,7 @@ class ConnectionManager implements PeerListener {
|
||||
* @param reason motivo do encerramento que será informado ao peer.
|
||||
*/
|
||||
public void closeConnection(TcpConnection connection, String reason) {
|
||||
SysInfoMessage.sendSystemInfo(connection, SysInfoType.CONNECTION_CLOSED, reason);
|
||||
InfoMessage.sendSystemInfo(connection, InfoType.CONNECTION_CLOSED, reason);
|
||||
closeConnection(connection);
|
||||
}
|
||||
|
||||
@@ -153,7 +155,7 @@ class ConnectionManager implements PeerListener {
|
||||
public void closeByAdress(InetAddress address, String reason) {
|
||||
List<TcpConnection> connections = privateConnections.get(address);
|
||||
for (TcpConnection connection : connections) {
|
||||
SysInfoMessage.sendSystemInfo(connection, SysInfoType.CONNECTION_CLOSED, reason);
|
||||
InfoMessage.sendSystemInfo(connection, InfoType.CONNECTION_CLOSED, reason);
|
||||
}
|
||||
closeByAdress(address);
|
||||
}
|
||||
@@ -205,7 +207,7 @@ class ConnectionManager implements PeerListener {
|
||||
public void closeAllConnections(String reason) {
|
||||
for (List<TcpConnection> connections : privateConnections.values()) {
|
||||
for (TcpConnection connection : connections) {
|
||||
SysInfoMessage.sendSystemInfo(connection, SysInfoType.CONNECTION_CLOSED, reason);
|
||||
InfoMessage.sendSystemInfo(connection, InfoType.CONNECTION_CLOSED, reason);
|
||||
}
|
||||
}
|
||||
closeAllConnections();
|
||||
@@ -245,8 +247,8 @@ class ConnectionManager implements PeerListener {
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void onPeersChanged(List<PeerInfo> peers) {
|
||||
Set<InetAddress> activePeers = peers.stream().map(PeerInfo::getAddress).collect(Collectors.toSet());
|
||||
public void onPeersChanged(List<User> peers) {
|
||||
Set<InetAddress> activePeers = peers.stream().map(User::getAddress).collect(Collectors.toSet());
|
||||
|
||||
for (InetAddress address : publicConnections.keySet()) {
|
||||
if (!activePeers.contains(address)) {
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
package pitiupi.net.udp;
|
||||
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
@@ -14,9 +13,10 @@ import java.net.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import pitiupi.net.HeartbeatMessage;
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.plugin.Plugin;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.control.plugins.PluginManager;
|
||||
import pitiupi.models.Messages.HeartbeatMessage;
|
||||
import pitiupi.models.Messages.Message;
|
||||
|
||||
/**
|
||||
* Gerencia a comunicação UDP multicast e unicast da aplicação.
|
||||
@@ -37,7 +37,10 @@ public class SocketUDP extends Thread {
|
||||
private MulticastSocket multicastSocket;
|
||||
|
||||
private InetAddress address;
|
||||
private MainWindow main;
|
||||
|
||||
private final ConnectionManager connectionManager;
|
||||
private final PluginManager pluginManager;
|
||||
|
||||
private volatile boolean running = true;
|
||||
public final static String INET_ADDR = "224.0.0.3";
|
||||
|
||||
@@ -47,22 +50,26 @@ public class SocketUDP extends Thread {
|
||||
* <p>O socket é associado à porta da aplicação e ingressa no grupo
|
||||
* multicast configurado.</p>
|
||||
*
|
||||
* @param main janela principal da aplicação.
|
||||
* @param connectionManager interface que gerencia toda conexão da aplicação.
|
||||
* @param pluginManager interface que gerencia os plugins da conexão.
|
||||
*/
|
||||
public SocketUDP(MainWindow main) {
|
||||
this.main = main;
|
||||
public SocketUDP(ConnectionManager connectionManager, PluginManager pluginManager) {
|
||||
this.connectionManager = connectionManager;
|
||||
this.pluginManager = pluginManager;
|
||||
|
||||
try {
|
||||
this.address = InetAddress.getByName(SocketUDP.INET_ADDR);
|
||||
} catch (UnknownHostException ex) {
|
||||
System.getLogger(SocketUDP.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex);
|
||||
}
|
||||
try {
|
||||
multicastSocket = new MulticastSocket(this.main.getPort());
|
||||
|
||||
multicastSocket = new MulticastSocket(connectionManager.getPort());
|
||||
multicastSocket.setSendBufferSize(256000);
|
||||
multicastSocket.setReceiveBufferSize(256000);
|
||||
multicastSocket.setReuseAddress(true);
|
||||
multicastSocket.joinGroup(address);
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
catch (UnknownHostException ex) {
|
||||
System.getLogger(SocketUDP.class.getName()).log(System.Logger.Level.ERROR, (String) null, ex);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
System.out.println("There is no socket connection. Sorry.");
|
||||
System.out.println(ex);
|
||||
}
|
||||
@@ -71,22 +78,22 @@ public class SocketUDP extends Thread {
|
||||
/**
|
||||
* Envia uma mensagem para o grupo multicast da aplicação.
|
||||
*
|
||||
* @param msg mensagem serializada a ser enviada.
|
||||
* @param msg mensagem a ser enviada.
|
||||
* @throws IOException caso ocorra um erro durante o envio.
|
||||
*/
|
||||
public void sendMulticast(Message msg) throws IOException {
|
||||
send(msg, address);
|
||||
send(msg.toByteArray(), this.address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Envia uma mensagem diretamente para um peer utilizando UDP.
|
||||
*
|
||||
* @param msg mensagem serializada a ser enviada.
|
||||
* @param msg mensagem a ser enviada.
|
||||
* @param destinationAddress endereço IP do peer destinatário.
|
||||
* @throws IOException caso ocorra um erro durante o envio.
|
||||
*/
|
||||
public void sendUnicast(Message msg, InetAddress destinationAddress) throws IOException {
|
||||
send(msg, destinationAddress);
|
||||
send(msg.toByteArray(), destinationAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,10 +103,9 @@ public class SocketUDP extends Thread {
|
||||
* @param destinationAddress endereço de destino.
|
||||
* @throws IOException caso ocorra um erro durante o envio.
|
||||
*/
|
||||
private void send(Message msg, InetAddress destinationAddress) throws IOException {
|
||||
private void send(byte[] msg, InetAddress destinationAddress) throws IOException {
|
||||
DatagramPacket msgPacket;
|
||||
byte[] buf = msg.toByteArray();
|
||||
msgPacket = new DatagramPacket(buf, buf.length, destinationAddress, this.main.getPort());
|
||||
msgPacket = new DatagramPacket(msg, msg.length, destinationAddress, connectionManager.getPort());
|
||||
multicastSocket.send(msgPacket);
|
||||
}
|
||||
|
||||
@@ -147,14 +153,11 @@ public class SocketUDP extends Thread {
|
||||
|
||||
HeartbeatMessage heartbeat = tryParseHeartbeat(msgPacket.getData());
|
||||
if (heartbeat != null) {
|
||||
main.getHeartbeatManager().receiveHeartbeat(heartbeat, msgPacket.getAddress());
|
||||
connectionManager.receiveHeartbeat(heartbeat, msgPacket.getAddress());
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Plugin plugin : main.getPlugins()) {
|
||||
System.out.println(msgPacket.getAddress().toString());
|
||||
plugin.receiveMessage(msgPacket.getData());
|
||||
}
|
||||
pluginManager.handleMessage(msgPacket.getData());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
|
||||
* Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Interface.java to edit this template
|
||||
*/
|
||||
package pitiupi.plugin;
|
||||
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
|
||||
/**
|
||||
* Interface base para plugins da aplicação.
|
||||
*
|
||||
* <p>Cada plugin deve implementar esta interface para ser carregado
|
||||
* pela aplicação e participar do sistema de comunicação por mensagens.</p>
|
||||
*
|
||||
* @author flavio
|
||||
*/
|
||||
public interface Plugin {
|
||||
|
||||
public String getName();
|
||||
public String getAuthor();
|
||||
public String getVersion();
|
||||
public String getIdentifier();
|
||||
|
||||
/**
|
||||
* Inicializa o plugin.
|
||||
*
|
||||
* <p>Este método é chamado pela aplicação após o carregamento do plugin.</p>
|
||||
*
|
||||
* @param window janela principal da aplicação.
|
||||
*/
|
||||
public void createPlugin(MainWindow window);
|
||||
|
||||
/**
|
||||
* Retorna uma mensagem utilizada pelo plugin.
|
||||
*
|
||||
* @return mensagem criada pelo plugin.
|
||||
*/
|
||||
public Message getMessage();
|
||||
|
||||
/**
|
||||
* Recebe uma mensagem enviada pela aplicação.
|
||||
*
|
||||
* <p>A mensagem é recebida em formato serializado. O plugin deve verificar
|
||||
* se a mensagem pertence ao seu tipo e realizar o processamento necessário.</p>
|
||||
*
|
||||
* @param message mensagem serializada recebida.
|
||||
*/
|
||||
public void receiveMessage(byte[] message);
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package pitiupi.plugin;
|
||||
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
|
||||
public interface PrivateConnectionPlugin extends Plugin {
|
||||
public void receivePrivateConnection(TcpConnection connection);
|
||||
public void receiveBytes(TcpConnection connection, byte[] bytes);
|
||||
public void onSocketClosed(TcpConnection connection);
|
||||
}
|
||||
Reference in new issue
Block a user