示例#1
0
    def append(self, param, req):
        tableName = param['tableName'].name
        val = param['val']
        if not tableName in self.tables:
            raise KeyError, 'Table Not Found!'

        args = {
            'tableName': tableName,
            'key': self.tables[tableName]['len'],
            'val': val
        }
        worker = self.workers[hash(self.tables[tableName]['len']) %
                              self.num_workers]

        #print 'MASTER -> {0} Append: {1} to key {2}'.format(worker, val, self.tables[tableName]['len'])
        self.client.fetch(formatQuery(worker, 'set', args))

        fu = Future()
        req.url = self.host
        fu.set_result(
            HTTPResponse(req,
                         200,
                         buffer=cStringIO.StringIO(
                             str(self.tables[tableName]['len']))))
        self.tables[tableName]['len'] += 1
        return fu
示例#2
0
 def wrapper(*args, **kwargs):
     future = TracebackFuture()
     try:
         result = func(*args, **kwargs)
     except (Return, StopIteration) as e:
         result = getattr(e, 'value', None)
     except Exception:
         future.set_exc_info(sys.exc_info())
         return future
     else:
         if isinstance(result, types.GeneratorType):
             # Inline the first iteration of Runner.run.  This lets us
             # avoid the cost of creating a Runner when the coroutine
             # never actually yields, which in turn allows us to
             # use "optional" coroutines in critical path code without
             # performance penalty for the synchronous case.
             try:
                 orig_stack_contexts = stack_context._state.contexts
                 yielded = next(result)
                 if stack_context._state.contexts is not orig_stack_contexts:
                     yielded = TracebackFuture()
                     yielded.set_exception(
                         stack_context.StackContextInconsistentError(
                             'stack_context inconsistency (probably caused '
                             'by yield within a "with StackContext" block)'))
             except (StopIteration, Return) as e:
                 future.set_result(getattr(e, 'value', None))
             except Exception:
                 future.set_exc_info(sys.exc_info())
             else:
                 # post runner into Cocaine ioloop
                 CocaineIO.instance().post(Runner, result, future, yielded)
             return future
     future.set_result(result)
     return future
class StubWebSocketClientConnection(object):
    """A stub version of tornado.websocket.WebSocketClientConnection for use in
    unit tests.

    Attributes:
        TIMEOUT: class constant, which should be overridden in subclasses, in
            order to vary the time from when the class is instantiated until the
            returned future is resolved.
        connect_future: the Future resolved when the client "connection" is
            made.
        written_messages: a list of messages passed to the write_message
            method to see they have been received.
    """
    TIMEOUT = datetime.timedelta(milliseconds=0)

    def __init__(self,
                 io_loop,
                 request,
                 on_message_callback=None,
                 compression_options=None):
        del request, on_message_callback, compression_options
        self.connect_future = TracebackFuture()
        self.written_messages = []

        io_loop.add_timeout(self.TIMEOUT, self._complete)

    def _complete(self):
        self.connect_future.set_result(self)

    def write_message(self, message):
        """Adds writen message to the written_messages buffer."""
        self.written_messages.append(message)
示例#4
0
    def create(self, param, req):
        tableName = param['tableName'].name
        initVal = param['initVal']
        if tableName in self.tables:
            raise KeyError, 'Table name already existed'

        #print 'MASTER CREATE:', initVal
        self.tables[tableName] = {
            'len': 0,
        }
        #Data Partition
        vals = {}
        for worker_id in xrange(self.num_workers):
            vals[worker_id] = {}
        for key in initVal:
            #Bookkeeping
            self.tables[tableName]['len'] += 1
            self.tables[tableName][key] = type(initVal[key])
            worker = hash(key) % self.num_workers
            vals[worker][key] = initVal[key]

        futures = []
        for worker_id in xrange(self.num_workers):
            args = {'tableName': tableName, 'initVal': vals[worker_id]}
            futures.append(
                self.client.fetch(
                    formatQuery(self.workers[worker_id], 'create', args)))

        fu = Future()
        req.url = self.host
        fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
        return fu
class StubWebSocketClientConnection(object):
    """A stub version of tornado.websocket.WebSocketClientConnection for use in
    unit tests.

    Attributes:
        TIMEOUT: class constant, which should be overridden in subclasses, in
            order to vary the time from when the class is instantiated until the
            returned future is resolved.
        connect_future: the Future resolved when the client "connection" is
            made.
        written_messages: a list of messages passed to the write_message
            method to see they have been received.
    """
    TIMEOUT = datetime.timedelta(milliseconds=0)

    def __init__(self, io_loop, request, on_message_callback=None,
                 compression_options=None):
        del request, on_message_callback, compression_options
        self.connect_future = TracebackFuture()
        self.written_messages = []

        io_loop.add_timeout(self.TIMEOUT, self._complete)

    def _complete(self):
        self.connect_future.set_result(self)

    def write_message(self, message):
        """Adds writen message to the written_messages buffer."""
        self.written_messages.append(message)
示例#6
0
  def create(self, param, req):
    tableName = param['tableName'].name
    initVal = param['initVal']
    if tableName in self.tables:
      raise KeyError, 'Table name already existed'

    #print 'MASTER CREATE:', initVal
    self.tables[tableName] = {'len': 0, }
    #Data Partition
    vals = {}
    for worker_id in xrange(self.num_workers):
      vals[worker_id] = {}
    for key in initVal:
      #Bookkeeping
      self.tables[tableName]['len'] += 1
      self.tables[tableName][key] = type(initVal[key])
      worker = hash(key) % self.num_workers
      vals[worker][key] = initVal[key]

    futures = []
    for worker_id in xrange(self.num_workers):
      args = {'tableName': tableName, 'initVal': vals[worker_id]}
      futures.append(self.client.fetch(formatQuery(self.workers[worker_id], 'create', args)))

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
    return fu
示例#7
0
    def wrapper(*args, **kwargs):
        runner = None
        future = TracebackFuture()

        if 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        def handle_exception(typ, value, tb):
            try:
                if runner is not None and runner.handle_exception(typ, value, tb):
                    return True
            except Exception:
                typ, value, tb = sys.exc_info()
            future.set_exc_info((typ, value, tb))
            return True
        with ExceptionStackContext(handle_exception):
            try:
                result = func(*args, **kwargs)
            except (Return, StopIteration) as e:
                result = getattr(e, 'value', None)
            except Exception:
                future.set_exc_info(sys.exc_info())
                return future
            else:
                if isinstance(result, types.GeneratorType):
                    def final_callback(value):
                        future.set_result(value)
                    runner = Runner(result, final_callback)
                    runner.run()
                    return future
            future.set_result(result)
        return future
示例#8
0
    def wrapper(*args, **kwargs):
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            # 调用的参数有callback,不实用future使用异步callback
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            # 调用实际的处理函数如果返回GeneratorType,那么进入Runner类循环执行直到终止
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = _value_from_stopiteration(e)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            # 生成器
            if isinstance(result, GeneratorType):
                # Inline the first iteration of Runner.run.  This lets us
                # avoid the cost of creating a Runner when the coroutine
                # never actually yields, which in turn allows us to
                # use "optional" coroutines in critical path code without
                # performance penalty for the synchronous case.
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    # 返回第一个Future,异步调用返回的Future,
                    # 在异步调用成功后会将这个Future给set_done
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)')
                        )
                except (StopIteration, Return) as e:
                    future.set_result(_value_from_stopiteration(e))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    Runner(result, future, yielded)
                try:
                    # 进入Runner,返回
                    return future
                finally:
                    # Subtle memory optimization: if next() raised an exception,
                    # the future's exc_info contains a traceback which
                    # includes this stack frame.  This creates a cycle,
                    # which will be collected at the next full GC but has
                    # been shown to greatly increase memory usage of
                    # benchmarks (relative to the refcount-based scheme
                    # used in the absence of cycles).  We can avoid the
                    # cycle by clearing the local variable after we return it.
                    future = None
        future.set_result(result)
        return future
示例#9
0
  def get(self, param, req):
    tableName = param['tableName']
    key = param['key']

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, 
                               buffer=cStringIO.StringIO(pickle.dumps(self.tables[tableName][key]))))
    return fu
示例#10
0
  def len(self, param, req):
    tableName = param['tableName'].name
    if not tableName in self.tables:
      raise KeyError, 'Table Not Found'

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO(str(self.tables[tableName]['len']))))
    return fu
示例#11
0
  def fetch_all(self, param, req):
    tableName = param['tableName']
    if not tableName in self.tables:
      raise KeyError, 'Table Not Found!'

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO(pickle.dumps(self.tables[tableName]))))
    return fu
示例#12
0
 def close(self):
     if self._cursor is None:
         future = TracebackFuture()
         future.set_result(None)
         return future
     future = async_call_method(self._cursor.close)
     def do_close(future):
         self._cursor = None
     future.add_done_callback(do_close)
     return future
示例#13
0
    def get(self, param, req):
        tableName = param['tableName']
        key = param['key']

        fu = Future()
        req.url = self.host
        fu.set_result(
            HTTPResponse(req,
                         200,
                         buffer=cStringIO.StringIO(
                             pickle.dumps(self.tables[tableName][key]))))
        return fu
示例#14
0
文件: gen.py 项目: maxos54/ServerSync
    def wrapper(*args, **kwargs):
        future = TracebackFuture()

        if replace_callback and "callback" in kwargs:
            callback = kwargs.pop("callback")
            IOLoop.current().add_future(future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = _value_from_stopiteration(e)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, GeneratorType):
                # Inline the first iteration of Runner.run.  This lets us
                # avoid the cost of creating a Runner when the coroutine
                # never actually yields, which in turn allows us to
                # use "optional" coroutines in critical path code without
                # performance penalty for the synchronous case.
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                "stack_context inconsistency (probably caused "
                                'by yield within a "with StackContext" block)'
                            )
                        )
                except (StopIteration, Return) as e:
                    future.set_result(_value_from_stopiteration(e))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    _futures_to_runners[future] = Runner(result, future, yielded)
                try:
                    return future
                finally:
                    # Subtle memory optimization: if next() raised an exception,
                    # the future's exc_info contains a traceback which
                    # includes this stack frame.  This creates a cycle,
                    # which will be collected at the next full GC but has
                    # been shown to greatly increase memory usage of
                    # benchmarks (relative to the refcount-based scheme
                    # used in the absence of cycles).  We can avoid the
                    # cycle by clearing the local variable after we return it.
                    future = None
        future.set_result(result)
        return future
示例#15
0
  def set(self, param, req):
    tableName = param['tableName']
    key = param['key']
    val = param['val']

    print 'Worker {0} SET: {1} with key {2} to {3}'.format(self.host, tableName, key, val)

    self.tables[tableName][key] = val

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
    return fu
示例#16
0
    def len(self, param, req):
        tableName = param['tableName'].name
        if not tableName in self.tables:
            raise KeyError, 'Table Not Found'

        fu = Future()
        req.url = self.host
        fu.set_result(
            HTTPResponse(req,
                         200,
                         buffer=cStringIO.StringIO(
                             str(self.tables[tableName]['len']))))
        return fu
示例#17
0
  def create(self, param, req):
    tableName = param['tableName']
    initVal = param['initVal']
    self.tables[tableName] = {}
    for key in initVal:
      self.tables[tableName][key] = initVal[key]
    print 'Worker {0} CREATE:'.format(self.host), self.tables[tableName]

    #Release
    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
    return fu
示例#18
0
    def fetch_all(self, param, req):
        tableName = param['tableName']
        if not tableName in self.tables:
            raise KeyError, 'Table Not Found!'

        fu = Future()
        req.url = self.host
        fu.set_result(
            HTTPResponse(req,
                         200,
                         buffer=cStringIO.StringIO(
                             pickle.dumps(self.tables[tableName]))))
        return fu
示例#19
0
    def set(self, param, req):
        tableName = param['tableName']
        key = param['key']
        val = param['val']

        #print 'Worker {0} SET: {1} with key {2} to {3}'.format(self.host, tableName, key, val)

        self.tables[tableName][key] = val

        fu = Future()
        req.url = self.host
        fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
        return fu
示例#20
0
    def create(self, param, req):
        tableName = param['tableName']
        initVal = param['initVal']
        self.tables[tableName] = {}
        for key in initVal:
            self.tables[tableName][key] = initVal[key]
        #print 'Worker {0} CREATE:'.format(self.host), self.tables[tableName]

        #Release
        fu = Future()
        req.url = self.host
        fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
        return fu
 def fetch(self, request, callback=None, **kwargs):
     if not isinstance(request, HTTPRequest):
         request = HTTPRequest(url=request, **kwargs)
     response_partial = RequestCollection.find(request)
     if response_partial:
         resp = response_partial(request)
     else:
         resp = HTTPResponse(request, 404)
     if callback is not None:
         callback(resp)
     else:
         future = TracebackFuture()
         future.set_result(resp)
         return future
示例#22
0
    def mock_fetch(self, request, callback=None, **kwargs):
        future = TracebackFuture()
        if callback is not None:
            callback = stack_context.wrap(callback)

            def handle_future(future):
                response = future.result()
                self.io_loop.add_callback(callback, response)
            future.add_done_callback(handle_future)

        res = MagicMock()
        future.set_result(res)

        return future
示例#23
0
    def remove(self, param, req):
        tableName = param['tableName']
        key = param['key']
        if not key in self.tables[tableName]:
            return Future().set_result('Key Error')

        if key is None:
            del self.tables[tableName]
        else:
            del self.tables[tableName][key]

        fu = Future()
        req.url = self.host
        fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
        return Future().set_result('OK')
示例#24
0
  def remove(self, param, req):
    tableName = param['tableName']
    key = param['key']
    if not key in self.tables[tableName]:
      return Future().set_result('Key Error')

    if key is None:
      del self.tables[tableName]
    else:
      del self.tables[tableName][key]

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
    return Future().set_result('OK')
示例#25
0
    def start_tls(self, server_side, ssl_options, server_hostname=None):
        if not isinstance(ssl_options, SSL.Context):
            raise ValueError("ssl_options is not SSL.Context")

        _socket = self.detach()
        _socket = SSL.Connection(ssl_options, _socket)
        if server_side:
            _socket.set_accept_state()
        else:
            _socket.set_connect_state()
            if server_hostname:
                _socket.set_tlsext_host_name(server_hostname.encode("idna"))

        orig_close_callback = self._close_callback
        self._close_callback = None

        future = TracebackFuture()
        ssl_stream = MicroProxySSLIOStream(_socket,
                                           server_hostname=server_hostname,
                                           ssl_options=ssl_options,
                                           io_loop=self.io_loop)

        def close_callback():
            if not future.done():
                future.set_exception(ssl_stream.error or StreamClosedError())
            if orig_close_callback is not None:
                orig_close_callback()

        ssl_stream.set_close_callback(close_callback)
        ssl_stream._ssl_connect_callback = lambda: future.set_result(ssl_stream)
        ssl_stream.max_buffer_size = self.max_buffer_size
        ssl_stream.read_chunk_size = self.read_chunk_size
        return future
示例#26
0
文件: test_gen.py 项目: zhaosir/Demo
    def wrapper(*args, **kwargs):
        future = TracebackFuture()
#        ipdb.set_trace()
        print args, kwargs
#        callback, args, kwargs = replacer.replace(lambda value=_NO_RESULT: future.set_result(value),args, kwargs)
        callback = None
        kwargs['callback'] = lambda value = _NO_RESULT: future.set_result(value)
        print callback, args, kwargs
        def handle_error(typ, value, tb):
            future.set_exc_info((typ, value, tb))
            return True

        exc_info = None
        with ExceptionStackContext(handle_error):
            try:
                result = f(*args, **kwargs)
                if result is not None:
                    raise ReturnValueIgnoredError('@return_future should not be used with function that return values')
            except:
                exc_info = sys.exc_info()
                raise

        if exc_info is not None:
            future.result()

        if callback is not None:
            def run_callback(future):
                result = future.result()
                if result is _NO_RESULT:
                    callback('result is NULL')
                else:
                    callback(future.result())
            future.add_done_callback(wrap(run_callback))
#        print future.result(), 'in the wapper'
        return future
示例#27
0
 def open(self):
     future = TracebackFuture()
     try:
         self._stream.open(lambda :future.set_result(None))
     except Exception:
         future.set_exc_info(sys.exc_info())
     return future
示例#28
0
    def read_message(self, callback=None):
        """读取来自 WebSocket 服务器的消息.

        如果在 WebSocket 初始化时指定了 on_message_callback ,那么这个方法永远不会返回消息

        如果连接已经关闭,返回结果会是一个结果是 message 的 future 对象或者是 None.
        如果 future 给出了回调参数, 这个参数将会在 future 完成时调用.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future
    def read_message(self, callback=None):
        """Reads a message from the WebSocket server.

        Returns a future whose result is the message, or None
        if the connection is closed.  If a callback argument
        is given it will be called with the future when it is
        ready.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future
示例#30
0
    def read_message(self, callback=None):
        """Reads a message from the WebSocket server.

        Returns a future whose result is the message, or None
        if the connection is closed.  If a callback argument
        is given it will be called with the future when it is
        ready.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future
示例#31
0
    def read_message(self, callback=None):
        """读取来自 WebSocket 服务器的消息.

        如果在 WebSocket 初始化时指定了 on_message_callback ,那么这个方法永远不会返回消息

        如果连接已经关闭,返回结果会是一个结果是 message 的 future 对象或者是 None.
        如果 future 给出了回调参数, 这个参数将会在 future 完成时调用.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future
示例#32
0
  def append(self, param, req):
    tableName = param['tableName'].name
    val = param['val']
    if not tableName in self.tables:
      raise KeyError, 'Table Not Found!'

    args = {'tableName': tableName, 'key': self.tables[tableName]['len'], 'val': val}
    worker = self.workers[hash(self.tables[tableName]['len']) % self.num_workers]

    #print 'MASTER -> {0} Append: {1} to key {2}'.format(worker, val, self.tables[tableName]['len'])
    self.client.fetch(formatQuery(worker, 'set', args))

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO(str(self.tables[tableName]['len']))))
    self.tables[tableName]['len'] += 1
    return fu
示例#33
0
  def remove(self, param, req):
    tableName = param['tableName'].name
    key = param['key']
    if not tableName in self.tables:
      #Silently fails
      return

    args = {'tableName': tableName, 'key': key}
    futures = []
    for worker in self.workers:
      futures.append(self.client.fetch(formatQuery(worker, 'remove', args)))
    if key is None:
      del self.tables[tableName]

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
    return fu
示例#34
0
  def set(self, param, req):
    tableName = param['tableName'].name
    key = param['key']
    val = param['val']
    if not tableName in self.tables:
      raise KeyError, 'Table not Found!'
    worker = self.workers[hash(key) % self.num_workers]
    args = {'tableName': tableName, 'key': key, 'val': val}

    print 'MASTER -> {0} SET: {1} with key {2} to {3}'.format(worker, tableName, key, val)

    futures = []
    futures.append(self.client.fetch(formatQuery(worker, 'set', args)))

    fu = Future()
    req.url = self.host
    fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
    return fu
示例#35
0
    def wrapper(*args, **kwargs):
        runner = None
        future = TracebackFuture()

        # 注册进去了......
        if 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        def handle_exception(typ, value, tb):
            try:
                if runner is not None and runner.handle_exception(typ, value, tb):
                    return True  # 这样就吃掉exception了?
            except Exception:
                typ, value, tb = sys.exc_info()
            future.set_exc_info((typ, value, tb))
            return True

        with ExceptionStackContext(handle_exception) as deactivate:
            try:
                result = func(*args, **kwargs)  # result是func调用返回的一个结果,有可能是一个iterator,比如我们的get、post方法里面塞几个yield的调用
            except (Return, StopIteration) as e:
                result = getattr(e, 'value', None)
            except Exception:
                deactivate()
                future.set_exc_info(sys.exc_info())
                return future
            else:
                if isinstance(result, types.GeneratorType):

                    def final_callback(value):
                        deactivate()
                        future.set_result(value)

                    # 这里的result很可能是一个iterator,看看头部的调用例子
                    runner = Runner(result, final_callback) # 关键点
                    runner.run()

                    return future

            deactivate()
            future.set_result(result)
        return future
示例#36
0
    def wrapper(*args, **kwargs):
        runner = None
        future = TracebackFuture()

        # 注册进去了......
        if 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        def handle_exception(typ, value, tb):
            try:
                if runner is not None and runner.handle_exception(
                        typ, value, tb):
                    return True  # 这样就吃掉exception了?
            except Exception:
                typ, value, tb = sys.exc_info()
            future.set_exc_info((typ, value, tb))
            return True

        with ExceptionStackContext(handle_exception) as deactivate:
            try:
                result = func(*args,
                              **kwargs)  # result是func调用返回的一个结果,有可能是一个iterator?
            except (Return, StopIteration) as e:
                result = getattr(e, 'value', None)  #TODO 这里也是
            except Exception:
                deactivate()
                future.set_exc_info(sys.exc_info())
                return future
            else:
                if isinstance(result, types.GeneratorType):

                    def final_callback(value):
                        deactivate()
                        future.set_result(value)

                    # 这里的result很可能是一个iterator,看看头部的调用例子
                    runner = Runner(result, final_callback)  # 关键点
                    runner.run()
                    return future
            deactivate()
            future.set_result(result)
        return future
示例#37
0
    def wrapper(*args, **kwargs):
        runner = None
        future = TracebackFuture()

        if 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        def handle_exception(typ, value, tb):
            try:
                if runner is not None and runner.handle_exception(typ, value, tb):
                    return True
            except Exception:
                typ, value, tb = sys.exc_info()
            if sys.getrefcount(future) == 2:
                # there are no references left to this future object
                # to prevent the error passing silently throw the exception right here
                # so it can be catched and handled by IOLoop.handle_callback_exception
                raise
            else:
                future.set_exc_info((typ, value, tb))
            return True
        with ExceptionStackContext(handle_exception) as deactivate:
            try:
                result = func(*args, **kwargs)
            except (Return, StopIteration) as e:
                result = getattr(e, 'value', None)
            except Exception:
                deactivate()
                future.set_exc_info(sys.exc_info())
                return future
            else:
                if isinstance(result, types.GeneratorType):
                    def final_callback(value):
                        deactivate()
                        future.set_result(value)
                    runner = Runner(result, final_callback)
                    runner.run()
                    return future
            deactivate()
            future.set_result(result)
        return future
示例#38
0
    def remove(self, param, req):
        tableName = param['tableName'].name
        key = param['key']
        if not tableName in self.tables:
            #Silently fails
            return

        args = {'tableName': tableName, 'key': key}
        futures = []
        for worker in self.workers:
            futures.append(
                self.client.fetch(formatQuery(worker, 'remove', args)))
        if key is None:
            del self.tables[tableName]

        fu = Future()
        req.url = self.host
        fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
        return fu
示例#39
0
    def set(self, param, req):
        tableName = param['tableName'].name
        key = param['key']
        val = param['val']
        if not tableName in self.tables:
            raise KeyError, 'Table not Found!'
        worker = self.workers[hash(key) % self.num_workers]
        args = {'tableName': tableName, 'key': key, 'val': val}

        print 'MASTER -> {0} SET: {1} with key {2} to {3}'.format(
            worker, tableName, key, val)

        futures = []
        futures.append(self.client.fetch(formatQuery(worker, 'set', args)))

        fu = Future()
        req.url = self.host
        fu.set_result(HTTPResponse(req, 200, buffer=cStringIO.StringIO('OK')))
        return fu
示例#40
0
    def wrapper(*args, **kwargs):
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            with Measure(func):
                result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = getattr(e, 'value', None)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, types.GeneratorType):
                try:
                    orig_stack_contexts = stack_context._state.contexts

                    with Measure(result, first=True):
                        yielded = next(result)

                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)'))
                except (StopIteration, Return) as e:
                    future.set_result(getattr(e, 'value', None))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    Runner(result, future, yielded)
                try:
                    return future
                finally:
                    future = None
        future.set_result(result)
        return future
示例#41
0
    def wrapper(*args, **kwargs):
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = getattr(e, 'value', None)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, types.GeneratorType):
                # Inline the first iteration of Runner.run.  This lets us
                # avoid the cost of creating a Runner when the coroutine
                # never actually yields, which in turn allows us to
                # use "optional" coroutines in critical path code without
                # performance penalty for the synchronous case.
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)')
                        )
                except (StopIteration, Return) as e:
                    future.set_result(getattr(e, 'value', None))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    Runner(result, future, yielded)
                return future
        future.set_result(result)
        return future
示例#42
0
    def wrapper(*args, **kwargs):
        runner = None
        future = TracebackFuture()

        if 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        def handle_exception(typ, value, tb):
            try:
                if runner is not None and runner.handle_exception(
                        typ, value, tb):
                    return True
            except Exception:
                typ, value, tb = sys.exc_info()
            future.set_exc_info((typ, value, tb))
            return True

        with ExceptionStackContext(handle_exception) as deactivate:
            try:
                result = func(*args, **kwargs)
            except (Return, StopIteration) as e:
                result = getattr(e, 'value', None)
            except Exception:
                deactivate()
                future.set_exc_info(sys.exc_info())
                return future
            else:
                if isinstance(result, types.GeneratorType):

                    def final_callback(value):
                        deactivate()
                        future.set_result(value)

                    runner = Runner(result, final_callback)
                    runner.run()
                    return future
            deactivate()
            future.set_result(result)
        return future
示例#43
0
    def wrapper(*args, **kwargs):
        future = TracebackFuture()

        if replace_callback and "callback" in kwargs:
            callback = kwargs.pop("callback")
            IOLoop.current().add_future(future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = getattr(e, "value", None)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, types.GeneratorType):
                # Inline the first iteration of Runner.run.  This lets us
                # avoid the cost of creating a Runner when the coroutine
                # never actually yields, which in turn allows us to
                # use "optional" coroutines in critical path code without
                # performance penalty for the synchronous case.
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                "stack_context inconsistency (probably caused "
                                'by yield within a "with StackContext" block)'
                            )
                        )
                except (StopIteration, Return) as e:
                    future.set_result(getattr(e, "value", None))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    Runner(result, future, yielded)
                return future
        future.set_result(result)
        return future
示例#44
0
    def get_connection(self):
        future = TracebackFuture()
        if self._closed:
            future.set_exception(ConnectionPoolClosedError())
            return future

        if not self._connections:
            if self._connections_count < self._max_connections:
                def _(succed, result):
                    if succed:
                        self._used_connections.append(result)
                        future.set_result(result)
                    else:
                        future.set_exc_info(result)
                self.init_connection(_)
            else:
                self._wait_connections.append(future)
        else:
            connection = self._connections.popleft()
            self._used_connections.append(connection)
            future.set_result(connection)
        return future
示例#45
0
    def wrapper(*args, **kwargs):
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = getattr(e, 'value', None)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, types.GeneratorType):
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)')
                        )
                except (StopIteration, Return) as e:
                    future.set_result(getattr(e, 'value', None))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    Runner(result, future, yielded)
                try:
                    return future
                finally:
                    future = None
        future.set_result(result)
        return future
示例#46
0
    def wrapper(*args, **kwargs):
        runner = None
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = getattr(e, 'value', None)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, types.GeneratorType):
                runner = Runner(result, future)
                runner.run()
                return future
        future.set_result(result)
        return future
示例#47
0
文件: gen.py 项目: EliseCheng/tornado
    def wrapper(*args, **kwargs):
        runner = None
        future = TracebackFuture()

        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            result = getattr(e, 'value', None)
        except Exception:
            future.set_exc_info(sys.exc_info())
            return future
        else:
            if isinstance(result, types.GeneratorType):
                runner = Runner(result, future)
                runner.run()
                return future
        future.set_result(result)
        return future
示例#48
0
 def wrapper(*args, **kwargs):
     if replacer.get_old_value(args, kwargs) is not None:
         # If a callaback is present, just call in to the decorated
         # function.  This is a slight optimization (by not creating a
         # Future that is unlikely to be used), but mainly avoids the
         # complexity of running the callback in the expected way.
         return f(*args, **kwargs)
     future = TracebackFuture()
     callback, args, kwargs = replacer.replace(
         lambda value=None: future.set_result(value), args, kwargs)
     f(*args, **kwargs)
     stream = args[0]
     stream._pending_futures.add(future)
     future.add_done_callback(
         lambda fut: stream._pending_futures.discard(fut))
     return future
示例#49
0
 def wrapper(*args, **kwargs):
     if replacer.get_old_value(args, kwargs) is not None:
         # If a callaback is present, just call in to the decorated
         # function.  This is a slight optimization (by not creating a
         # Future that is unlikely to be used), but mainly avoids the
         # complexity of running the callback in the expected way.
         return f(*args, **kwargs)
     future = TracebackFuture()
     callback, args, kwargs = replacer.replace(
         lambda value=None: future.set_result(value),
         args, kwargs)
     f(*args, **kwargs)
     stream = args[0]
     stream._pending_futures.add(future)
     future.add_done_callback(
         lambda fut: stream._pending_futures.discard(fut))
     return future
示例#50
0
文件: test_gen.py 项目: zhaosir/Demo
    def wrapper(*args, **kwargs):
        ipdb.set_trace()
        future = TracebackFuture()
        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')
            IOLoop.current().add_future(future, lambda future: callback(future.result()))

        try:
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
#            ipdb.set_trace()
            result = gen._value_from_stopiteration(e)
        except Exception:
#            ipdb.set_trace()
            future.set_exc_info(sys.exc_info())
            return future
        else:
#            ipdb.set_trace()
            if isinstance(result, GeneratorType):
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    yielded = next(result)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(stack_context.StackContextInconsistentError('stack_context inconsistency (probably caused'))
                except (StopIteration, Return) as e:
                    future.set_result(gen._value_from_stopiteration(e))
                except Exception:
                    future.set_exc_info(sys.exc_info())
                else:
                    try:
                        result.send(yielded.result()) 
                    except (StopIteration, Return) as e:
                        ipdb.set_trace()
                        future.set_result(gen._value_from_stopiteration(e))
                        
#                    gen.Runner(result, future, yielded)
                try:
                    return future
                finally:
                    future = None

        future.set_result(result)
        return future
示例#51
0
class WebSocketClientConnection(simple_httpclient._HTTPConnection):
    """WebSocket 客户端连接

    这个类不应当直接被实例化, 请使用 `websocket_connect`

    """
    def __init__(self,
                 io_loop,
                 request,
                 on_message_callback=None,
                 compression_options=None):
        self.compression_options = compression_options
        self.connect_future = TracebackFuture()
        self.protocol = None
        self.read_future = None
        self.read_queue = collections.deque()
        self.key = base64.b64encode(os.urandom(16))
        self._on_message_callback = on_message_callback
        self.close_code = self.close_reason = None

        scheme, sep, rest = request.url.partition(':')
        scheme = {'ws': 'http', 'wss': 'https'}[scheme]
        request.url = scheme + sep + rest
        request.headers.update({
            'Upgrade': 'websocket',
            'Connection': 'Upgrade',
            'Sec-WebSocket-Key': self.key,
            'Sec-WebSocket-Version': '13',
        })
        if self.compression_options is not None:
            # Always offer to let the server set our max_wbits (and even though
            # we don't offer it, we will accept a client_no_context_takeover
            # from the server).
            # TODO: set server parameters for deflate extension
            # if requested in self.compression_options.
            request.headers['Sec-WebSocket-Extensions'] = (
                'permessage-deflate; client_max_window_bits')

        self.tcp_client = TCPClient(io_loop=io_loop)
        super(WebSocketClientConnection,
              self).__init__(io_loop, None, request, lambda: None,
                             self._on_http_response, 104857600,
                             self.tcp_client, 65536, 104857600)

    def close(self, code=None, reason=None):
        """关闭 websocket 连接

        ``code`` 和 ``reason`` 的文档在 `WebSocketHandler.close` 下已给出.

        .. versionadded:: 3.2

        .. versionchanged:: 4.0

           添加 ``code`` 和 ``reason`` 这两个参数
        """
        if self.protocol is not None:
            self.protocol.close(code, reason)
            self.protocol = None

    def on_connection_close(self):
        if not self.connect_future.done():
            self.connect_future.set_exception(StreamClosedError())
        self.on_message(None)
        self.tcp_client.close()
        super(WebSocketClientConnection, self).on_connection_close()

    def _on_http_response(self, response):
        if not self.connect_future.done():
            if response.error:
                self.connect_future.set_exception(response.error)
            else:
                self.connect_future.set_exception(
                    WebSocketError("Non-websocket response"))

    def headers_received(self, start_line, headers):
        if start_line.code != 101:
            return super(WebSocketClientConnection,
                         self).headers_received(start_line, headers)

        self.headers = headers
        self.protocol = self.get_websocket_protocol()
        self.protocol._process_server_headers(self.key, self.headers)
        self.protocol._receive_frame()

        if self._timeout is not None:
            self.io_loop.remove_timeout(self._timeout)
            self._timeout = None

        self.stream = self.connection.detach()
        self.stream.set_close_callback(self.on_connection_close)
        # Once we've taken over the connection, clear the final callback
        # we set on the http request.  This deactivates the error handling
        # in simple_httpclient that would otherwise interfere with our
        # ability to see exceptions.
        self.final_callback = None

        self.connect_future.set_result(self)

    def write_message(self, message, binary=False):
        """发送消息到 websocket 服务器."""
        return self.protocol.write_message(message, binary)

    def read_message(self, callback=None):
        """读取来自 WebSocket 服务器的消息.

        如果在 WebSocket 初始化时指定了 on_message_callback ,那么这个方法永远不会返回消息

        如果连接已经关闭,返回结果会是一个结果是 message 的 future 对象或者是 None.
        如果 future 给出了回调参数, 这个参数将会在 future 完成时调用.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future

    def on_message(self, message):
        if self._on_message_callback:
            self._on_message_callback(message)
        elif self.read_future is not None:
            self.read_future.set_result(message)
            self.read_future = None
        else:
            self.read_queue.append(message)

    def on_pong(self, data):
        pass

    def get_websocket_protocol(self):
        return WebSocketProtocol13(
            self,
            mask_outgoing=True,
            compression_options=self.compression_options)
示例#52
0
class Runner(object):
    """Internal implementation of `tornado.gen.engine`.

    Maintains information about pending callbacks and their results.

    The results of the generator are stored in ``result_future`` (a
    `.TracebackFuture`)
    """
    def __init__(self, gen, result_future, first_yielded):
        self.gen = gen
        self.result_future = result_future
        self.future = _null_future
        self.yield_point = None
        self.pending_callbacks = None
        self.results = None
        self.running = False
        self.finished = False
        self.had_exception = False
        self.io_loop = IOLoop.current()
        # For efficiency, we do not create a stack context until we
        # reach a YieldPoint (stack contexts are required for the historical
        # semantics of YieldPoints, but not for Futures).  When we have
        # done so, this field will be set and must be called at the end
        # of the coroutine.
        self.stack_context_deactivate = None
        if self.handle_yield(first_yielded):
            self.run()

    def register_callback(self, key):
        """Adds ``key`` to the list of callbacks."""
        if self.pending_callbacks is None:
            # Lazily initialize the old-style YieldPoint data structures.
            self.pending_callbacks = set()
            self.results = {}
        if key in self.pending_callbacks:
            raise KeyReuseError("key %r is already pending" % (key, ))
        self.pending_callbacks.add(key)

    def is_ready(self, key):
        """Returns true if a result is available for ``key``."""
        if self.pending_callbacks is None or key not in self.pending_callbacks:
            raise UnknownKeyError("key %r is not pending" % (key, ))
        return key in self.results

    def set_result(self, key, result):
        """Sets the result for ``key`` and attempts to resume the generator."""
        self.results[key] = result
        if self.yield_point is not None and self.yield_point.is_ready():
            try:
                self.future.set_result(self.yield_point.get_result())
            except:
                self.future.set_exc_info(sys.exc_info())
            self.yield_point = None
            self.run()

    def pop_result(self, key):
        """Returns the result for ``key`` and unregisters it."""
        self.pending_callbacks.remove(key)
        return self.results.pop(key)

    def run(self):
        """Starts or resumes the generator, running until it reaches a
        yield point that is not ready.
        """
        if self.running or self.finished:
            return
        try:
            self.running = True
            while True:
                future = self.future
                if not future.done():
                    return
                self.future = None
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    try:
                        value = future.result()
                    except Exception:
                        self.had_exception = True
                        yielded = self.gen.throw(*sys.exc_info())
                    else:
                        yielded = self.gen.send(value)
                    if stack_context._state.contexts is not orig_stack_contexts:
                        self.gen.throw(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)')
                        )
                except (StopIteration, Return) as e:
                    self.finished = True
                    self.future = _null_future
                    if self.pending_callbacks and not self.had_exception:
                        # If we ran cleanly without waiting on all callbacks
                        # raise an error (really more of a warning).  If we
                        # had an exception then some callbacks may have been
                        # orphaned, so skip the check in that case.
                        raise LeakedCallbackError(
                            "finished without waiting for callbacks %r" %
                            self.pending_callbacks)
                    self.result_future.set_result(getattr(e, 'value', None))
                    self.result_future = None
                    self._deactivate_stack_context()
                    return
                except Exception:
                    self.finished = True
                    self.future = _null_future
                    self.result_future.set_exc_info(sys.exc_info())
                    self.result_future = None
                    self._deactivate_stack_context()
                    return
                if not self.handle_yield(yielded):
                    return
        finally:
            self.running = False

    def handle_yield(self, yielded):
        if isinstance(yielded, list):
            if all(is_future(f) for f in yielded):
                yielded = multi_future(yielded)
            else:
                yielded = Multi(yielded)
        elif isinstance(yielded, dict):
            if all(is_future(f) for f in yielded.values()):
                yielded = multi_future(yielded)
            else:
                yielded = Multi(yielded)

        if isinstance(yielded, YieldPoint):
            self.future = TracebackFuture()

            def start_yield_point():
                try:
                    yielded.start(self)
                    if yielded.is_ready():
                        self.future.set_result(yielded.get_result())
                    else:
                        self.yield_point = yielded
                except Exception:
                    self.future = TracebackFuture()
                    self.future.set_exc_info(sys.exc_info())

            if self.stack_context_deactivate is None:
                # Start a stack context if this is the first
                # YieldPoint we've seen.
                with stack_context.ExceptionStackContext(
                        self.handle_exception) as deactivate:
                    self.stack_context_deactivate = deactivate

                    def cb():
                        start_yield_point()
                        self.run()

                    self.io_loop.add_callback(cb)
                    return False
            else:
                start_yield_point()
        elif is_future(yielded):
            self.future = yielded
            if not self.future.done() or self.future is moment:
                self.io_loop.add_future(self.future, lambda f: self.run())
                return False
        else:
            self.future = TracebackFuture()
            self.future.set_exception(
                BadYieldError("yielded unknown object %r" % (yielded, )))
        return True

    def result_callback(self, key):
        return stack_context.wrap(
            _argument_adapter(functools.partial(self.set_result, key)))

    def handle_exception(self, typ, value, tb):
        if not self.running and not self.finished:
            self.future = TracebackFuture()
            self.future.set_exc_info((typ, value, tb))
            self.run()
            return True
        else:
            return False

    def _deactivate_stack_context(self):
        if self.stack_context_deactivate is not None:
            self.stack_context_deactivate()
            self.stack_context_deactivate = None
class WebSocketClientConnection(simple_httpclient._HTTPConnection):
    """WebSocket client connection.

    This class should not be instantiated directly; use the
    `websocket_connect` function instead.
    """
    def __init__(self, io_loop, request):
        self.connect_future = TracebackFuture()
        self.read_future = None
        self.read_queue = collections.deque()
        self.key = base64.b64encode(os.urandom(16))

        scheme, sep, rest = request.url.partition(':')
        scheme = {'ws': 'http', 'wss': 'https'}[scheme]
        request.url = scheme + sep + rest
        request.headers.update({
            'Upgrade': 'websocket',
            'Connection': 'Upgrade',
            'Sec-WebSocket-Key': self.key,
            'Sec-WebSocket-Version': '13',
        })

        self.tcp_client = TCPClient(io_loop=io_loop)
        super(WebSocketClientConnection,
              self).__init__(io_loop, None, request, lambda: None,
                             self._on_http_response, 104857600,
                             self.tcp_client, 65536)

    def close(self, code=None, reason=None):
        """Closes the websocket connection.

        ``code`` and ``reason`` are documented under
        `WebSocketHandler.close`.

        .. versionadded:: 3.2

        .. versionchanged:: 4.0

           Added the ``code`` and ``reason`` arguments.
        """
        if self.protocol is not None:
            self.protocol.close(code, reason)
            self.protocol = None

    def _on_close(self):
        self.on_message(None)
        self.resolver.close()
        super(WebSocketClientConnection, self)._on_close()

    def _on_http_response(self, response):
        if not self.connect_future.done():
            if response.error:
                self.connect_future.set_exception(response.error)
            else:
                self.connect_future.set_exception(
                    WebSocketError("Non-websocket response"))

    def headers_received(self, start_line, headers):
        if start_line.code != 101:
            return super(WebSocketClientConnection,
                         self).headers_received(start_line, headers)

        self.headers = headers
        assert self.headers['Upgrade'].lower() == 'websocket'
        assert self.headers['Connection'].lower() == 'upgrade'
        accept = WebSocketProtocol13.compute_accept_value(self.key)
        assert self.headers['Sec-Websocket-Accept'] == accept

        self.protocol = WebSocketProtocol13(self, mask_outgoing=True)
        self.protocol._receive_frame()

        if self._timeout is not None:
            self.io_loop.remove_timeout(self._timeout)
            self._timeout = None

        self.stream = self.connection.detach()
        self.stream.set_close_callback(self._on_close)

        self.connect_future.set_result(self)

    def write_message(self, message, binary=False):
        """Sends a message to the WebSocket server."""
        self.protocol.write_message(message, binary)

    def read_message(self, callback=None):
        """Reads a message from the WebSocket server.

        Returns a future whose result is the message, or None
        if the connection is closed.  If a callback argument
        is given it will be called with the future when it is
        ready.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future

    def on_message(self, message):
        if self.read_future is not None:
            self.read_future.set_result(message)
            self.read_future = None
        else:
            self.read_queue.append(message)

    def on_pong(self, data):
        pass
示例#54
0
class SSHClient(object):
    _host_map = {}

    def __init__(self, io_loop=None):
        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        # self.transport = None
        self.channel = None
        self.io_loop = io_loop or IOLoop.current()
        self.future = None
        self._result = ''
        self.sftp_client = None
        self.count = 0

    def connect(self, host, uesrname, port, **kwargs):
        self.client.connect(host,
                            username=uesrname,
                            port=port,
                            allow_agent=False,
                            **kwargs)

    def put_file(self, filename):
        try:
            self.future = TracebackFuture()

            transport = self.client.get_transport()
            self.sftp_client = SFTPClient.from_transport(transport)
            self.remote = self.sftp_client.open(filename, 'wb')
            self.local = open(filename, 'rb')
            # self.remote.setblocking(0)
            # _buf = self.local.read(100)
            # self.remote.write(_buf)
            self.io_loop.add_handler(self.sftp_client.sock, self._handle_write,
                                     self.io_loop.WRITE | self.io_loop.ERROR)

            return self.future

        except Exception as e:
            print(e)
            pass

    def _handle_write(self, fd, events):
        # print("EVENT=%d,fd=%s" % (events, fd))
        if events & self.io_loop.WRITE:
            _buf = self.local.read(BLOCK_SIZE)
            if _buf:
                try:
                    a = time.time()
                    self.remote.write(_buf)
                    b = time.time()
                    self.count += len(_buf)
                    c = b - a
                except IOError as e:
                    print(e)
            else:
                self.io_loop.remove_handler(fd)
                self.remote.close()
                self.local.close()
                self.future.set_result('FINISH')

    def exec_command(self, command):
        request_log.info('EXECUTE %s', command)

        try:
            self.future = TracebackFuture()
            transport = self.client.get_transport()
            self.channel = transport.open_session()
            self.channel.exec_command(command)

            self.io_loop.add_handler(self.channel.fileno(),
                                     self._handle_events,
                                     self.io_loop.READ | self.io_loop.ERROR)

            return self.future
        except Exception as e:
            print(e)
            pass

    def _handle_events(self, fd, events):
        # print("EVENT=" + str(events))
        if events & self.io_loop.READ:
            _buf = self.channel.recv(1024)
            if len(_buf):
                print(_buf.decode())
                self._result += _buf.decode()
            else:
                self.io_loop.remove_handler(self.channel.fileno())
                self.future.set_result(self._result)

        if events & self.io_loop.ERROR:
            self.io_loop.remove_handler(self.channel.fileno())
            self.future.set_result('ERROR')
示例#55
0
class WebSocketClientConnection(simple_httpclient._HTTPConnection):
    """WebSocket client connection.

    This class should not be instantiated directly; use the
    `websocket_connect` function instead.
    """
    def __init__(self, io_loop, request, on_message_callback=None,
                 compression_options=None):
        self.compression_options = compression_options
        self.connect_future = TracebackFuture()
        self.protocol = None
        self.read_future = None
        self.read_queue = collections.deque()
        self.key = base64.b64encode(os.urandom(16))
        self._on_message_callback = on_message_callback

        scheme, sep, rest = request.url.partition(':')
        scheme = {'ws': 'http', 'wss': 'https'}[scheme]
        request.url = scheme + sep + rest
        request.headers.update({
            'Upgrade': 'websocket',
            'Connection': 'Upgrade',
            'Sec-WebSocket-Key': self.key,
            'Sec-WebSocket-Version': '13',
        })
        if self.compression_options is not None:
            # Always offer to let the server set our max_wbits (and even though
            # we don't offer it, we will accept a client_no_context_takeover
            # from the server).
            # TODO: set server parameters for deflate extension
            # if requested in self.compression_options.
            request.headers['Sec-WebSocket-Extensions'] = (
                'permessage-deflate; client_max_window_bits')

        self.tcp_client = TCPClient(io_loop=io_loop)
        super(WebSocketClientConnection, self).__init__(
            io_loop, None, request, lambda: None, self._on_http_response,
            104857600, self.tcp_client, 65536)

    def close(self, code=None, reason=None):
        """Closes the websocket connection.

        ``code`` and ``reason`` are documented under
        `WebSocketHandler.close`.

        .. versionadded:: 3.2

        .. versionchanged:: 4.0

           Added the ``code`` and ``reason`` arguments.
        """
        if self.protocol is not None:
            self.protocol.close(code, reason)
            self.protocol = None

    def on_connection_close(self):
        if not self.connect_future.done():
            self.connect_future.set_exception(StreamClosedError())
        self.on_message(None)
        self.tcp_client.close()
        super(WebSocketClientConnection, self).on_connection_close()

    def _on_http_response(self, response):
        if not self.connect_future.done():
            if response.error:
                self.connect_future.set_exception(response.error)
            else:
                self.connect_future.set_exception(WebSocketError(
                    "Non-websocket response"))

    def headers_received(self, start_line, headers):
        if start_line.code != 101:
            return super(WebSocketClientConnection, self).headers_received(
                start_line, headers)

        self.headers = headers
        self.protocol = self.get_websocket_protocol()
        self.protocol._process_server_headers(self.key, self.headers)
        self.protocol._receive_frame()

        if self._timeout is not None:
            self.io_loop.remove_timeout(self._timeout)
            self._timeout = None

        self.stream = self.connection.detach()
        self.stream.set_close_callback(self.on_connection_close)
        # Once we've taken over the connection, clear the final callback
        # we set on the http request.  This deactivates the error handling
        # in simple_httpclient that would otherwise interfere with our
        # ability to see exceptions.
        self.final_callback = None

        self.connect_future.set_result(self)

    def write_message(self, message, binary=False):
        """Sends a message to the WebSocket server."""
        self.protocol.write_message(message, binary)

    def read_message(self, callback=None):
        """Reads a message from the WebSocket server.

        If on_message_callback was specified at WebSocket
        initialization, this function will never return messages

        Returns a future whose result is the message, or None
        if the connection is closed.  If a callback argument
        is given it will be called with the future when it is
        ready.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future

    def on_message(self, message):
        if self._on_message_callback:
            self._on_message_callback(message)
        elif self.read_future is not None:
            self.read_future.set_result(message)
            self.read_future = None
        else:
            self.read_queue.append(message)

    def on_pong(self, data):
        pass

    def get_websocket_protocol(self):
        return WebSocketProtocol13(self, mask_outgoing=True,
                                   compression_options=self.compression_options)
示例#56
0
class WebSocketClientConnection(simple_httpclient._HTTPConnection):
    """WebSocket client connection."""
    def __init__(self, io_loop, request):
        self.connect_future = TracebackFuture()
        self.read_future = None
        self.read_queue = collections.deque()
        self.key = base64.b64encode(os.urandom(16))

        scheme, sep, rest = request.url.partition(':')
        scheme = {'ws': 'http', 'wss': 'https'}[scheme]
        request.url = scheme + sep + rest
        request.headers.update({
            'Upgrade': 'websocket',
            'Connection': 'Upgrade',
            'Sec-WebSocket-Key': self.key,
            'Sec-WebSocket-Version': '13',
        })

        self.resolver = Resolver(io_loop=io_loop)
        super(WebSocketClientConnection,
              self).__init__(io_loop, None, request, lambda: None,
                             self._on_http_response, 104857600, self.resolver)

    def _on_close(self):
        self.on_message(None)
        self.resolver.close()

    def _on_http_response(self, response):
        if not self.connect_future.done():
            if response.error:
                self.connect_future.set_exception(response.error)
            else:
                self.connect_future.set_exception(
                    WebSocketError("Non-websocket response"))

    def _handle_1xx(self, code):
        assert code == 101
        assert self.headers['Upgrade'].lower() == 'websocket'
        assert self.headers['Connection'].lower() == 'upgrade'
        accept = WebSocketProtocol13.compute_accept_value(self.key)
        assert self.headers['Sec-Websocket-Accept'] == accept

        self.protocol = WebSocketProtocol13(self, mask_outgoing=True)
        self.protocol._receive_frame()

        if self._timeout is not None:
            self.io_loop.remove_timeout(self._timeout)
            self._timeout = None

        self.connect_future.set_result(self)

    def write_message(self, message, binary=False):
        """Sends a message to the WebSocket server."""
        self.protocol.write_message(message, binary)

    def read_message(self, callback=None):
        """Reads a message from the WebSocket server.

        Returns a future whose result is the message, or None
        if the connection is closed.  If a callback argument
        is given it will be called with the future when it is
        ready.
        """
        assert self.read_future is None
        future = TracebackFuture()
        if self.read_queue:
            future.set_result(self.read_queue.popleft())
        else:
            self.read_future = future
        if callback is not None:
            self.io_loop.add_future(future, callback)
        return future

    def on_message(self, message):
        if self.read_future is not None:
            self.read_future.set_result(message)
            self.read_future = None
        else:
            self.read_queue.append(message)

    def on_pong(self, data):
        pass
示例#57
0
class Runner(object):
    """Internal implementation of `tornado.gen.engine`.

    Maintains information about pending callbacks and their results.

    The results of the generator are stored in ``result_future`` (a
    `.TracebackFuture`)
    """
    def __init__(self, gen, result_future, first_yielded):
        self.gen = gen
        self.result_future = result_future
        # 第一次在handle_yield指向first_yielded,之后指向gen()
        self.future = _null_future
        self.yield_point = None
        self.pending_callbacks = None
        self.results = None
        self.running = False
        self.finished = False
        self.had_exception = False
        self.io_loop = IOLoop.current()
        # For efficiency, we do not create a stack context until we
        # reach a YieldPoint (stack contexts are required for the historical
        # semantics of YieldPoints, but not for Futures).  When we have
        # done so, this field will be set and must be called at the end
        # of the coroutine.
        self.stack_context_deactivate = None
        if self.handle_yield(first_yielded):
            self.run()

    def register_callback(self, key):
        """Adds ``key`` to the list of callbacks."""
        if self.pending_callbacks is None:
            # Lazily initialize the old-style YieldPoint data structures.
            self.pending_callbacks = set()
            self.results = {}
        if key in self.pending_callbacks:
            raise KeyReuseError("key %r is already pending" % (key, ))
        self.pending_callbacks.add(key)

    def is_ready(self, key):
        """Returns true if a result is available for ``key``."""
        if self.pending_callbacks is None or key not in self.pending_callbacks:
            raise UnknownKeyError("key %r is not pending" % (key, ))
        return key in self.results

    def set_result(self, key, result):
        """Sets the result for ``key`` and attempts to resume the generator."""
        self.results[key] = result
        if self.yield_point is not None and self.yield_point.is_ready():
            try:
                self.future.set_result(self.yield_point.get_result())
            except:
                self.future.set_exc_info(sys.exc_info())
            self.yield_point = None
            self.run()

    def pop_result(self, key):
        """Returns the result for ``key`` and unregisters it."""
        self.pending_callbacks.remove(key)
        return self.results.pop(key)

    def run(self):
        """Starts or resumes the generator, running until it reaches a
        yield point that is not ready.
        """
        if self.running or self.finished:
            return
        try:
            self.running = True
            while True:
                future = self.future
                if not future.done():
                    return
                self.future = None
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    exc_info = None

                    try:
                        value = future.result()
                    except Exception:
                        self.had_exception = True
                        exc_info = sys.exc_info()

                    if exc_info is not None:
                        yielded = self.gen.throw(*exc_info)
                        exc_info = None
                    else:
                        # 发送异步调用结果,通知任务完成
                        yielded = self.gen.send(value)
                        # self.gen为生成器,即被@gen.coroutine修饰的函数,
                        # self.gen.send发送结果到 yield语句进行赋值,即
                        # result = yield clien.fetch(url),这里的result
                        # 即为value,生成器结束会得到StopIteration异常结束
                        # 调用,否则继续调用self.handle_yield
                    if stack_context._state.contexts is not orig_stack_contexts:
                        self.gen.throw(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)')
                        )
                except (StopIteration, Return) as e:
                    # 捕捉到StopIteration 或者 Return 异常,说明 self.gen生成器
                    # 结束,Return 异常一般由用户调用 raise Return(True)
                    self.finished = True
                    self.future = _null_future
                    if self.pending_callbacks and not self.had_exception:
                        # If we ran cleanly without waiting on all callbacks
                        # raise an error (really more of a warning).  If we
                        # had an exception then some callbacks may have been
                        # orphaned, so skip the check in that case.
                        raise LeakedCallbackError(
                            "finished without waiting for callbacks %r" %
                            self.pending_callbacks)
                    # 如果是 Return 异常设置返回值
                    self.result_future.set_result(_value_from_stopiteration(e))
                    self.result_future = None
                    self._deactivate_stack_context()
                    return
                except Exception:
                    self.finished = True
                    self.future = _null_future
                    self.result_future.set_exc_info(sys.exc_info())
                    self.result_future = None
                    self._deactivate_stack_context()
                    return
                # 返回True说明yielded已经完成done,继续运行返回结果给上层,如果yielded
                # 还在等待Future完成,那么直接返回,handle_yield已经将yielded放到ioloop
                # 进行处理,完成后回调run运行
                if not self.handle_yield(yielded):
                    return
        finally:
            self.running = False

    def handle_yield(self, yielded):
        # 返回True已经完成,False表示Future未完成,添加到ioloop中
        # Lists containing YieldPoints require stack contexts;
        # other lists are handled in convert_yielded.
        # 处理 yield list or dict 情况
        if _contains_yieldpoint(yielded):
            yielded = multi(yielded)

        if isinstance(yielded, YieldPoint):
            # YieldPoints are too closely coupled to the Runner to go
            # through the generic convert_yielded mechanism.
            self.future = TracebackFuture()

            def start_yield_point():
                try:
                    yielded.start(self)
                    if yielded.is_ready():
                        self.future.set_result(yielded.get_result())
                    else:
                        self.yield_point = yielded
                except Exception:
                    self.future = TracebackFuture()
                    self.future.set_exc_info(sys.exc_info())

            if self.stack_context_deactivate is None:
                # Start a stack context if this is the first
                # YieldPoint we've seen.
                with stack_context.ExceptionStackContext(
                        self.handle_exception) as deactivate:
                    self.stack_context_deactivate = deactivate

                    def cb():
                        start_yield_point()
                        self.run()

                    self.io_loop.add_callback(cb)
                    return False
            else:
                start_yield_point()
        else:
            # Future情况,为r = yield fetch()之类返回的Future
            try:
                self.future = convert_yielded(yielded)
            except BadYieldError:
                self.future = TracebackFuture()
                self.future.set_exc_info(sys.exc_info())

        if not self.future.done() or self.future is moment:
            self.io_loop.add_future(self.future, lambda f: self.run())
            return False
        return True

    def result_callback(self, key):
        return stack_context.wrap(
            _argument_adapter(functools.partial(self.set_result, key)))

    def handle_exception(self, typ, value, tb):
        if not self.running and not self.finished:
            self.future = TracebackFuture()
            self.future.set_exc_info((typ, value, tb))
            self.run()
            return True
        else:
            return False

    def _deactivate_stack_context(self):
        if self.stack_context_deactivate is not None:
            self.stack_context_deactivate()
            self.stack_context_deactivate = None
示例#58
0
class Runner(object):
    """Internal implementation of `tornado.gen.engine`.

    Maintains information about pending callbacks and their results.

    The results of the generator are stored in ``result_future`` (a
    `.TracebackFuture`)
    """
    def __init__(self, gen, result_future, first_yielded):
        self.gen = gen
        self.result_future = result_future
        self.future = _null_future
        self.yield_point = None
        self.pending_callbacks = None
        self.results = None
        self.running = False
        self.finished = False
        self.had_exception = False
        self.io_loop = IOLoop.current()
        # For efficiency, we do not create a stack context until we
        # reach a YieldPoint (stack contexts are required for the historical
        # semantics of YieldPoints, but not for Futures).  When we have
        # done so, this field will be set and must be called at the end
        # of the coroutine.
        self.stack_context_deactivate = None
        if self.handle_yield(first_yielded):
            # handle_yield 在 coroutine yield 的对象有了结果时返回
            # True,这个时候就会马上执行 run 方法。
            self.run()

    def register_callback(self, key):
        """Adds ``key`` to the list of callbacks."""
        if self.pending_callbacks is None:
            # Lazily initialize the old-style YieldPoint data structures.
            self.pending_callbacks = set()
            self.results = {}
        if key in self.pending_callbacks:
            raise KeyReuseError("key %r is already pending" % (key, ))
        self.pending_callbacks.add(key)

    def is_ready(self, key):
        """Returns true if a result is available for ``key``."""
        if self.pending_callbacks is None or key not in self.pending_callbacks:
            raise UnknownKeyError("key %r is not pending" % (key, ))
        return key in self.results

    def set_result(self, key, result):
        """Sets the result for ``key`` and attempts to resume the generator."""
        self.results[key] = result
        if self.yield_point is not None and self.yield_point.is_ready():
            try:
                self.future.set_result(self.yield_point.get_result())
            except:
                self.future.set_exc_info(sys.exc_info())
            self.yield_point = None
            self.run()

    def pop_result(self, key):
        """Returns the result for ``key`` and unregisters it."""
        self.pending_callbacks.remove(key)
        return self.results.pop(key)

    def run(self):
        """Starts or resumes the generator, running until it reaches a
        yield point that is not ready.
        """
        if self.running or self.finished:
            # 如果 run 方法已经在被执行,则返回。
            return
        try:
            self.running = True
            while True:
                future = self.future
                if not future.done():
                    # Runner 对应的 coroutine yield
                    # 的对象还没有准备好,则返回。
                    return
                self.future = None
                try:
                    orig_stack_contexts = stack_context._state.contexts
                    exc_info = None

                    try:
                        value = future.result()
                    except Exception:
                        # 如果执行过程中有抛出异常,则捕获之,并让 coroutine
                        # 也抛出该异常。Python 中的 generator 在 2.5 版本后才
                        # 提供了 throw 方法来提供实现 coroutine
                        # 的可能性,详情可以参考:
                        # https://www.python.org/dev/peps/pep-0342/
                        self.had_exception = True
                        exc_info = sys.exc_info()

                    if exc_info is not None:
                        # 如果有异常,让 coroutine 抛出。
                        yielded = self.gen.throw(*exc_info)
                        exc_info = None
                    else:
                        # 如果一切正常,则将结果反馈给 coroutine。
                        yielded = self.gen.send(value)

                    if stack_context._state.contexts \
                            is not orig_stack_contexts:
                        self.gen.throw(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)')
                        )
                except (StopIteration, Return) as e:
                    # coroutine 的执行绪执行完毕,Runner 的任务也完成了。
                    self.finished = True
                    self.future = _null_future
                    if self.pending_callbacks and not self.had_exception:
                        # If we ran cleanly without waiting on all callbacks
                        # raise an error (really more of a warning).  If we
                        # had an exception then some callbacks may have been
                        # orphaned, so skip the check in that case.
                        raise LeakedCallbackError(
                            "finished without waiting for callbacks %r" %
                            self.pending_callbacks)
                    # 从 Exception 对象中获得最终结果,并反馈给
                    # result_future,进而触发 result_future 的 done callbacks。
                    self.result_future.set_result(_value_from_stopiteration(e))
                    self.result_future = None
                    self._deactivate_stack_context()
                    return
                except Exception:
                    self.finished = True
                    self.future = _null_future
                    self.result_future.set_exc_info(sys.exc_info())
                    self.result_future = None
                    self._deactivate_stack_context()
                    return
                if not self.handle_yield(yielded):
                    return
        finally:
            self.running = False

    def handle_yield(self, yielded):
        # handle_yield 方法会对 coroutine yield 的结果进行转化,进而判断 yield
        # 的异步执行的代码是否已经执行完毕并且已经得到了结果,如果没有,则将相
        # 应得 future 对象放到 Event Loop 中,等待下一次 Event Loop
        # 执行到时再判断执行结果

        # Lists containing YieldPoints require stack contexts;
        # other lists are handled in convert_yielded.
        if _contains_yieldpoint(yielded):
            # 如果 coroutine yield 的结果中包含 YieldPoint,则用 stack context
            # 将其包装一次
            yielded = multi(yielded)

        if isinstance(yielded, YieldPoint):
            # YieldPoints are too closely coupled to the Runner to go
            # through the generic convert_yielded mechanism.
            self.future = TracebackFuture()

            def start_yield_point():
                try:
                    yielded.start(self)
                    if yielded.is_ready():
                        self.future.set_result(yielded.get_result())
                    else:
                        self.yield_point = yielded
                except Exception:
                    self.future = TracebackFuture()
                    self.future.set_exc_info(sys.exc_info())

            if self.stack_context_deactivate is None:
                # Start a stack context if this is the first
                # YieldPoint we've seen.
                with stack_context.ExceptionStackContext(
                        self.handle_exception) as deactivate:
                    self.stack_context_deactivate = deactivate

                    def cb():
                        start_yield_point()
                        self.run()

                    self.io_loop.add_callback(cb)
                    return False
            else:
                start_yield_point()
        else:
            # 经过前面的处理,YieldPoint 都已经被正确包装、转化,接下来就可以将
            # coroutine yield 的内容转化成一个 future 对象。
            try:
                self.future = convert_yielded(yielded)
            except BadYieldError:
                self.future = TracebackFuture()
                self.future.set_exc_info(sys.exc_info())

        if not self.future.done() or self.future is moment:
            # 如果 future 还没有收到结果,不是 done 的状态,则将其添加到 IOLoop
            # 实例中,在后续某一次 Event Loop 中,future 被赋予了结果后再去执行
            # run 方法,从而让 coroutine 获得结果并继续执行下去。
            self.io_loop.add_future(self.future, lambda f: self.run())
            # 这时便不用去执行 run 方法去获得 future 中的结果并反馈给 coroutine
            # 了,一切都等到之后的 Event Loop 中见分晓。
            return False

        # Future 对象这个时候已经有了结果,便可以去执行 run 方法,并将结果反馈给
        # coroutine,让之继续后面的执行绪了。
        return True

    def result_callback(self, key):
        return stack_context.wrap(
            _argument_adapter(functools.partial(self.set_result, key)))

    def handle_exception(self, typ, value, tb):
        if not self.running and not self.finished:
            self.future = TracebackFuture()
            self.future.set_exc_info((typ, value, tb))
            self.run()
            return True
        else:
            return False

    def _deactivate_stack_context(self):
        if self.stack_context_deactivate is not None:
            self.stack_context_deactivate()
            self.stack_context_deactivate = None
示例#59
0
    def wrapper(*args, **kwargs):
        future = TracebackFuture()  # 一个future的跟踪对象,这个是关键

        # 原来的func不支持callback的参数,修饰之后是可以使用的
        # 下面的这个future好好读懂,然后好好理解传说中的future功能
        if replace_callback and 'callback' in kwargs:
            callback = kwargs.pop('callback')

            # 就是future成功了,执行lambda future: callback(future.result())函数,参数就是这个future
            # 也就是把这个可能执行的语句放到IOLoop里面去,这个就是这个add_future的功能
            IOLoop.current().add_future(
                future, lambda future: callback(future.result()))

        # 异步的HTTP和异步的IOStream也许返回的类型不一样,
        # 感觉两个异步的东西才是tornado的关键
        try:
            # 尝试运行函数,这里会yield出来,所以不会被阻塞的
            # 1. 返回一个Return 2. 返回一个StopIteration(这个不是很清楚??)
            # 3. 返回一个Exception?就是运行错误了
            result = func(*args, **kwargs)
        except (Return, StopIteration) as e:
            # 到这里说明结果已经出来了,future的任务结束了
            # ?StopIteration无法理解
            result = getattr(e, 'value', None)
        except Exception:  # 如果出错的话
            # 运行出错了,这个时候依旧会添加到IOLoop._callbacks
            # 下面这句话执行这个future全部的回调
            future.set_exc_info(sys.exc_info())
            return future  # 一但结果确定,直接返回一个future
        else:
            # 如果内部有yield,直接返回一个types.GeneratorType
            if isinstance(result, types.GeneratorType):
                # Inline the first iteration of Runner.run.  This lets us
                # avoid the cost of creating a Runner when the coroutine
                # never actually yields, which in turn allows us to
                # use "optional" coroutines in critical path code without
                # performance penalty for the synchronous case.
                try:
                    orig_stack_contexts = stack_context._state.contexts

                    # 这里是获取yield的结果的地方,一般还是一个future的东西
                    yielded = next(result)  # 获取yield的结果,这里一般是一个future类型yield出来的东西

                    # 先忽略下面的出错处理
                    if stack_context._state.contexts is not orig_stack_contexts:
                        yielded = TracebackFuture()
                        yielded.set_exception(
                            stack_context.StackContextInconsistentError(
                                'stack_context inconsistency (probably caused '
                                'by yield within a "with StackContext" block)'))
                except (StopIteration, Return) as e:  # 直接出结果
                    future.set_result(getattr(e, 'value', None))
                except Exception:  # bug了
                    future.set_exc_info(sys.exc_info())
                else:  # 返回一个future
                    Runner(result, future, yielded)

                # 如果是一个Exception,这里记录到future,然后返回了
                return future
        future.set_result(result)  # 这个时候添加回调到了IOLoop
        return future