package network.thunder.core.communication.processor.implementations.gossip; import network.thunder.core.communication.Message; import network.thunder.core.communication.objects.messages.MessageExecutor; import network.thunder.core.communication.objects.messages.impl.message.gossip.GossipGetMessage; import network.thunder.core.communication.objects.messages.impl.message.gossip.GossipInvMessage; import network.thunder.core.communication.objects.messages.impl.message.gossip.GossipSendMessage; import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.P2PDataObject; import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.PubkeyIPObject; import network.thunder.core.communication.objects.messages.interfaces.factories.ContextFactory; import network.thunder.core.communication.objects.messages.interfaces.factories.GossipMessageFactory; import network.thunder.core.communication.objects.messages.interfaces.message.gossip.Gossip; import network.thunder.core.communication.processor.interfaces.GossipProcessor; import network.thunder.core.database.DBHandler; import network.thunder.core.etc.Tools; import network.thunder.core.mesh.NodeClient; import network.thunder.core.mesh.NodeServer; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Random; public class GossipProcessorImpl extends GossipProcessor { GossipMessageFactory messageFactory; GossipSubject subject; DBHandler dbHandler; NodeClient node; NodeServer nodeServer; MessageExecutor messageExecutor; boolean firstMessage = true; int randomNumber; public GossipProcessorImpl (ContextFactory contextFactory, DBHandler dbHandler, NodeClient node) { this.messageFactory = contextFactory.getGossipMessageFactory(); this.subject = contextFactory.getGossipSubject(); this.dbHandler = dbHandler; this.node = node; this.nodeServer = contextFactory.getServerSettings(); } @Override public void onInboundMessage (Message message) { consumeMessage(message); } @Override public boolean consumesInboundMessage (Object object) { return object instanceof Gossip; } @Override public boolean consumesOutboundMessage (Object object) { return false; } @Override public void onLayerActive (MessageExecutor messageExecutor) { this.randomNumber = new Random().nextInt(); this.messageExecutor = messageExecutor; subject.registerObserver(this); sendOwnIPAddress(); messageExecutor.sendNextLayerActive(); } @Override public void onLayerClose () { subject.removeObserver(this); } @Override public void update (List<ByteBuffer> newObjectList) { sendInvMessage(newObjectList); } private void consumeMessage (Message message) { if (message instanceof GossipInvMessage) { processGossipInvMessage(message); } else if (message instanceof GossipSendMessage) { processGossipSendMessage(message); } else if (message instanceof GossipGetMessage) { processGossipGetMessage(message); } else { throw new UnsupportedOperationException("Don't know this Gossip Message: " + message); } } private void processGossipInvMessage (Message message) { GossipInvMessage invMessage = (GossipInvMessage) message; List<byte[]> objectsToGet = new ArrayList<>(); for (byte[] hash : invMessage.inventoryList) { if (!subject.parseInv(this, hash)) { objectsToGet.add(hash); } } if (objectsToGet.size() > 0) { sendGossipGetMessage(objectsToGet); } } private void processGossipSendMessage (Message message) { GossipSendMessage sendMessage = (GossipSendMessage) message; subject.receivedNewObjects(this, sendMessage.getDataList()); //TODO: Hack to show the other hostname in debugs if (firstMessage && sendMessage.pubkeyIPList.size() > 0) { node.port = sendMessage.pubkeyIPList.get(0).port; node.host = sendMessage.pubkeyIPList.get(0).IP; firstMessage = false; } } private void processGossipGetMessage (Message message) { GossipGetMessage getMessage = (GossipGetMessage) message; sendGossipSendMessage(getMessage.inventoryList); } private synchronized void sendInvMessage (List<ByteBuffer> invList) { Message invMessage = messageFactory.getGossipInvMessage(Tools.byteBufferListToByteArrayList(invList)); messageExecutor.sendMessageUpwards(invMessage); } private void sendOwnIPAddress () { if (nodeServer.hostServer == null || nodeServer.hostServer.equals("")) { return; } PubkeyIPObject pubkeyIPObject = new PubkeyIPObject(); pubkeyIPObject.pubkey = nodeServer.pubKeyServer.getPubKey(); pubkeyIPObject.port = nodeServer.portServer; pubkeyIPObject.IP = nodeServer.hostServer; pubkeyIPObject.timestamp = Tools.currentTimeFlooredToCurrentDay(); pubkeyIPObject.sign(nodeServer.pubKeyServer); List<P2PDataObject> ipAddresses = new ArrayList<>(); ipAddresses.add(pubkeyIPObject); Message gossipSendMessage = messageFactory.getGossipSendMessage(ipAddresses); messageExecutor.sendMessageUpwards(gossipSendMessage); //Hack to register the object we sent out here.. subject.receivedNewObjects(this, ipAddresses); } private void sendGossipSendMessage (List<byte[]> objectsToSend) { List<P2PDataObject> listToSend = buildObjectList(objectsToSend); Message gossipSendMessage = messageFactory.getGossipSendMessage(listToSend); messageExecutor.sendMessageUpwards(gossipSendMessage); } private void sendGossipGetMessage (List<byte[]> objectsToGet) { Message gossipGetMessage = messageFactory.getGossipGetMessage(objectsToGet); messageExecutor.sendMessageUpwards(gossipGetMessage); } private List<P2PDataObject> buildObjectList (List<byte[]> objectsToSend) { List<P2PDataObject> listToSend = new ArrayList<>(); for (byte[] hash : objectsToSend) { addP2PObjectToList(hash, listToSend); } return listToSend; } private void addP2PObjectToList (byte[] hash, List<P2PDataObject> objectListToAdd) { //TODO optimize using a Cache somewhere.. P2PDataObject object = dbHandler.getP2PDataObjectByHash(hash); if (object != null) { objectListToAdd.add(object); } } private List<byte[]> translateP2PDataObjectListToHashList (List<P2PDataObject> objectList) { List<byte[]> hashList = new ArrayList<>(); for (P2PDataObject object : objectList) { hashList.add(object.getHash()); } return hashList; } @Override public boolean equals (Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } GossipProcessorImpl that = (GossipProcessorImpl) o; return randomNumber == that.randomNumber; } @Override public int hashCode () { return randomNumber; } }