MagicWebSocketInstance.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /*
  2. * Nextcloud Talk application
  3. *
  4. * @author Mario Danic
  5. * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.nextcloud.talk.webrtc;
  21. import android.text.TextUtils;
  22. import android.util.Log;
  23. import com.bluelinelabs.logansquare.LoganSquare;
  24. import com.nextcloud.talk.application.NextcloudTalkApplication;
  25. import com.nextcloud.talk.events.WebSocketCommunicationEvent;
  26. import com.nextcloud.talk.models.database.UserEntity;
  27. import com.nextcloud.talk.models.json.signaling.NCMessageWrapper;
  28. import com.nextcloud.talk.models.json.websocket.BaseWebSocketMessage;
  29. import com.nextcloud.talk.models.json.websocket.CallOverallWebSocketMessage;
  30. import com.nextcloud.talk.models.json.websocket.ErrorOverallWebSocketMessage;
  31. import com.nextcloud.talk.models.json.websocket.EventOverallWebSocketMessage;
  32. import com.nextcloud.talk.models.json.websocket.HelloResponseOverallWebSocketMessage;
  33. import com.nextcloud.talk.models.json.websocket.JoinedRoomOverallWebSocketMessage;
  34. import com.nextcloud.talk.models.json.websocket.RoomOverallWebSocketMessage;
  35. import com.nextcloud.talk.utils.MagicMap;
  36. import org.greenrobot.eventbus.EventBus;
  37. import java.io.IOException;
  38. import java.util.HashMap;
  39. import java.util.Map;
  40. import javax.inject.Inject;
  41. import autodagger.AutoInjector;
  42. import okhttp3.OkHttpClient;
  43. import okhttp3.Request;
  44. import okhttp3.Response;
  45. import okhttp3.WebSocket;
  46. import okhttp3.WebSocketListener;
  47. import okio.ByteString;
  48. @AutoInjector(NextcloudTalkApplication.class)
  49. public class MagicWebSocketInstance extends WebSocketListener {
  50. private static final String TAG = "MagicWebSocketInstance";
  51. @Inject
  52. OkHttpClient okHttpClient;
  53. @Inject
  54. EventBus eventBus;
  55. private UserEntity conversationUser;
  56. private String webSocketTicket;
  57. private String resumeId;
  58. private String sessionId;
  59. private boolean hasMCU;
  60. private boolean connected;
  61. private WebSocketConnectionHelper webSocketConnectionHelper;
  62. private WebSocket webSocket;
  63. private MagicMap magicMap;
  64. MagicWebSocketInstance(UserEntity conversationUser, String connectionUrl, String webSocketTicket) {
  65. NextcloudTalkApplication.getSharedApplication().getComponentApplication().inject(this);
  66. Request request = new Request.Builder().url(connectionUrl).build();
  67. this.webSocket = okHttpClient.newWebSocket(request, this);
  68. this.conversationUser = conversationUser;
  69. this.webSocketTicket = webSocketTicket;
  70. this.webSocketConnectionHelper = new WebSocketConnectionHelper();
  71. magicMap = new MagicMap();
  72. }
  73. @Override
  74. public void onOpen(WebSocket webSocket, Response response) {
  75. try {
  76. if (TextUtils.isEmpty(resumeId)) {
  77. webSocket.send(LoganSquare.serialize(webSocketConnectionHelper.getAssembledHelloModel(conversationUser, webSocketTicket)));
  78. } else {
  79. webSocket.send(LoganSquare.serialize(webSocketConnectionHelper.getAssembledHelloModelForResume(resumeId)));
  80. }
  81. } catch (IOException e) {
  82. Log.e(TAG, "Failed to serialize hello model");
  83. }
  84. }
  85. @Override
  86. public void onMessage(WebSocket webSocket, String text) {
  87. Log.d(TAG, "Receiving : " + text);
  88. try {
  89. BaseWebSocketMessage baseWebSocketMessage = LoganSquare.parse(text, BaseWebSocketMessage.class);
  90. String messageType = baseWebSocketMessage.getType();
  91. switch (messageType) {
  92. case "hello":
  93. connected = true;
  94. HelloResponseOverallWebSocketMessage helloResponseWebSocketMessage = LoganSquare.parse(text, HelloResponseOverallWebSocketMessage.class);
  95. resumeId = helloResponseWebSocketMessage.getHelloResponseWebSocketMessage().getResumeId();
  96. sessionId = helloResponseWebSocketMessage.getHelloResponseWebSocketMessage().getSessionId();
  97. hasMCU = helloResponseWebSocketMessage.getHelloResponseWebSocketMessage().serverHasMCUSupport();
  98. eventBus.post(new WebSocketCommunicationEvent("hello", null));
  99. break;
  100. case "error":
  101. ErrorOverallWebSocketMessage errorOverallWebSocketMessage = LoganSquare.parse(text, ErrorOverallWebSocketMessage.class);
  102. break;
  103. case "room":
  104. JoinedRoomOverallWebSocketMessage joinedRoomOverallWebSocketMessage = LoganSquare.parse(text, JoinedRoomOverallWebSocketMessage.class);
  105. if (joinedRoomOverallWebSocketMessage.getRoomWebSocketMessage().getRoomPropertiesWebSocketMessage() != null) {
  106. HashMap<String, String> joinRoomHashMap = new HashMap<>();
  107. joinRoomHashMap.put("roomToken", joinedRoomOverallWebSocketMessage.getRoomWebSocketMessage().getRoomId());
  108. eventBus.post(new WebSocketCommunicationEvent("roomJoined", joinRoomHashMap));
  109. }
  110. break;
  111. case "event":
  112. // Nothing for now
  113. EventOverallWebSocketMessage eventOverallWebSocketMessage = LoganSquare.parse(text, EventOverallWebSocketMessage.class);
  114. if (eventOverallWebSocketMessage.getEventMap() != null) {
  115. String target = (String) eventOverallWebSocketMessage.getEventMap().get("target");
  116. switch (target) {
  117. case "room":
  118. if (eventOverallWebSocketMessage.getType().equals("message")) {
  119. if (eventOverallWebSocketMessage.getEventMap().containsKey("data")) {
  120. Map<String, Object> dataHashMap = (Map<String, Object>) eventOverallWebSocketMessage.getEventMap().get("data");
  121. if (dataHashMap.containsKey("chat")) {
  122. boolean shouldRefreshChat;
  123. Map<String, Object> chatMap = (Map<String, Object>) dataHashMap.get("chat");
  124. if (chatMap.containsKey("refresh")) {
  125. shouldRefreshChat = (boolean) chatMap.get("refresh");
  126. if (shouldRefreshChat) {
  127. HashMap<String, String> refreshChatHashMap = new HashMap<>();
  128. refreshChatHashMap.put("roomToken", (String) eventOverallWebSocketMessage.getEventMap().get("roomid"));
  129. eventBus.post(new WebSocketCommunicationEvent("refreshChat", refreshChatHashMap));
  130. }
  131. }
  132. }
  133. }
  134. }
  135. break;
  136. case "participants":
  137. if (eventOverallWebSocketMessage.getEventMap().get("type").equals("update")) {
  138. HashMap<String, String> refreshChatHashMap = new HashMap<>();
  139. HashMap<String, Object> updateEventMap = (HashMap<String, Object>) eventOverallWebSocketMessage.getEventMap().get("update");
  140. refreshChatHashMap.put("roomToken", (String) updateEventMap.get("roomid"));
  141. refreshChatHashMap.put("jobId", Integer.toString(magicMap.add(updateEventMap.get("users"))));
  142. eventBus.post(new WebSocketCommunicationEvent("participantsUpdate", refreshChatHashMap));
  143. }
  144. break;
  145. }
  146. }
  147. break;
  148. case "message":
  149. CallOverallWebSocketMessage callOverallWebSocketMessage = LoganSquare.parse(text, CallOverallWebSocketMessage.class);
  150. HashMap<String, String> messageHashMap = new HashMap<>();
  151. messageHashMap.put("jobId", Integer.toString(magicMap.add(callOverallWebSocketMessage.getCallWebSocketMessage().getNcSignalingMessage())));
  152. eventBus.post(new WebSocketCommunicationEvent("signalingMessage", messageHashMap));
  153. break;
  154. default:
  155. break;
  156. }
  157. } catch (IOException e) {
  158. Log.e(TAG, "Failed to WebSocket message");
  159. }
  160. }
  161. @Override
  162. public void onMessage(WebSocket webSocket, ByteString bytes) {
  163. Log.d(TAG, "Receiving bytes : " + bytes.hex());
  164. }
  165. @Override
  166. public void onClosing(WebSocket webSocket, int code, String reason) {
  167. Log.d(TAG, "Closing : " + code + " / " + reason);
  168. connected = false;
  169. }
  170. @Override
  171. public void onFailure(WebSocket webSocket, Throwable t, Response response) {
  172. Log.d(TAG, "Error : " + t.getMessage());
  173. connected = false;
  174. }
  175. public String getSessionId() {
  176. return sessionId;
  177. }
  178. public boolean hasMCU() {
  179. return hasMCU;
  180. }
  181. public void joinRoomWithRoomTokenAndSession(String roomToken, String normalBackendSession) {
  182. try {
  183. webSocket.send(LoganSquare.serialize(webSocketConnectionHelper.getAssembledJoinOrLeaveRoomModel(roomToken, normalBackendSession)));
  184. } catch (IOException e) {
  185. Log.e(TAG, "Failed to serialize room overall websocket message");
  186. }
  187. }
  188. public void sendCallMessage(NCMessageWrapper ncMessageWrapper) {
  189. try {
  190. webSocket.send(LoganSquare.serialize(webSocketConnectionHelper.getAssembledCallMessageModel(ncMessageWrapper)));
  191. } catch (IOException e) {
  192. Log.e(TAG, "Failed to serialize signaling message");
  193. }
  194. }
  195. public Object getJobWithId(Integer id) {
  196. Object copyJob = magicMap.get(id);
  197. magicMap.remove(id);
  198. return copyJob;
  199. }
  200. public void requestOfferForSessionIdWithType(String sessionId, String roomType) {
  201. try {
  202. webSocket.send(LoganSquare.serialize(webSocketConnectionHelper.getAssembledRequestOfferModel(sessionId, roomType)));
  203. } catch (IOException e) {
  204. Log.e(TAG, "Failed to offer request");
  205. }
  206. }
  207. }