home / connvers / src / main / java / avividi / connvers / Connvers.java

Connvers.java



package avividi.connvers;

import avividi.connvers.client.Client;
import avividi.connvers.crypto.EncryptedMessageEncoder;
import avividi.connvers.protocol.Message;
import avividi.connvers.protocol.MessageEncoder;
import avividi.connvers.protocol.ValidationException;
import avividi.connvers.server.Server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

import static avividi.connvers.protocol.BasicMessageEncoder.validateUserName;

public class Connvers {

  public static final String VERSION = "0.5.0";
  public static final String SERVER_USER = "server";
  public static final String SYSTEM_USER = "system";
  public static final int MAX_LENGTH_USER_NAME = 16;
  public static final int MAX_MESSAGE_LENGTH = 256;
  private static final int PORT = 7749;
  public static final int HANDSHAKE_TIMEOUT_MS = 5 * 1000;
  public static final int HEARTBEAT_TIMEOUT_MS = 60 * 1000;
  public static final int HEARTBEAT_FREQUENCY_MS = 45 * 1000;

  public static DateTimeFormatter timestampFormat = DateTimeFormatter.ofPattern("HH:mm:ss")
      .withZone(ZoneId.systemDefault());

  public enum MessagePrintType {
    system("\u001B[36m"), server("\u001B[35m"), user("\u001B[34m");

    final String color;

    MessagePrintType(String color) {
      this.color = color;
    }
  }

  public static void main(String[] args) throws IOException {
    printWelcome();

    if (args.length == 0) {
      throw new RuntimeException("no host given");
    }
    String arg1 = args[0];

    boolean isServer = arg1.equals("server");
    String host = isServer ? null : arg1;

    MessageEncoder messageEncoder =
        new EncryptedMessageEncoder("aCWIdn3tGn3d2VxgnmC1tw==");

    if (isServer) {
      printSystemLine(String.format("Starting up server on port %d.", PORT));
    }
    else {
      printSystemLine(String.format("Starting up client towards %s:%d.", host, PORT));
    }

    String user;
    if (args.length > 1) {
      user = args[1];
    }
    else {
      BufferedReader userNameReader = new BufferedReader(new InputStreamReader(System.in));
      System.out.print("User name?\n>");
      user = userNameReader.readLine();
    }
    try {
      validateUserName(user);
    } catch (ValidationException e) {
      printSystemLine(e.getMessage());
      System.exit(0);
    }

    if (isServer) {
      new Server(user, PORT, messageEncoder).start();
    }
    else {
      new Client(user, PORT, host, messageEncoder).start();
    }
  }

  private static void printWelcome() {
    System.out.println();
    System.out.printf("\033[47m  \033[1m\033[30mConnvers v%s  \033[0m\n", VERSION);
    System.out.println();
  }

  public static void checkAndPrintNewDay(Message message, Message prev) {
    LocalDate today = LocalDate.ofInstant(message.time(), ZoneId.systemDefault());
    if (prev == null || today.isAfter(LocalDate.ofInstant(prev.time(), ZoneId.systemDefault()))) {
      insertLine(String.format("\033[1m%s\033[0m\n", today));
    }
  }

  public static void printSystemLine(String message) {
    printLine(MessagePrintType.system, Instant.now(), SYSTEM_USER, message);
  }

  public static void printLine(MessagePrintType messagePrintType, Instant instant, String user, String message) {
    insertLine(String.format("[%s] %s%s\u001B[0m %s\n",
        timestampFormat.format(instant),
        messagePrintType.color,
        String.format("<%s>", user),
        message));
  }

  public static void insertLine(String message) {
    System.out.print("\0337"); // save cursor pos (alternative \0337[s)
    System.out.print("\n"); // add new line
    System.out.print("\033[1A"); // move cursor 1 line up
    System.out.print("\033[1L"); // insert new line
    System.out.print(message); // write message
    System.out.print("\0338"); // restore cursor pos (alternative \0337[u)
    System.out.print("\033[1B"); // move back down
    System.out.flush();
  }

}