ClientRepository.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. """ClientRepository module: contains the ClientRepository class"""
  2. from PandaModules import *
  3. from TaskManagerGlobal import *
  4. from MsgTypes import *
  5. import Task
  6. import DirectNotifyGlobal
  7. import ClientDistClass
  8. import CRCache
  9. # The repository must import all known types of Distributed Objects
  10. import DistributedObject
  11. import DistributedToon
  12. import DirectObject
  13. class ClientRepository(DirectObject.DirectObject):
  14. notify = DirectNotifyGlobal.directNotify.newCategory("ClientRepository")
  15. def __init__(self, dcFileName, AIClientFlag=0):
  16. self.AIClientFlag=AIClientFlag
  17. self.number2cdc={}
  18. self.name2cdc={}
  19. self.doId2do={}
  20. self.doId2cdc={}
  21. self.parseDcFile(dcFileName)
  22. self.cache=CRCache.CRCache()
  23. return None
  24. def parseDcFile(self, dcFileName):
  25. self.dcFile = DCFile()
  26. self.dcFile.read(dcFileName)
  27. return self.parseDcClasses(self.dcFile)
  28. def parseDcClasses(self, dcFile):
  29. numClasses = dcFile.getNumClasses()
  30. for i in range(0, numClasses):
  31. # Create a clientDistClass from the dcClass
  32. dcClass = dcFile.getClass(i)
  33. clientDistClass = ClientDistClass.ClientDistClass(dcClass)
  34. # List the cdc in the number and name dictionaries
  35. self.number2cdc[dcClass.getNumber()]=clientDistClass
  36. self.name2cdc[dcClass.getName()]=clientDistClass
  37. return None
  38. def connect(self, serverName, serverPort):
  39. self.qcm=QueuedConnectionManager()
  40. self.tcpConn = self.qcm.openTCPClientConnection(
  41. serverName, serverPort, 1000)
  42. self.qcr=QueuedConnectionReader(self.qcm, 0)
  43. self.qcr.addConnection(self.tcpConn)
  44. self.cw=ConnectionWriter(self.qcm, 0)
  45. self.startReaderPollTask()
  46. def startReaderPollTask(self):
  47. task = Task.Task(self.readerPollUntilEmpty)
  48. taskMgr.spawnTaskNamed(task, "readerPollTask")
  49. return None
  50. def readerPollUntilEmpty(self, task):
  51. while self.readerPollOnce():
  52. pass
  53. return Task.cont
  54. def readerPollOnce(self):
  55. availGetVal = self.qcr.dataAvailable()
  56. if availGetVal:
  57. #print "Client: Incoming message!"
  58. datagram = NetDatagram()
  59. readRetVal = self.qcr.getData(datagram)
  60. if readRetVal:
  61. self.handleDatagram(datagram)
  62. else:
  63. ClientRepository.notify.warning("getData returned false")
  64. return availGetVal
  65. def handleDatagram(self, datagram):
  66. # This class is meant to be pure virtual, and any classes that
  67. # inherit from it need to make their own handleDatagram method
  68. pass
  69. def handleGenerateWithRequired(self, di):
  70. # Get the class Id
  71. classId = di.getArg(STUint16);
  72. # Get the DO Id
  73. doId = di.getArg(STUint32)
  74. # Look up the cdc
  75. cdc = self.number2cdc[classId]
  76. # Create a new distributed object, and put it in the dictionary
  77. distObj = self.generateWithRequiredFields(cdc,
  78. eval(cdc.name + \
  79. "." + \
  80. cdc.name),
  81. doId, di)
  82. return None
  83. def generateWithRequiredFields(self, cdc, constructor, doId, di):
  84. # Someday, this function will look in a cache of old distributed
  85. # objects to see if this object is in there, and pull it
  86. # out if necessary. For now, we'll just check to see if
  87. # it is in the standard dictionary, and ignore this update
  88. # if it is there. The right thing to do would be to update
  89. # all the required fields, but that will come later, too.
  90. # Is it in our dictionary?
  91. if self.doId2do.has_key(doId):
  92. # If so, just update it.
  93. distObj = self.doId2do[doId]
  94. distObj.updateRequiredFields(cdc, di)
  95. # Is it in the cache? If so, pull it out, put it in the dictionaries,
  96. # and update it.
  97. elif self.cache.contains(doId):
  98. # If so, pull it out of the cache...
  99. distObj = self.cache.retrieve(doId)
  100. # put it in both dictionaries...
  101. self.doId2do[doId] = distObj
  102. self.doId2cdc[doId] = cdc
  103. # and update it.
  104. distObj.updateRequiredFields(cdc, di)
  105. # If it is not in the dictionary or the cache, then...
  106. else:
  107. # Construct a new one
  108. distObj = constructor(self)
  109. # Assign it an Id
  110. distObj.doId = doId
  111. # Update the required fields
  112. distObj.updateRequiredFields(cdc, di)
  113. # Put the new do in both dictionaries
  114. self.doId2do[doId] = distObj
  115. self.doId2cdc[doId] = cdc
  116. return distObj
  117. def handleDisable(self, di):
  118. # Get the DO Id
  119. doId = di.getArg(STUint32)
  120. # Make sure the object exists
  121. if self.doId2do.has_key(doId):
  122. # Look up the object
  123. distObj = self.doId2do[doId]
  124. # remove the object from both dictionaries
  125. del(self.doId2do[doId])
  126. del(self.doId2cdc[doId])
  127. assert(len(self.doId2do) == len(self.doId2cdc))
  128. # cache the object
  129. self.cache.cache(distObj)
  130. else:
  131. ClientRepository.notify.warning("Disable failed. DistObj " +
  132. str(doId) +
  133. " is not in dictionary")
  134. return None
  135. def handleDelete(self, di):
  136. # Get the DO Id
  137. doId = di.getArg(STUint32)
  138. # If it is in the dictionaries, remove it.
  139. if self.doId2do.has_key(doId):
  140. del(self.doId2do[doId])
  141. del(self.doId2cdc[doId])
  142. assert(len(self.doId2do) == len(self.doId2cdc))
  143. # If it is in the cache, remove it.
  144. elif self.cache.contains(doId):
  145. self.cache.delete(doId)
  146. # Otherwise, ignore it
  147. else:
  148. ClientRepository.notify.warning(
  149. "Asked to delete non-existent DistObj " + str(doId))
  150. return None
  151. def handleUpdateField(self, di):
  152. # Get the DO Id
  153. doId = di.getArg(STUint32)
  154. #print("Updating " + str(doId))
  155. # Find the DO
  156. assert(self.doId2do.has_key(doId))
  157. do = self.doId2do[doId]
  158. # Find the cdc
  159. assert(self.doId2cdc.has_key(doId))
  160. cdc = self.doId2cdc[doId]
  161. # Let the cdc finish the job
  162. cdc.updateField(do, di)
  163. def sendUpdate(self, do, fieldName, args):
  164. # Get the DO id
  165. doId = do.doId
  166. # Get the cdc
  167. assert(self.doId2cdc.has_key(doId))
  168. cdc = self.doId2cdc[doId]
  169. # Let the cdc finish the job
  170. cdc.sendUpdate(self, do, fieldName, args)
  171. def send(self, datagram):
  172. self.cw.send(datagram, self.tcpConn)
  173. return None