Archived
1
0
Fork 0

Merge branch 'ziedelth'

# Conflicts:
#	src/fr/univ/lyon1/client/Client.java
#	src/fr/univ/lyon1/client/ClientReceive.java
#	src/fr/univ/lyon1/common/ServerConfiguration.java
This commit is contained in:
Ethanell 2022-01-30 17:16:27 +01:00
commit 538b2d30f4
17 changed files with 489 additions and 253 deletions

View file

@ -49,9 +49,13 @@ public class Client {
this.port = port; this.port = port;
this.username = username; this.username = username;
this.password = password; this.password = password;
System.out.println("Init SSL...");
socket = initSSL(); socket = initSSL();
System.out.println("Set output stream...");
out = new ObjectOutputStream(socket.getOutputStream()); out = new ObjectOutputStream(socket.getOutputStream());
System.out.println("Get In...");
getIn(); getIn();
System.out.println("Client ok");
} }
/** /**
@ -61,9 +65,7 @@ public class Client {
*/ */
private Socket initSSL() throws IOException { private Socket initSSL() throws IOException {
SSLContext ctx = ChatSSL.getSSLContext(); SSLContext ctx = ChatSSL.getSSLContext();
SocketFactory factory = ctx.getSocketFactory(); SocketFactory factory = ctx.getSocketFactory();
Socket connection = factory.createSocket(address, port); Socket connection = factory.createSocket(address, port);
((SSLSocket) connection).setEnabledProtocols(new String[] {ChatSSL.tlsVersion}); ((SSLSocket) connection).setEnabledProtocols(new String[] {ChatSSL.tlsVersion});
SSLParameters sslParams = new SSLParameters(); SSLParameters sslParams = new SSLParameters();
@ -234,7 +236,7 @@ public class Client {
Thread clientSendThread = new Thread(new ClientSend(this, out, socket)); Thread clientSendThread = new Thread(new ClientSend(this, out, socket));
clientSendThread.start(); clientSendThread.start();
Thread clientReceiveThread = new Thread(new ClientReceive(this, socket)); Thread clientReceiveThread = new Thread(new ClientReceive(this));
clientReceiveThread.start(); clientReceiveThread.start();
started = true; started = true;

View file

@ -2,7 +2,6 @@ package fr.univ.lyon1.client;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
/** /**
@ -10,17 +9,13 @@ import java.net.SocketException;
*/ */
public class ClientReceive implements Runnable { public class ClientReceive implements Runnable {
private final Client client; private final Client client;
private ObjectInputStream in;
private final Socket socket;
/** /**
* Create a receiver manager from a client and a socket * Create a receiver manager from a client and a socket
* @param client the client * @param client the client
* @param socket the client socket to the server
*/ */
public ClientReceive(Client client, Socket socket) { public ClientReceive(Client client) {
this.client = client; this.client = client;
this.socket = socket;
} }
/** /**
@ -28,6 +23,8 @@ public class ClientReceive implements Runnable {
*/ */
@Override @Override
public void run() { public void run() {
ObjectInputStream in;
try { try {
in = client.getIn(); in = client.getIn();
} catch (IOException e) { } catch (IOException e) {
@ -37,6 +34,7 @@ public class ClientReceive implements Runnable {
while(true) { while(true) {
Object data; Object data;
try { try {
data = in.readObject(); data = in.readObject();
} catch (ClassNotFoundException|IOException e) { } catch (ClassNotFoundException|IOException e) {
@ -44,13 +42,16 @@ public class ClientReceive implements Runnable {
System.err.println("Connexion closed"); System.err.println("Connexion closed");
break; break;
} }
System.err.println("Fail to read object !"); System.err.println("Fail to read object !");
e.printStackTrace(); e.printStackTrace();
try { try {
Thread.sleep(1000); Thread.currentThread().join(1000);
} catch (InterruptedException ex) { } catch (InterruptedException ex) {
break; break;
} }
continue; continue;
} }

View file

@ -12,7 +12,7 @@ import java.util.Properties;
* The client server configuration * The client server configuration
* ToDo should be in gui and not in common ? * ToDo should be in gui and not in common ?
*/ */
public record ServerConfiguration(@NotNull String address, int port) { public record ServerConfiguration(@NotNull String address, int port, @NotNull String pseudo, @NotNull String password) {
@NotNull @NotNull
private static final File file = new File("connection.properties"); private static final File file = new File("connection.properties");
@ -20,10 +20,14 @@ public record ServerConfiguration(@NotNull String address, int port) {
* Create a configuration * Create a configuration
* @param address the server address * @param address the server address
* @param port the server port * @param port the server port
* @param pseudo the username
* @param password the user password
*/ */
public ServerConfiguration(@NotNull String address, int port) { public ServerConfiguration(@NotNull String address, int port, @NotNull String pseudo, @NotNull String password) {
this.address = address; this.address = address;
this.port = port; this.port = port;
this.pseudo = pseudo;
this.password = password;
} }
/** /**
@ -40,7 +44,7 @@ public record ServerConfiguration(@NotNull String address, int port) {
@NotNull final Properties properties = new Properties(); @NotNull final Properties properties = new Properties();
properties.load(new FileReader(file)); properties.load(new FileReader(file));
return new ServerConfiguration(properties.getProperty("address"), Integer.parseInt(properties.getProperty("port"))); return new ServerConfiguration(properties.getProperty("address"), Integer.parseInt(properties.getProperty("port")), properties.getProperty("pseudo"), properties.getProperty("password"));
} }
/** /**
@ -51,6 +55,8 @@ public record ServerConfiguration(@NotNull String address, int port) {
@NotNull final Properties properties = new Properties(); @NotNull final Properties properties = new Properties();
properties.setProperty("address", this.address); properties.setProperty("address", this.address);
properties.setProperty("port", String.valueOf(this.port)); properties.setProperty("port", String.valueOf(this.port));
properties.setProperty("pseudo", this.pseudo);
properties.setProperty("password", this.password);
properties.store(new FileWriter(file), "Information needed to connect to the server"); properties.store(new FileWriter(file), "Information needed to connect to the server");
} }
@ -69,4 +75,12 @@ public record ServerConfiguration(@NotNull String address, int port) {
public int getPort() { public int getPort() {
return port; return port;
} }
public String getPseudo() {
return pseudo;
}
public String getPassword() {
return password;
}
} }

View file

@ -1,39 +0,0 @@
package fr.univ.lyon1.gui;
import fr.univ.lyon1.client.Client;
import fr.univ.lyon1.client.ClientReceive;
import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.common.command.CommandType;
import fr.univ.lyon1.gui.handlers.MainHandler;
import fr.univ.lyon1.common.command.Command;
import java.io.IOException;
import java.util.List;
public class ClientGUI extends Client {
private final MainHandler gui;
public ClientGUI(MainHandler handler, String address, int port) throws IOException {
super(address, port, null, null);
this.gui = handler;
}
@Override
protected void commandMessage(Command cmd) {
gui.receiveMessage(cmd.getArgs().get(0).toString());
}
@Override
public void run() throws IOException {
if (started)
return;
Thread clientReceiveThread = new Thread(new ClientReceive(this, super.socket));
clientReceiveThread.start();
out.writeObject(new Command(CommandType.login, List.of("test", "test"))); // ToDo: Setup login
out.flush();
started = true;
}
}

View file

@ -1,86 +0,0 @@
package fr.univ.lyon1.gui;
import fr.univ.lyon1.gui.handlers.MainHandler;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
public class ClientPanel extends Parent {
private final TextArea textToSend = new TextArea();
private final TextFlow receivedText = new TextFlow();
private final MainHandler gui;
public ClientPanel(MainHandler gui) {
this.gui = gui;
ScrollPane scrollReceivedText = new ScrollPane();
scrollReceivedText.setLayoutX(20);
scrollReceivedText.setLayoutY(20);
scrollReceivedText.setPrefWidth(400);
scrollReceivedText.setPrefHeight(350);
scrollReceivedText.setContent(receivedText);
scrollReceivedText.vvalueProperty().bind(receivedText.heightProperty());
this.getChildren().add(scrollReceivedText);
Button sendBtn = new Button();
sendBtn.setPrefWidth(80);
int btnMargin = 20;
textToSend.setLayoutX(scrollReceivedText.getLayoutX());
textToSend.setLayoutY(scrollReceivedText.getLayoutY() + scrollReceivedText.getPrefHeight() + 20);
textToSend.setPrefWidth(400- sendBtn.getPrefWidth()-btnMargin);
textToSend.setPrefHeight(100);
this.getChildren().add(textToSend);
textToSend.setOnKeyPressed(this::textToSendKeyPressed);
sendBtn.setText("Send");
sendBtn.setLayoutX(textToSend.getLayoutX() + textToSend.getPrefWidth() + btnMargin);
sendBtn.setLayoutY(textToSend.getLayoutY());
sendBtn.setPrefWidth(80);
sendBtn.setPrefHeight(40);
sendBtn.setVisible(true);
this.getChildren().add(sendBtn);
sendBtn.setOnAction(this::sendBtnAction);
Button clearBtn = new Button();
clearBtn.setText("Clear");
clearBtn.setLayoutX(sendBtn.getLayoutX());
clearBtn.setPrefWidth(sendBtn.getPrefWidth());
clearBtn.setPrefHeight(sendBtn.getPrefHeight());
clearBtn.setLayoutY(textToSend.getLayoutY() + textToSend.getPrefHeight() - clearBtn.getPrefHeight());
clearBtn.setVisible(true);
this.getChildren().add(clearBtn);
clearBtn.setOnAction(this::clearBtnAction);
}
private void send() {
String msg = textToSend.getText();
gui.sendMessage(msg);
textToSend.clear();
addMessage(msg);
}
private void sendBtnAction(ActionEvent e) {
send();
}
private void textToSendKeyPressed(KeyEvent e) {
if (e.getCode() == KeyCode.ENTER)
send();
}
private void clearBtnAction(ActionEvent e) {
textToSend.clear();
}
public void addMessage(String message) {
Platform.runLater(() -> receivedText.getChildren().add(new Text(message+"\n")));
}
}

View file

@ -0,0 +1,45 @@
package fr.univ.lyon1.gui;
import javafx.scene.control.Alert;
import org.jetbrains.annotations.NotNull;
public class Dialog {
/**
* Show an error alert dialog for user interface
* @param title Title of the alert
* @param description Description of the alert
*/
public static void showErrorDialog(String title, String description) {
@NotNull
final Alert alert = new Alert(Alert.AlertType.WARNING);
extracted(title, description, alert);
}
/**
* Show a success alert dialog for user interface
* @param title Title of the alert
* @param description Description of the alert
*/
public static void showSuccessDialog(String title, String description) {
System.out.println("Create success dialog...");
@NotNull
final Alert alert = new Alert(Alert.AlertType.INFORMATION);
System.out.println("Extracting...");
extracted(title, description, alert);
}
/**
* Method used to avoid duplication code
* @param title Title of the alert
* @param description Description of the alert
* @param alert Alert interface
*/
private static void extracted(String title, String description, @NotNull Alert alert) {
System.out.println("Set title");
alert.setTitle(title);
System.out.println("Set description");
alert.setContentText(description);
System.out.println("Show");
alert.show();
}
}

View file

@ -1,6 +1,6 @@
package fr.univ.lyon1.gui; package fr.univ.lyon1.gui;
import fr.univ.lyon1.gui.handlers.MainHandler; import fr.univ.lyon1.gui.handlers.ApplicationHandler;
import fr.univ.lyon1.gui.handlers.ServerConfigurationHandler; import fr.univ.lyon1.gui.handlers.ServerConfigurationHandler;
import javafx.application.Application; import javafx.application.Application;
import javafx.application.Platform; import javafx.application.Platform;
@ -12,8 +12,10 @@ public class MainGui extends Application {
@Override @Override
public void start(Stage stage) { public void start(Stage stage) {
try { try {
new MainHandler().launch(stage); new ApplicationHandler().launch(stage);
} catch (IOException e) { } catch (IOException e) {
System.out.println(e.getMessage());
// Launch server configuration // Launch server configuration
try { try {
new ServerConfigurationHandler().launch(stage); new ServerConfigurationHandler().launch(stage);

View file

@ -0,0 +1,266 @@
package fr.univ.lyon1.gui.controller;
import fr.univ.lyon1.common.Channel;
import fr.univ.lyon1.common.ChatSSL;
import fr.univ.lyon1.common.Message;
import fr.univ.lyon1.common.ServerConfiguration;
import fr.univ.lyon1.common.command.Command;
import fr.univ.lyon1.common.command.CommandType;
import fr.univ.lyon1.common.exception.ChatException;
import fr.univ.lyon1.common.exception.LoginInvalid;
import fr.univ.lyon1.common.exception.UnknownCommand;
import fr.univ.lyon1.gui.handlers.ServerConfigurationHandler;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.Text;
import javafx.scene.text.TextFlow;
import javafx.stage.Stage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.net.SocketFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Controller used by interface resources/message_gui.fxml
*/
public class ApplicationController {
@NotNull
private final List<Channel> channels = new ArrayList<>();
@Nullable
private Channel currentChannel = null;
private boolean isRunning = true;
@NotNull
private final Socket socket;
@NotNull
private final ObjectOutputStream objectOutputStream;
@NotNull
private final ObjectInputStream objectInputStream;
@FXML
public TextArea textSendArea;
@FXML
public TextFlow textReceiveArea;
@FXML
public VBox vboxChannelsList;
public ApplicationController() throws IOException {
System.out.println("Loading configuration...");
@NotNull
final ServerConfiguration serverConfiguration = ServerConfiguration.load();
// Init secure socket
System.out.println("Init socket...");
this.socket = this.initSSLSocket(serverConfiguration.getAddress(), serverConfiguration.getPort());
this.objectOutputStream = new ObjectOutputStream(this.socket.getOutputStream());
this.objectInputStream = new ObjectInputStream(this.socket.getInputStream());
// Main thread when server send object
@NotNull
final Thread receiveObjectThread = new Thread(() -> {
while (this.isRunning) {
try {
@Nullable
final Object object = this.objectInputStream.readObject();
if (object != null) {
if (object instanceof Command command) {
switch (command.getType()) {
// If client receive login type message
case login -> {
// Request all list of users
this.sendObject(new Command(CommandType.list, null));
// TODO: List all channels available
// Join a channel
this.sendObject(new Command(CommandType.join, List.of("general")));
}
// If client receive a message type
case message -> {
@NotNull
final Message message = (Message) command.getArgs().get(0);
System.out.println("Message received : " + message.toString());
// If same channel
if (this.currentChannel != null && message.getChannel().getUUID().equals(this.currentChannel.getUUID())) {
Platform.runLater(() -> this.textReceiveArea.getChildren().add(new Text("@" + message.getSender().getUsername() + ": " + message.getContent())));
}
}
// If client receive all users
case list -> System.out.println("Connected users : " + Arrays.toString(command.getArgs().toArray()));
// If client receive a join type message
case join -> {
@NotNull
final Channel channel = (Channel) command.getArgs().get(0);
boolean ifChannelExists = this.channels.stream().anyMatch(fChannel -> fChannel.getName().equalsIgnoreCase(channel.getName()));
System.out.println("Channel exists : " + ifChannelExists);
this.currentChannel = channel;
this.channels.add(channel);
System.out.println("Successfully connected to : " + this.currentChannel.toString());
if (!ifChannelExists) {
@NotNull
final Text text = new Text("- #" + channel.getName());
text.setFill(Color.RED);
text.setOnMousePressed(event -> {
System.out.println("Selected channel : #" + channel.getName());
try {
this.sendObject(new Command(CommandType.join, List.of(channel.getName())));
} catch (IOException e) {
e.printStackTrace();
}
});
Platform.runLater(() -> this.vboxChannelsList.getChildren().add(text));
} else {
this.vboxChannelsList.getChildren().stream().filter(node -> node instanceof Text).forEach(txt -> ((Text) txt).setFill(Color.BLACK));
@NotNull
final Text text = (Text) this.vboxChannelsList.getChildren().stream().filter(node -> node instanceof Text txt && txt.getText().equalsIgnoreCase("- #" + channel.getName())).toList().get(0);
text.setFill(Color.RED);
}
}
}
} else if (object instanceof LoginInvalid) {
Platform.runLater(() -> {
try {
this.closeSocket();
@NotNull
final Stage stage = (Stage) this.vboxChannelsList.getScene().getWindow();
new ServerConfigurationHandler().launch(stage);
} catch (IOException e) {
e.printStackTrace();
}
});
} else if (object instanceof ChatException chatException) {
System.out.println("?");
chatException.printStackTrace();
} else {
this.sendObject(new UnknownCommand());
}
} else {
try {
this.closeSocket();
} catch (IOException ex) {
System.out.println("Can not close connection");
ex.printStackTrace();
}
}
} catch (IOException | ClassNotFoundException e) {
if (e instanceof SocketException) {
try {
this.closeSocket();
} catch (IOException ex) {
System.out.println("Can not close connection");
ex.printStackTrace();
}
}
}
}
});
receiveObjectThread.start();
// Login the user with the server configuration
System.out.println("Login...");
this.sendObject(new Command(CommandType.login, List.of(serverConfiguration.getPseudo(), serverConfiguration.getPassword())));
}
/**
* Close properly the socket
*/
private void closeSocket() throws IOException {
this.isRunning = false;
this.objectOutputStream.close();
this.objectInputStream.close();
this.socket.close();
}
/**
* Init the secure socket with SSL
* @param address Address of the server
* @param port Port of the server
* @return Secure socket
*/
@NotNull
private Socket initSSLSocket(@NotNull String address, int port) throws IOException {
SSLContext ctx = ChatSSL.getSSLContext();
SocketFactory factory = ctx.getSocketFactory();
Socket connection = factory.createSocket(address, port);
((SSLSocket) connection).setEnabledProtocols(new String[] {ChatSSL.tlsVersion});
SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
((SSLSocket) connection).setSSLParameters(sslParams);
return connection;
}
/**
* Send object to the server
* @param object Object to send
*/
private void sendObject(@NotNull Object object) throws IOException {
this.objectOutputStream.writeObject(object);
this.objectOutputStream.flush();
}
/**
* Event when a key is pressed on the text area message
* @param keyEvent Key event
*/
public void keyPressedOnTextSendArea(KeyEvent keyEvent) {
// If the key pressed is enter, send the current message
if (keyEvent.getCode() == KeyCode.ENTER)
this.send();
}
/**
* Send the current message to server
*/
public void send() {
// Get current message
@NotNull
final String textToSend = this.textSendArea.getText();
// Clear the textarea content
this.clear();
// Add the message to the current client
System.out.print(">> Send : " + textToSend);
Platform.runLater(() -> this.textReceiveArea.getChildren().add(new Text("*>> " + textToSend)));
if (this.currentChannel != null) {
try {
// Send the message to the server
this.sendObject(new Command(CommandType.message, List.of(new Message(textToSend, this.currentChannel))));
} catch (IOException e) {
System.out.println("Can not send message to server : " + e.getMessage());
e.printStackTrace();
}
}
}
/**
* Clear the current textarea message
*/
public void clear() {
this.textSendArea.setText("");
}
}

View file

@ -1,7 +1,8 @@
package fr.univ.lyon1.gui.controller; package fr.univ.lyon1.gui.controller;
import fr.univ.lyon1.common.ServerConfiguration; import fr.univ.lyon1.common.ServerConfiguration;
import fr.univ.lyon1.gui.handlers.MainHandler; import fr.univ.lyon1.gui.Dialog;
import fr.univ.lyon1.gui.handlers.ApplicationHandler;
import javafx.fxml.FXML; import javafx.fxml.FXML;
import javafx.scene.control.Button; import javafx.scene.control.Button;
import javafx.scene.control.TextField; import javafx.scene.control.TextField;
@ -11,16 +12,23 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
/**
* Controller used by interface resources/connect_gui.fxml
*/
public class ConnectGuiController { public class ConnectGuiController {
@FXML @FXML
public TextField addressTextField; public TextField addressTextField;
@FXML @FXML
public TextField portTextField; public TextField portTextField;
@FXML @FXML
public TextField pseudoTextField;
@FXML
public TextField passwordTextField;
@FXML
public Button connectButton; public Button connectButton;
/** /**
* Called by submit button in resources/connect_gui.fxml * Called by connect button
*/ */
public void connect() { public void connect() {
this.connectButton.setDisable(true); this.connectButton.setDisable(true);
@ -29,7 +37,14 @@ public class ConnectGuiController {
final String address = this.addressTextField.getText(); final String address = this.addressTextField.getText();
@NotNull @NotNull
final String port = this.portTextField.getText(); final String port = this.portTextField.getText();
@NotNull
final String pseudo = this.pseudoTextField.getText();
@NotNull
final String password = this.passwordTextField.getText();
System.out.println("Checking if all text fields is not empty");
// If all fields is not empty
if (!address.isEmpty() && !port.isEmpty() && !pseudo.isEmpty() && !password.isEmpty()) {
System.out.println("Checking if port is valid..."); System.out.println("Checking if port is valid...");
// Check if the port is a number and if it's an available port // Check if the port is a number and if it's an available port
if (this.isNumber(port) && this.isAvailablePort(Integer.parseInt(port))) { if (this.isNumber(port) && this.isAvailablePort(Integer.parseInt(port))) {
@ -43,14 +58,17 @@ public class ConnectGuiController {
try { try {
// Save server configuration // Save server configuration
new ServerConfiguration(address, iPort).save(); new ServerConfiguration(address, iPort, pseudo, password).save();
Dialog.showSuccessDialog("Connecté", "Vous êtes bien connecté au serveur"); Dialog.showSuccessDialog("Connecté", "Vous êtes bien connecté au serveur");
System.out.println("File saved, next step..."); System.out.println("File saved, next step...");
// Change scene for the main application
@NotNull @NotNull
final Stage stage = (Stage) this.connectButton.getScene().getWindow(); final Stage stage = (Stage) this.connectButton.getScene().getWindow();
new MainHandler().launch(stage); new ApplicationHandler().launch(stage);
} catch (IOException e) { } catch (IOException e) {
System.out.println(e.getMessage());
Dialog.showErrorDialog("Erreur", "Impossible de sauvegarder les informations de connexion au serveur"); Dialog.showErrorDialog("Erreur", "Impossible de sauvegarder les informations de connexion au serveur");
this.connectButton.setDisable(false); this.connectButton.setDisable(false);
System.out.println("Failed to save file, error: " + e.getMessage()); System.out.println("Failed to save file, error: " + e.getMessage());
@ -64,8 +82,17 @@ public class ConnectGuiController {
Dialog.showErrorDialog("Erreur", "Veuillez saisir un numéro de port valide"); Dialog.showErrorDialog("Erreur", "Veuillez saisir un numéro de port valide");
this.connectButton.setDisable(false); this.connectButton.setDisable(false);
} }
} else {
Dialog.showErrorDialog("Erreur", "Veuillez renseigner tout les champs");
this.connectButton.setDisable(false);
}
} }
/**
* Check if a string is a number
* @param text String to check
* @return Is number
*/
private boolean isNumber(String text) { private boolean isNumber(String text) {
try { try {
Integer.parseInt(text); Integer.parseInt(text);
@ -75,17 +102,30 @@ public class ConnectGuiController {
} }
} }
/**
* Check if a port is in correct range of ports
* @param port Port to check
* @return If port is available
*/
private boolean isAvailablePort(int port) { private boolean isAvailablePort(int port) {
return !(port < 0 || port > 0xFFFF); return !(port < 0 || port > 0xFFFF);
} }
/**
* Check if an address with port is available through a socket
* @param address Address of the server
* @param port Port used by the server
* @return If socket has successfully connected to the server
*/
private boolean isAccessible(String address, int port) { private boolean isAccessible(String address, int port) {
try { try {
@NotNull @NotNull
final Socket socket = new Socket(address, port); final Socket socket = new Socket(address, port);
socket.setSoTimeout(5 * 1000); socket.setSoTimeout(5 * 1000);
boolean connected = socket.isConnected();
socket.close();
return true; return connected;
} catch (IOException exception) { } catch (IOException exception) {
return false; return false;
} }

View file

@ -1,24 +0,0 @@
package fr.univ.lyon1.gui.controller;
import javafx.scene.control.Alert;
import org.jetbrains.annotations.NotNull;
public class Dialog {
public static void showErrorDialog(String title, String description) {
@NotNull
final Alert alert = new Alert(Alert.AlertType.WARNING);
extracted(title, description, alert);
}
public static void showSuccessDialog(String title, String description) {
@NotNull
final Alert alert = new Alert(Alert.AlertType.INFORMATION);
extracted(title, description, alert);
}
private static void extracted(String title, String description, @NotNull Alert alert) {
alert.setTitle(title);
alert.setContentText(description);
alert.show();
}
}

View file

@ -0,0 +1,18 @@
package fr.univ.lyon1.gui.handlers;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class ApplicationHandler implements Handler {
@Override
public void launch(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("message_gui.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 600, 400);
stage.setTitle("Chat client");
stage.setScene(scene);
stage.show();
}
}

View file

@ -1,50 +0,0 @@
package fr.univ.lyon1.gui.handlers;
import fr.univ.lyon1.common.ServerConfiguration;
import fr.univ.lyon1.gui.ClientGUI;
import fr.univ.lyon1.gui.ClientPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
public class MainHandler implements Handler {
private ClientPanel clientPanel;
@Nullable
private ClientGUI client;
@Override
public void launch(Stage stage) throws IOException {
@NotNull
final ServerConfiguration serverConfiguration = ServerConfiguration.load();
this.client = new ClientGUI(this, serverConfiguration.getAddress(), serverConfiguration.getPort());
stage.setTitle("Chat client");
stage.setWidth(440);
this.clientPanel = new ClientPanel(this);
Group root = new Group();
root.getChildren().add(this.clientPanel);
Scene scene = new Scene(root, 600, 500);
stage.setScene(scene);
stage.show();
if (this.client != null) {
this.client.run();
}
}
public void sendMessage(String msg) {
if (client != null) {
client.sendMessage(msg);
}
}
public void receiveMessage(String msg) {
clientPanel.addMessage(msg);
}
}

View file

@ -10,7 +10,7 @@ public class ServerConfigurationHandler implements Handler {
@Override @Override
public void launch(Stage stage) throws IOException { public void launch(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("connect_gui.fxml")); FXMLLoader fxmlLoader = new FXMLLoader(ClassLoader.getSystemClassLoader().getResource("connect_gui.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 320, 240); Scene scene = new Scene(fxmlLoader.load(), 640, 480);
stage.setTitle("Configuration du serveur"); stage.setTitle("Configuration du serveur");
stage.setScene(scene); stage.setScene(scene);
stage.show(); stage.show();

View file

@ -180,7 +180,8 @@ public class ConnectedClient implements Runnable {
actionCommand((Command) data); actionCommand((Command) data);
else else
throw new UnknownCommand(); throw new UnknownCommand();
} catch (ChatException e) { } catch (IOException | ChatException e) {
System.out.println("Error server " + e.getLocalizedMessage());
out.writeObject(e); out.writeObject(e);
out.flush(); out.flush();
} }

View file

@ -5,9 +5,7 @@
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?> <?import javafx.scene.text.*?>
<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" <VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univ.lyon1.gui.controller.ConnectGuiController">
prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.2" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="fr.univ.lyon1.gui.controller.ConnectGuiController">
<Label text="Connexion"> <Label text="Connexion">
<font> <font>
<Font name="System Bold" size="18.0" /> <Font name="System Bold" size="18.0" />
@ -30,7 +28,22 @@
</HBox.margin> </HBox.margin>
</TextField> </TextField>
</HBox> </HBox>
<Button mnemonicParsing="false" text="Se connecter" onAction="#connect" fx:id="connectButton"> <HBox alignment="CENTER" prefHeight="50.0" prefWidth="200.0">
<Label text="Pseudonyme :"/>
<TextField fx:id="pseudoTextField">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</TextField>
<StackPane prefHeight="50.0" prefWidth="90.0"/>
<Label text="Mot de passe :"/>
<TextField fx:id="passwordTextField" cache="true">
<HBox.margin>
<Insets left="10.0"/>
</HBox.margin>
</TextField>
</HBox>
<Button fx:id="connectButton" mnemonicParsing="false" onAction="#connect" text="Se connecter">
<VBox.margin> <VBox.margin>
<Insets top="20.0" /> <Insets top="20.0" />
</VBox.margin> </VBox.margin>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<VBox alignment="CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/16" xmlns:fx="http://javafx.com/fxml/1" fx:controller="fr.univ.lyon1.gui.controller.ApplicationController">
<SplitPane dividerPositions="0.29797979797979796" prefHeight="542.0" prefWidth="600.0">
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<VBox prefHeight="400.0" prefWidth="175.0">
<Label alignment="CENTER" contentDisplay="CENTER" prefHeight="31.0" prefWidth="175.0" text="Channels" textAlignment="CENTER" />
<VBox prefHeight="371.0" prefWidth="175.0" fx:id="vboxChannelsList" />
</VBox>
</AnchorPane>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0">
<VBox prefHeight="398.0" prefWidth="417.0">
<ScrollPane prefHeight="280.0" prefWidth="417.0">
<TextFlow fx:id="textReceiveArea" prefHeight="276.0" prefWidth="415.0" />
</ScrollPane>
<Separator prefHeight="25.0" prefWidth="417.0" />
<HBox prefHeight="100.0" prefWidth="200.0">
<TextArea fx:id="textSendArea" onKeyPressed="#keyPressedOnTextSendArea" prefHeight="100.0" prefWidth="300.0" />
<StackPane prefHeight="98.0" prefWidth="29.0" />
<VBox prefHeight="200.0" prefWidth="100.0">
<Button mnemonicParsing="false" onAction="#send" prefHeight="40.0" prefWidth="128.0" text="Envoyer" />
<StackPane prefHeight="20.0" prefWidth="100.0" />
<Button layoutX="10.0" layoutY="10.0" mnemonicParsing="false" onAction="#clear" prefHeight="40.0" prefWidth="207.0" text="Nettoyer" />
</VBox>
</HBox>
</VBox>
</AnchorPane>
</SplitPane>
</VBox>

View file

@ -1,4 +1,4 @@
module fr.univ.lyon { module fr.univ.lyon1 {
requires javafx.controls; requires javafx.controls;
requires javafx.fxml; requires javafx.fxml;