Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d9faa93f8 | ||
|
|
e5eb4f3f9c | ||
|
|
581a924afc | ||
|
|
7a699cd280 | ||
|
|
88b75ad75f | ||
|
|
d551324e8b | ||
|
|
a628490fcb | ||
|
|
395363e4bd | ||
|
|
12497594e4 | ||
|
|
6a597092fe | ||
|
|
ffd474e7ff | ||
|
|
4d39648ee7 | ||
|
|
095af14463 | ||
|
|
d0083e8069 | ||
|
|
dda324228f | ||
|
|
840183ee9f | ||
|
|
eb3ce132cd | ||
|
|
d1dc427185 | ||
|
|
7c9e61ce0f | ||
|
|
6538dac8af | ||
|
|
67813e4881 | ||
|
|
4cc07a3754 | ||
|
|
fa696194aa | ||
|
|
9fb4952f32 | ||
|
|
96b8faca5b | ||
|
|
cac549f1ee | ||
|
|
a86f4dbf82 | ||
|
|
7168431bcd | ||
|
|
0b7c67fef6 | ||
|
|
15ea8ac207 |
No files matched your search
+3
-9
@@ -1,9 +1,3 @@
|
||||
/pitiupi/build/
|
||||
/pitiupi/dist/
|
||||
/pitiupi.chat/build/
|
||||
/pitiupi.chat/dist/
|
||||
/pitiupi.chat/nbproject/private/
|
||||
/pitiupi.screenCast/build/
|
||||
/pitiupi.screenCast/dist/
|
||||
|
||||
.idea/
|
||||
build/
|
||||
dist/
|
||||
*.class
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="pitiupi">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/pitiupi.screenCast/dist/lib/pitiupi.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="pitiupi.chat">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/pitiupi.chat/dist/pitiupi.chat.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
<component name="libraryTable">
|
||||
<library name="pitiupi.screenCast">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/pitiupi.screenCast/dist/pitiupi.screenCast.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
<component name="libraryTable">
|
||||
<library name="plugins">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/pitiupi/plugins/pitiupi.screenCast.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/pitiupi/plugins/pitiupi.chat.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
Generated
+4
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="openjdk-27" project-jdk-type="JavaSDK" />
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/pitiupi.iml" filepath="$PROJECT_DIR$/.idea/pitiupi.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
<?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$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,10 +1,13 @@
|
||||
# pitiupi
|
||||
|
||||
Ferramenta p2p para práticas em rede
|
||||
Este repositório tem 4 projetos Java que são independentes:
|
||||
|
||||
Este repositório tem 3 projetos Java que são independentes:
|
||||
### Sistema:
|
||||
- A ferramenta pitiupi (P2P)
|
||||
|
||||
### Plugins:
|
||||
- Um plugin de Chat
|
||||
- Um plugin de Chat multiprotocolo (TCP/UDP)
|
||||
- Um plugin de ScreenCast
|
||||
|
||||
Cada um destes projetos deve ser compilado individualmente. Para isso, use a ferramenta ant no diretório do projeto.
|
||||
@@ -21,9 +24,26 @@ Para criar links simbólicos no Linux, use o comando:
|
||||
```
|
||||
cd pitiupi/plugins
|
||||
ln -s ../../pitiupi.chat/dist/*.jar .
|
||||
ln -s ../../pitiupi.mpChat/dist/*.jar .
|
||||
ln -s ../../pitiupi.screenCast/dist/*.jar .
|
||||
```
|
||||
Isso deve resolver!
|
||||
|
||||
Para criar um novo plugin:
|
||||
## Como um plugin conversa com o pitiupi
|
||||
|
||||
Um plugin nunca recebe acesso direto às classes internas do núcleo (ConnectionManager, GuiManager). Em vez disso, recebe uma facade, a classe Pitiupi, que expõe só o que um plugin precisa: enviar mensagem (multicast, unicast ou tcp), abrir conexão tcp privada, ler nome de usuário e porta, criar menu.
|
||||
|
||||
```java
|
||||
public abstract void createPlugin(Pitiupi pitiupi);
|
||||
```
|
||||
|
||||
## Para criar um novo plugin
|
||||
|
||||
1. Implemente `pitiupi.models.Plugin`, incluindo `createPlugin(Pitiupi pitiupi)`
|
||||
2. Registre a classe em `src/META-INF/services/pitiupi.models.Plugin`, com o nome completo da classe numa linha
|
||||
3. Compile com `ant jar`
|
||||
4. Linke o `.jar` em `pitiupi/plugins`
|
||||
|
||||
Use `pitiupi.chat` como referência — é o exemplo mais simples e completo.
|
||||
|
||||
Plugins que ainda não foram atualizados para a Pitiupi (como uma versão mais antiga do screenCast) não compilam contra o núcleo atual e precisam de migração antes de serem usados.
|
||||
@@ -1,6 +0,0 @@
|
||||
#Mon, 17 Aug 2026 14:26:26 -0300
|
||||
|
||||
|
||||
C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi.chat=
|
||||
|
||||
C\:\\Users\\extre\\OneDrive\\Documentos\\Faculdade\\2026_02\\Monitoria\\Pitiupi\\pitiupi=
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -47,8 +47,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}
|
||||
|
||||
File renamed without changes.
@@ -1 +0,0 @@
|
||||
pitiupi.chat.plugin.ChatPlugin
|
||||
@@ -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,37 +5,35 @@
|
||||
*/
|
||||
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.plugin.Pitiupi;
|
||||
import pitiupi.models.Messages.Message;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author tony
|
||||
* @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;
|
||||
|
||||
public ChatWindow(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
initComponents();
|
||||
}
|
||||
private final Pitiupi pitiupi;
|
||||
|
||||
public ChatWindow(Pitiupi pitiupi) {
|
||||
this.pitiupi = pitiupi;
|
||||
initComponents();
|
||||
}
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
@@ -43,23 +41,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 +92,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(pitiupi.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);
|
||||
}
|
||||
pitiupi.sendUdpMulticast(message);
|
||||
}
|
||||
|
||||
public void receiveChatMessage(ChatMessage message) {
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
*/
|
||||
package pitiupi.chat.net;
|
||||
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.net.Message;
|
||||
|
||||
import pitiupi.models.Messages.Message;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author flavio
|
||||
*/
|
||||
public class ChatMessage extends Message{
|
||||
public class ChatMessage extends Message {
|
||||
|
||||
private String text;
|
||||
private String name;
|
||||
|
||||
@@ -4,48 +4,43 @@
|
||||
*/
|
||||
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.plugin.Pitiupi;
|
||||
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.models.Menus.MenuCategory;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.models.Plugin;
|
||||
|
||||
/**
|
||||
*
|
||||
*@author tony
|
||||
* @author flavio
|
||||
*/
|
||||
public class ChatPlugin implements Plugin {
|
||||
public class ChatPlugin extends Plugin {
|
||||
|
||||
private ChatWindow chatWindow;
|
||||
private MainWindow mainWindow;
|
||||
|
||||
public ChatPlugin() {
|
||||
@Override
|
||||
public void createPlugin(Pitiupi pitiupi) {
|
||||
this.chatWindow = new ChatWindow(pitiupi);
|
||||
pitiupi.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));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveMessage(byte[] message) {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(message);
|
||||
ObjectInputStream ois;
|
||||
try {
|
||||
ois = new ObjectInputStream(bis);
|
||||
if (ois.readObject() instanceof ChatMessage msg) {
|
||||
this.chatWindow.receiveChatMessage(msg);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
System.out.println(ex.toString());
|
||||
} catch (ClassNotFoundException ex) {
|
||||
System.out.println(ex.toString());
|
||||
public List<Class<? extends Message>> getMessages() {
|
||||
return List.of(ChatMessage.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receiveMessage(Message message) {
|
||||
if (message instanceof ChatMessage msg) {
|
||||
this.chatWindow.receiveChatMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +60,9 @@ public class ChatPlugin implements Plugin {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessage() {
|
||||
return new ChatMessage();
|
||||
public String getIdentifier() {
|
||||
return "Pitiupi.Chat.Example";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Generated
+5
@@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
Generated
+5
@@ -0,0 +1,5 @@
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="openjdk-26" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/pitiupi.mpChat.iml" filepath="$PROJECT_DIR$/pitiupi.mpChat.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -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)"/*
|
||||
@@ -0,0 +1 @@
|
||||
plugin.MultiProtocolChat
|
||||
File renamed without changes.
@@ -0,0 +1,22 @@
|
||||
package GUI;
|
||||
|
||||
import pitiupi.models.Menus.MulticastMenus.MulticastActionMenu;
|
||||
|
||||
public class MulticastMpChatMenu extends MulticastActionMenu {
|
||||
PublicChatWindow publicChatWindow;
|
||||
|
||||
public MulticastMpChatMenu(PublicChatWindow publicChatWindow) {
|
||||
this.publicChatWindow = publicChatWindow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
publicChatWindow.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "MP-Chat";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package GUI;
|
||||
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
import pitiupi.plugin.Pitiupi;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.net.InetAddress;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PrivateChatWindow extends JFrame {
|
||||
|
||||
private final Pitiupi pitiupi;
|
||||
private final TcpConnection connection;
|
||||
|
||||
private final JTextArea receivedMessagesArea;
|
||||
private final JTextField messageField;
|
||||
|
||||
public PrivateChatWindow(
|
||||
Pitiupi pitiupi,
|
||||
TcpConnection connection
|
||||
) {
|
||||
this.pitiupi = pitiupi;
|
||||
this.connection = connection;
|
||||
|
||||
setTitle("Chat privado");
|
||||
setSize(700, 500);
|
||||
setLocationRelativeTo(null);
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(
|
||||
BorderFactory.createEmptyBorder(10, 10, 10, 10)
|
||||
);
|
||||
|
||||
receivedMessagesArea = new JTextArea();
|
||||
receivedMessagesArea.setEditable(false);
|
||||
receivedMessagesArea.setLineWrap(true);
|
||||
receivedMessagesArea.setWrapStyleWord(true);
|
||||
|
||||
JScrollPane messagesScrollPane =
|
||||
new JScrollPane(receivedMessagesArea);
|
||||
|
||||
messagesScrollPane.setBorder(
|
||||
BorderFactory.createTitledBorder("Mensagens")
|
||||
);
|
||||
|
||||
mainPanel.add(
|
||||
messagesScrollPane,
|
||||
BorderLayout.CENTER
|
||||
);
|
||||
|
||||
JPanel bottomPanel = new JPanel(
|
||||
new BorderLayout(10, 10)
|
||||
);
|
||||
|
||||
messageField = new JTextField();
|
||||
|
||||
JButton tcpButton = new JButton("TCP");
|
||||
tcpButton.addActionListener(e -> sendTCP());
|
||||
|
||||
bottomPanel.add(
|
||||
messageField,
|
||||
BorderLayout.CENTER
|
||||
);
|
||||
|
||||
bottomPanel.add(
|
||||
tcpButton,
|
||||
BorderLayout.EAST
|
||||
);
|
||||
|
||||
mainPanel.add(
|
||||
bottomPanel,
|
||||
BorderLayout.SOUTH
|
||||
);
|
||||
|
||||
setContentPane(mainPanel);
|
||||
}
|
||||
|
||||
private void sendTCP() {
|
||||
try {
|
||||
String nome = pitiupi.getUserName();
|
||||
|
||||
MpChatMessage message = new MpChatMessage(
|
||||
nome,
|
||||
InetAddress.getLocalHost().getHostAddress(),
|
||||
"TCP Private",
|
||||
messageField.getText()
|
||||
);
|
||||
|
||||
connection.send(message.toByteArray());
|
||||
receiveMessage(message);
|
||||
|
||||
messageField.setText("");
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(
|
||||
PrivateChatWindow.class.getName()
|
||||
).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveMessage(MpChatMessage message) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
String texto = String.format(
|
||||
"[%s] %s (%s): %s%n",
|
||||
message.getTipoMensagem(),
|
||||
message.getNome(),
|
||||
message.getIp(),
|
||||
message.getMessage()
|
||||
);
|
||||
|
||||
receivedMessagesArea.append(texto);
|
||||
|
||||
receivedMessagesArea.setCaretPosition(
|
||||
receivedMessagesArea.getDocument().getLength()
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package GUI;
|
||||
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.control.ConnectionManager;
|
||||
import pitiupi.plugin.Pitiupi;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.SimpleAttributeSet;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.text.StyledDocument;
|
||||
import java.awt.*;
|
||||
import java.net.InetAddress;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PublicChatWindow extends JFrame {
|
||||
private final Pitiupi pitiupi;
|
||||
|
||||
private JTextPane receivedMessagesArea;
|
||||
private JTextField messageField;
|
||||
private JTextField ipField;
|
||||
|
||||
public PublicChatWindow(Pitiupi pitiupi) {
|
||||
this.pitiupi = pitiupi;
|
||||
|
||||
initComponents();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
setTitle("Public Chat");
|
||||
setSize(700, 500);
|
||||
setLocationRelativeTo(null);
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
|
||||
mainPanel.setBorder(
|
||||
BorderFactory.createEmptyBorder(10, 10, 10, 10)
|
||||
);
|
||||
|
||||
initReceivedMessagesPanel(mainPanel);
|
||||
initBottomPanel(mainPanel);
|
||||
|
||||
setContentPane(mainPanel);
|
||||
}
|
||||
|
||||
private void initReceivedMessagesPanel(JPanel mainPanel) {
|
||||
receivedMessagesArea = new JTextPane();
|
||||
|
||||
receivedMessagesArea.setEditable(false);
|
||||
|
||||
JScrollPane messagesScrollPane = new JScrollPane(receivedMessagesArea);
|
||||
|
||||
messagesScrollPane.setBorder(
|
||||
BorderFactory.createTitledBorder("Mensagens recebidas")
|
||||
);
|
||||
|
||||
mainPanel.add(messagesScrollPane, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private void initBottomPanel(JPanel mainPanel) {
|
||||
messageField = new JTextField();
|
||||
|
||||
JPanel bottomPanel = new JPanel(
|
||||
new BorderLayout(10, 10)
|
||||
);
|
||||
|
||||
bottomPanel.add(messageField, BorderLayout.CENTER);
|
||||
|
||||
initIpField(bottomPanel);
|
||||
initCommunicationButtons(bottomPanel);
|
||||
|
||||
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
private void initIpField(JPanel bottomPanel) {
|
||||
ipField = new JTextField();
|
||||
ipField.setPreferredSize(new Dimension(130, 30));
|
||||
|
||||
JPanel ipPanel = new JPanel(
|
||||
new BorderLayout(5, 5)
|
||||
);
|
||||
|
||||
ipPanel.add(
|
||||
new JLabel("IP destino:"),
|
||||
BorderLayout.WEST
|
||||
);
|
||||
|
||||
ipPanel.add(
|
||||
ipField,
|
||||
BorderLayout.CENTER
|
||||
);
|
||||
|
||||
bottomPanel.add(ipPanel, BorderLayout.WEST);
|
||||
}
|
||||
|
||||
private void initCommunicationButtons(JPanel bottomPanel) {
|
||||
JButton tcpButton = new JButton("TCP");
|
||||
JButton udpButton = new JButton("UDP");
|
||||
JButton multicastButton = new JButton("Multicast");
|
||||
|
||||
tcpButton.addActionListener(e -> sendTCP());
|
||||
udpButton.addActionListener(e -> sendUDP());
|
||||
multicastButton.addActionListener(e -> sendMulticast());
|
||||
|
||||
JPanel buttonsPanel = new JPanel(
|
||||
new FlowLayout(FlowLayout.RIGHT, 5, 0)
|
||||
);
|
||||
|
||||
buttonsPanel.add(tcpButton);
|
||||
buttonsPanel.add(udpButton);
|
||||
buttonsPanel.add(multicastButton);
|
||||
|
||||
bottomPanel.add(
|
||||
buttonsPanel,
|
||||
BorderLayout.EAST
|
||||
);
|
||||
}
|
||||
|
||||
private MpChatMessage createMessage(String tipoMensagem) {
|
||||
try {
|
||||
String nome = pitiupi.getUserName();
|
||||
String ip = InetAddress.getLocalHost().getHostAddress();
|
||||
String message = messageField.getText();
|
||||
|
||||
return new MpChatMessage(
|
||||
nome,
|
||||
ip,
|
||||
tipoMensagem,
|
||||
message
|
||||
);
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveMessage(MpChatMessage msg) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
String mensagem = String.format(
|
||||
"[%s] %s (%s): %s%n",
|
||||
msg.getTipoMensagem(),
|
||||
msg.getNome(),
|
||||
msg.getIp(),
|
||||
msg.getMessage()
|
||||
);
|
||||
|
||||
StyledDocument document = receivedMessagesArea.getStyledDocument();
|
||||
|
||||
SimpleAttributeSet attributes = new SimpleAttributeSet();
|
||||
|
||||
if (msg.getTipoMensagem().equals("TCP Unicast") || msg.getTipoMensagem().equals("UDP Unicast")) {
|
||||
StyleConstants.setForeground(attributes, new Color(128, 0, 128));
|
||||
}
|
||||
|
||||
try {
|
||||
document.insertString(
|
||||
document.getLength(),
|
||||
mensagem,
|
||||
attributes
|
||||
);
|
||||
|
||||
receivedMessagesArea.setCaretPosition(
|
||||
document.getLength()
|
||||
);
|
||||
|
||||
} catch (BadLocationException ex) {
|
||||
Logger.getLogger(PublicChatWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendTCP() {
|
||||
try {
|
||||
MpChatMessage msg = createMessage("TCP Unicast");
|
||||
|
||||
InetAddress ip = InetAddress.getByName(ipField.getText());
|
||||
|
||||
pitiupi.sendTcp(msg, ip);
|
||||
receiveMessage(msg);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(
|
||||
PublicChatWindow.class.getName()
|
||||
).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendUDP() {
|
||||
try {
|
||||
MpChatMessage msg = createMessage("UDP Unicast");
|
||||
|
||||
InetAddress ip = InetAddress.getByName(ipField.getText());
|
||||
|
||||
pitiupi.sendUdpUnicast(msg, ip);
|
||||
receiveMessage(msg);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(
|
||||
PublicChatWindow.class.getName()
|
||||
).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMulticast() {
|
||||
try {
|
||||
MpChatMessage msg = createMessage("UDP Multicast");
|
||||
|
||||
pitiupi.sendUdpMulticast(msg);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(
|
||||
PublicChatWindow.class.getName()
|
||||
).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package GUI;
|
||||
|
||||
import control.PrivateChatController;
|
||||
import pitiupi.models.Menus.UnicastMenus.UnicastActionMenu;
|
||||
import pitiupi.models.User;
|
||||
|
||||
public class UnicastMpChatMenu extends UnicastActionMenu {
|
||||
|
||||
private final PrivateChatController controller;
|
||||
|
||||
public UnicastMpChatMenu(
|
||||
PrivateChatController controller
|
||||
) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(User user) {
|
||||
controller.openChat(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "Start Private Chat";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
plugin.MultiProtocolChat
|
||||
@@ -0,0 +1,116 @@
|
||||
package control;
|
||||
|
||||
import GUI.PrivateChatWindow;
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.models.User;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
import pitiupi.plugin.Pitiupi;
|
||||
import plugin.MultiProtocolChat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class PrivateChatController {
|
||||
|
||||
private final Pitiupi pitiupi;
|
||||
private final MultiProtocolChat multiProtocolChat;
|
||||
|
||||
/*
|
||||
* Relaciona o endereço do usuário à janela de chat.
|
||||
*/
|
||||
private final Map<String, PrivateChatWindow> windows;
|
||||
|
||||
/*
|
||||
* Endereços para os quais uma conexão já foi solicitada,
|
||||
* mas ainda não chegou.
|
||||
*/
|
||||
private final Set<String> pendingConnections;
|
||||
|
||||
public PrivateChatController(
|
||||
Pitiupi pitiupi,
|
||||
MultiProtocolChat multiProtocolChat
|
||||
) {
|
||||
this.pitiupi = pitiupi;
|
||||
this.multiProtocolChat = multiProtocolChat;
|
||||
|
||||
this.windows = new HashMap<>();
|
||||
this.pendingConnections = new HashSet<>();
|
||||
}
|
||||
|
||||
public void openChat(User user) {
|
||||
String address = user.getAddress().getHostAddress();
|
||||
|
||||
PrivateChatWindow window = windows.get(address);
|
||||
|
||||
/*
|
||||
* Já existe uma janela para esse usuário.
|
||||
*/
|
||||
if (window != null) {
|
||||
window.setVisible(true);
|
||||
window.toFront();
|
||||
window.requestFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Já estamos esperando uma conexão para esse usuário.
|
||||
*/
|
||||
if (pendingConnections.contains(address)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ainda não existe conexão.
|
||||
*/
|
||||
pendingConnections.add(address);
|
||||
|
||||
multiProtocolChat.openConnection(address);
|
||||
}
|
||||
|
||||
public void receiveMessage(TcpConnection connection, MpChatMessage message) {
|
||||
String address = connection.getAddress().toString();
|
||||
|
||||
PrivateChatWindow window = windows.get(address);
|
||||
|
||||
if (window == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.receiveMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deve ser chamado quando uma nova conexão privada chegar.
|
||||
*/
|
||||
public void connectionReceived(TcpConnection connection) {
|
||||
String address = connection.getAddress().toString();
|
||||
|
||||
pendingConnections.remove(address);
|
||||
|
||||
PrivateChatWindow window = new PrivateChatWindow(
|
||||
pitiupi,
|
||||
connection
|
||||
);
|
||||
|
||||
windows.put(address, window);
|
||||
|
||||
window.setVisible(true);
|
||||
window.toFront();
|
||||
window.requestFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fecha a janela e remove o relacionamento.
|
||||
*/
|
||||
public void closeChat(TcpConnection connection) {
|
||||
String address = connection.getAddress().toString();
|
||||
|
||||
PrivateChatWindow window = windows.remove(address);
|
||||
|
||||
if (window != null) {
|
||||
window.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
+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;
|
||||
@@ -0,0 +1,125 @@
|
||||
package plugin;
|
||||
|
||||
import GUI.MulticastMpChatMenu;
|
||||
import GUI.PrivateChatWindow;
|
||||
import GUI.PublicChatWindow;
|
||||
import GUI.UnicastMpChatMenu;
|
||||
import control.PrivateChatController;
|
||||
import net.MpChatMessage;
|
||||
import pitiupi.models.Menus.MenuCategory;
|
||||
import pitiupi.models.Messages.Message;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
import pitiupi.models.Plugin;
|
||||
import pitiupi.plugin.Pitiupi;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
|
||||
public class MultiProtocolChat extends Plugin {
|
||||
Pitiupi pitiupi;
|
||||
|
||||
PrivateChatController privateChatController;
|
||||
PublicChatWindow publicChatWindow;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "MultiProtocol chat";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return "Gustavo Henrique";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "Multi.Protocol.Chat.Pitiupi";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPlugin(Pitiupi pitiupi) {
|
||||
this.pitiupi = pitiupi;
|
||||
|
||||
privateChatController = new PrivateChatController(pitiupi, this);
|
||||
|
||||
publicChatWindow = new PublicChatWindow(pitiupi);
|
||||
|
||||
MulticastMpChatMenu multicastMpChatMenu = new MulticastMpChatMenu(publicChatWindow);
|
||||
UnicastMpChatMenu unicastMpChatMenu = new UnicastMpChatMenu(privateChatController);
|
||||
|
||||
pitiupi.createMenu(MenuCategory.Social, multicastMpChatMenu);
|
||||
pitiupi.createMenu(MenuCategory.Social, unicastMpChatMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Message>> getMessages() {
|
||||
return List.of(MpChatMessage.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveMessage(Message message) {
|
||||
if (message instanceof MpChatMessage mpChatMessage) {
|
||||
publicChatWindow.receiveMessage(mpChatMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean receivePrivateConnection(TcpConnection connection) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
privateChatController.connectionReceived(connection);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean receiveBytes(TcpConnection connection, byte[] bytes) {
|
||||
MpChatMessage mpChatMessage = parseMessage(bytes);
|
||||
if (mpChatMessage == null) {
|
||||
System.out.println("Invalid message received");
|
||||
return true;
|
||||
}
|
||||
else System.out.println(mpChatMessage.getMessage());
|
||||
|
||||
privateChatController.receiveMessage(connection, mpChatMessage);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSocketClosed(TcpConnection connection) {
|
||||
privateChatController.closeChat(connection);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void openConnection(String ip) {
|
||||
try {
|
||||
pitiupi.connectTcp(InetAddress.getByName(ip), getIdentifier(), getIdentifier());
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Error opening connection: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private MpChatMessage parseMessage(byte[] bytes) {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois;
|
||||
try {
|
||||
ois = new ObjectInputStream(bis);
|
||||
if (ois.readObject() instanceof MpChatMessage msg) {
|
||||
return msg;
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException ex) {
|
||||
System.out.println(ex.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<?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$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
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.
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>
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+10
@@ -0,0 +1,10 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Ignored default folder with query files
|
||||
/queries/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/pitiupi.testSocket.iml" filepath="$PROJECT_DIR$/pitiupi.testSocket.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +0,0 @@
|
||||
plugin.TestChat
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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,94 +0,0 @@
|
||||
package GUI;
|
||||
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
public abstract class ChatWindow extends JFrame {
|
||||
|
||||
protected final MainWindow mainWindow;
|
||||
|
||||
private JTextArea receivedMessagesArea;
|
||||
protected JTextField messageField;
|
||||
|
||||
public ChatWindow(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
initComponents();
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
setTitle("Socket Test");
|
||||
setSize(700, 500);
|
||||
setLocationRelativeTo(null);
|
||||
setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
|
||||
initReceivedMessagesPanel(mainPanel);
|
||||
initBottomPanel(mainPanel);
|
||||
|
||||
setContentPane(mainPanel);
|
||||
}
|
||||
|
||||
private void initReceivedMessagesPanel(JPanel mainPanel) {
|
||||
receivedMessagesArea = new JTextArea();
|
||||
receivedMessagesArea.setEditable(false);
|
||||
receivedMessagesArea.setLineWrap(true);
|
||||
receivedMessagesArea.setWrapStyleWord(true);
|
||||
|
||||
JScrollPane messagesScrollPane = new JScrollPane(receivedMessagesArea);
|
||||
|
||||
messagesScrollPane.setBorder(BorderFactory.createTitledBorder("Mensagens recebidas"));
|
||||
|
||||
mainPanel.add(messagesScrollPane, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
private void initBottomPanel(JPanel mainPanel) {
|
||||
messageField = new JTextField();
|
||||
|
||||
JPanel bottomPanel = new JPanel(new BorderLayout(10, 10));
|
||||
|
||||
bottomPanel.add(messageField, BorderLayout.CENTER);
|
||||
|
||||
initButtons(bottomPanel);
|
||||
|
||||
mainPanel.add(bottomPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
protected abstract void initButtons(JPanel bottomPanel);
|
||||
|
||||
protected TestChatMessage createMessage(String tipoMensagem) {
|
||||
try {
|
||||
String nome = mainWindow.getUserName();
|
||||
String ip = InetAddress.getLocalHost().getHostAddress();
|
||||
String message = messageField.getText();
|
||||
|
||||
return new TestChatMessage(nome, ip, tipoMensagem, message);
|
||||
|
||||
} catch (UnknownHostException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void receiveMessage(TestChatMessage msg) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
String mensagem = String.format(
|
||||
"[%s] %s (%s): %s%n",
|
||||
msg.getTipoMensagem(),
|
||||
msg.getNome(),
|
||||
msg.getIp(),
|
||||
msg.getMessage()
|
||||
);
|
||||
|
||||
receivedMessagesArea.append(mensagem);
|
||||
|
||||
receivedMessagesArea.setCaretPosition(receivedMessagesArea.getDocument().getLength());
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package GUI;
|
||||
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PrivateChatWindow extends ChatWindow {
|
||||
|
||||
private final TcpConnection connection;
|
||||
|
||||
public PrivateChatWindow(MainWindow mainWindow, TcpConnection connection) {
|
||||
this.connection = connection;
|
||||
|
||||
super(mainWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initButtons(JPanel bottomPanel) {
|
||||
JButton tcpButton = new JButton("TCP");
|
||||
|
||||
tcpButton.addActionListener(e -> sendTCP());
|
||||
|
||||
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
|
||||
|
||||
buttonsPanel.add(tcpButton);
|
||||
|
||||
bottomPanel.add(buttonsPanel, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
private void sendTCP() {
|
||||
try {
|
||||
TestChatMessage msg = createMessage("TCP Private");
|
||||
connection.send(msg.toByteArray());
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(
|
||||
PrivateChatWindow.class.getName()
|
||||
).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package GUI;
|
||||
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.net.InetAddress;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PublicChatWindow extends ChatWindow {
|
||||
|
||||
private JTextField ipField;
|
||||
|
||||
public PublicChatWindow(MainWindow mainWindow) {
|
||||
super(mainWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initButtons(JPanel bottomPanel) {
|
||||
initIpField(bottomPanel);
|
||||
initCommunicationButtons(bottomPanel);
|
||||
}
|
||||
|
||||
private void initIpField(JPanel bottomPanel) {
|
||||
ipField = new JTextField();
|
||||
ipField.setPreferredSize(new Dimension(130, 30));
|
||||
|
||||
JPanel ipPanel = new JPanel(new BorderLayout(5, 5));
|
||||
|
||||
ipPanel.add(new JLabel("IP destino:"), BorderLayout.WEST);
|
||||
|
||||
ipPanel.add(ipField, BorderLayout.CENTER);
|
||||
|
||||
bottomPanel.add(ipPanel, BorderLayout.WEST);
|
||||
}
|
||||
|
||||
private void initCommunicationButtons(JPanel bottomPanel) {
|
||||
JButton tcpButton = new JButton("TCP");
|
||||
JButton udpButton = new JButton("UDP");
|
||||
JButton multicastButton = new JButton("Multicast");
|
||||
|
||||
tcpButton.addActionListener(e -> sendTCP());
|
||||
udpButton.addActionListener(e -> sendUDP());
|
||||
multicastButton.addActionListener(e -> sendMulticast());
|
||||
|
||||
JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 0));
|
||||
|
||||
buttonsPanel.add(tcpButton);
|
||||
buttonsPanel.add(udpButton);
|
||||
buttonsPanel.add(multicastButton);
|
||||
|
||||
bottomPanel.add(buttonsPanel, BorderLayout.EAST);
|
||||
}
|
||||
|
||||
private void sendTCP() {
|
||||
try {
|
||||
TestChatMessage msg = createMessage("TCP Unicast");
|
||||
|
||||
InetAddress ip = InetAddress.getByName(ipField.getText());
|
||||
|
||||
mainWindow.getSocketTCP().send(msg, ip);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(PublicChatWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendUDP() {
|
||||
try {
|
||||
TestChatMessage msg = createMessage("UDP Unicast");
|
||||
|
||||
InetAddress ip = InetAddress.getByName(ipField.getText());
|
||||
|
||||
mainWindow.getSocketUDP().sendUnicast(msg, ip);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(PublicChatWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMulticast() {
|
||||
try {
|
||||
TestChatMessage msg = createMessage("UDP Multicast");
|
||||
|
||||
mainWindow.getSocketUDP().sendMulticast(msg);
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.getLogger(PublicChatWindow.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
plugin.TestChat
|
||||
@@ -1,61 +0,0 @@
|
||||
package control;
|
||||
|
||||
import GUI.ChatMenu;
|
||||
import GUI.ChatWindow;
|
||||
import GUI.PrivateChatWindow;
|
||||
import GUI.PublicChatWindow;
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ChatController {
|
||||
MainWindow mainWindow;
|
||||
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);
|
||||
|
||||
chatMenus = new HashMap<>();
|
||||
chatWindows = new HashMap<>();
|
||||
|
||||
this.chatMenu = chatMenu;
|
||||
|
||||
this.chatMenu.newMenuItem(new JMenuItem("Show global chat"), publicChatWindow);
|
||||
}
|
||||
|
||||
public void addChatWindow(TcpConnection tcpConnection) {
|
||||
if (chatWindows.containsKey(tcpConnection)) return;
|
||||
|
||||
PrivateChatWindow newChat = new PrivateChatWindow(mainWindow, tcpConnection);
|
||||
chatWindows.put(tcpConnection, newChat);
|
||||
JMenuItem newMenuItem = new JMenuItem();
|
||||
chatMenus.put(tcpConnection, newMenuItem);
|
||||
newMenuItem.setText(tcpConnection.getAddress().toString());
|
||||
chatMenu.newMenuItem(newMenuItem, newChat);
|
||||
}
|
||||
|
||||
public void removeChatWindow(TcpConnection tcpConnection) {
|
||||
ChatWindow removedWindow = chatWindows.remove(tcpConnection);
|
||||
JMenuItem removedMenu = chatMenus.remove(tcpConnection);
|
||||
|
||||
chatMenu.removeMenuItem(removedMenu);
|
||||
removedWindow.setVisible(false);
|
||||
removedWindow.dispose();
|
||||
}
|
||||
|
||||
public void receivePublic(TestChatMessage message) {
|
||||
publicChatWindow.receiveMessage(message);
|
||||
}
|
||||
public void receivePrivate(TcpConnection tcpConnection, TestChatMessage message) {
|
||||
chatWindows.get(tcpConnection).receiveMessage(message);
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package plugin;
|
||||
|
||||
import GUI.ChatMenu;
|
||||
import control.ChatController;
|
||||
import net.TestChatMessage;
|
||||
import pitiupi.GUI.MainWindow;
|
||||
import pitiupi.net.Message;
|
||||
import pitiupi.net.tcp.TcpConnection;
|
||||
import pitiupi.plugin.PrivateConnectionPlugin;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.net.InetAddress;
|
||||
|
||||
public class TestChat implements PrivateConnectionPlugin{
|
||||
ChatController chatController;
|
||||
MainWindow mainWindow;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "MultiProtocol chat";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return "Gustavo Henrique";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "Multi.Protocol.Chat.Pitiupi";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createPlugin(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
|
||||
ChatMenu chatMenu = new ChatMenu(this);
|
||||
chatController = new ChatController(mainWindow, chatMenu);
|
||||
mainWindow.addMenu(chatMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message getMessage() {
|
||||
return new TestChatMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveMessage(byte[] message) {
|
||||
TestChatMessage testChatMessage = parseMessage(message);
|
||||
chatController.receivePublic(testChatMessage);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receivePrivateConnection(TcpConnection tcpConnection) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
chatController.addChatWindow(tcpConnection);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveBytes(TcpConnection connection, byte[] bytes) {
|
||||
TestChatMessage testChatMessage = parseMessage(bytes);
|
||||
chatController.receivePrivate(connection, testChatMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSocketClosed(TcpConnection tcpConnection) {
|
||||
chatController.removeChatWindow(tcpConnection);
|
||||
}
|
||||
|
||||
public boolean openConnection(String ip) {
|
||||
try {
|
||||
mainWindow.getSocketTCP().createPrivateConnection(InetAddress.getByName(ip), getIdentifier(), getIdentifier());
|
||||
return true;
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("Error opening connection: " + e.getMessage());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private TestChatMessage parseMessage(byte[] bytes) {
|
||||
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois;
|
||||
try {
|
||||
ois = new ObjectInputStream(bis);
|
||||
if (ois.readObject() instanceof TestChatMessage msg) {
|
||||
return msg;
|
||||
}
|
||||
} catch (IOException | ClassNotFoundException ex) {
|
||||
System.out.println(ex.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
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:
|
||||
|
||||
```
|
||||
|
||||
@@ -1,2 +1,512 @@
|
||||
# Como criar plugins para o Share my Sheet
|
||||
# Como criar plugins para o Pitiupi
|
||||
|
||||
Aqui serão discutidos os métodos e classes que um desenvolvedor pode ou deve usar para criar um plugin para a plataforma Pitiupi.
|
||||
|
||||
Alguns deles estarão marcados com um <span style="color: red;">[REF]</span>, isso indica que eles estão sendo alterados para a versão 3.0 e deixarão de existir ou vão mudar consideravelmente.
|
||||
|
||||
## GUI
|
||||
|
||||
O Pitiupi é feito usando a biblioteca Swing do Java, por isso é altamente recomendado que os plugins também a utilizem na hora de criar sua interface gráfica, porém não é obrigatório.
|
||||
|
||||
## Como tornar o seu plugin visível para o Pitiupi
|
||||
|
||||
A busca por plugins é realizada em três etapas pelo pitiupi:
|
||||
|
||||
1. Encontra todos os jars em `plugins`.
|
||||
2. Verifica o `META-INF` dos jars para saber onde estão as implementações da classe `Plugin`.
|
||||
3. Carrega o plugin no sistema.
|
||||
|
||||
Em relação ao `META-INF`, ele deve conter um diretório `resources` e dentro dele um arquivo contendo o nome completamente qualificado da classe `Plugin` do pitiupi: `pitiupi.models.Plugin`, por fim dentro desse arquivo você deve colocar o nome completamente qualificado de todas as classes que implementam `Plugin` do seu projeto, um em cada linha.
|
||||
|
||||
```
|
||||
build/
|
||||
|---->META-INF/resources/pitiupi.models.Plugin
|
||||
|---->MeusPlugins/...
|
||||
|---->MinhasMensagens/...
|
||||
|---->Restante dos .class
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
src/MeusPlugins/MeuPrimeiroPlugin
|
||||
src/MeusPlugins/MeuSegundoPlugin
|
||||
...
|
||||
```
|
||||
|
||||
### Dicas
|
||||
|
||||
- Faça um makefile que automaticamente mova o META-INF para o build/ quando você compilar uma nova versão caso ele esteja sendo alterado com frequência.
|
||||
Ex:
|
||||
```
|
||||
JAR = ../pitiupi/dist/pitiupi.jar
|
||||
BUILD_DIR = build
|
||||
META-INF_DIR = src/META-INF
|
||||
DIST = dist/mpChat.jar
|
||||
|
||||
SOURCES = $(shell find -name "*.java")
|
||||
|
||||
all:
|
||||
mkdir -p "$(BUILD_DIR)"
|
||||
mkdir -p "$(dir $(DIST))"
|
||||
javac -cp "$(JAR)" -d "$(BUILD_DIR)" $(SOURCES)
|
||||
cp -r "$(META-INF_DIR)" "$(BUILD_DIR)"
|
||||
jar cf "$(DIST)" -C "$(BUILD_DIR)" .
|
||||
|
||||
clean:
|
||||
rm -rf "$(BUILD_DIR)"/*
|
||||
```
|
||||
|
||||
- Para a versão 3.0 será necessário fazer o mesmo processo para as implementações da classe `Message`, então se quiser deixar preparado para a nova versão adicione `pitiupi.models.Messages.Message` em `resources` e coloque nele todas suas implementações de `Message`, assim como você fez para os de `Plugin`.
|
||||
|
||||
## Pitiupi
|
||||
|
||||
A classe `Pitiupi` é a interface que o seu plugin vai receber quando for criado, ela fornece os métodos necessários para interagir com a interface gráfica e comunicação para outros peers.
|
||||
|
||||
### boolean sendUdpMulticast(Message message)
|
||||
|
||||
Envia uma mensagem multicast, retorna `boolean` indicando se teve sucesso.
|
||||
|
||||
### boolean sendUdpUnicast(Message message, InetAddress address)
|
||||
|
||||
Envia uma mensagem unicast via udp para o endereço fornecido, retorna `boolean` indicando se teve sucesso.
|
||||
|
||||
### boolean sendTcp(Message message, InetAddress address)
|
||||
|
||||
Envia uma mensagem unicast via tcp para o endereço fornecido, retorna `boolean` indicando se teve sucesso.
|
||||
|
||||
### <span style="color: red;">[REF]</span> TcpConnection connectTcp(InetAddress address, String senderId, String receiverId)
|
||||
|
||||
Pede uma conexão tcp privada para o seu plugin com outro usuário, para utilizar essa funcionalidade é necessário implementar alguns métodos opcionais em Plugin. Maisinformações serão discutidas na seção TcpConnection.
|
||||
|
||||
### String getUserName()
|
||||
|
||||
Retorna o nome do usuário conectado
|
||||
|
||||
### int getPort()
|
||||
|
||||
Retorna a porta que o usuário está usando o Pitiupi
|
||||
|
||||
### void createMenu(MenuCategory category, Menu menu)
|
||||
|
||||
Adiciona um menu ao pitiupi, category define em qual das categoria de Menus ele será adicionado: Jogos, Social, Streaming.
|
||||
|
||||
Os `Menus` serão discutidos em uma seção posterior.
|
||||
|
||||
## Classe Plugin
|
||||
|
||||
Essa é a classe que o pitiupi vai procurar ao carregar o seu plugin, ela define um contrato de métodos que todo plugin deve possuir.
|
||||
|
||||
### getName()
|
||||
|
||||
Indica o nome público do plugin.
|
||||
|
||||
### getAuthor()
|
||||
|
||||
Indica o nome dos desenvolvedores do plugin.
|
||||
|
||||
### getVersion()
|
||||
|
||||
Indica a versão atual do plugin.
|
||||
|
||||
### getIdentifier()
|
||||
|
||||
Indica um id que o pitiupi vai utilizar para enontrar seu plugin, por isso é importante que ele seja bem especifico para evitar que dois plugins sejam confundidos durante a comunicação. Procure usar algo como: MeuPlugin.Autor.Números
|
||||
|
||||
### createPlugin(Pitiupi pitiupi)
|
||||
|
||||
Após o pitiupi identificar e carregar o seu plugin, ele vai chamar esse método para inicializá-lo, por isso pense nele como o construtor do seu plugin, é aqui que você inicializa atributos, adiciona os menus inciais, etc.
|
||||
|
||||
### getMessages()
|
||||
|
||||
Esse método indica ao pitiupi quais tipos de mensagem seu plugin quer receber, normalmente as que ele mesmo implementar.
|
||||
Nesse caso, é normal que ele faça:
|
||||
|
||||
```
|
||||
return List.of(
|
||||
SuaMensagem1.class,
|
||||
SuaMensagem2.class,
|
||||
...
|
||||
);
|
||||
```
|
||||
|
||||
Caso você queira que seu plugin receba todo tipo de mensagem, existe um método `receiveAllTypes()` que ele pode sobreescrever para receber todas mensagens
|
||||
que não sejam consideradas privadas.
|
||||
|
||||
### receiveMessage(Message message)
|
||||
|
||||
Esse é o método que o pitiupi vai chamar quando quiser te entregar uma mensagem pelo canal publico de mensagens. Note que ele entrega uma `Message`, então é necessário que
|
||||
seu plugin confira o tipo real ele mesmo. Como em:
|
||||
|
||||
```
|
||||
if (message instanceOf MinhaMensagem minhaMensagem) {...}
|
||||
```
|
||||
|
||||
O pitiupi garante que é uma mensagem de um tipo que o seu plugin diz aceitar.
|
||||
|
||||
### <span style="color: red;">[REF]</span> métodos opcionais
|
||||
|
||||
Os métodos a seguir possuem uma implementação padrão da própria classe que retornam false. Os três ultimos são necessários caso seu plugin deseje criar e receber conexões privadas.
|
||||
|
||||
### <span style="color: red;">[REF]</span> receiveAllTypes()
|
||||
|
||||
Indica ao Pitiupi que seu plugin deseja receber todas as mensagens publicas da plataforma, independente do tipo.
|
||||
|
||||
### <span style="color: red;">[REF]</span> receivePrivateConnection(TcpConnection connection)
|
||||
|
||||
Esse método é chamado quando o Pitiupi precisa entregar uma `TcpConnection` ao seu plugin, seja um que você pediu ou recebeu de um peer.
|
||||
|
||||
### <span style="color: red;">[REF]</span> receiveBytes(TcpConnection connection, byte[] bytes)
|
||||
|
||||
Esse método é chamado para entregar as mensagens recebidas por um `TcpConnection`, o tcpConnection no parametro indica qual a fonte da mensagem.
|
||||
|
||||
### <span style="color: red;">[REF]</span> onSocketClosed(TcpConnection connection)
|
||||
|
||||
Esse é método é chamado quando o socket de um `TcpConnection` pertencente ao plugin é fechado.
|
||||
|
||||
## Message
|
||||
|
||||
Essa é a classe abstrata que o pitiupi usa para comunicação nos canais publicos.
|
||||
|
||||
<span style="color: red;">[REF]</span> Ela possui um atributo isPublic que por padrão é true, mas é possível defini-lo no construtor como false caso a mensagem deva ser privada.
|
||||
|
||||
Essa classe implementa `Serializable` e possui um método `toByteArray` que transforma a mensagem em `byte[]`. Porém é importante notar que caso ela possua um objeto de outra classe como atributo aquela classe também deve implementar `Serializable`.
|
||||
|
||||
## <span style="color: red;">[REF]</span> TcpConnection
|
||||
|
||||
Representa uma conexão Tcp ativa para algum outro peer, mensagens enviadas por essa conexão não chegam ao canal publico e em vez disso vão direto para destinatário.
|
||||
|
||||
Caso fique inativa (Sem enviar ou receber mensagens) por 5 minutos a conexão é fechada automaticamente e o dono é notificado.
|
||||
|
||||
### <span style="color: red;">[REF]</span> void send(byte[] message)
|
||||
|
||||
Envia um conjunto de bytes[] para o destinatario.
|
||||
|
||||
Caso queira enviar uma `Message` chame o método toByteArray para transforma-la em bytes primeiro.
|
||||
|
||||
### <span style="color: red;">[REF]</span> boolean isClosed()
|
||||
|
||||
Indica se a conexão esta fechada
|
||||
|
||||
### <span style="color: red;">[REF]</span> InetAddress getAddress()
|
||||
|
||||
Retorna o endereço do peer que ela esta conectada.
|
||||
|
||||
### <span style="color: red;">[REF]</span> String getReceiver()
|
||||
|
||||
Retorna o identificador do plugin que ela esta conectada.
|
||||
|
||||
### <span style="color: red;">[REF]</span> getReceiver()
|
||||
|
||||
Retorna o identifador do plugin que pediu pela conexão.
|
||||
|
||||
## Menu
|
||||
|
||||
Essa é a classe que indica ao pitiupi que um menu deve ser adicionado a janela principal da aplicação.
|
||||
|
||||
Menus podem ser de dois tipos `UnicastMenu` e `MulticastMenu` com a principal diferença entre eles sendo onde eles são adicionados na janela principal. Outras mudanças serão discutidas quando for relevante nas classes a seguir.
|
||||
|
||||
Atualmente Menus não podem ser alterados uma vez que são adicionados, então é importante que eles sejam feitos com isso em mente.
|
||||
|
||||
Tem um método `String getText()` que retorna o que deve ser escrito no Menu`.
|
||||
|
||||
### SubMenu
|
||||
|
||||
Permite que o `Menu` expanda em uma nova seção de menus.
|
||||
|
||||
`UnicastSubMenu` o método `getMenu()` retorna `List<UnicastMenu>`
|
||||
|
||||
`MulticastSubMenu` o método `getMenu()` retorna `List<MulticastMenu>`
|
||||
|
||||
Exemplo:
|
||||
|
||||
```
|
||||
|
||||
ChatCasualMulticastMenu chatCasualMulticastMenu;
|
||||
ChatEstudoMutlticastMenu chatEstudoMutlticastMenu;
|
||||
|
||||
...
|
||||
|
||||
@Override
|
||||
public List<MulticastMenu> getMenus() {
|
||||
return List.of(chatCasualMulticastMenu, chatEstudoMutlticastMenu);
|
||||
}
|
||||
```
|
||||
|
||||
### ActionMenu
|
||||
|
||||
É um `Menu` que que realiza alguma ação quando selecionado pelo usuário.
|
||||
|
||||
`UnicastActionMenu` o método `onClick(User user)` é chamado quando selecionado pelo usuário, recebendo como parametro o peer escolhido pelo usuário.
|
||||
|
||||
`MulticastActionMenu` o método `onClick()` é chamado quando selecionado pelo usuário.
|
||||
|
||||
Exemplo:
|
||||
|
||||
```
|
||||
|
||||
@Override
|
||||
public void onClick(User user) {
|
||||
callManager.openCallWindow(user);
|
||||
}
|
||||
```
|
||||
|
||||
## Exemplo de plugin no pitiupi:
|
||||
|
||||
### Plugin
|
||||
|
||||
Implementa o contrato de plugin.
|
||||
|
||||
Inicializa a janela principal e cria os menus.
|
||||
|
||||
Também define quais tipos de mensagem ele quer receber.
|
||||
|
||||
```
|
||||
public class ChatPlugin extends Plugin {
|
||||
|
||||
private ChatWindow chatWindow;
|
||||
|
||||
@Override
|
||||
public void createPlugin(Pitiupi pitiupi) {
|
||||
this.chatWindow = new ChatWindow(pitiupi);
|
||||
pitiupi.createMenu(MenuCategory.Social, new ChatMenu(chatWindow));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Message>> getMessages() {
|
||||
return List.of(ChatMessage.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void receiveMessage(Message message) {
|
||||
if (message instanceof ChatMessage msg) {
|
||||
this.chatWindow.receiveChatMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Chat";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthor() {
|
||||
return "Flávio Schiavoni";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "Pitiupi.Chat.Example.123456";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Message
|
||||
|
||||
Implementa uma mensagem customizada que o plugin vai utilizar para comunicação.
|
||||
|
||||
```
|
||||
public class ChatMessage extends Message {
|
||||
|
||||
private String text;
|
||||
private String name;
|
||||
|
||||
|
||||
public ChatMessage(){
|
||||
|
||||
}
|
||||
|
||||
public ChatMessage(String name, String text){
|
||||
this.name = name;
|
||||
this.text = text;
|
||||
}
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the text
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param text the text to set
|
||||
*/
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Menus
|
||||
|
||||
Implementa os dois menus de Multicast utilizados pela aplicação.
|
||||
|
||||
#### ActionMenu
|
||||
|
||||
Esse menu apenas abre a janela principal do plugin.
|
||||
|
||||
```
|
||||
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);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Esse menu abre a seção de menus do plugin Chat.
|
||||
|
||||
#### SubMenu
|
||||
|
||||
```
|
||||
public class ChatMenu extends MulticastSubMenu {
|
||||
ChatMulticastMenu chatMulticastMenu;
|
||||
|
||||
public ChatMenu(ChatWindow chatWindow) {
|
||||
this.chatMulticastMenu = new ChatMulticastMenu(chatWindow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return "Chat";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MulticastMenu> getMenus() {
|
||||
return List.of(chatMulticastMenu);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### GUI
|
||||
|
||||
Essa é a janela principal do plugin de chat.
|
||||
|
||||
```
|
||||
public class ChatWindow extends JDialog {
|
||||
|
||||
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 Pitiupi pitiupi;
|
||||
|
||||
public ChatWindow(Pitiupi pitiupi) {
|
||||
this.pitiupi = pitiupi;
|
||||
initComponents();
|
||||
}
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
* regenerated by the Form Editor.
|
||||
*/
|
||||
private void initComponents() {
|
||||
|
||||
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 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(JSplitPane.VERTICAL_SPLIT);
|
||||
jEditorPane1.setContentType("text/html");
|
||||
jPanel1.setLayout(new java.awt.BorderLayout());
|
||||
jTextArea1.setColumns(20);
|
||||
jTextArea1.setRows(5);
|
||||
jTextArea1.addKeyListener(new java.awt.event.KeyAdapter() {
|
||||
@Override
|
||||
public void keyTyped(java.awt.event.KeyEvent evt) {
|
||||
if (evt.getKeyChar() == '\n') {
|
||||
sendMessage();
|
||||
}
|
||||
}
|
||||
});
|
||||
jButton1.setText("Send");
|
||||
|
||||
jScrollPane1.setViewportView(jEditorPane1);
|
||||
jScrollPane2.setViewportView(jTextArea1);
|
||||
jSplitPane1.setTopComponent(jScrollPane1);
|
||||
|
||||
jPanel1.add(jScrollPane2, java.awt.BorderLayout.CENTER);
|
||||
jPanel2.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT));
|
||||
jButton1.addActionListener((java.awt.event.ActionEvent evt) -> {
|
||||
sendMessage();
|
||||
});
|
||||
jPanel2.add(jButton1);
|
||||
jPanel1.add(jPanel2, java.awt.BorderLayout.PAGE_END);
|
||||
jSplitPane1.setRightComponent(jPanel1);
|
||||
getContentPane().add(jSplitPane1, java.awt.BorderLayout.CENTER);
|
||||
pack();
|
||||
}
|
||||
|
||||
private void sendMessage() {
|
||||
if (jTextArea1.getText().trim().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ChatMessage message = new ChatMessage(pitiupi.getUserName(), jTextArea1.getText());
|
||||
this.sendChatMessage(message);
|
||||
jTextArea1.setText("");
|
||||
}
|
||||
|
||||
public void sendChatMessage(Message message) {
|
||||
pitiupi.sendUdpMulticast(message);
|
||||
}
|
||||
|
||||
public void receiveChatMessage(ChatMessage message) {
|
||||
SimpleDateFormat dt = new SimpleDateFormat("dd/MM/yyyyy hh:mm:ss");
|
||||
Date date = new Date();
|
||||
this.receiveChatMessage(dt.format(date) + " "
|
||||
+ "<b>" + message.getName() + "</b>: "
|
||||
+ message.getText() + "<br>");
|
||||
}
|
||||
|
||||
public void receiveChatMessage(String message) {
|
||||
jEditorPane1.setText(message + jEditorPane1.getText());
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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,69 @@ 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){
|
||||
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,82 @@
|
||||
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) {
|
||||
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,156 @@
|
||||
package pitiupi.control.plugins;
|
||||
|
||||
import pitiupi.plugin.Pitiupi;
|
||||
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 true;
|
||||
}
|
||||
|
||||
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"));
|
||||
Pitiupi pitiupi = new Pitiupi(connectionManager, guiManager);
|
||||
|
||||
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) {
|
||||
LoadedPlugin loadedPlugin = new LoadedPlugin(plugin, classLoader);
|
||||
|
||||
plugin.createPlugin(pitiupi);
|
||||
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,
|
||||
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user