1 from __future__ import division
5 from twisted.internet import defer, reactor
6 from twisted.python import failure, log
10 reactor.callLater(t, d.callback, None)
13 def retry(message, delay):
15 @retry('Error getting block:', 1)
16 @defer.inlineCallbacks
22 @defer.inlineCallbacks
23 def f(*args, **kwargs):
26 result = yield func(*args, **kwargs)
35 defer.returnValue(result)
39 class ReplyMatcher(object):
41 Converts request/got response interface to deferred interface
44 def __init__(self, func, timeout=5):
46 self.timeout = timeout
49 def __call__(self, id):
51 uniq = random.randrange(2**256)
54 df, timer = self.map[id].pop(uniq)
55 df.errback(failure.Failure(defer.TimeoutError()))
58 self.map.setdefault(id, {})[uniq] = (df, reactor.callLater(self.timeout, timeout))
61 def got_response(self, id, resp):
62 if id not in self.map:
64 for df, timer in self.map.pop(id).itervalues():
68 class GenericDeferrer(object):
70 Converts query with identifier/got response interface to deferred interface
73 def __init__(self, max_id, func, timeout=5):
76 self.timeout = timeout
79 def __call__(self, *args, **kwargs):
81 id = random.randrange(self.max_id)
82 if id not in self.map:
87 df.errback(failure.Failure(defer.TimeoutError()))
88 timer = reactor.callLater(self.timeout, timeout)
89 self.func(id, *args, **kwargs)
90 self.map[id] = df, timer
93 def got_response(self, id, resp):
94 if id not in self.map:
96 df, timer = self.map.pop(id)
100 class NotNowError(Exception):
103 class DeferredCacher(object):
105 like memoize, but for functions that return Deferreds
112 @DeferredCacher.with_backing(bsddb.hashopen(...))
119 def with_backing(cls, backing):
120 return lambda func: cls(func, backing)
122 def __init__(self, func, backing=None):
127 self.backing = backing
130 @defer.inlineCallbacks
131 def __call__(self, key):
132 if key in self.waiting:
133 yield self.waiting[key]
135 if key in self.backing:
136 defer.returnValue(self.backing[key])
138 self.waiting[key] = defer.Deferred()
140 value = yield self.func(key)
142 self.waiting.pop(key).callback(None)
144 self.backing[key] = value
145 defer.returnValue(value)
147 def call_now(self, key):
148 if key in self.waiting:
151 if key in self.backing:
152 return self.backing[key]
154 self.waiting[key] = defer.Deferred()
156 self.backing[key] = value
157 self.waiting.pop(key).callback(None)
159 self.waiting.pop(key).callback(None)
161 print 'Error when requesting noncached value:'
162 fail.printTraceback()
164 self.func(key).addCallback(cb).addErrback(eb)