home /
connvers /
src /
main /
java /
avividi /
connvers /
client /
Client.java
Client.java
package avividi.connvers.client;
import avividi.connvers.protocol.MessageEncoder;
import avividi.connvers.protocol.MessageTopic;
import avividi.connvers.protocol.Message;
import avividi.connvers.UserInputHandler;
import avividi.connvers.CommandInterpreter;
import avividi.connvers.protocol.ValidationException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static avividi.connvers.Connvers.HEARTBEAT_FREQUENCY_MS;
import static avividi.connvers.Connvers.checkAndPrintNewDay;
import static avividi.connvers.Connvers.printSystemLine;
public class Client {
private final String user;
private final int port;
private final String host;
private final MessageEncoder messageEncoder;
public Client(String user, int port, String host, MessageEncoder messageEncoder) {
this.user = user;
this.port = port;
this.host = host;
this.messageEncoder = messageEncoder;
}
public void start() {
try(
Socket clientSocket = new Socket(host, port);
//create output stream attached to socket
DataOutputStream outStream = new DataOutputStream(clientSocket.getOutputStream());
//create input stream attached to socket
DataInputStream inStream = new DataInputStream(clientSocket.getInputStream())
) {
handshake(outStream, inStream);
// handler for user input
new Thread(new UserInputHandler(
user,
true,
m -> sendMessage(outStream, m),
new CommandInterpreter() {})
).start();
// schedule heartbeat messages
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
try {
sendMessage(outStream, new Message(user, Instant.now(), MessageTopic.heartbeat, null));
} catch (IOException e) {
e.printStackTrace();
System.exit(0);
}
}, HEARTBEAT_FREQUENCY_MS, HEARTBEAT_FREQUENCY_MS, TimeUnit.MILLISECONDS);
// listen for incoming messages
Message prevMessage = null;
while (!Thread.currentThread().isInterrupted()) {
String rawMessage = inStream.readUTF();
Message message = messageEncoder.decode(rawMessage);
checkAndPrintNewDay(message, prevMessage);
prevMessage = message;
message.print();
}
}
catch (IOException e) {
printSystemLine("Disconnected from server.");
System.exit(0);
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
private synchronized void sendMessage(DataOutputStream outStream, Message message) throws IOException {
outStream.writeUTF(messageEncoder.encode(message));
}
private void handshake(DataOutputStream outStream, DataInputStream inStream) throws IOException, ValidationException {
outStream.writeUTF(messageEncoder.encode(new Message(user, Instant.now(), MessageTopic.join, null)));
boolean welcome = false;
while (!welcome) {
String rawMessage = inStream.readUTF();
Message message = messageEncoder.decode(rawMessage);
welcome = message.topic() == MessageTopic.welcome;
if (message.topic() == MessageTopic.error) {
printSystemLine(String.format("Server error: %s", message.content()));
}
}
}
}