Archived
1
0
Fork 0
This repository has been archived on 2024-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
Java_TP/src/fr/univ/lyon1/client/Client.java

260 lines
8.2 KiB
Java

package fr.univ.lyon1.client;
import fr.univ.lyon1.common.Channel;
import fr.univ.lyon1.common.ChatSSL;
import fr.univ.lyon1.common.Message;
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.NotInChannel;
import fr.univ.lyon1.common.exception.UnknownCommand;
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.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* The core of the client side
*/
public class Client {
private final int port;
private final String address;
private final String username;
private final String password;
protected final Socket socket;
protected final ObjectOutputStream out;
private ObjectInputStream in;
private final List<Channel> channels = new ArrayList<>();
protected boolean started = false;
/**
* A client need a server and login
* @param address the server address
* @param port the server port
* @param username thr username
* @param password the password
* @throws IOException When the initial communication with the server fail
*/
public Client(String address, int port, String username, String password) throws IOException {
this.address = address;
this.port = port;
this.username = username;
this.password = password;
socket = initSSL();
out = new ObjectOutputStream(socket.getOutputStream());
getIn();
}
/**
* Initialise the SSL WebSocket connection with the server
* @return the socket
* @throws IOException when unable to connect with the server
*/
private Socket initSSL() 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;
}
/**
* Close all connection to the server
* @throws IOException if fail to close the connection to the server
*/
public void disconnectedServer() throws IOException {
socket.close();
out.close();
if (in != null)
in.close();
System.exit(0);
}
/**
* Send a command to the server
* @param cmd the command
*/
private void send(Command cmd) {
try {
out.writeObject(cmd);
out.flush();
} catch (IOException e) {
System.err.println("Fail to send command !");
e.printStackTrace();
}
}
/**
* Send a message in the first channel
* @param content the content of the message
*/
public void sendMessage(String content) {
send(new Command(CommandType.message, List.of(new Message(content, channels.get(0)))));
}
/**
* Send a command
* @param content the command name an args (/commandName arg1 arh2 arg3)
* @throws UnknownCommand if the command can't be found
*/
public void sendCommand(String content) throws UnknownCommand {
List<String> args = Arrays.asList(content.split(" "));
String commandName = args.get(0).replace("/", "");
CommandType commandType;
try {
commandType = CommandType.valueOf(commandName);
} catch (IllegalArgumentException e) {
throw new UnknownCommand(commandName);
}
send(new Command(commandType, new ArrayList<>(args.subList(1, args.size()))));
}
/**
* Send a message with a specific channel
* @param content the channel name and the message content (#chanemName content of the message)
* @throws NotInChannel if the client isn't in the channel
*/
public void sendMessageChannel(String content) throws NotInChannel {
String[] args = content.split(" ");
String channelName = args[0].replace("#", "");
content = String.join(" ", Arrays.stream(args).toList().subList(1, args.length));
Channel channel = channels.stream().filter(c -> c.getName().equals(channelName)).findFirst().orElse(null);
if (channel == null)
throw new NotInChannel(channelName);
send(new Command(CommandType.message, List.of(new Message(content, channel))));
}
/**
* Manage income data from the server
* @param data the data
* @throws IOException if a connection error occur with the server
*/
public void action(Object data) throws IOException {
if (data instanceof Command)
command((Command) data);
else if (data instanceof ChatException)
((ChatException) data).printStackTrace();
else {
out.writeObject(new UnknownCommand());
out.flush();
}
}
/**
* Command manager
* @param cmd the command
* @throws IOException if a connection error occur with the server
*/
private void command(Command cmd) throws IOException {
switch (cmd.getType()) {
case login -> commandLogin();
case message -> commandMessage(cmd);
case list -> commandList(cmd);
case listChannels -> commandListChannels(cmd);
case join -> commandJoin(cmd);
}
}
/**
* After login handler
* @throws IOException if a connection error occur with the server
*/
private void commandLogin() throws IOException {
out.writeObject(new Command(CommandType.list, null));
out.flush();
out.writeObject(new Command(CommandType.listChannels, null));
out.flush();
out.writeObject(new Command(CommandType.join, List.of("general")));
out.flush();
}
/**
* Receiving message from the server
* @param cmd the message command
*/
protected void commandMessage(Command cmd) {
System.out.println();
System.out.println(cmd.getArgs().get(0));
}
/**
* User list handler
* @param cmd the command list
*/
private void commandList(Command cmd) {
System.out.println("Users: "+cmd.getArgs().stream().map(Object::toString).collect(Collectors.joining(", ")));
}
/**
* Channel list handler
* @param cmd the command channel list
*/
private void commandListChannels(Command cmd) {
System.out.println("Channels: "+cmd.getArgs().stream().map(Object::toString).collect(Collectors.joining(", ")));
}
/**
* The channel join handler
* @param cmd the command join
*/
private void commandJoin(Command cmd) {
Channel chan = (Channel) cmd.getArgs().get(0);
channels.add(chan);
System.out.println("You join "+chan);
}
/**
* Main thread function, creating sub thread for user input and output CLI management
* @throws InterruptedException If the client force exit
* @throws IOException if a connection error occur with the server
*/
public void run() throws InterruptedException, IOException {
if (started)
return;
Thread clientSendThread = new Thread(new ClientSend(this, out, socket));
clientSendThread.start();
Thread clientReceiveThread = new Thread(new ClientReceive(this, socket));
clientReceiveThread.start();
started = true;
out.writeObject(new Command(CommandType.login, List.of(username, password)));
out.flush();
clientSendThread.join();
socket.close();
clientReceiveThread.interrupt();
}
/**
* Get the in stream of the WebSocket
* @return the in stream
* @throws IOException if a connection error occur with the server
*/
public ObjectInputStream getIn() throws IOException {
if (in == null)
in = new ObjectInputStream(socket.getInputStream());
return in;
}
}