| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- """ClientRepository module: contains the ClientRepository class"""
- from PandaModules import *
- from TaskManagerGlobal import *
- from MsgTypes import *
- import Task
- import DirectNotifyGlobal
- import ClientDistClass
- import CRCache
- # The repository must import all known types of Distributed Objects
- import DistributedObject
- import DistributedToon
- import DirectObject
- class ClientRepository(DirectObject.DirectObject):
- notify = DirectNotifyGlobal.directNotify.newCategory("ClientRepository")
- def __init__(self, dcFileName, AIClientFlag=0):
- self.AIClientFlag=AIClientFlag
- self.number2cdc={}
- self.name2cdc={}
- self.doId2do={}
- self.doId2cdc={}
- self.parseDcFile(dcFileName)
- self.cache=CRCache.CRCache()
- return None
- def parseDcFile(self, dcFileName):
- self.dcFile = DCFile()
- self.dcFile.read(dcFileName)
- return self.parseDcClasses(self.dcFile)
- def parseDcClasses(self, dcFile):
- numClasses = dcFile.getNumClasses()
- for i in range(0, numClasses):
- # Create a clientDistClass from the dcClass
- dcClass = dcFile.getClass(i)
- clientDistClass = ClientDistClass.ClientDistClass(dcClass)
- # List the cdc in the number and name dictionaries
- self.number2cdc[dcClass.getNumber()]=clientDistClass
- self.name2cdc[dcClass.getName()]=clientDistClass
- return None
- def connect(self, serverName, serverPort):
- self.qcm=QueuedConnectionManager()
- self.tcpConn = self.qcm.openTCPClientConnection(
- serverName, serverPort, 1000)
- self.qcr=QueuedConnectionReader(self.qcm, 0)
- self.qcr.addConnection(self.tcpConn)
- self.cw=ConnectionWriter(self.qcm, 0)
- self.startReaderPollTask()
- def startReaderPollTask(self):
- task = Task.Task(self.readerPollUntilEmpty)
- taskMgr.spawnTaskNamed(task, "readerPollTask")
- return None
- def readerPollUntilEmpty(self, task):
- while self.readerPollOnce():
- pass
- return Task.cont
- def readerPollOnce(self):
- availGetVal = self.qcr.dataAvailable()
- if availGetVal:
- #print "Client: Incoming message!"
- datagram = NetDatagram()
- readRetVal = self.qcr.getData(datagram)
- if readRetVal:
- self.handleDatagram(datagram)
- else:
- ClientRepository.notify.warning("getData returned false")
- return availGetVal
- def handleDatagram(self, datagram):
- # This class is meant to be pure virtual, and any classes that
- # inherit from it need to make their own handleDatagram method
- pass
- def handleGenerateWithRequired(self, di):
- # Get the class Id
- classId = di.getArg(STUint16);
- # Get the DO Id
- doId = di.getArg(STUint32)
- # Look up the cdc
- cdc = self.number2cdc[classId]
- # Create a new distributed object, and put it in the dictionary
- distObj = self.generateWithRequiredFields(cdc,
- eval(cdc.name + \
- "." + \
- cdc.name),
- doId, di)
- return None
- def generateWithRequiredFields(self, cdc, constructor, doId, di):
- # Someday, this function will look in a cache of old distributed
- # objects to see if this object is in there, and pull it
- # out if necessary. For now, we'll just check to see if
- # it is in the standard dictionary, and ignore this update
- # if it is there. The right thing to do would be to update
- # all the required fields, but that will come later, too.
- # Is it in our dictionary?
- if self.doId2do.has_key(doId):
- # If so, just update it.
- distObj = self.doId2do[doId]
- distObj.updateRequiredFields(cdc, di)
- # Is it in the cache? If so, pull it out, put it in the dictionaries,
- # and update it.
- elif self.cache.contains(doId):
- # If so, pull it out of the cache...
- distObj = self.cache.retrieve(doId)
- # put it in both dictionaries...
- self.doId2do[doId] = distObj
- self.doId2cdc[doId] = cdc
- # and update it.
- distObj.updateRequiredFields(cdc, di)
- # If it is not in the dictionary or the cache, then...
- else:
- # Construct a new one
- distObj = constructor(self)
- # Assign it an Id
- distObj.doId = doId
- # Update the required fields
- distObj.updateRequiredFields(cdc, di)
- # Put the new do in both dictionaries
- self.doId2do[doId] = distObj
- self.doId2cdc[doId] = cdc
-
- return distObj
- def handleDisable(self, di):
- # Get the DO Id
- doId = di.getArg(STUint32)
- # Make sure the object exists
- if self.doId2do.has_key(doId):
- # Look up the object
- distObj = self.doId2do[doId]
- # remove the object from both dictionaries
- del(self.doId2do[doId])
- del(self.doId2cdc[doId])
- assert(len(self.doId2do) == len(self.doId2cdc))
- # cache the object
- self.cache.cache(distObj)
- else:
- ClientRepository.notify.warning("Disable failed. DistObj " +
- str(doId) +
- " is not in dictionary")
- return None
- def handleDelete(self, di):
- # Get the DO Id
- doId = di.getArg(STUint32)
- # If it is in the dictionaries, remove it.
- if self.doId2do.has_key(doId):
- del(self.doId2do[doId])
- del(self.doId2cdc[doId])
- assert(len(self.doId2do) == len(self.doId2cdc))
- # If it is in the cache, remove it.
- elif self.cache.contains(doId):
- self.cache.delete(doId)
- # Otherwise, ignore it
- else:
- ClientRepository.notify.warning(
- "Asked to delete non-existent DistObj " + str(doId))
- return None
- def handleUpdateField(self, di):
- # Get the DO Id
- doId = di.getArg(STUint32)
- #print("Updating " + str(doId))
- # Find the DO
- assert(self.doId2do.has_key(doId))
- do = self.doId2do[doId]
- # Find the cdc
- assert(self.doId2cdc.has_key(doId))
- cdc = self.doId2cdc[doId]
- # Let the cdc finish the job
- cdc.updateField(do, di)
-
- def sendUpdate(self, do, fieldName, args):
- # Get the DO id
- doId = do.doId
- # Get the cdc
- assert(self.doId2cdc.has_key(doId))
- cdc = self.doId2cdc[doId]
- # Let the cdc finish the job
- cdc.sendUpdate(self, do, fieldName, args)
- def send(self, datagram):
- self.cw.send(datagram, self.tcpConn)
- return None
|