def getPeerAround(self, targetPosition, emitter_id, isClockWise=True): """ Return the peer that is the closest to a target position and that is in the right half plane. targetPosition : target position which we are looking around isClockWise : boolean indicating if we we searching in the right or the left half-plane - optional Return : a peer or None if there is no peer in the half plane """ found = False around = None distClosest = 0 nodePosition = self.node.getPosition() for p in self.peers.values(): if p.getId() == emitter_id: continue if Geometry.inHalfPlane(nodePosition, targetPosition, p.getPosition()) == isClockWise: # first entity in right half-plane if not found: found = True around = p distClosest = Geometry.distance(targetPosition, p.getPosition()) else: dist = Geometry.distance(targetPosition, p.getPosition()) # this peer is closer if dist < distClosest: around = p distClosest = dist return around
def isCloser(self, peerB, targetPosition): """ Return True if this peer is closer than peerB to targetPosition """ d1 = Geometry.distance(self.getPosition(), targetPosition) d2 = Geometry.distance(peerB.getPosition(), targetPosition) return d1 < d2
def AROUND(self, event): """ A peer sent us an AROUND message """ # cancel timer since we got our response self.timer.cancel() peer = event.createRemotePeer() # current number of neighbours nbNeighbours = len(self.neighbours) # last neighbour found last = self.neighbours[nbNeighbours-1] nodePos = self.node.getPosition() # our position bestPos = self.best.getPosition() # position of best node peerPos = Geometry.relativePosition(peer.getPosition(), self.node.getPosition()) # check if turn ends : we have at least 3 neighbours and either we got back # to the first peer (=> turn completed) or our last neighbour was in the # left half plane and this peer is in the right half plane if ( nbNeighbours > 2 ) and (peer.getId() == self.best.getId()) or ( not Geometry.inHalfPlane(bestPos, nodePos, last.getPosition()) and Geometry.inHalfPlane(bestPos, nodePos, peerPos) ): # Our awarenesse radius is the distance between us and our closest # neighbour, because we are sure to know all the entities between us # and the best. bestRelativePos = Geometry.relativePosition(bestPos, nodePos) minDistance = Geometry.distance(bestRelativePos, nodePos) self.node.setAwarenessRadius(minDistance) # register these peers with the peerManager and connect ! manager = self.node.getPeersManager() for p in self.neighbours: # FIXME : should we add the peer upon receiving the CONNECT msg? manager.addPeer(p) factory = EventFactory.getInstance(PeerEvent.TYPE) hello = factory.createHELLO() hello.setRecipientAddress(p.getAddress()) self.node.dispatch(hello) self.node.setState(Connecting()) else: # add this peer to our list of neighbours self.addPeerAround(peer) # send this peer a queryaround message bestDist = Geometry.distance(bestPos, nodePos) factory = EventFactory.getInstance(PeerEvent.TYPE) queryaround = factory.createQUERYAROUND(self.best.getId(), bestDist) queryaround.setRecipientAddress(peer.getAddress()) self.node.dispatch(queryaround) self.startTimer()
def NEAREST(self, event): """ While scanning around our target a position, a peer informs us that there exists a peer that is closer than our current best. """ peerPos = event.getArg(protocol.ARG_REMOTE_POSITION) # check if this peer is closer than our current best currentBestDistance = Geometry.distance(self.best.getPosition(), self.node.getPosition()) newDist = Geometry.distance(peerPos, self.node.getPosition()) if newDist < currentBestDistance: super(Scanning,self).NEAREST(event) self.node.setState(Locating())
def BEST(self, event): """ A peer sent us a BEST message This is the default behaviour """ # unexpected message, do not process it msg = 'BEST' if not self.isExpected(msg): self.logger.debug('Error, reception of a ' + msg + 'message in state ' + str(self.__class__)) return self.timer.cancel() # Get the ID and the position of the BEST peer bestId = event.getArg(protocol.ARG_ID) bestPos = event.getArg(protocol.ARG_POSITION) bestAddress = event.getSenderAddress() # send a queryaround message bestDistance = Geometry.distance(self.node.getPosition(), bestPos) factory = EventFactory.getInstance(PeerEvent.TYPE) queryaround = factory.createQUERYAROUND(bestId, bestDistance) queryaround.setRecipientAddress(bestAddress) self.node.dispatch(queryaround) # Create a turning state and store the Best peer bestPeer = Peer(id=bestId, address=event.getSenderAddress(), position=bestPos) scanning = Scanning() scanning.setBestPeer(bestPeer) # go to the Scanning state self.node.setState(scanning)
def QUERYAROUND(self, event): """ A peer sent us a QUERYAROUND message """ #peer, idNearest, distNearest: source_id = event.getArg(protocol.ARG_ID) idNearest = event.getArg(protocol.ARG_BEST_ID) distNearest = event.getArg(protocol.ARG_BEST_DISTANCE) manager = self.node.getPeersManager() target = event.getArg(protocol.ARG_POSITION) closest = manager.getClosestPeer(target, source_id) factory = EventFactory.getInstance(PeerEvent.TYPE) # found a closest peer and this peer is a new one (it isn't idNearest moving # toward target position). if ( (Geometry.distance(closest.getPosition(), target) < distNearest) and closest.getId() <> idNearest ): # send a nearest message nearestEvent = factory.createNEAREST(closest) nearestEvent.setRecipientAddress(event.getSenderAddress()) self.node.dispatch(nearestEvent) else: # search for a peer around target position around = manager.getPeerAround(target, source_id) if around is not None: aroundEvt = factory.createAROUND(around) aroundEvt.setRecipientAddress(event.getSenderAddress()) self.node.dispatch(aroundEvt) else: self.logger.debug('no peer around position: ' + str(target))
def computeAwarenessRadius(self): """ Based on curent the repartition of our peers (number, position), compute what should be our awareness radius Return an awareness radius (integer) """ if self.hasTooManyPeers(): offset = self.getNumberOfPeers() - self.maxPeers # get the awareness radius of the last peer that is inside our AR # in distance order index = len(self.distPeers) - offset -1 return self.distPeers.ll[index].getAwarenessRadius() elif self.hasTooFewPeers(): fartherPeerPos = self.distPeers.ll[len(self.distPeers) - 1].getPosition() maxDist = Geometry.distance(self.node.getPosition(), fartherPeerPos) density = maxDist / self.getNumberOfPeers() return self.expectedPeers / density else: fartherPeerPos = self.distPeers.ll[len(self.distPeers) - 1].getPosition() return Geometry.distance(self.node.getPosition(), fartherPeerPos)
def computeAwarenessRadius(self): """ Based on curent the repartition of our peers (number, position), compute what should be our awareness radius Return an awareness radius (integer) """ if self.hasTooManyPeers(): offset = self.getNumberOfPeers() - self.maxPeers index = len(self.distPeers) - offset - 1 # Get the average between the max inside distance and the min outside distance pos_outside = self.distPeers.ll[index].getPosition() pos_inside = self.distPeers.ll[index - 1].getPosition() dist_outside = Geometry.distance(self.node.getPosition(), pos_outside) dist_inside = Geometry.distance(self.node.getPosition(), pos_inside) return (dist_outside + dist_inside) // 2 if self.hasTooFewPeers(): fartherPeerPos = self.distPeers.ll[len(self.distPeers) - 1].getPosition() maxDist = Geometry.distance(self.node.getPosition(), fartherPeerPos) # Areal density return maxDist * math.sqrt(self.expectedPeers / self.getNumberOfPeers()) else: fartherPeerPos = self.distPeers.ll[len(self.distPeers) - 1].getPosition() return Geometry.distance(self.node.getPosition(), fartherPeerPos)
def getWorstPeers(self): """ Return a list of peers with which we should disconnect. Removing these peers must NOT break the global connectivity rule. Return a list of peers or [] if we cannot remove a peer """ if not self.hasTooManyPeers(): return [] # filter list of neighbors # keep only entities not in Awareness Area which do not provoke mis-respect # of Global Connectivity Rule FilterList = [] endFilter = True indexFilter = len(self.distPeers) - 1 nodePos = self.node.getPosition() while endFilter and indexFilter > 0: ent = self.distPeers.ll[indexFilter] distEnt = Geometry.distance(ent.getPosition(), nodePos) # first, verify that ent is not in Awareness Area if distEnt > self.node.getAwarenessRadius() : # and that we are not in its AR if distEnt > ent.getAwarenessRadius(): indInCcw = self.ccwPeers.ll.index(ent) successor = self.ccwPeers.ll[(indInCcw + 1) % len(self.ccwPeers)] predecessor = self.ccwPeers.ll[indInCcw - 1] # then verify that ent is not mandatory for Rule respect if Geometry.inHalfPlane(predecessor.getPosition(), nodePos, successor.getPosition()): FilterList.append(ent) else: # stop iteration because all following entities are in Awareness # Radius endFilter = False indexFilter -= 1 return FilterList
def DETECT(self, event): """ Notification that a peer is moving towards us""" peer = event.createRemotePeer() id_ = peer.getId() manager = self.node.getPeersManager() # Sanity check 1: don't connect with ourselves if id_ == self.node.getId(): return # Sanity check 2: don't connect with someone too far from us dist = Geometry.distance(self.node.getPosition(), peer.getPosition()) ar = self.node.getAwarenessRadius() if dist > ar: return # we are only interested by entities that are not yet in our peer list if not manager.hasPeer(id_): # Check we don't have too many peers, or have worse peers than this one if manager.isPeerAccepted(peer): # Connect to this peer factory = EventFactory.getInstance(PeerEvent.TYPE) hello = factory.createHELLO() hello.setRecipientAddress(peer.getAddress()) self.node.dispatch(hello)
def UPDATE(self, event): """ A peer sent us an UPDATE message.""" # extract the peer from the event peer = event.createPeer() id_ = peer.getId() manager = self.node.getPeersManager() if not manager.hasPeer(id_): self.logger.debug('UPDATE from %s, but we are not connected' % peer.getId()) return # save peer old value oldPeer = manager.getPeer(event.getArg(protocol.ARG_ID)) # update peer manager.updatePeer(peer) # notify the controller that a peer has changed ctlFact = EventFactory.getInstance(ControlEvent.TYPE) upd = ctlFact.createUPDATE(peer) self.node.dispatch(upd) oldPosition = oldPeer.getPosition() newPosition = peer.getPosition() nodePosition = self.node.getPosition() oldAR = oldPeer.getAwarenessRadius() newAR = peer.getAwarenessRadius() peerFct = EventFactory.getInstance(PeerEvent.TYPE) # peer position changed if not oldPosition == newPosition: # verify entities that could be interested by the entity id for ent in manager.enumeratePeers(): if ent.getId() == id_: continue itsAR = ent.getAwarenessRadius() # get distance between self and ent ourDist = Geometry.distance(nodePosition, ent.getPosition()) # get distance between ent and entity id theirDist = Geometry.distance(ent.getPosition(), newPosition) # get old distance between ent and entity id theirOldDist = Geometry.distance(ent.getPosition(), oldPosition) if (theirDist < itsAR < theirOldDist) or \ (theirDist < ourDist < theirOldDist): # modified entity enters in Awareness Area of ent # OR moving entity is now closer than us to ent # The moving peer is notified to a fixed entity detect = peerFct.createDETECT(peer) detect.setRecipientAddress(ent.getAddress()) self.node.dispatch(detect) elif oldAR < theirOldDist and newAR >= theirDist: # The entity is notified to the moving peer detect = peerFct.createDETECT(ent) detect.setRecipientAddress(peer.getAddress()) self.node.dispatch(detect) # peer awareness radius changed if not oldAR == newAR: self.logger.debug('AR updated %d -> %d' % (oldAR, newAR)) # verify entities that could be interested by the modified entity. for ent in manager.enumeratePeers(): if ent.getId() == id_: continue # get distance between ent and modified entity position = ent.getPosition() theirDist = Geometry.distance(position, newPosition) theirOldDist = Geometry.distance(position, oldPosition) self.logger.debug('peer %s: position (%s), old dist %d, new dist %d' % (ent.getId(), str(position), theirDist, theirOldDist)) if oldAR < theirOldDist and newAR >= theirDist: # ent enter in Awareness Area of modified entity. # DETECT message sent to modified entity. detect = peerFct.createDETECT(ent) detect.setRecipientAddress(peer.getAddress()) self.node.dispatch(detect)