package network.thunder.core.communication.processor.implementations.gossip; import network.thunder.core.communication.objects.messages.impl.message.gossip.objects.P2PDataObject; import network.thunder.core.communication.objects.messages.interfaces.helper.LNEventHelper; import network.thunder.core.communication.processor.interfaces.GossipProcessor; import network.thunder.core.database.DBHandler; import java.nio.ByteBuffer; import java.util.*; /** * Created by matsjerratsch on 01/12/2015. */ public class GossipSubjectImpl implements GossipSubject, BroadcastHelper { DBHandler dbHandler; LNEventHelper eventHelper; List<NodeObserver> observerList = new ArrayList<>(); Map<NodeObserver, List<ByteBuffer>> dataObjectMap = new HashMap<>(); Set<ByteBuffer> objectsKnownAlready = new HashSet<>(); public GossipSubjectImpl (DBHandler dbHandler, LNEventHelper eventHelper) { this.dbHandler = dbHandler; this.eventHelper = eventHelper; } @Override public void registerObserver (NodeObserver observer) { observerList.add(observer); dataObjectMap.put(observer, new ArrayList<>()); } @Override public void removeObserver (NodeObserver observer) { observerList.remove(observer); dataObjectMap.remove(observer); } @Override public void receivedNewObjects (NodeObserver nodeObserver, List<P2PDataObject> dataObjects) { List<P2PDataObject> objectsToInsertIntoDatabase = new ArrayList<>(); for (P2PDataObject dataObject : dataObjects) { boolean newEntry = insertNewDataObject(nodeObserver, dataObject); if (newEntry) { objectsToInsertIntoDatabase.add(dataObject); } } dbHandler.syncDatalist(objectsToInsertIntoDatabase); eventHelper.onP2PDataReceived(); broadcast(); } @Override public boolean parseInv (NodeObserver nodeObserver, byte[] hash) { ByteBuffer b = ByteBuffer.wrap(hash); dataObjectMap.get(nodeObserver).remove(b); return objectsKnownAlready.contains(ByteBuffer.wrap(hash)); } //Brand new object that should be broadcasted to all peers.. //Part of BroadcastHelper @Override public void broadcastNewObject (P2PDataObject dataObject) { List<P2PDataObject> wrapper = new ArrayList<>(); wrapper.add(dataObject); dbHandler.syncDatalist(wrapper); insertNewDataObject(null, dataObject); broadcast(); } private boolean insertNewDataObject (NodeObserver nodeObserver, P2PDataObject dataObject) { if (objectsKnownAlready.add(ByteBuffer.wrap(dataObject.getHash()))) { addNewDataObjectToMap(nodeObserver, dataObject); return true; } return false; } private void broadcast () { for (NodeObserver observer : observerList) { List<ByteBuffer> objectList = dataObjectMap.get(observer); if (objectList.size() > GossipProcessor.OBJECT_AMOUNT_TO_SEND) { observer.update(new ArrayList<>(objectList)); objectList.clear(); } } } private void addNewDataObjectToMap (NodeObserver nodeObserver, P2PDataObject dataObject) { for (NodeObserver nodeObserver1 : observerList) { if (nodeObserver == null || nodeObserver != nodeObserver1) { List<ByteBuffer> bufferList = dataObjectMap.get(nodeObserver1); ByteBuffer buffer = ByteBuffer.wrap(dataObject.getHash()); if (!bufferList.contains(buffer)) { bufferList.add(buffer); } } } } }