| # Copyright 2015 The Chromium Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| import itertools | |
| import sys | |
| import mojo_system | |
| from mojo_bindings import promise | |
| class DataPipeCopyException(Exception): | |
| def __init__(self, *args, **kwargs): | |
| Exception.__init__(self, *args, **kwargs) | |
| self.__traceback__ = sys.exc_info()[2] | |
| def CopyFromDataPipe(data_pipe, deadline): | |
| """ | |
| Returns a Promise that operates as follows: | |
| - If |data_pipe| is successfully read from, the promise resolves with the | |
| bytes that were read. | |
| - Otherwise, the promise rejects with an exception whose message contains the | |
| status from the attempted read. | |
| """ | |
| class DataPipeCopyHelper(): | |
| def __init__(self, data_pipe, deadline, resolve, reject): | |
| self.data_pipe = data_pipe | |
| self.original_deadline = deadline | |
| self.start_time = mojo_system.GetTimeTicksNow() | |
| self.resolve = resolve | |
| self.reject = reject | |
| self.buffer_size = 1024 | |
| self.data = bytearray(self.buffer_size) | |
| self.index = 0 | |
| def _ComputeCurrentDeadline(self): | |
| if self.original_deadline == mojo_system.DEADLINE_INDEFINITE: | |
| return self.original_deadline | |
| elapsed_time = mojo_system.GetTimeTicksNow() - self.start_time | |
| return max(0, self.original_deadline - elapsed_time) | |
| def CopyFromDataPipeAsync(self, result): | |
| while result == mojo_system.RESULT_OK: | |
| assert self.index <= len(self.data) | |
| if self.index == len(self.data): | |
| self.buffer_size *= 2 | |
| self.data.extend(itertools.repeat(0, self.buffer_size)) | |
| # Careful! Have to construct a memoryview object here as otherwise the | |
| # slice operation will create a copy of |data| and hence not write into | |
| # |data| as desired. | |
| result, read_bytes = self.data_pipe.ReadData( | |
| memoryview(self.data)[self.index:]) | |
| if read_bytes: | |
| self.index += len(read_bytes) | |
| del read_bytes | |
| if result == mojo_system.RESULT_SHOULD_WAIT: | |
| data_pipe.AsyncWait(mojo_system.HANDLE_SIGNAL_READABLE, | |
| self._ComputeCurrentDeadline(), | |
| self.CopyFromDataPipeAsync) | |
| return | |
| # Treat a failed precondition as EOF. | |
| if result == mojo_system.RESULT_FAILED_PRECONDITION: | |
| self.resolve(self.data[:self.index]) | |
| return | |
| self.reject(DataPipeCopyException("Result: %d" % result)) | |
| def GenerationMethod(resolve, reject): | |
| helper = DataPipeCopyHelper(data_pipe, deadline, resolve, reject) | |
| helper.CopyFromDataPipeAsync(mojo_system.RESULT_OK) | |
| return promise.Promise(GenerationMethod) |