No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

PeerUser.java 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. package fr.insa.clavardator.client.users;
  2. import fr.insa.clavardator.client.chat.ChatHistory;
  3. import fr.insa.clavardator.client.db.DatabaseController;
  4. import fr.insa.clavardator.lib.errors.UsernameTakenException;
  5. import fr.insa.clavardator.lib.message.FileMessage;
  6. import fr.insa.clavardator.lib.message.Message;
  7. import fr.insa.clavardator.lib.network.TcpConnection;
  8. import fr.insa.clavardator.lib.users.User;
  9. import fr.insa.clavardator.lib.users.UserInformation;
  10. import fr.insa.clavardator.lib.util.ErrorCallback;
  11. import fr.insa.clavardator.lib.util.Log;
  12. import org.jetbrains.annotations.NotNull;
  13. import org.jetbrains.annotations.Nullable;
  14. import java.io.EOFException;
  15. import java.io.File;
  16. import java.io.IOException;
  17. import java.util.Date;
  18. public class PeerUser extends User implements Comparable<PeerUser> {
  19. protected transient ChatHistory history;
  20. private State state = State.DISCONNECTED;
  21. private transient TcpConnection connection;
  22. public PeerUser(String id, String username) {
  23. super(id, username);
  24. history = new ChatHistory(this);
  25. }
  26. public PeerUser(String id) {
  27. super(id);
  28. history = new ChatHistory(this);
  29. }
  30. public PeerUser() {
  31. super();
  32. history = new ChatHistory(this);
  33. }
  34. /**
  35. * Sends a basic text message to this user
  36. *
  37. * @param msg The text message to send
  38. * @param errorCallback Callback on error
  39. */
  40. public void sendTextMessage(String msg, @Nullable ErrorCallback errorCallback) {
  41. if (connection != null) {
  42. Log.v(this.getClass().getSimpleName(),
  43. "Sending message to " + this.getUsername() + " / " + this.getId() + ": " + msg);
  44. final Message message = new Message(CurrentUser.getInstance(), this, new Date(), msg);
  45. connection.send(message, () -> history.addMessage(message, errorCallback), errorCallback);
  46. } else {
  47. Log.e(this.getClass().getSimpleName(), "Could not send message: connection is not initialized");
  48. }
  49. }
  50. /**
  51. * Sends a message containing a file to this user
  52. *
  53. * @param msg The text message to send
  54. * @param errorCallback Callback on error
  55. */
  56. public void sendFileMessage(String msg, File file, @Nullable ErrorCallback errorCallback) {
  57. if (connection != null) {
  58. Log.v(this.getClass().getSimpleName(),
  59. "Sending file message to " + this.getUsername() + " / " + this.getId() + ": " + msg);
  60. try {
  61. final FileMessage message = new FileMessage(CurrentUser.getInstance(), this, new Date(), msg, file.getPath());
  62. message.storeFile();
  63. connection.send(message, () -> history.addMessage(message, errorCallback), errorCallback);
  64. } catch (IOException e) {
  65. Log.e(this.getClass().getSimpleName(), "Could not send message: error while opening file", e);
  66. if (errorCallback != null) {
  67. errorCallback.onError(e);
  68. }
  69. }
  70. } else {
  71. Log.e(this.getClass().getSimpleName(), "Could not send message: connection is not initialized");
  72. }
  73. }
  74. /**
  75. * Sends current user information to this user
  76. *
  77. * @param errorCallback Callback on error
  78. */
  79. public void sendCurrentUser(@Nullable ErrorCallback errorCallback) {
  80. if (connection != null) {
  81. final String username = CurrentUser.getInstance().getUsername();
  82. Log.v(this.getClass().getSimpleName(),
  83. "Sending current user information to " + this.getUsername() + " / " + this.getId() + ": " + username);
  84. connection.send(
  85. new UserInformation(CurrentUser.getInstance()),
  86. null,
  87. errorCallback);
  88. } else {
  89. Log.e(this.getClass().getSimpleName(), "Could not send new username: connection is not initialized");
  90. }
  91. }
  92. private void sendUsernameTaken(TcpConnection thisConnection) {
  93. Log.v(this.getClass().getSimpleName(), "Received username request using current username");
  94. thisConnection.send(new UsernameTakenException("Username taken", getId()), this::disconnect, null);
  95. }
  96. public void init(TcpConnection connection, String id, String username, ErrorCallback errorCallback) {
  97. this.connection = connection;
  98. this.setId(id);
  99. setUsername(username);
  100. setState(State.CONNECTED);
  101. subscribeToMessages((e) -> {
  102. disconnect();
  103. errorCallback.onError(e);
  104. });
  105. }
  106. /**
  107. * Subscribe to this user messages.
  108. * If receiving new user info, update this user.
  109. * If receiving text message, store it in the history.
  110. *
  111. * @param errorCallback Callback on error
  112. */
  113. private void subscribeToMessages(ErrorCallback errorCallback) {
  114. connection.receive(
  115. msg -> {
  116. Log.v(this.getClass().getSimpleName(), "Received message from " + getId());
  117. if (msg instanceof UserInformation) {
  118. assert ((UserInformation) msg).id.equals(getId());
  119. final String receivedUsername = ((UserInformation) msg).getUsername();
  120. Log.v(this.getClass().getSimpleName(), "Message username: " + receivedUsername);
  121. if (CurrentUser.getInstance().getUsername().equals(receivedUsername)) {
  122. sendUsernameTaken(connection);
  123. } else {
  124. setUsername(receivedUsername);
  125. }
  126. } else if (msg instanceof Message) {
  127. assert !((Message) msg).getRecipient().id.equals(getId());
  128. Log.v(this.getClass().getSimpleName(), "Message text: " + ((Message) msg).getText());
  129. if (msg instanceof FileMessage) {
  130. ((FileMessage) msg).storeFile();
  131. }
  132. history.addMessage((Message) msg, errorCallback);
  133. } else if (msg instanceof UsernameTakenException) {
  134. disconnect();
  135. errorCallback.onError(new Exception("Received username already taken message"));
  136. }
  137. },
  138. e -> {
  139. if (e instanceof EOFException) {
  140. disconnect();
  141. } else {
  142. Log.e(this.getClass().getSimpleName(), "Error receiving message from " + getId(), e);
  143. errorCallback.onError(e);
  144. }
  145. });
  146. }
  147. /**
  148. * Close the connection and set state to disconnected
  149. */
  150. public void disconnect() {
  151. Log.v(this.getClass().getSimpleName(), "Disconnecting from user: " + getId());
  152. closeConnection();
  153. setState(State.DISCONNECTED);
  154. }
  155. @Override
  156. protected void setUsername(String newUsername) {
  157. super.setUsername(newUsername);
  158. final DatabaseController db = new DatabaseController();
  159. db.updateUsername(new UserInformation(this),
  160. null,
  161. e -> Log.e(getClass().getSimpleName(), "Unable to update the username", e));
  162. }
  163. /**
  164. * Close the connection to this user
  165. */
  166. private void closeConnection() {
  167. if (connection != null && connection.isOpen()) {
  168. connection.close();
  169. connection = null;
  170. }
  171. }
  172. /**
  173. * Gets the value of history
  174. *
  175. * @return the value of history
  176. */
  177. public ChatHistory getHistory() {
  178. return history;
  179. }
  180. /**
  181. * Sets this user state
  182. *
  183. * @param state The new state
  184. */
  185. protected void setState(State state) {
  186. getPcs().firePropertyChange("state", this.state, state);
  187. this.state = state;
  188. }
  189. /**
  190. * Check if this user is active.
  191. *
  192. * @return True id active, false otherwise
  193. */
  194. public boolean isActive() {
  195. return state == State.CONNECTED;
  196. }
  197. @Override
  198. public int compareTo(@NotNull PeerUser peerUser) {
  199. if (peerUser.isActive() && !this.isActive()) {
  200. return 1;
  201. } else if (!peerUser.isActive() && this.isActive()) {
  202. return -1;
  203. }
  204. return getUsername().compareTo(peerUser.getUsername());
  205. }
  206. /**
  207. * The user connection state
  208. */
  209. public enum State {
  210. CONNECTED,
  211. DISCONNECTED,
  212. }
  213. }