mirror of
https://github.com/ChronosX88/Influence-P2P.git
synced 2024-11-26 00:42:19 +00:00
Implemented basic notification system (on top of FreePastry)
This commit is contained in:
parent
ff8aa48b3e
commit
3d2230bea4
BIN
app/libs/FreePastry-2.1.jar
Normal file
BIN
app/libs/FreePastry-2.1.jar
Normal file
Binary file not shown.
Binary file not shown.
@ -13,7 +13,10 @@ import com.instacart.library.truetime.TrueTime;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import io.github.chronosx88.influence.notificationSystem.NotificationSystem;
|
||||||
import io.github.chronosx88.influence.observable.MainObservable;
|
import io.github.chronosx88.influence.observable.MainObservable;
|
||||||
|
import rice.environment.Environment;
|
||||||
|
import rice.pastry.PastryNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended Application class which designed for centralized getting various objects from anywhere in the application.
|
* Extended Application class which designed for centralized getting various objects from anywhere in the application.
|
||||||
@ -25,9 +28,11 @@ public class AppHelper extends MultiDexApplication {
|
|||||||
private static String peerID;
|
private static String peerID;
|
||||||
private static PeerDHT peerDHT;
|
private static PeerDHT peerDHT;
|
||||||
private static RoomHelper chatDB;
|
private static RoomHelper chatDB;
|
||||||
private static NetworkHandler networkHandler;
|
|
||||||
private static String username = "";
|
private static String username = "";
|
||||||
private static SharedPreferences preferences;
|
private static SharedPreferences preferences;
|
||||||
|
private static PastryNode pastryNode;
|
||||||
|
private static Environment pastryEnvironment;
|
||||||
|
private static NotificationSystem notificationSystem;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
@ -67,9 +72,27 @@ public class AppHelper extends MultiDexApplication {
|
|||||||
|
|
||||||
public static RoomHelper getChatDB() { return chatDB; }
|
public static RoomHelper getChatDB() { return chatDB; }
|
||||||
|
|
||||||
public static void initNetworkHandler() { networkHandler = new NetworkHandler(); }
|
|
||||||
|
|
||||||
public static SharedPreferences getPreferences() {
|
public static SharedPreferences getPreferences() {
|
||||||
return preferences;
|
return preferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void storePastryNode(PastryNode node) { pastryNode = node; }
|
||||||
|
|
||||||
|
public static PastryNode getPastryNode() { return pastryNode; }
|
||||||
|
|
||||||
|
public static void storePastryEnvironment(Environment env) {
|
||||||
|
pastryEnvironment = env;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Environment getPastryEnvironment() {
|
||||||
|
return pastryEnvironment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void storeNotificationSystem(NotificationSystem system) {
|
||||||
|
notificationSystem = system;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static NotificationSystem getNotificationSystem() {
|
||||||
|
return notificationSystem;
|
||||||
|
}
|
||||||
}
|
}
|
@ -56,6 +56,15 @@ import io.github.chronosx88.influence.helpers.actions.UIActions;
|
|||||||
import io.github.chronosx88.influence.models.ChatMetadata;
|
import io.github.chronosx88.influence.models.ChatMetadata;
|
||||||
import io.github.chronosx88.influence.models.NewChatRequestMessage;
|
import io.github.chronosx88.influence.models.NewChatRequestMessage;
|
||||||
import io.github.chronosx88.influence.models.PublicUserProfile;
|
import io.github.chronosx88.influence.models.PublicUserProfile;
|
||||||
|
import io.github.chronosx88.influence.notificationSystem.NotificationHandler;
|
||||||
|
import io.github.chronosx88.influence.notificationSystem.NotificationSystem;
|
||||||
|
import rice.environment.Environment;
|
||||||
|
import rice.p2p.scribe.ScribeContent;
|
||||||
|
import rice.pastry.NodeHandle;
|
||||||
|
import rice.pastry.NodeIdFactory;
|
||||||
|
import rice.pastry.PastryNode;
|
||||||
|
import rice.pastry.socket.internet.InternetPastryNodeFactory;
|
||||||
|
import rice.pastry.standard.RandomNodeIdFactory;
|
||||||
|
|
||||||
public class MainLogic implements CoreContracts.IMainLogicContract {
|
public class MainLogic implements CoreContracts.IMainLogicContract {
|
||||||
private static final String LOG_TAG = MainLogic.class.getName();
|
private static final String LOG_TAG = MainLogic.class.getName();
|
||||||
@ -71,6 +80,7 @@ public class MainLogic implements CoreContracts.IMainLogicContract {
|
|||||||
private KeyPairManager keyPairManager;
|
private KeyPairManager keyPairManager;
|
||||||
private Thread checkNewChatsThread = null;
|
private Thread checkNewChatsThread = null;
|
||||||
private Storage storage;
|
private Storage storage;
|
||||||
|
private PastryNode pastryNode;
|
||||||
|
|
||||||
public MainLogic() {
|
public MainLogic() {
|
||||||
this.context = AppHelper.getContext();
|
this.context = AppHelper.getContext();
|
||||||
@ -151,19 +161,35 @@ public class MainLogic implements CoreContracts.IMainLogicContract {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(!createPastryNode(7244, new InetSocketAddress(bootstrapAddress, 7244))) {
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
jsonObject.addProperty("action", UIActions.BOOTSTRAP_ERROR);
|
||||||
|
AppHelper.getObservable().notifyUIObservers(jsonObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
JsonObject jsonObject = new JsonObject();
|
||||||
|
jsonObject.addProperty("action", UIActions.BOOTSTRAP_ERROR);
|
||||||
|
AppHelper.getObservable().notifyUIObservers(jsonObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject jsonObject = new JsonObject();
|
JsonObject jsonObject = new JsonObject();
|
||||||
jsonObject.addProperty("action", UIActions.BOOTSTRAP_SUCCESS);
|
jsonObject.addProperty("action", UIActions.BOOTSTRAP_SUCCESS);
|
||||||
AppHelper.getObservable().notifyUIObservers(jsonObject);
|
AppHelper.getObservable().notifyUIObservers(jsonObject);
|
||||||
AppHelper.storePeerID(preferences.getString("peerID", null));
|
AppHelper.storePeerID(preferences.getString("peerID", null));
|
||||||
AppHelper.updateUsername(preferences.getString("username", null));
|
AppHelper.updateUsername(preferences.getString("username", null));
|
||||||
AppHelper.storePeerDHT(peerDHT);
|
AppHelper.storePeerDHT(peerDHT);
|
||||||
AppHelper.initNetworkHandler();
|
AppHelper.storePastryNode(pastryNode);
|
||||||
//setReceiveHandler();
|
AppHelper.storeNotificationSystem(new NotificationSystem());
|
||||||
gson = new Gson();
|
gson = new Gson();
|
||||||
publicProfileToDHT();
|
publicProfileToDHT();
|
||||||
SettingsLogic.Companion.publishUsername(AppHelper.getUsername(), AppHelper.getUsername());
|
SettingsLogic.Companion.publishUsername(AppHelper.getUsername(), AppHelper.getUsername());
|
||||||
NetworkHandler.handlePendingChatRequests();
|
NetworkHandler.handlePendingChatRequests();
|
||||||
TimerTask timerTask = new TimerTask() {
|
AppHelper.getNotificationSystem().subscribe(AppHelper.getPeerID() + "_newChats", notification -> NetworkHandler.handlePendingChatRequests());
|
||||||
|
/*TimerTask timerTask = new TimerTask() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
if(checkNewChatsThread == null) {
|
if(checkNewChatsThread == null) {
|
||||||
@ -177,7 +203,7 @@ public class MainLogic implements CoreContracts.IMainLogicContract {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
Timer timer = new Timer();
|
Timer timer = new Timer();
|
||||||
timer.schedule(timerTask, 1, 5000);
|
timer.schedule(timerTask, 1, 5000);*/
|
||||||
replication = new IndirectReplication(peerDHT).start();
|
replication = new IndirectReplication(peerDHT).start();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -227,14 +253,6 @@ public class MainLogic implements CoreContracts.IMainLogicContract {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setReceiveHandler() {
|
|
||||||
AppHelper.getPeerDHT().peer().objectDataReply((s, r) -> {
|
|
||||||
Log.i(LOG_TAG, "# Incoming message: " + r);
|
|
||||||
AppHelper.getObservable().notifyNetworkObservers(r);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdownPeer() {
|
public void shutdownPeer() {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
@ -274,29 +292,14 @@ public class MainLogic implements CoreContracts.IMainLogicContract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ChannelClientConfiguration createChannelClientConfig() {
|
private ChannelClientConfiguration createChannelClientConfig() {
|
||||||
ChannelClientConfiguration channelClientConfiguration = new ChannelClientConfiguration();
|
ChannelClientConfiguration channelClientConfiguration = PeerBuilder.createDefaultChannelClientConfiguration();
|
||||||
channelClientConfiguration.bindings(new Bindings());
|
|
||||||
channelClientConfiguration.maxPermitsPermanentTCP(250);
|
|
||||||
channelClientConfiguration.maxPermitsTCP(250);
|
|
||||||
channelClientConfiguration.maxPermitsUDP(250);
|
|
||||||
channelClientConfiguration.pipelineFilter(new PeerBuilder.DefaultPipelineFilter());
|
|
||||||
channelClientConfiguration.signatureFactory(new RSASignatureFactory());
|
channelClientConfiguration.signatureFactory(new RSASignatureFactory());
|
||||||
channelClientConfiguration.senderTCP((new InetSocketAddress(0)).getAddress());
|
|
||||||
channelClientConfiguration.senderUDP((new InetSocketAddress(0)).getAddress());
|
|
||||||
channelClientConfiguration.byteBufPool(false);
|
|
||||||
return channelClientConfiguration;
|
return channelClientConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChannelServerConfiguration createChannelServerConfig() {
|
private ChannelServerConfiguration createChannelServerConfig() {
|
||||||
ChannelServerConfiguration channelServerConfiguration = new ChannelServerConfiguration();
|
ChannelServerConfiguration channelServerConfiguration = PeerBuilder.createDefaultChannelServerConfiguration();
|
||||||
channelServerConfiguration.bindings(new Bindings());
|
|
||||||
//these two values may be overwritten in the peer builder
|
|
||||||
channelServerConfiguration.ports(new Ports(Ports.DEFAULT_PORT, Ports.DEFAULT_PORT));
|
|
||||||
channelServerConfiguration.portsForwarding(new Ports(Ports.DEFAULT_PORT, Ports.DEFAULT_PORT));
|
|
||||||
channelServerConfiguration.behindFirewall(false);
|
|
||||||
channelServerConfiguration.pipelineFilter(new PeerBuilder.DefaultPipelineFilter());
|
|
||||||
channelServerConfiguration.signatureFactory(new RSASignatureFactory());
|
channelServerConfiguration.signatureFactory(new RSASignatureFactory());
|
||||||
channelServerConfiguration.byteBufPool(false);
|
|
||||||
return channelServerConfiguration;
|
return channelServerConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,4 +372,31 @@ public class MainLogic implements CoreContracts.IMainLogicContract {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean createPastryNode(int bindPort, InetSocketAddress bootAddress) throws Exception {
|
||||||
|
Environment env = new Environment();
|
||||||
|
env.getParameters().setString("probe_for_external_address","true");
|
||||||
|
AppHelper.storePastryEnvironment(env);
|
||||||
|
NodeIdFactory nidFactory = new RandomNodeIdFactory(env);
|
||||||
|
InternetPastryNodeFactory factory = new InternetPastryNodeFactory(nidFactory, bindPort, env);
|
||||||
|
NodeHandle bootHandle = factory.getNodeHandle(bootAddress);
|
||||||
|
PastryNode node;
|
||||||
|
if(bootHandle != null) {
|
||||||
|
node = factory.newNode(bootHandle);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// the node may require sending several messages to fully boot into the ring
|
||||||
|
synchronized(node) {
|
||||||
|
while(!node.isReady() && !node.joinFailed()) {
|
||||||
|
node.wait(100);
|
||||||
|
if (node.joinFailed()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Log.i(LOG_TAG, "# [Pastry] Finished creating new Pastry node: " + node);
|
||||||
|
this.pastryNode = node;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 ChronosX88
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.chronosx88.influence.notificationSystem;
|
||||||
|
|
||||||
|
import rice.p2p.scribe.ScribeContent;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface NotificationHandler {
|
||||||
|
void handleNotification(ScribeContent notification);
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 ChronosX88
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.chronosx88.influence.notificationSystem;
|
||||||
|
|
||||||
|
import rice.p2p.scribe.ScribeContent;
|
||||||
|
|
||||||
|
public class NotificationSystem {
|
||||||
|
private ScribeClient scribeClient = new ScribeClient();
|
||||||
|
|
||||||
|
public void subscribe(String topicName, NotificationHandler handler) {
|
||||||
|
scribeClient.subscribeToTopic(topicName, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribe(String topicName) {
|
||||||
|
scribeClient.unsubscribeFromTopic(topicName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void publish(String topicName, ScribeContent message) {
|
||||||
|
scribeClient.publishToTopic(topicName, message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 ChronosX88
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.chronosx88.influence.notificationSystem;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import io.github.chronosx88.influence.helpers.AppHelper;
|
||||||
|
import rice.p2p.commonapi.NodeHandle;
|
||||||
|
import rice.p2p.scribe.Scribe;
|
||||||
|
import rice.p2p.scribe.ScribeContent;
|
||||||
|
import rice.p2p.scribe.ScribeImpl;
|
||||||
|
import rice.p2p.scribe.Topic;
|
||||||
|
import rice.pastry.commonapi.PastryIdFactory;
|
||||||
|
|
||||||
|
public class ScribeClient implements rice.p2p.scribe.ScribeClient {
|
||||||
|
private Map<String, Topic> topicMap = new ConcurrentHashMap<>();
|
||||||
|
private Map<Topic, NotificationHandler> notificationHandlerMap = new ConcurrentHashMap<>();
|
||||||
|
private Scribe scribe = new ScribeImpl(AppHelper.getPastryNode(), "scribeInstance");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean anycast(Topic topic, ScribeContent scribeContent) {
|
||||||
|
// We don't need anycast. Therefore, just suspend the wave.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deliver(Topic topic, ScribeContent scribeContent) {
|
||||||
|
if(notificationHandlerMap.containsKey(topic)) {
|
||||||
|
notificationHandlerMap.get(topic).handleNotification(scribeContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void childAdded(Topic topic, NodeHandle nodeHandle) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void childRemoved(Topic topic, NodeHandle nodeHandle) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void subscribeFailed(Topic topic) {
|
||||||
|
// Nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
public void subscribeToTopic(String topicName, NotificationHandler handler) {
|
||||||
|
Topic topic = new Topic(new PastryIdFactory(AppHelper.getPastryEnvironment()), topicName);
|
||||||
|
scribe.subscribe(topic, this);
|
||||||
|
topicMap.put(topicName, topic);
|
||||||
|
notificationHandlerMap.put(topic, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unsubscribeFromTopic(String topicName) {
|
||||||
|
if(topicMap.containsKey(topicName)) {
|
||||||
|
scribe.unsubscribe(topicMap.get(topicName), this);
|
||||||
|
notificationHandlerMap.remove(topicMap.get(topicName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void publishToTopic(String topicName, ScribeContent content) {
|
||||||
|
Topic topic = new Topic(new PastryIdFactory(AppHelper.getPastryEnvironment()), topicName);
|
||||||
|
scribe.publish(topic, content);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user