def login(self, ownerName, databaseId): ownerId = self.idb.getOwnerId(ownerName) self.addr = StrAddress(ownerId, databaseId=databaseId) src = self.addr dst = StrAddress.EMPTY self.link.write("meta.login.req " + str(src) + " " + str(dst) + " " + ownerName) return self.addr.ownerId
def match(wanted, gotMsg, gotSrc, gotDst): #trace("match:" + str(wanted) + " " + str(gotMsg) + " " + str(gotSrc) + " " + str(gotDst)) # Check message filter wmsg = wanted.msg if wmsg != None and wmsg == "*": wmsg = None if wmsg != None and gotMsg != wmsg: #trace("message did not match") return False # Check src filter wsrc = wanted.src if wsrc != None and not StrAddress.match(wsrc, gotSrc): # TODO check order #trace("src address did not match") return False # Check dst filter wdst = wanted.dst if wdst != None and not StrAddress.match(wdst, gotDst): # TODO check order #trace("dst address did not match") return False #trace("MATCH") return True
def unbind(self, ownerId, databaseId, nodeId, pointId): #trace("Meta.unbind") #TODO does this update some persistent record of local follows? #i.e. to allow them to be restored on reboot? ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) self.link.write("meta.unbind.req " + str(src) + " " + str(dst))
def __init__(self, link, databaseId, dbPath=None): self.link = link self.poller = ConnectionPoller(link) self.databaseId = databaseId self.addr = StrAddress(databaseId=databaseId) self.idb = IdDatabase(dbPath) self.idb.open() anyAddr = StrAddress.EMPTY self.poller.registerListener(None, anyAddr, anyAddr, self.handleMeta)
def signup(self, ownerName, databaseId): """signs up a new owner to the space""" self.addr.ownerId = self.idb.createOwner(ownerName) src = StrAddress(self.addr.ownerId, databaseId=databaseId) dst = StrAddress.EMPTY self.link.write("meta.signup.req " + str(src) + " " + str(dst) + " " + ownerName) return self.addr.ownerId
def createPoint(self, pointType, pointName): #trace("Meta.createPoint:" + str(pointType) + " " + str(pointName)) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? pointId = self.idb.createPoint(self.addr.ownerId, self.addr.nodeId, pointType, pointName) src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.link.write( "meta.createpoint.req " + str(src) + " " + str(dst) + " " + str(pointType) + " " + str(pointName)) return pointId
def approvedBind(self, bindType, ownerId, databaseId, nodeId, pointId): #trace("Meta.approvedBind:" + str(ownerId) + " " + str(nodeId) + " " + str(pointId)) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, databaseId=self.databaseId) dst = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) # The other end of the binding makes the decision to allow/deny the bind. self.link.write("meta.bind.req " + str(src) + " " + str(dst) + " " + str(bindType)) #TODO inner class, should this be in VirtualSpace?? class Binding(): def __init__(self, meta, bindType, ownerId, nodeId, pointId): self.bindType = bindType self.ownerId = ownerId self.nodeId = nodeId self.pointId = pointId self.meta = meta def unbind(self): self.meta.unbind(self.ownerId, self.nodeId, self.pointId) return Binding(self, bindType, ownerId, nodeId, pointId)
def parse(line): """parse a line into msg, src, dest, data""" #trace("parse:" + line) # message (? ? ?) (? ? ?) data parts = line.split(" ", 1) # Get message msg = parts[0] if len(parts) == 1: # only a message, this is allowed return msg, None, None, None parts = parts[1] # Get src address try: lb = parts.index('(') rb = parts.index(')') except ValueError: trace("warning: No src address in line:" + str(line)) return None # No valid message found src = parts[lb:rb + 1] # Get dst address parts = parts[rb + 2:] try: lb = parts.index('(') rb = parts.index(')') except ValueError: trace("warning: No dst address in line:" + str(line)) return None # No valid message found dst = parts[lb:rb + 1] # Get optional data data = parts[rb + 2:] return msg, StrAddress.createFrom(src), StrAddress.createFrom(dst), data
def assumedBind(self, bindType, ownerId, databaseId, nodeId, pointId): #trace("Meta.assumedBind: (" + str(ownerId) + " " + str(nodeId) + " " + str(pointId) + ")") ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, databaseId=self.databaseId) dst = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) #trace("assumedBind: src=" + str(src) + " dst=" + str(dst)) self.link.write("meta.bind.ind " + str(src) + " " + str(dst) + " " + str(bindType)) # This is an assumed bind, so we write it directly to our database self.idb.bind(bindType, src.ownerId, src.databaseId, src.nodeId, src.pointId, dst.ownerId, dst.databaseId, dst.nodeId, dst.pointId) #TODO inner class, should this be in VirtualSpace?? class Binding(): def __init__(self, meta, bindType, ownerId, nodeId, pointId): self.bindType = bindType self.ownerId = ownerId self.nodeId = nodeId self.pointId = pointId self.meta = meta def unbind(self): self.meta.unbind(self.ownerId, self.nodeId, self.pointId) return Binding(self, bindType, ownerId, nodeId, pointId)
def waitBind(self, bindType, ownerId, databaseId, nodeId, pointId): #trace("waiting for bind to succeed") src = self.addr dst = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) if bindType=="ONE_TO_MANY": # addresses must be swapped for follow src, dst = dst, src while True: self.loop() # allow message processing b = self.idb.isBound(src, dst, bindType) if b: return # bound #trace("WAIT for bind bindType:" + str(bindType) + " src:" + str(src) + " dst:" + str(dst)) time.sleep(1)
def createPointRec(self, ownerId, nodeId, pointType, pointName, pointId, databaseId, isLocal=False): """Low level POINT record creation""" rec = { "type": 'POINT', "ownerId": ownerId, "databaseId":databaseId, "nodeId": nodeId, 'name': pointName, "pointType": pointType } if isLocal: if pointId != None: rec["id"] = pointId newPointId = self.db.write(rec, morekeys=["pointId"]) if isLocal: self.writeId(StrAddress(ownerId, nodeId, newPointId, databaseId=self.databaseId), "POINT", pointName) return newPointId
def createOwnerRec(self, ownerName, databaseId, ownerId=None, isLocal=False): """Create a record in db for an owner""" #This might be a locally created owner, or an address reference to an owner rec = { "type": "OWNER", "name": ownerName, "databaseId": databaseId } if isLocal: if ownerId != None: rec["id"] = ownerId newOwnerId = self.db.write(rec, morekeys=["ownerId"]) if isLocal: # Only locally created ownerId's get written to our id cache self.writeId(StrAddress(newOwnerId), "OWNER", ownerName) return newOwnerId
def createNodeRec(self, ownerId, nodeId, databaseId, nodeName, isLocal=False): """low-level create a brand new nodeId, fail if it already exists""" rec = { "type": "NODE", "ownerId": ownerId, "name": nodeName, "databaseId": databaseId } if isLocal: if nodeId != None: # forcing a nodeId rec["id"] = nodeId newNodeId = self.db.write(rec, morekeys=["nodeId"]) self.writeId(StrAddress(ownerId, newNodeId, databaseId=self.databaseId), "NODE", nodeName) else: # remote if nodeId == None: raise ValueError("Remote Node requires a nodeId") rec["nodeId"] = nodeId newNodeId = self.db.write(rec) return newNodeId
def remove(self, pointId): ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.link.write("meta.remove.req " + str(src) + " " + str(dst)) self.idb.deletePoint(self.addr.ownerId, self.addr.nodeId, pointId)
def __init__(self, ownerId, databaseId, nodeId, link): self.link = link self.poller = ConnectionPoller(link) self.addr = StrAddress(ownerId, nodeId, databaseId=databaseId) self.databaseId = databaseId
def hide(self, pointId): #TODO unadvertise ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.idb.changePointState(self.addr.ownerId, self.addr.nodeId, pointId, "HIDDEN") self.link.write("meta.hide.req " + str(src) + " " + str(dst))
def sendto(self, ownerId, databaseId, nodeId, pointId, data=None, fromPointId=None): #trace("Data.sendto: o=" + str(ownerId) + " d=" + str(databaseId) + " n=" + str(nodeId) + " p=" + str(pointId)) src = StrAddress(self.addr.ownerId, self.addr.nodeId, fromPointId, databaseId=self.databaseId) dest = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) self.link.write("data.payload " + str(src) + " " + str(dest) + " " + str(data))
def setNodeStateForId(self, ownerId, nodeId, state): #trace("Meta.setNodeState:" + str(ownerId) + " " + str(nodeId) + " " + str(state)) self.idb.changeNodeState(ownerId, nodeId, state) src = StrAddress(ownerId, nodeId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.link.write("meta.state.ind " + str(src) + " " + str(dst) + " " + state)
def send(self, data=None, fromPointId=None): #trace("Data.send: fromPointId=" + str(fromPointId)) src = StrAddress(self.addr.ownerId, self.addr.nodeId, fromPointId, databaseId=self.databaseId) dst = StrAddress() #trace("Data.send:" + str(src) + " " + str(dst)) self.link.write("data.payload " + str(src) + " " + str(dst) + " " + str(data))
class Meta(): @staticmethod def dbExists(dbPath): return IdDatabase.exists(dbPath) @staticmethod def getOwnerNames(dbPath): """Get a list of owner names in dbPath database""" idb = IdDatabase(dbPath) idb.open() ownerNames = idb.getOwnerNames() idb.close() return ownerNames @staticmethod def getExistingDatabaseId(dbPath): """Get the id of an existing database, by opening it and reading the DATABASE rec""" idb = IdDatabase(dbPath) idb.open() databaseId = idb.getDatabaseId() idb.close() return databaseId @staticmethod def createDatabase(dbPath, databaseId): if dbPath == None: raise ValueError("must provide a dbPath") if databaseId == None: raise ValueError("must provide a databaseId") IdDatabase.create(dbPath, databaseId) def __init__(self, link, databaseId, dbPath=None): self.link = link self.poller = ConnectionPoller(link) self.databaseId = databaseId self.addr = StrAddress(databaseId=databaseId) self.idb = IdDatabase(dbPath) self.idb.open() anyAddr = StrAddress.EMPTY self.poller.registerListener(None, anyAddr, anyAddr, self.handleMeta) # DATABASE SYNC ---------------------------------------------------- # Must watch all meta messages on the link # to keep the distributed id database up to date def whoisOwner(self, ownerName): #trace("whoisOwner:" + str(ownerName)) src = StrAddress(self.addr.ownerId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.link.write("meta.whois.req " + str(src) + " " + str(dst) + " " + str(ownerName)) def whoisNode(self, ownerId, nodeName): #trace("whoisNode:" + str(ownerId) + " " + str(nodeName)) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, databaseId=self.databaseId) dst = StrAddress(ownerId) self.link.write("meta.whois.req " + str(src) + " " + str(dst) + " " + str(nodeName)) def iAmNode(self, ownerId, databaseId, nodeId, nodeName, dst): #trace("iAmNode:" + str(ownerId) + " " + str(databaseId) + " " + str(nodeId) + " " + str(nodeName) + " => " + str(dst)) src = StrAddress(ownerId, nodeId, databaseId=databaseId) self.link.write("meta.whois.rsp " + str(src) + " " + str(dst) + " " + nodeName) def whoisPoint(self, ownerId, databaseId, nodeId, pointName): #trace("whoisPoint:" + str(ownerId) + " " + str(nodeId) + " " + str(pointName)) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, databaseId=self.databaseId) dst = StrAddress(ownerId, nodeId, databaseId=databaseId) self.link.write("meta.whois.req " + str(src) + " " + str(dst) + " " + str(pointName)) def iAmPoint(self, ownerId, databaseId, nodeId, pointId, pointName, dst): #trace("iAmPoint:" + str(ownerId) + " " + str(databaseId) + " " + str(nodeId) + " " + str(pointId) + " " + str(pointName) + " => " + str(dst)) src = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) self.link.write("meta.whois.rsp " + str(src) + " " + str(dst) + " " + pointName) def handleMeta(self, info, data): #trace("Meta.handleMeta:" + str(info) + " " + str(data)) msg = info.msg src = info.src dst = info.dst # if it's from our own node, ignore it, as we already know! #TODO: This filtering should be done in the DISPATCHER, NOT HERE # TODO: if the dst address is us, we should process it anyway. # all we should squash is our own broadcasts. # IGNORE MY OWNER BROADCASTS (unless directed at me) #TODO: why is login not from a node?? signup should be only one! if src.nodeId == None: # just an owner message if src.ownerId != None and str(src.ownerId) == str(self.addr.ownerId): # we ignore broadcasts from ourself if dst.ownerId != None and str(dst.ownerId) != str(self.addr.ownerId): # but allow any that are directed at ourself #trace("DROP owner message from myself and not to myself:" + str(info) + " " + str(data)) return # IGNORE MY NODE BROADCASTS (unless directed at me) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? if src.ownerId != None and str(src.ownerId) == str(self.addr.ownerId) \ and src.nodeId != None and str(src.nodeId) == str(self.addr.nodeId): # a node message from ourself ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? if src.nodeId != None and str(dst.nodeId) != str(self.addr.nodeId): # but allow any that are directed at ourself #trace("DROP node message from myself and not to myself:" + str(info) + " " + str(data)) return # ignore misdirected messages that are not meta. messages if not msg.startswith("meta."): #TODO add wildcarding earlier?? #trace("Ignoring non meta message:" + msg) return #trace("Meta.handleMeta:" + msg) if msg == "meta.signup.req": self.syncSignup(src, data) elif msg == "meta.create.req": self.syncCreate(src, data) elif msg == "meta.createpoint.req": #first word of data is type of point pointType, name = data.split(" ", 1) #trace("DB.pointType is" + pointType) #trace("name:" + name) self.syncCreatePoint(pointType, src, name) elif msg == "meta.advertise.req": self.syncAdvertise(src) elif msg == "meta.hide.req": #TODO unadvertise self.syncHide(src) elif msg == "meta.bind.req": self.syncBind(src, dst, data) elif msg == "meta.bind.cnf": self.syncBindConfirm(src, dst, data) elif msg == "meta.bind.ind": self.syncBindIndication(src, dst, data) elif msg == "meta.unbind.req": self.syncUnbind(src, dst) elif msg == "meta.follow.req": #TODO point specific self.syncFollow(src, dst) elif msg == "meta.unfollow.req": #TODO point specific self.syncUnfollow(src, dst) elif msg == "meta.attach.req": #TODO point specific self.syncAttach(src, dst) elif msg == "meta.release.req": #TODO point specific self.syncRelease(src, dst) elif msg == "meta.state.ind": self.syncState(src, data) elif msg == "meta.login.req": pass # nothing to do else: pass #trace("unhandled:" + str(info) + " " + str(data)) def syncSignup(self, addr, ownerName): #trace("syncSignup:" + str(addr) + " " + str(ownerName)) ownerId = addr.ownerId self.idb.rememberOwner(ownerName, ownerId=ownerId, databaseId=addr.databaseId) def syncCreate(self, addr, nodeName): #trace("syncCreate:" + str(addr) + " " + str(nodeName)) ownerId = addr.ownerId nodeId = addr.nodeId databaseId = addr.databaseId self.idb.rememberNode(ownerId, nodeName, nodeId=nodeId, databaseId=databaseId) def syncCreatePoint(self, pointType, addr, name): #trace("syncCreatePoint:[" + str(addr) + "] [" + str(name) + "]") #TODO see if our id_database knows this name already #TODO add (addr) name to id_database as a POINT of type P ownerId = addr.ownerId nodeId = addr.nodeId pointId = addr.pointId databaseId = addr.databaseId if self.idb.pointExists(ownerId, nodeId, pointType, name, databaseId): #trace("point already in database, ignoring:" + str(pointType) + " " + str(addr) + " " + name) return pointIdlocal = self.idb.rememberPoint(ownerId, nodeId, pointType, name, pointId, databaseId) return pointIdlocal def syncAdvertise(self, addr): #trace("syncAdvertise:" + str(addr)) self.idb.advertise(addr.ownerId, addr.nodeId, addr.pointId, databaseId=addr.databaseId) def syncHide(self, addr): #TODO: unadvertise self.idb.hide(addr.ownerId, addr.nodeId, addr.pointId) def syncBind(self, src, dst, data): #trace("syncBind:" + str(src) + " " + str(dst) + " " + str(data)) pass # TODO this logic should be in Point.handleMeta??? #syncronisation at the DB level should just keep the DB in step #but of course, the accept must be done by the Point() # perhaps a bind.cnf should be sent, that is picked up here # to keep the database up to date? def syncBindConfirm(self, src, dst, bindType): #trace("syncBindConfirm: src=" + str(src) + " dst=" + str(dst) + " bindType=" + str(bindType)) self.idb.bind(bindType, src.ownerId, src.databaseId, src.nodeId, src.pointId, dst.ownerId, dst.databaseId, dst.nodeId, dst.pointId) def syncBindIndication(self, src, dst, bindType): #trace("syncBindIndication: src=" + str(src) + " dst=" + str(dst) + " bindType=" + str(bindType)) self.idb.bind(bindType, src.ownerId, src.databaseId, src.nodeId, src.pointId, dst.ownerId, dst.databaseId, dst.nodeId, dst.pointId) def syncUnbind(self, src, dst): #trace("syncUnbind:" + str(src) + " " + str(dst)) self.idb.unbind(src.ownerId, src.nodeId, dst.ownerId, dst.nodeId, dst.pointId) #def syncFollow(self, src, dst): #TODO this is point specific # trace("deprecated syncFollow") # #trace("syncFollow:" + str(src) + " " + str(dst)) # self.idb.follow(src.ownerId, src.nodeId, # dst.ownerId, dst.nodeId, dst.pointId) #def syncUnfollow(self, src, dst): #TODO this is point specific # trace("deprecated syncUnfollow") # self.idb.unfollow(src.ownerId, src.nodeId, # dst.ownerId, dst.nodeId, dst.pointId) #def syncAttach(self, src, dst): #TODO this is point specific # trace("deprecated syncAttach") # #trace("Meta.syncAttach:" + str(src) + " " + str(dst)) # self.idb.attach(src.ownerId, src.nodeId, # dst.ownerId, dst.nodeId, dst.pointId) #def syncRelease(self, src, dst): #TODO this is point specific # trace("deprecated syncRelease") # self.idb.release(src.ownerId, src.nodeId, # dst.ownerId, dst.nodeId, dst.pointId) def syncState(self, src, state): if state == "AWAKE": self.idb.wakeup(src.ownerId, src.nodeId) elif state == "ASLEEP": self.idb.sleep(src.ownerId, src.nodeId) else: pass #warning("unhandled state change:" + state) # ACCOUNT MANAGEMENT ----------------------------------------------- def reset(self): """Reset the Meta database to empty, mainly for testing""" self.idb.clear() def signup(self, ownerName, databaseId): """signs up a new owner to the space""" self.addr.ownerId = self.idb.createOwner(ownerName) src = StrAddress(self.addr.ownerId, databaseId=databaseId) dst = StrAddress.EMPTY self.link.write("meta.signup.req " + str(src) + " " + str(dst) + " " + ownerName) return self.addr.ownerId def login(self, ownerName, databaseId): ownerId = self.idb.getOwnerId(ownerName) self.addr = StrAddress(ownerId, databaseId=databaseId) src = self.addr dst = StrAddress.EMPTY self.link.write("meta.login.req " + str(src) + " " + str(dst) + " " + ownerName) return self.addr.ownerId def getOwnerId(self, ownerName=None): """Get owner id for name, or None if not known""" #trace("getOwnerId:" + str(ownerName)) if ownerName == None: return self.addr.ownerId else: #trace("lookup") return self.idb.getOwnerId(ownerName) def getOwnerName(self, ownerId): return self.idb.getOwnerName(ownerId) def dissolve(self, ownerName): """removes an owner account, like a company shutting down""" ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? if self.addr.nodeId != None: raise ValueError("Can't dissolve, node still in use") ownerId = self.getOwnerId(ownerName) if ownerId != self.addr.ownerId: raise ValueError("Not owner, can't dissolve") self.addr.setNodeId(None) src = self.addr dst = StrAddress.EMPTY self.link.write("meta.dissolve.req " + str(src) + " " + str(dst)) self.idb.deleteOwner(self.addr.ownerId) self.addr = None # NODE MANAGEMENT -------------------------------------------------- def getNodeStateForName(self, ownerName, nodeName): # trace("Meta.getNodeState:" + str(ownerName) + " " + str(nodeName)) ownerId = self.idb.getOwnerId(ownerName) if ownerId == None: return None nodeAddr = self.idb.getNodeAddr(ownerId, nodeName) if nodeAddr == None: return None databaseId = nodeAddr[0] nodeId = nodeAddr[1] return self.getNodeStateForId(ownerId, nodeId, databaseId) def getNodeStateForId(self, ownerId, nodeId, databaseId): return self.idb.getNodeState(ownerId, nodeId, databaseId) def setNodeStateForId(self, ownerId, nodeId, state): #trace("Meta.setNodeState:" + str(ownerId) + " " + str(nodeId) + " " + str(state)) self.idb.changeNodeState(ownerId, nodeId, state) src = StrAddress(ownerId, nodeId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.link.write("meta.state.ind " + str(src) + " " + str(dst) + " " + state) def create(self, nodeName, nodeId=None): """joins a new node to the space, creating an node in that space""" if self.addr.ownerId == None: raise ValueError("no ownerId set") nodeId = self.idb.createNode(self.addr.ownerId, nodeId, self.databaseId, nodeName) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? self.addr.nodeId = nodeId src = self.addr dst = StrAddress.EMPTY #should this only happen if it really creates it??? self.link.write("meta.create.req " + str(src) + " " + str(dst) + " " + nodeName) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? return self.addr.nodeId def createNodeRef(self, ownerId, databaseId, nodeId, nodeName): """Create a reference in db to someone else's node""" if ownerId == None: raise ValueError("Must supply an ownerId") if databaseId == None: raise ValueError("Must supply a databaseId") if nodeId == None: raise ValueError("Must supply a nodeId") if nodeName == None: raise ValueError("Must supply a nodeName") self.idb.createRemoteNode(ownerId, databaseId, nodeId, nodeName) def createPointRef(self, ownerId, databaseId, nodeId, pointId, pointName): """Create a reference in db to someone else's node""" if ownerId == None: raise ValueError("Must supply an ownerId") if databaseId == None: raise ValueError("Must supply a databaseId") if nodeId == None: raise ValueError("Must supply a nodeId") if pointId == None: raise ValueError("Must supply a pointId") if pointName == None: raise ValueError("Must supply a pointName") self.idb.createRemotePoint(ownerId, databaseId, nodeId, pointId, pointName) def getNodeId(self, ownerId=None, nodeName=None): """Get the id of the node this Meta object represents""" #trace("meta.getNodeId: ownerId:" + str(ownerId) + " nodeName:" + str(nodeName)) if ownerId == None: # use our ownerId if self.addr.ownerId == None: raise ValueError("my ownerId unexpectedly None") ownerId = self.addr.ownerId if nodeName == None: # get our nodeId ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? if self.addr.nodeId == None: raise ValueError("My nodeId unexpectedly None") ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? return self.addr.nodeId else: #trace("looking up nodeId") return self.idb.getNodeId(ownerId, nodeName) def getNodeAddr(self, ownerId, nodeName): if ownerId == None: raise ValueError("Must provide an ownerId") if nodeName == None: raise ValueError("Must provide a nodeName") return self.idb.getNodeAddr(ownerId, nodeName) def getNodeName(self, ownerId, nodeId): return self.idb.getNodeName(ownerId, nodeId) def wakeup(self, ownerId, nodeId): """rejoins an existing node to the space, waking up the avatar""" #trace("meta.wakeup") self.addr.set(ownerId, nodeId) src = self.addr dst = StrAddress.EMPTY ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? self.idb.changeNodeState(self.addr.ownerId, self.addr.nodeId, "AWAKE") self.link.write("meta.wakeup.req " + str(src) + " " + str(dst)) def sleep(self): """temporary leave of a node, making the avatar sleep""" #TODO would be nice to check state to see if already asleep? src = self.addr dst = StrAddress.EMPTY ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? self.idb.changeNodeState(self.addr.ownerId, self.addr.nodeId, "ASLEEP") self.link.write("meta.sleep.req " + str(src) + " " + str(dst)) # This will prevent other services from working, intentionally ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? self.addr.nodeId = None def delete(self, nodeName): """permanent deletion of a node""" ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? if self.addr.nodeId != None: raise ValueError("Can't delete node, it's still in use") nodeId = self.idb.getNodeId(self.addr.ownerId, nodeName) src = self.addr dst = StrAddress.EMPTY self.link.write("meta.delete.req " + str(src) + " " + str(dst)) self.idb.deleteNode(self.addr.ownerId, nodeId) # POINT MANAGEMENT ------------------------------------------------- ####REORDER PARAMS def getPointId(self, ownerId, nodeId, pointName, databaseId): """Get the id of the point for an owner and node""" if ownerId == None: # use our ownerId ownerId = self.addr.ownerId if nodeId == None: # get our nodeId ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? nodeId = self.addr.nodeId return self.idb.getPointId(ownerId, nodeId, pointName, databaseId=databaseId) def getPointType(self, ownerId, nodeId, pointId, databaseId): return self.idb.getPointType(ownerId, nodeId, pointId, databaseId=databaseId) def createPoint(self, pointType, pointName): #trace("Meta.createPoint:" + str(pointType) + " " + str(pointName)) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? pointId = self.idb.createPoint(self.addr.ownerId, self.addr.nodeId, pointType, pointName) src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.link.write( "meta.createpoint.req " + str(src) + " " + str(dst) + " " + str(pointType) + " " + str(pointName)) return pointId def advertise(self, pointId): ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.idb.changePointState(self.addr.ownerId, self.addr.nodeId, pointId, "ADVERTISED") self.link.write("meta.advertise.req " + str(src) + " " + str(dst)) #TODO: we don't change our idb.advertise here - why is this??? #is this because we expect it to come back in via syncAdvertise?? def hide(self, pointId): #TODO unadvertise ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.idb.changePointState(self.addr.ownerId, self.addr.nodeId, pointId, "HIDDEN") self.link.write("meta.hide.req " + str(src) + " " + str(dst)) def remove(self, pointId): ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.link.write("meta.remove.req " + str(src) + " " + str(dst)) self.idb.deletePoint(self.addr.ownerId, self.addr.nodeId, pointId) #This is a general case of follow() and attach() def bind(self, bindType, ownerId, databaseId, nodeId, pointId): #return self.approvedBind(bindType, ownerId, databaseId, nodeId, pointId) return self.assumedBind(bindType, ownerId, databaseId, nodeId, pointId) def waitBind(self, bindType, ownerId, databaseId, nodeId, pointId): #trace("waiting for bind to succeed") src = self.addr dst = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) if bindType=="ONE_TO_MANY": # addresses must be swapped for follow src, dst = dst, src while True: self.loop() # allow message processing b = self.idb.isBound(src, dst, bindType) if b: return # bound #trace("WAIT for bind bindType:" + str(bindType) + " src:" + str(src) + " dst:" + str(dst)) time.sleep(1) def assumedBind(self, bindType, ownerId, databaseId, nodeId, pointId): #trace("Meta.assumedBind: (" + str(ownerId) + " " + str(nodeId) + " " + str(pointId) + ")") ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, databaseId=self.databaseId) dst = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) #trace("assumedBind: src=" + str(src) + " dst=" + str(dst)) self.link.write("meta.bind.ind " + str(src) + " " + str(dst) + " " + str(bindType)) # This is an assumed bind, so we write it directly to our database self.idb.bind(bindType, src.ownerId, src.databaseId, src.nodeId, src.pointId, dst.ownerId, dst.databaseId, dst.nodeId, dst.pointId) #TODO inner class, should this be in VirtualSpace?? class Binding(): def __init__(self, meta, bindType, ownerId, nodeId, pointId): self.bindType = bindType self.ownerId = ownerId self.nodeId = nodeId self.pointId = pointId self.meta = meta def unbind(self): self.meta.unbind(self.ownerId, self.nodeId, self.pointId) return Binding(self, bindType, ownerId, nodeId, pointId) #TODO: This is a general case of follow() and attach() def approvedBind(self, bindType, ownerId, databaseId, nodeId, pointId): #trace("Meta.approvedBind:" + str(ownerId) + " " + str(nodeId) + " " + str(pointId)) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, databaseId=self.databaseId) dst = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) # The other end of the binding makes the decision to allow/deny the bind. self.link.write("meta.bind.req " + str(src) + " " + str(dst) + " " + str(bindType)) #TODO inner class, should this be in VirtualSpace?? class Binding(): def __init__(self, meta, bindType, ownerId, nodeId, pointId): self.bindType = bindType self.ownerId = ownerId self.nodeId = nodeId self.pointId = pointId self.meta = meta def unbind(self): self.meta.unbind(self.ownerId, self.nodeId, self.pointId) return Binding(self, bindType, ownerId, nodeId, pointId) def isBound(self, src, dst, bindType): return self.idb.isBound(src, dst, bindType) def bindConfirm(self, src, dst, bindType): self.link.write("meta.bind.cnf " + str(src) + " " + str(dst) + " " + str(bindType)) def getBindingsFor(self, bindType, src=None, dst=None): return self.idb.getBindingsFor(bindType, src, dst) #TODO this is the general case of unfollow and release def unbind(self, ownerId, databaseId, nodeId, pointId): #trace("Meta.unbind") #TODO does this update some persistent record of local follows? #i.e. to allow them to be restored on reboot? ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, pointId, databaseId=self.databaseId) dst = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) self.link.write("meta.unbind.req " + str(src) + " " + str(dst)) def find(self, ownerName=None, nodeName=None, pointName=None, limit=1): """find point by name, returns tuples:[(ownerId, nodeId, pointId)]""" #trace("meta.find ownerName:" + str(ownerName) + " nodeName:" + str(nodeName) + " pointName:" + str(pointName)) #TODO need to consult global repository also eventually if ownerName == None: # find a list of owners #trace("FIND OWNERS LIST") ownerIds = self.idb.getOwnerIds(limit=None) return ownerIds elif nodeName == None: # find a list of nodes for an owner #trace("FIND NODE LIST FOR OWNER") ownerId = self.idb.getOwnerId(ownerName) nodeAddrs = self.idb.getNodeAddrs(ownerId, limit=None) return nodeAddrs elif pointName == None: # find a list of points for a node #trace("FIND POINT LIST FOR NODE AND OWNER") ownerId = self.idb.getOwnerId(ownerName) nodeAddr = self.idb.getNodeAddr(ownerId, nodeName) databaseId = nodeAddr[0] nodeId = nodeAddr[1] pointIds = self.idb.getPointIds(ownerId, nodeId, databaseId=databaseId, limit=None) return pointIds else: # find a specific point name #trace("FIND POINT BY NAME") #trace("finding a point: ownerName:" + str(ownerName) + " nodeName:" + str(nodeName) + " pointName:" + str(pointName)) ownerId = self.idb.getOwnerId(ownerName) if ownerId == None: raise ValueError("Unknown owner:" + str(ownerName)) nodeAddr = self.idb.getNodeAddr(ownerId, nodeName) if nodeAddr == None: raise ValueError("Unknown node:" + str(nodeName)) databaseId = nodeAddr[0] nodeId = nodeAddr[1] pointId = self.idb.getPointId(ownerId, nodeId, pointName, databaseId=databaseId) return pointId def search(self, forType): """search for all points matching requirement""" raise ValueError("not yet implemented") #results = [] #if (forType & PRODUCER) != 0: # # find all producers # for name in self.db: # node = self.db[name] # p = node["producers"] # if len(p) > 0: # results += p # #if (forType & CONSUMER) != 0: # # find all consumers # for name in self.db: # node = self.db[name] # c = node["consumers"] # if len(c) > 0: # results += c #TODO: block, waiting for right response #TODO: exception, or return #return results return None # TODO def getNodeInfo(self, nodeId, databaseId): """Get information about this node""" info = self.idb.getNodeRec(self.addr.ownerId, nodeId, databaseId=databaseId) return info def getPointRec(self, ownerId, nodeId, pointId, databaseId): #trace("getPointRec for:" + str(ownerId) + " " + str(nodeId) + " " + str(pointId)) rec = self.idb.getPointRec(ownerId, nodeId, pointId, databaseId=databaseId) if rec == None: raise ValueError("No such point:" + str(ownerId) + " " + str(databaseId) + " " + str(nodeId) + " " + str(pointId)) return rec def getPath(self, addr): """Turn the numbered 'addr' into a string path""" #trace("meta.getpath: (" + str(addr)) #This is a bit like turning an IP address into a DNS name r = "(" if addr.ownerId != None: ownerName = self.idb.getOwnerName(addr.ownerId) r += ownerName if addr.nodeId != None: nodeName = self.idb.getNodeName(addr.ownerId, addr.nodeId, databaseId=addr.databaseId) r += "/" + nodeName if addr.pointId != None: pointName = self.idb.getPointName(addr.ownerId, addr.nodeId, addr.pointId, databaseId=addr.databaseId) r += "/" + pointName r += ")" return r #getPointRecs def getPoints(self, ownerId, nodeId): """Get info records for all points for this nodeId""" #trace("Meta.getPoints") points = self.idb.getPointRecs(ownerId, nodeId, databaseId=self.addr.databaseId) return points #def getFollows(self, ownerId, nodeId, pointId): # #trace("Meta.getFollows") # follows = self.idb.getFollowRecs(ownerId, nodeId, pointId) # return follows #def getAttachments(self, ownerId, nodeId, pointId): # #trace("Meta.getAttachments") # attachments = self.idb.getAttachmentRecs(ownerId, nodeId, pointId) # return attachments def loop(self): """Perform any regular message processing and housekeeping""" #trace("Meta.loop") self.poller.loop() def registerListener(self, msg, src, dst, handler, duplicate=None): #trace("Meta.registerListener for:" + str(msg) + " " + str(src) + " " + str(dst) + " " + str(handler)) self.poller.registerListener(msg, src, dst, handler, duplicate) def unregisterListener(self, l): self.poller.unregisterListener(l) def getConfig(self, indent=0): return self.poller.dispatcher.getConfig(indent=indent)
def iAmPoint(self, ownerId, databaseId, nodeId, pointId, pointName, dst): #trace("iAmPoint:" + str(ownerId) + " " + str(databaseId) + " " + str(nodeId) + " " + str(pointId) + " " + str(pointName) + " => " + str(dst)) src = StrAddress(ownerId, nodeId, pointId, databaseId=databaseId) self.link.write("meta.whois.rsp " + str(src) + " " + str(dst) + " " + pointName)
def whoisPoint(self, ownerId, databaseId, nodeId, pointName): #trace("whoisPoint:" + str(ownerId) + " " + str(nodeId) + " " + str(pointName)) ####POSSIBLY DANGEROUS meta.addr.nodeId USAGE??? src = StrAddress(self.addr.ownerId, self.addr.nodeId, databaseId=self.databaseId) dst = StrAddress(ownerId, nodeId, databaseId=databaseId) self.link.write("meta.whois.req " + str(src) + " " + str(dst) + " " + str(pointName))
def whoisOwner(self, ownerName): #trace("whoisOwner:" + str(ownerName)) src = StrAddress(self.addr.ownerId, databaseId=self.databaseId) dst = StrAddress.EMPTY self.link.write("meta.whois.req " + str(src) + " " + str(dst) + " " + str(ownerName))