| Viewing file:  publish.py (4.35 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# -*- test-case-name: twisted.test.test_pb -*-# Copyright (c) Twisted Matrix Laboratories.
 # See LICENSE for details.
 
 """
 Persistently cached objects for PB.
 
 Maintainer: Glyph Lefkowitz
 
 Future Plans: None known.
 """
 
 import time
 
 from twisted.internet import defer
 from twisted.spread import banana, jelly, flavors
 
 
 class Publishable(flavors.Cacheable):
 """An object whose cached state persists across sessions.
 """
 def __init__(self, publishedID):
 self.republish()
 self.publishedID = publishedID
 
 def republish(self):
 """Set the timestamp to current and (TODO) update all observers.
 """
 self.timestamp = time.time()
 
 def view_getStateToPublish(self, perspective):
 '(internal)'
 return self.getStateToPublishFor(perspective)
 
 def getStateToPublishFor(self, perspective):
 """Implement me to special-case your state for a perspective.
 """
 return self.getStateToPublish()
 
 def getStateToPublish(self):
 """Implement me to return state to copy as part of the publish phase.
 """
 raise NotImplementedError("%s.getStateToPublishFor" % self.__class__)
 
 def getStateToCacheAndObserveFor(self, perspective, observer):
 """Get all necessary metadata to keep a clientside cache.
 """
 if perspective:
 pname = perspective.perspectiveName
 sname = perspective.getService().serviceName
 else:
 pname = "None"
 sname = "None"
 
 return {"remote": flavors.ViewPoint(perspective, self),
 "publishedID": self.publishedID,
 "perspective": pname,
 "service": sname,
 "timestamp": self.timestamp}
 
 class RemotePublished(flavors.RemoteCache):
 """The local representation of remote Publishable object.
 """
 isActivated = 0
 _wasCleanWhenLoaded = 0
 def getFileName(self, ext='pub'):
 return ("%s-%s-%s.%s" %
 (self.service, self.perspective, str(self.publishedID), ext))
 
 def setCopyableState(self, state):
 self.__dict__.update(state)
 self._activationListeners = []
 try:
 dataFile = file(self.getFileName(), "rb")
 data = dataFile.read()
 dataFile.close()
 except IOError:
 recent = 0
 else:
 newself = jelly.unjelly(banana.decode(data))
 recent = (newself.timestamp == self.timestamp)
 if recent:
 self._cbGotUpdate(newself.__dict__)
 self._wasCleanWhenLoaded = 1
 else:
 self.remote.callRemote('getStateToPublish').addCallbacks(self._cbGotUpdate)
 
 def __getstate__(self):
 other = self.__dict__.copy()
 # Remove PB-specific attributes
 del other['broker']
 del other['remote']
 del other['luid']
 # remove my own runtime-tracking stuff
 del other['_activationListeners']
 del other['isActivated']
 return other
 
 def _cbGotUpdate(self, newState):
 self.__dict__.update(newState)
 self.isActivated = 1
 # send out notifications
 for listener in self._activationListeners:
 listener(self)
 self._activationListeners = []
 self.activated()
 dataFile = file(self.getFileName(), "wb")
 dataFile.write(banana.encode(jelly.jelly(self)))
 dataFile.close()
 
 
 def activated(self):
 """Implement this method if you want to be notified when your
 publishable subclass is activated.
 """
 
 def callWhenActivated(self, callback):
 """Externally register for notification when this publishable has received all relevant data.
 """
 if self.isActivated:
 callback(self)
 else:
 self._activationListeners.append(callback)
 
 def whenReady(d):
 """
 Wrap a deferred returned from a pb method in another deferred that
 expects a RemotePublished as a result.  This will allow you to wait until
 the result is really available.
 
 Idiomatic usage would look like::
 
 publish.whenReady(serverObject.getMeAPublishable()).addCallback(lookAtThePublishable)
 """
 d2 = defer.Deferred()
 d.addCallbacks(_pubReady, d2.errback,
 callbackArgs=(d2,))
 return d2
 
 def _pubReady(result, d2):
 '(internal)'
 result.callWhenActivated(d2.callback)
 
 |