105 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			Python
		
	
	
# -*- coding: utf-8 -*-
 | 
						|
# Copyright 2014, 2015 OpenMarket Ltd
 | 
						|
#
 | 
						|
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
# you may not use this file except in compliance with the License.
 | 
						|
# You may obtain a copy of the License at
 | 
						|
#
 | 
						|
#     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
# Unless required by applicable law or agreed to in writing, software
 | 
						|
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
# See the License for the specific language governing permissions and
 | 
						|
# limitations under the License.
 | 
						|
 | 
						|
 | 
						|
from twisted.internet import defer, reactor
 | 
						|
 | 
						|
from .logcontext import preserve_context_over_deferred
 | 
						|
 | 
						|
 | 
						|
def sleep(seconds):
 | 
						|
    d = defer.Deferred()
 | 
						|
    reactor.callLater(seconds, d.callback, seconds)
 | 
						|
    return preserve_context_over_deferred(d)
 | 
						|
 | 
						|
 | 
						|
def run_on_reactor():
 | 
						|
    """ This will cause the rest of the function to be invoked upon the next
 | 
						|
    iteration of the main loop
 | 
						|
    """
 | 
						|
    return sleep(0)
 | 
						|
 | 
						|
 | 
						|
class ObservableDeferred(object):
 | 
						|
    """Wraps a deferred object so that we can add observer deferreds. These
 | 
						|
    observer deferreds do not affect the callback chain of the original
 | 
						|
    deferred.
 | 
						|
 | 
						|
    If consumeErrors is true errors will be captured from the origin deferred.
 | 
						|
 | 
						|
    Cancelling or otherwise resolving an observer will not affect the original
 | 
						|
    ObservableDeferred.
 | 
						|
    """
 | 
						|
 | 
						|
    __slots__ = ["_deferred", "_observers", "_result"]
 | 
						|
 | 
						|
    def __init__(self, deferred, consumeErrors=False):
 | 
						|
        object.__setattr__(self, "_deferred", deferred)
 | 
						|
        object.__setattr__(self, "_result", None)
 | 
						|
        object.__setattr__(self, "_observers", set())
 | 
						|
 | 
						|
        def callback(r):
 | 
						|
            object.__setattr__(self, "_result", (True, r))
 | 
						|
            while self._observers:
 | 
						|
                try:
 | 
						|
                    self._observers.pop().callback(r)
 | 
						|
                except:
 | 
						|
                    pass
 | 
						|
            return r
 | 
						|
 | 
						|
        def errback(f):
 | 
						|
            object.__setattr__(self, "_result", (False, f))
 | 
						|
            while self._observers:
 | 
						|
                try:
 | 
						|
                    self._observers.pop().errback(f)
 | 
						|
                except:
 | 
						|
                    pass
 | 
						|
 | 
						|
            if consumeErrors:
 | 
						|
                return None
 | 
						|
            else:
 | 
						|
                return f
 | 
						|
 | 
						|
        deferred.addCallbacks(callback, errback)
 | 
						|
 | 
						|
    def observe(self):
 | 
						|
        if not self._result:
 | 
						|
            d = defer.Deferred()
 | 
						|
 | 
						|
            def remove(r):
 | 
						|
                self._observers.discard(d)
 | 
						|
                return r
 | 
						|
            d.addBoth(remove)
 | 
						|
 | 
						|
            self._observers.add(d)
 | 
						|
            return d
 | 
						|
        else:
 | 
						|
            success, res = self._result
 | 
						|
            return defer.succeed(res) if success else defer.fail(res)
 | 
						|
 | 
						|
    def observers(self):
 | 
						|
        return self._observers
 | 
						|
 | 
						|
    def __getattr__(self, name):
 | 
						|
        return getattr(self._deferred, name)
 | 
						|
 | 
						|
    def __setattr__(self, name, value):
 | 
						|
        setattr(self._deferred, name, value)
 | 
						|
 | 
						|
    def __repr__(self):
 | 
						|
        return "<ObservableDeferred object at %s, result=%r, _deferred=%r>" % (
 | 
						|
            id(self), self._result, self._deferred,
 | 
						|
        )
 |