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 SEARCH(self, event): """ search an entity to restore the global connectivity of an other node reception of message: SEARCH, id, wise = 1 if counterclockwise""" id_ = event.getArg(protocol.ARG_ID) wise = event.getArg(protocol.ARG_CLOCKWISE) manager = self.node.getPeersManager() queryEnt = None try: # queryEnt is the querying entity queryEnt = manager.getPeer(id_) except UnknownIdError: self.logger.debug('Error, reception of SEARCH message with unknown ' + 'peer ID: ' + id_) return # update the status of querying entity manager.heartbeat(id_) around = manager.getPeerAround(queryEnt.getPosition(), id_, wise) # send message if an entity has been found. if around is not None: factory = EventFactory.getInstance(PeerEvent.TYPE) aroundEvt = factory.createFOUND(around) aroundEvt.setRecipientAddress(event.getSenderAddress()) self.node.dispatch(aroundEvt)
def CLOSE(self, event): """ Connection closed with one of our peers.""" id_ = event.getArg(protocol.ARG_ID) manager = self.node.getPeersManager() manager.removePeer(id_) # notify controler that we lost connection with a peer factory = EventFactory.getInstance(ControlEvent.TYPE) dead = factory.createDEAD(id_) self.node.dispatch(dead) # check what is our state if manager.hasTooFewPeers(): self.increaseAr() # we don't have enough peers but our Global Connectivity is OK if manager.hasGlobalConnectity(): self.node.setState(NotEnoughPeers()) # not enough peers + GC is NOK else: self.searchPeers() self.node.setState(NotEnoughPeersAndNoGlobalConnectivity()) # we still have enough peers else: # but we don't have our GC if not manager.hasGlobalConnectity(): self.searchPeers() self.node.setState(NotEnoughPeersAndNoGlobalConnectivity())
def sendUpdates(self): """ Send an UPDATE message to all our peers""" mng = self.node.getPeersManager() update = EventFactory.getInstance(PeerEvent.TYPE).createUPDATE() for p in mng.enumeratePeers(): update.setRecipientAddress(p.getAddress()) self.node.dispatch(update)
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 CONNECT(self, event): """ reception of a connect message """ # TODO :check that we sent a HELLO message to this peer peer = event.createPeer() mng = self.node.getPeersManager() if not mng.hasPeer(peer.getId()): mng.addPeer(peer) factory = EventFactory.getInstance(ControlEvent.TYPE) newPeerEvent = factory.createNEW(peer) self.node.dispatch(newPeerEvent) # Give the list of our services to the peer for s in self.node.enumerateServices(): factory = EventFactory.getInstance(PeerEvent.TYPE) srvEvt = factory.createADDSERVICE(s.getId()) srvEvt.setRecipientAddress(event.getSenderAddress()) self.node.dispatch(srvEvt)
def addPeer(self, peer): """ Add a peer and send the necessary notification messages. """ manager = self.node.getPeersManager() manager.addPeer(peer) factory = EventFactory.getInstance(ControlEvent.TYPE) newPeerEvent = factory.createNEW(peer) self.node.dispatch(newPeerEvent) if type(self) == Idle: if manager.hasTooManyPeers(): self.node.setState(TooManyPeers())
def removePeer(self, peer): """ Remove a peer and send the necessary notification messages. """ manager = self.node.getPeersManager() id_ = peer.getId() manager.removePeer(id_) # notify controler that we lost connection with a peer factory = EventFactory.getInstance(ControlEvent.TYPE) dead = factory.createDEAD(id_) self.node.dispatch(dead)
def sendFindNearest(self, peerAddress): """ Send a FINNEAREST event and return the timer object assocoiated with this request peerAddress : network address of the peer who will receive this request """ # create a findnearest event factory = EventFactory.getInstance(PeerEvent.TYPE) findnearest = factory.createFINDNEAREST() findnearest.setRecipientAddress(peerAddress) self.node.dispatch(findnearest)
def OnTimeOut(self): """ The timer expired, add a TIMER event to the event Queue. This method is called from a timer thread, queing a new event will ensure that the timer procedure will be executed from the main thread """ factory = EventFactory.getInstance(ControlEvent.TYPE) timerEvt = factory.createTIMER() # this event is directly added to the event queue (and not using the # node.dispatch() method) because we don't want this event to be processed # by the controller connector but by the node itself self.node.events.put(timerEvt)
def OnHeartbeat(self, node): """ Heartbeat function : send an heartbeat to all peers node : the node that is going to send heartbeat """ factory = EventFactory.getInstance(PeerEvent.TYPE) hb = factory.createHEARTBEAT() # send heartbeat to all our peers for p in node.getPeersManager().enumeratePeers(): hb.setRecipientAddress(p.getAddress()) node.dispatch(hb)
def FOUND(self, event): """ an entity detected in an empty sector reception of message: FOUND""" peer = event.createRemotePeer() manager = self.node.getPeersManager() id_ = peer.getId() factory = EventFactory.getInstance(PeerEvent.TYPE) # verify that new entity is neither self neither an already known entity. if id_ != self.node.getId() and not manager.hasPeer(id_): hello = factory.createHELLO() hello.setRecipientAddress(peer.getAddress()) self.node.dispatch(hello)
def TIMER(self, event): """ Timeout : check if we still have too many peers peers""" manager = self.node.getPeersManager() factory = EventFactory.getInstance(PeerEvent.TYPE) while manager.getNumberOfPeers() > manager.getExpectedPeers(): peer = manager.getWorstPeer() close = factory.createCLOSE() close.setRecipientAddress(peer.getAddress()) self.node.dispatch(close) self.removePeer(peer) self.updateAwarenessRadius() self.node.setState(Idle())
def DELSERVICE(self, event): """ A peer sent us a DELSERVICE message. The described service is longer available for this peer """ # get service ID srvId = event.getArg(protocol.ARG_SERVICE_ID) # update the corresponding peer id_ = event.getArg(protocol.ARG_ID) peer = self.node.getPeersManager().getPeer(id_) peer.delService(srvId) # notify the controller that this peer deleted a service factory = EventFactory.getInstance(ControlEvent.TYPE) delsrv = factory.createDELSERVICE(id_, srvId) self.node.dispatch(delsrv)
def TIMER(self, event): """ Timeout : check if we still have too many peers peers""" manager = self.node.getPeersManager() factory = EventFactory.getInstance(PeerEvent.TYPE) for p in manager.getWorstPeers(): close = factory.createCLOSE() close.setRecipientAddress(p.getAddress()) manager.removePeer(p.getId()) self.node.dispatch(close) self.node.setAwarenessRadius(manager.computeAwarenessRadius()) self.sendUpdate() self.setState(Idle())
def searchPeers(self): """ Our Global connectivity is NOT OK, we have to search for new peers""" manager = self.node.getPeersManager() factory = EventFactory.getInstance(PeerEvent.TYPE) # send msg SEARCH. searchEntities = manager.getBadGlobalConnectivityPeers() for pair in searchEntities: # send message to each entity searchClockWise = factory.createSEARCH(True) searchCounterclockWise = factory.createSEARCH(False) searchClockWise.setRecipientAddress(pair[0].getAddress()) searchCounterclockWise.setRecipientAddress(pair[1].getAddress()) self.node.dispatch(searchClockWise) self.node.dispatch(searchCounterclockWise)
def DETECT(self, event): """ Notification that a peer is moving towards us""" peer = event.createRemotePeer() manager = self.node.getPeersManager() # we are only interested by entities that are not yet in our peer list if not manager.hasPeer(peer.getId()): # with this new peer, we now have too many peers # and the newly added peer is in fact our worst neighbour # so we remove this peer, and we don't contact this peer if manager.isWorstPeer(peer): pass else: # Connect to this peer factory = EventFactory.getInstance(PeerEvent.TYPE) hello = factory.createHELLO() hello.setRecipientAddress(peer.getAddress()) self.node.dispatch(hello)
def jump(self): """ Jump to the node's current position. This involves the recursive teleportation algorithm. """ manager = self.node.getPeersManager() peer = manager.getRandomPeer() self.sendFindNearest(peer.getAddress()) # Disconnect from our current peers peerFct = EventFactory.getInstance(PeerEvent.TYPE) for peer in manager.enumeratePeers(): evt = peerFct.createCLOSE() evt.setRecipientAddress(peer.getAddress()) self.node.dispatch(evt) self.removePeer(peer) # Go to the tracking state self.node.setState(Locating())
def FINDNEAREST(self, event): """ A peer sent us a FINDNEAREST message """ targetPosition = event.getArg(protocol.ARG_POSITION) nearestPeer = self.node.getPeersManager().getClosestPeer(targetPosition) factory = EventFactory.getInstance(PeerEvent.TYPE) # check if I am not closer than nearestPeer if (nearestPeer.isCloser(self.node, targetPosition)): response = factory.createNEAREST(nearestPeer) # I'm closer : send a best message else: response = factory.createBEST() response.setRecipientAddress(event.getSenderAddress()) # send reply to remote peer self.node.dispatch(response)
def ADDSERVICE(self, event): """ A peer sent us a ADDSERVICE message """ # get service information srvId = event.getArg(protocol.ARG_SERVICE_ID) srvDesc =event.getArg(protocol.ARG_SERVICE_DESC) srvAddress = event.getArg(protocol.ARG_SERVICE_ADDRESS) # See solipsis.navigator.service srv = Service(srvId, srvDesc, srvAddress) # update the corresponding peer id_ = event.getArg(protocol.ARG_ID) peer = self.node.getPeersManager().getPeer(id_) peer.addService(srv) # notify the controller that this peer has a new service available factory = EventFactory.getInstance(ControlEvent.TYPE) addsrv = factory.createADDSERVICE(id_, srvId, srvDesc, srvAddress) self.node.dispatch(addsrv)
def CLOSE(self, event): """ A peer sent us a CLOSE message.""" # remove the corresponding peer id_ = event.getArg(protocol.ARG_ID) manager = self.node.getPeersManager() manager = removePeer(id_) # notify the controller that we lost connection with this peer factory = EventFactory.getInstance(ControlEvent.TYPE) dead = factory.createDEAD(id_) self.node.dispatch(dead) if manager.hasTooFewPeers(): if not manager.hasGlobalConnectivity(): self.node.setState(NotEnoughPeersAndNoGlobalConnectivity()) else: self.node.setState(NotEnoughPeers()) elif not manager.hasGlobalConnectivity(): self.node.setState(NoGlobalConnectivity())
def searchPeers(self): """ Our Global connectivity is NOT OK, we have to search for new peers""" manager = self.node.getPeersManager() factory = EventFactory.getInstance(PeerEvent.TYPE) if manager.getNumberOfPeers() == 0: self.logger.info("All peers lost, relaunching JUMP algorithm") self.jump() else: # send msg SEARCH pair = manager.getBadGlobalConnectivityPeers() if pair: # send message to each entity searchClockWise = factory.createSEARCH(True) searchCounterclockWise = factory.createSEARCH(False) searchClockWise.setRecipientAddress(pair[0].getAddress()) searchCounterclockWise.setRecipientAddress(pair[1].getAddress()) self.node.dispatch(searchClockWise) self.node.dispatch(searchCounterclockWise)
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 HELLO(self, event): """ A new peer is contacting us """ peer = event.createPeer() manager = self.node.getPeersManager() factory = EventFactory.getInstance(PeerEvent.TYPE) # We have now too many peers and this is the worst one if manager.isWorstPeer(peer): # refuse connection close = factory.createCLOSE() close.setRecipientAddress(peer.getAddress()) self.node.dispatch(close) else: # check if we have not already connected to this peer if not manager.hasPeer(peer.getId()): manager.addPeer(peer) connect = factory.createCONNECT() connect.setRecipientAddress(peer.getAddress()) self.node.dispatch(connect) else: self.logger.debug('HELLO from %s, but we are already connected', peer.getId())
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)
def get_events(self): response = self.client.get(url=event_host + '/v3/events', timeout=self.config['lp_wait_timeout']) if response.json()['events']: return [EventFactory.create(event_json) for event_json in response.json()['events']] else: return []
def GETNODEINFO(self, event): factory = EventFactory.getInstance(ControlEvent.TYPE) info = factory.createNODEINFO() self.node.dispatch(info)
def connectionError(self): factory = EventFactory.getInstance(ControlEvent.TYPE) error = factory.createERROR('Error: cannot connect to Solipsis') self.node.setState(NotConnected()) self.node.dispatch(error)