3
from twisted.python import defer
14
class Publishable(flavors.Cacheable):
15
"""An object whose cached state persists across sessions.
17
def __init__(self, publishedID):
19
self.publishedID = publishedID
22
"""Set the timestamp to current and (TODO) update all observers.
24
self.timestamp = time.time()
26
def view_getStateToPublish(self, perspective):
28
return self.getStateToPublishFor(perspective)
30
def getStateToPublishFor(self, perspective):
31
"""Implement me to special-case your state for a perspective.
33
return self.getStateToPublish()
35
def getStateToPublish(self):
36
"""Implement me to return state to copy as part of the publish phase.
38
raise NotImplementedError("%s.getStateToPublishFor" % self.__class__)
40
def getStateToCacheAndObserveFor(self, perspective, observer):
41
"""Get all necessary metadata to keep a clientside cache.
44
pname = perspective.perspectiveName
45
sname = perspective.getService().serviceName
50
return {"remote": flavors.ViewPoint(perspective, self),
51
"publishedID": self.publishedID,
54
"timestamp": self.timestamp}
56
class RemotePublished(flavors.RemoteCache):
57
"""The local representation of remote Publishable object.
60
_wasCleanWhenLoaded = 0
61
def getFileName(self, ext='pub'):
62
return ("%s-%s-%s.%s" %
63
(self.service, self.perspective, str(self.publishedID), ext))
65
def setCopyableState(self, state):
66
self.__dict__.update(state)
67
self._activationListeners = []
69
data = open(self.getFileName()).read()
71
print "** Didn't find the file."
74
newself = jelly.unjelly(banana.decode(data))
75
print '** Found the file.'
76
recent = (newself.timestamp == self.timestamp)
77
print '** ', newself.timestamp, self.timestamp, recent
79
self._cbGotUpdate(newself.__dict__)
80
self._wasCleanWhenLoaded = 1
82
self.remote.callRemote('getStateToPublish').addCallbacks(self._cbGotUpdate)
84
def __getstate__(self):
85
other = copy.copy(self.__dict__)
86
# Remove PB-specific attributes
89
# remove my own runtime-tracking stuff
90
del other['_activationListeners']
91
del other['isActivated']
94
def _cbGotUpdate(self, newState):
95
self.__dict__.update(newState)
97
# send out notifications
98
for listener in self._activationListeners:
100
self._activationListeners = []
102
open(self.getFileName(), "wb").write(banana.encode(jelly.jelly(self)))
105
"""Implement this method if you want to be notified when your
106
publishable subclass is activated.
109
def callWhenActivated(self, callback):
110
"""Externally register for notification when this publishable has received all relevant data.
115
self._activationListeners.append(callback)
119
Wrap a deferred returned from a pb method in another deferred that
120
expects a RemotePublished as a result. This will allow you to wait until
121
the result is really available.
123
Idiomatic usage would look like:
125
publish.whenReady(serverObject.getMeAPublishable()).addCallback(lookAtThePublishable)
127
d2 = defer.Deferred()
128
d.addCallbacks(_pubReady, d2.armAndErrback,
132
def _pubReady(result, d2):
134
result.callWhenActivated(d2.armAndCallback)