OLD | NEW |
| (Empty) |
1 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
2 # See LICENSE for details. | |
3 | |
4 | |
5 """ | |
6 Persistently cached objects for PB. | |
7 | |
8 Maintainer: U{Glyph Lefkowitz<mailto:glyph@twistedmatrix.com>} | |
9 | |
10 Future Plans: None known. | |
11 """ | |
12 | |
13 # Twisted imports | |
14 from twisted.internet import defer | |
15 | |
16 # sibling imports | |
17 import jelly | |
18 import banana | |
19 import flavors | |
20 | |
21 # System Imports | |
22 import time | |
23 | |
24 class Publishable(flavors.Cacheable): | |
25 """An object whose cached state persists across sessions. | |
26 """ | |
27 def __init__(self, publishedID): | |
28 self.republish() | |
29 self.publishedID = publishedID | |
30 | |
31 def republish(self): | |
32 """Set the timestamp to current and (TODO) update all observers. | |
33 """ | |
34 self.timestamp = time.time() | |
35 | |
36 def view_getStateToPublish(self, perspective): | |
37 '(internal)' | |
38 return self.getStateToPublishFor(perspective) | |
39 | |
40 def getStateToPublishFor(self, perspective): | |
41 """Implement me to special-case your state for a perspective. | |
42 """ | |
43 return self.getStateToPublish() | |
44 | |
45 def getStateToPublish(self): | |
46 """Implement me to return state to copy as part of the publish phase. | |
47 """ | |
48 raise NotImplementedError("%s.getStateToPublishFor" % self.__class__) | |
49 | |
50 def getStateToCacheAndObserveFor(self, perspective, observer): | |
51 """Get all necessary metadata to keep a clientside cache. | |
52 """ | |
53 if perspective: | |
54 pname = perspective.perspectiveName | |
55 sname = perspective.getService().serviceName | |
56 else: | |
57 pname = "None" | |
58 sname = "None" | |
59 | |
60 return {"remote": flavors.ViewPoint(perspective, self), | |
61 "publishedID": self.publishedID, | |
62 "perspective": pname, | |
63 "service": sname, | |
64 "timestamp": self.timestamp} | |
65 | |
66 class RemotePublished(flavors.RemoteCache): | |
67 """The local representation of remote Publishable object. | |
68 """ | |
69 isActivated = 0 | |
70 _wasCleanWhenLoaded = 0 | |
71 def getFileName(self, ext='pub'): | |
72 return ("%s-%s-%s.%s" % | |
73 (self.service, self.perspective, str(self.publishedID), ext)) | |
74 | |
75 def setCopyableState(self, state): | |
76 self.__dict__.update(state) | |
77 self._activationListeners = [] | |
78 try: | |
79 data = open(self.getFileName()).read() | |
80 except IOError: | |
81 recent = 0 | |
82 else: | |
83 newself = jelly.unjelly(banana.decode(data)) | |
84 recent = (newself.timestamp == self.timestamp) | |
85 if recent: | |
86 self._cbGotUpdate(newself.__dict__) | |
87 self._wasCleanWhenLoaded = 1 | |
88 else: | |
89 self.remote.callRemote('getStateToPublish').addCallbacks(self._cbGot
Update) | |
90 | |
91 def __getstate__(self): | |
92 other = self.__dict__.copy() | |
93 # Remove PB-specific attributes | |
94 del other['broker'] | |
95 del other['remote'] | |
96 del other['luid'] | |
97 # remove my own runtime-tracking stuff | |
98 del other['_activationListeners'] | |
99 del other['isActivated'] | |
100 return other | |
101 | |
102 def _cbGotUpdate(self, newState): | |
103 self.__dict__.update(newState) | |
104 self.isActivated = 1 | |
105 # send out notifications | |
106 for listener in self._activationListeners: | |
107 listener(self) | |
108 self._activationListeners = [] | |
109 self.activated() | |
110 open(self.getFileName(), "wb").write(banana.encode(jelly.jelly(self))) | |
111 | |
112 def activated(self): | |
113 """Implement this method if you want to be notified when your | |
114 publishable subclass is activated. | |
115 """ | |
116 | |
117 def callWhenActivated(self, callback): | |
118 """Externally register for notification when this publishable has receiv
ed all relevant data. | |
119 """ | |
120 if self.isActivated: | |
121 callback(self) | |
122 else: | |
123 self._activationListeners.append(callback) | |
124 | |
125 def whenReady(d): | |
126 """ | |
127 Wrap a deferred returned from a pb method in another deferred that | |
128 expects a RemotePublished as a result. This will allow you to wait until | |
129 the result is really available. | |
130 | |
131 Idiomatic usage would look like:: | |
132 | |
133 publish.whenReady(serverObject.getMeAPublishable()).addCallback(lookAtTh
ePublishable) | |
134 """ | |
135 d2 = defer.Deferred() | |
136 d.addCallbacks(_pubReady, d2.errback, | |
137 callbackArgs=(d2,)) | |
138 return d2 | |
139 | |
140 def _pubReady(result, d2): | |
141 '(internal)' | |
142 result.callWhenActivated(d2.callback) | |
OLD | NEW |