From 0bca327949e5f658c6870d065d3c31d0135b015f Mon Sep 17 00:00:00 2001 From: ChronosX88 Date: Sat, 23 Mar 2019 21:30:24 +0400 Subject: [PATCH] Made offline chat send request --- .../influence/helpers/NetworkHandler.java | 118 ++++++++++++++++-- .../influence/helpers/ObservableUtils.java | 11 ++ .../influence/helpers/actions/UIActions.java | 1 + .../chronosx88/influence/logic/MainLogic.java | 3 + .../influence/logic/StartChatLogic.java | 10 +- .../presenters/ChatListPresenter.java | 25 ++-- .../presenters/StartChatPresenter.java | 6 + .../views/fragments/ChatListFragment.java | 5 +- .../views/fragments/StartChatFragment.java | 13 +- .../main/res/layout/start_chat_fragment.xml | 4 +- 10 files changed, 161 insertions(+), 35 deletions(-) create mode 100644 app/src/main/java/io/github/chronosx88/influence/helpers/ObservableUtils.java diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java b/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java index 3c2afd7..8ef2684 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/NetworkHandler.java @@ -6,10 +6,19 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonParser; +import net.tomp2p.dht.FutureGet; +import net.tomp2p.dht.FuturePut; import net.tomp2p.dht.PeerDHT; +import net.tomp2p.futures.FuturePing; +import net.tomp2p.peers.Number160; +import net.tomp2p.peers.Number640; import net.tomp2p.peers.PeerAddress; +import net.tomp2p.storage.Data; +import java.io.IOException; import java.util.List; +import java.util.Map; +import java.util.UUID; import io.github.chronosx88.influence.contracts.observer.NetworkObserver; import io.github.chronosx88.influence.helpers.actions.NetworkActions; @@ -19,12 +28,11 @@ import io.github.chronosx88.influence.models.roomEntities.ChatEntity; public class NetworkHandler implements NetworkObserver { private final static String LOG_TAG = "NetworkHandler"; - private Gson gson; - private PeerDHT peerDHT; + private static Gson gson = new Gson(); + private static PeerDHT peerDHT = AppHelper.getPeerDHT(); + private static KeyPairManager keyPairManager = new KeyPairManager(); public NetworkHandler() { - gson = new Gson(); - peerDHT = AppHelper.getPeerDHT(); AppHelper.getObservable().register(this); } @@ -45,9 +53,11 @@ public class NetworkHandler implements NetworkObserver { case NetworkActions.SUCCESSFULL_CREATE_CHAT: { NewChatRequestMessage newChatRequestMessage = gson.fromJson((String) object, NewChatRequestMessage.class); createChatEntry(newChatRequestMessage.getChatID(), newChatRequestMessage.getSenderID(), newChatRequestMessage.getSenderPeerAddress()); - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("action", UIActions.NEW_CHAT); - AppHelper.getObservable().notifyUIObservers(jsonObject); + ObservableUtils.notifyUI(UIActions.SUCCESSFULL_CREATE_CHAT); + peerDHT.remove(Number160.createHash(newChatRequestMessage.getSenderID() + "_pendingChats")) + .contentKey(Number160.createHash(newChatRequestMessage.getChatID())) + .start() + .awaitUninterruptibly(); break; } } @@ -59,7 +69,7 @@ public class NetworkHandler implements NetworkObserver { return jsonObject.get("action").getAsInt(); } - private void createChatEntry(String chatID, String name, PeerAddress peerAddress) { + private static void createChatEntry(String chatID, String name, PeerAddress peerAddress) { List chatEntities = AppHelper.getChatDB().chatDao().getChatByChatID(chatID); if (chatEntities.size() > 0) { Log.e(LOG_TAG, "Failed to create chat " + chatID + " because chat exists!"); @@ -74,4 +84,96 @@ public class NetworkHandler implements NetworkObserver { newChatRequestMessage.setAction(NetworkActions.SUCCESSFULL_CREATE_CHAT); AppHelper.getPeerDHT().peer().sendDirect(chatStarterAddress).object(gson.toJson(newChatRequestMessage)).start().awaitUninterruptibly(); } + + public static void handlePendingChats() { + FutureGet futureGetPendingChats = peerDHT + .get(Number160.createHash(AppHelper.getPeerID() + "_pendingChats")) + .all() + .start() + .awaitUninterruptibly(); + if(!futureGetPendingChats.isEmpty()) { + for(Map.Entry entry : futureGetPendingChats.dataMap().entrySet()) { + NewChatRequestMessage newChatRequestMessage = null; + try { + newChatRequestMessage = gson.fromJson((String) entry.getValue().object(), NewChatRequestMessage.class); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + createChatEntry( + newChatRequestMessage.getChatID(), + newChatRequestMessage.getSenderID(), + newChatRequestMessage.getSenderPeerAddress() + ); + + FuturePing ping = peerDHT + .peer() + .ping() + .peerAddress(newChatRequestMessage.getSenderPeerAddress()) + .start() + .awaitUninterruptibly(); + NewChatRequestMessage newChatRequestReply = new NewChatRequestMessage(AppHelper.getPeerID(), peerDHT.peerAddress()); + newChatRequestReply.setAction(NetworkActions.SUCCESSFULL_CREATE_CHAT); + if(ping.isSuccess()) { + peerDHT + .peer() + .sendDirect(newChatRequestMessage.getSenderPeerAddress()) + .object(gson.toJson(newChatRequestReply)) + .start() + .awaitUninterruptibly(); + } else { + try { + FuturePut put = peerDHT.put(Number160.createHash(newChatRequestMessage.getSenderID() + "_pendingAcceptedChats")) + .data(Number160.createHash(UUID.randomUUID().toString()), new Data(gson.toJson(newChatRequestReply)) + .protectEntry(keyPairManager.openMainKeyPair())) + .start() + .awaitUninterruptibly(); + if(put.isSuccess()) { + Log.i(LOG_TAG, "# Successfully put message SUCCESSFULLY_CREATE_CHAT in " + newChatRequestMessage.getSenderID() + "_pendingAcceptedChats, because receiver is offline."); + } else { + Log.e(LOG_TAG, "# Failed to put message SUCCESSFULLY_CREATE_CHAT in " + newChatRequestMessage.getSenderID() + "_pendingAcceptedChats. Reason: " + put.failedReason()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + ObservableUtils.notifyUI(UIActions.NEW_CHAT); + } + } + } + + public static void handlePendingAcceptedChats() { + FutureGet futureGetPendingAcceptedChats = peerDHT + .get(Number160.createHash(AppHelper.getPeerID() + "_pendingAcceptedChats")) + .all() + .start() + .awaitUninterruptibly(); + if(!futureGetPendingAcceptedChats.isEmpty()) { + for(Map.Entry entry : futureGetPendingAcceptedChats.dataMap().entrySet()) { + NewChatRequestMessage newChatRequestMessage = null; + + try { + newChatRequestMessage = gson.fromJson((String) entry.getValue().object(), NewChatRequestMessage.class); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + peerDHT.remove(Number160.createHash(newChatRequestMessage.getSenderID() + "_pendingChats")) + .contentKey(Number160.createHash(newChatRequestMessage.getChatID())) + .start() + .awaitUninterruptibly(); + + createChatEntry( + newChatRequestMessage.getChatID(), + newChatRequestMessage.getSenderID(), + newChatRequestMessage.getSenderPeerAddress() + ); + ObservableUtils.notifyUI(UIActions.NEW_CHAT); + } + } + } } diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/ObservableUtils.java b/app/src/main/java/io/github/chronosx88/influence/helpers/ObservableUtils.java new file mode 100644 index 0000000..6a02596 --- /dev/null +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/ObservableUtils.java @@ -0,0 +1,11 @@ +package io.github.chronosx88.influence.helpers; + +import com.google.gson.JsonObject; + +public class ObservableUtils { + public static void notifyUI(int action) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("action", action); + AppHelper.getObservable().notifyUIObservers(jsonObject); + } +} diff --git a/app/src/main/java/io/github/chronosx88/influence/helpers/actions/UIActions.java b/app/src/main/java/io/github/chronosx88/influence/helpers/actions/UIActions.java index a784fcb..357e479 100644 --- a/app/src/main/java/io/github/chronosx88/influence/helpers/actions/UIActions.java +++ b/app/src/main/java/io/github/chronosx88/influence/helpers/actions/UIActions.java @@ -10,4 +10,5 @@ public class UIActions { public static final int NEW_CHAT = 0x6; public static final int PEER_NOT_EXIST = 0x7; public static final int SUCCESSFULL_CREATE_CHAT = 0x8; + public static final int SUCCESSFULL_CREATE_OFFLINE_CHAT = 0x9; } diff --git a/app/src/main/java/io/github/chronosx88/influence/logic/MainLogic.java b/app/src/main/java/io/github/chronosx88/influence/logic/MainLogic.java index fc578d4..1103d24 100644 --- a/app/src/main/java/io/github/chronosx88/influence/logic/MainLogic.java +++ b/app/src/main/java/io/github/chronosx88/influence/logic/MainLogic.java @@ -37,6 +37,7 @@ import io.github.chronosx88.influence.contracts.main.MainLogicContract; import io.github.chronosx88.influence.helpers.AppHelper; import io.github.chronosx88.influence.helpers.DSAKey; import io.github.chronosx88.influence.helpers.KeyPairManager; +import io.github.chronosx88.influence.helpers.NetworkHandler; import io.github.chronosx88.influence.helpers.StorageMVStore; import io.github.chronosx88.influence.helpers.actions.UIActions; import io.github.chronosx88.influence.models.PublicUserProfile; @@ -138,6 +139,8 @@ public class MainLogic implements MainLogicContract { setReceiveHandler(); gson = new Gson(); publicProfileToDHT(); + NetworkHandler.handlePendingChats(); + NetworkHandler.handlePendingAcceptedChats(); replication = new AutoReplication(peerDHT.peer()).start(); } catch (IOException e) { e.printStackTrace(); diff --git a/app/src/main/java/io/github/chronosx88/influence/logic/StartChatLogic.java b/app/src/main/java/io/github/chronosx88/influence/logic/StartChatLogic.java index 6fc654e..b09b801 100644 --- a/app/src/main/java/io/github/chronosx88/influence/logic/StartChatLogic.java +++ b/app/src/main/java/io/github/chronosx88/influence/logic/StartChatLogic.java @@ -19,6 +19,7 @@ import java.util.UUID; import io.github.chronosx88.influence.contracts.startchat.StartChatLogicContract; import io.github.chronosx88.influence.helpers.AppHelper; import io.github.chronosx88.influence.helpers.KeyPairManager; +import io.github.chronosx88.influence.helpers.ObservableUtils; import io.github.chronosx88.influence.helpers.actions.UIActions; import io.github.chronosx88.influence.models.NewChatRequestMessage; import io.github.chronosx88.influence.models.PublicUserProfile; @@ -54,14 +55,17 @@ public class StartChatLogic implements StartChatLogicContract { try { NewChatRequestMessage newChatRequestMessage = new NewChatRequestMessage(AppHelper.getPeerID(), peerDHT.peerAddress()); FuturePut futurePut = peerDHT - .put(Number160.createHash(peerID)) - .data(Number160.createHash(UUID.randomUUID().toString()), new Data(gson.toJson(newChatRequestMessage)) - .protectEntry(keyPairManager.openMainKeyPair())).start().awaitUninterruptibly(); + .put(Number160.createHash(peerID + "_pendingChats")) + .data(Number160.createHash(newChatRequestMessage.getChatID()), new Data(gson.toJson(newChatRequestMessage)) + .protectEntry(keyPairManager.openMainKeyPair())) + .start() + .awaitUninterruptibly(); if(futurePut.isSuccess()) { Log.i(LOG_TAG, "# Create new offline chat request is successful! ChatID: " + newChatRequestMessage.getChatID()); } else { Log.e(LOG_TAG, "# Failed to create chat: " + futurePut.failedReason()); } + ObservableUtils.notifyUI(UIActions.SUCCESSFULL_CREATE_OFFLINE_CHAT); } catch (IOException e) { e.printStackTrace(); } diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatListPresenter.java b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatListPresenter.java index 93261d2..b62c90b 100644 --- a/app/src/main/java/io/github/chronosx88/influence/presenters/ChatListPresenter.java +++ b/app/src/main/java/io/github/chronosx88/influence/presenters/ChatListPresenter.java @@ -2,18 +2,18 @@ package io.github.chronosx88.influence.presenters; import android.view.MenuItem; -import com.google.gson.JsonObject; +import net.tomp2p.dht.FutureRemove; +import net.tomp2p.peers.Number160; import io.github.chronosx88.influence.contracts.chatlist.ChatListLogicContract; import io.github.chronosx88.influence.contracts.chatlist.ChatListPresenterContract; import io.github.chronosx88.influence.contracts.chatlist.ChatListViewContract; -import io.github.chronosx88.influence.contracts.observer.Observer; import io.github.chronosx88.influence.helpers.AppHelper; import io.github.chronosx88.influence.helpers.ChatListAdapter; -import io.github.chronosx88.influence.helpers.actions.UIActions; import io.github.chronosx88.influence.logic.ChatListLogic; +import io.github.chronosx88.influence.models.roomEntities.ChatEntity; -public class ChatListPresenter implements ChatListPresenterContract, Observer { +public class ChatListPresenter implements ChatListPresenterContract { private ChatListViewContract view; private ChatListLogicContract logic; private ChatListAdapter chatListAdapter; @@ -23,7 +23,6 @@ public class ChatListPresenter implements ChatListPresenterContract, Observer { chatListAdapter = new ChatListAdapter(); this.logic = new ChatListLogic(); this.view.setRecycleAdapter(chatListAdapter); - AppHelper.getObservable().register(this); } @Override @@ -41,19 +40,13 @@ public class ChatListPresenter implements ChatListPresenterContract, Observer { switch(item.getItemId()) { case 0: { if(chatListAdapter.onClickPosition != -1) { - AppHelper.getChatDB().chatDao().deleteChat(chatListAdapter.getItem(chatListAdapter.onClickPosition).chatID); - view.updateChatList(chatListAdapter, logic.loadAllChats()); + new Thread(() -> { + ChatEntity chat = chatListAdapter.getItem(chatListAdapter.onClickPosition); + AppHelper.getChatDB().chatDao().deleteChat(chat.chatID); + view.updateChatList(chatListAdapter, logic.loadAllChats()); + }).start(); } } } } - - @Override - public void handleEvent(JsonObject object) { - switch (object.get("action").getAsInt()) { - case UIActions.NEW_CHAT: { - updateChatList(); - } - } - } } diff --git a/app/src/main/java/io/github/chronosx88/influence/presenters/StartChatPresenter.java b/app/src/main/java/io/github/chronosx88/influence/presenters/StartChatPresenter.java index 2d75f13..14169af 100644 --- a/app/src/main/java/io/github/chronosx88/influence/presenters/StartChatPresenter.java +++ b/app/src/main/java/io/github/chronosx88/influence/presenters/StartChatPresenter.java @@ -22,6 +22,7 @@ public class StartChatPresenter implements StartChatPresenterContract, Observer @Override public void startChatWithPeer(String peerID) { + view.showProgressDialog(true); logic.sendStartChatMessage(peerID); } @@ -39,6 +40,11 @@ public class StartChatPresenter implements StartChatPresenterContract, Observer view.showMessage("Чат успешно создан"); break; } + case UIActions.SUCCESSFULL_CREATE_OFFLINE_CHAT: { + view.showProgressDialog(false); + view.showMessage("В сеть отправлен запрос на создание чата, так как получатель не в сети."); + break; + } } } } diff --git a/app/src/main/java/io/github/chronosx88/influence/views/fragments/ChatListFragment.java b/app/src/main/java/io/github/chronosx88/influence/views/fragments/ChatListFragment.java index 15b0a6e..fcf4251 100644 --- a/app/src/main/java/io/github/chronosx88/influence/views/fragments/ChatListFragment.java +++ b/app/src/main/java/io/github/chronosx88/influence/views/fragments/ChatListFragment.java @@ -1,6 +1,7 @@ package io.github.chronosx88.influence.views.fragments; import android.os.Bundle; +import android.os.Handler; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -28,11 +29,13 @@ import io.github.chronosx88.influence.presenters.ChatListPresenter; public class ChatListFragment extends Fragment implements ChatListViewContract, Observer { private ChatListPresenterContract presenter; private RecyclerView chatList; + private Handler mainThreadHandler; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AppHelper.getObservable().register(this); + this.mainThreadHandler = new Handler(getContext().getMainLooper()); } @Override @@ -73,7 +76,7 @@ public class ChatListFragment extends Fragment implements ChatListViewContract, @Override public void updateChatList(ChatListAdapter adapter, List chats) { - requireActivity().runOnUiThread(() -> { + mainThreadHandler.post(() -> { adapter.setChatList(chats); adapter.notifyDataSetChanged(); }); diff --git a/app/src/main/java/io/github/chronosx88/influence/views/fragments/StartChatFragment.java b/app/src/main/java/io/github/chronosx88/influence/views/fragments/StartChatFragment.java index c35666c..27a9e5c 100644 --- a/app/src/main/java/io/github/chronosx88/influence/views/fragments/StartChatFragment.java +++ b/app/src/main/java/io/github/chronosx88/influence/views/fragments/StartChatFragment.java @@ -52,11 +52,14 @@ public class StartChatFragment extends Fragment implements StartChatViewContract @Override public void showProgressDialog(boolean enabled) { - if(enabled) { - progressDialog.show(); - } else { - progressDialog.dismiss(); - } + // TODO: make run on mainHandlerThread + requireActivity().runOnUiThread(() -> { + if(enabled) { + progressDialog.show(); + } else { + progressDialog.dismiss(); + } + }); } // TODO: clear text input diff --git a/app/src/main/res/layout/start_chat_fragment.xml b/app/src/main/res/layout/start_chat_fragment.xml index 5243f66..66e2815 100644 --- a/app/src/main/res/layout/start_chat_fragment.xml +++ b/app/src/main/res/layout/start_chat_fragment.xml @@ -13,11 +13,11 @@