Ejemplo n.º 1
0
	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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
	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))
Ejemplo n.º 4
0
	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)
Ejemplo n.º 5
0
	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
Ejemplo n.º 6
0
	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
Ejemplo n.º 7
0
	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)
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
	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)
Ejemplo n.º 10
0
	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)
Ejemplo n.º 11
0
	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
Ejemplo n.º 12
0
	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
Ejemplo n.º 13
0
	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
Ejemplo n.º 14
0
	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)
Ejemplo n.º 15
0
	def __init__(self, ownerId, databaseId, nodeId, link):
		self.link = link
		self.poller = ConnectionPoller(link)
		self.addr = StrAddress(ownerId, nodeId, databaseId=databaseId)
		self.databaseId = databaseId
Ejemplo n.º 16
0
	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))
Ejemplo n.º 17
0
	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))
Ejemplo n.º 18
0
	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)
Ejemplo n.º 19
0
	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))
Ejemplo n.º 20
0
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)
Ejemplo n.º 21
0
	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)
Ejemplo n.º 22
0
	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))
Ejemplo n.º 23
0
	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))