Made offline chat send request

This commit is contained in:
ChronosX88 2019-03-23 21:30:24 +04:00
parent 6ee7223fcd
commit 0bca327949
Signed by: ChronosXYZ
GPG Key ID: 085A69A82C8C511A
10 changed files with 161 additions and 35 deletions

View File

@ -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<ChatEntity> 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<Number640, Data> 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<Number640, Data> 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);
}
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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();
}
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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<ChatEntity> chats) {
requireActivity().runOnUiThread(() -> {
mainThreadHandler.post(() -> {
adapter.setChatList(chats);
adapter.notifyDataSetChanged();
});

View File

@ -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

View File

@ -13,11 +13,11 @@
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputPeerID"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="346dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:hint="Peer ID"/>