root/trunk/twisted/spread/publish.py

Revision 30752, 4.4 KB (checked in by exarkun, 15 months ago)

Rewrite the copyright headers to exclude date information.

Author: exarkun
Reviewer: glyph
Fixes: #4857

To avoid the need to perpetually update copyright dates in each file in Twisted,
remove the dates from most files and just leave them in the LICENSE file.

As a side effect, some files also have had a trailing newline added where it was
missing before.

Line 
1# -*- test-case-name: twisted.test.test_pb -*-
2# Copyright (c) Twisted Matrix Laboratories.
3# See LICENSE for details.
4
5"""
6Persistently cached objects for PB.
7
8Maintainer: Glyph Lefkowitz
9
10Future Plans: None known.
11"""
12
13import time
14
15from twisted.internet import defer
16from twisted.spread import banana, jelly, flavors
17
18
19class Publishable(flavors.Cacheable):
20    """An object whose cached state persists across sessions.
21    """
22    def __init__(self, publishedID):
23        self.republish()
24        self.publishedID = publishedID
25
26    def republish(self):
27        """Set the timestamp to current and (TODO) update all observers.
28        """
29        self.timestamp = time.time()
30
31    def view_getStateToPublish(self, perspective):
32        '(internal)'
33        return self.getStateToPublishFor(perspective)
34   
35    def getStateToPublishFor(self, perspective):
36        """Implement me to special-case your state for a perspective.
37        """
38        return self.getStateToPublish()
39
40    def getStateToPublish(self):
41        """Implement me to return state to copy as part of the publish phase.
42        """
43        raise NotImplementedError("%s.getStateToPublishFor" % self.__class__)
44
45    def getStateToCacheAndObserveFor(self, perspective, observer):
46        """Get all necessary metadata to keep a clientside cache.
47        """
48        if perspective:
49            pname = perspective.perspectiveName
50            sname = perspective.getService().serviceName
51        else:
52            pname = "None"
53            sname = "None"
54
55        return {"remote": flavors.ViewPoint(perspective, self),
56                "publishedID": self.publishedID,
57                "perspective": pname,
58                "service": sname,
59                "timestamp": self.timestamp}
60
61class RemotePublished(flavors.RemoteCache):
62    """The local representation of remote Publishable object.
63    """
64    isActivated = 0
65    _wasCleanWhenLoaded = 0
66    def getFileName(self, ext='pub'):
67        return ("%s-%s-%s.%s" %
68                (self.service, self.perspective, str(self.publishedID), ext))
69   
70    def setCopyableState(self, state):
71        self.__dict__.update(state)
72        self._activationListeners = []
73        try:
74            dataFile = file(self.getFileName(), "rb")
75            data = dataFile.read()
76            dataFile.close()
77        except IOError:
78            recent = 0
79        else:
80            newself = jelly.unjelly(banana.decode(data))
81            recent = (newself.timestamp == self.timestamp)
82        if recent:
83            self._cbGotUpdate(newself.__dict__)
84            self._wasCleanWhenLoaded = 1
85        else:
86            self.remote.callRemote('getStateToPublish').addCallbacks(self._cbGotUpdate)
87
88    def __getstate__(self):
89        other = self.__dict__.copy()
90        # Remove PB-specific attributes
91        del other['broker']
92        del other['remote']
93        del other['luid']
94        # remove my own runtime-tracking stuff
95        del other['_activationListeners']
96        del other['isActivated']
97        return other
98
99    def _cbGotUpdate(self, newState):
100        self.__dict__.update(newState)
101        self.isActivated = 1
102        # send out notifications
103        for listener in self._activationListeners:
104            listener(self)
105        self._activationListeners = []
106        self.activated()
107        dataFile = file(self.getFileName(), "wb")
108        dataFile.write(banana.encode(jelly.jelly(self)))
109        dataFile.close()
110
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 received all relevant data.
119        """
120        if self.isActivated:
121            callback(self)
122        else:
123            self._activationListeners.append(callback)
124
125def 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(lookAtThePublishable)
134    """
135    d2 = defer.Deferred()
136    d.addCallbacks(_pubReady, d2.errback,
137                   callbackArgs=(d2,))
138    return d2
139
140def _pubReady(result, d2):
141    '(internal)'
142    result.callWhenActivated(d2.callback)
Note: See TracBrowser for help on using the browser.