Home | History | Annotate | Download | only in js
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/edk/js/drain_data.h"
      6 
      7 #include <stddef.h>
      8 #include <stdint.h>
      9 
     10 #include "base/bind.h"
     11 #include "gin/array_buffer.h"
     12 #include "gin/converter.h"
     13 #include "gin/dictionary.h"
     14 #include "gin/per_context_data.h"
     15 #include "gin/per_isolate_data.h"
     16 #include "mojo/public/cpp/system/core.h"
     17 
     18 namespace mojo {
     19 namespace edk {
     20 namespace js {
     21 
     22 DrainData::DrainData(v8::Isolate* isolate, mojo::Handle handle)
     23     : isolate_(isolate), handle_(DataPipeConsumerHandle(handle.value())) {
     24   v8::Handle<v8::Context> context(isolate_->GetCurrentContext());
     25   runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
     26 
     27   WaitForData();
     28 }
     29 
     30 v8::Handle<v8::Value> DrainData::GetPromise() {
     31   CHECK(resolver_.IsEmpty());
     32   v8::Handle<v8::Promise::Resolver> resolver(
     33       v8::Promise::Resolver::New(isolate_));
     34   resolver_.Reset(isolate_, resolver);
     35   return resolver->GetPromise();
     36 }
     37 
     38 DrainData::~DrainData() {
     39   resolver_.Reset();
     40 }
     41 
     42 void DrainData::WaitForData() {
     43   handle_watcher_.Start(
     44       handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
     45       base::Bind(&DrainData::DataReady, base::Unretained(this)));
     46 }
     47 
     48 void DrainData::DataReady(MojoResult result) {
     49   if (result != MOJO_RESULT_OK) {
     50     DeliverData(result);
     51     return;
     52   }
     53   while (result == MOJO_RESULT_OK) {
     54     result = ReadData();
     55     if (result == MOJO_RESULT_SHOULD_WAIT)
     56       WaitForData();
     57     else if (result != MOJO_RESULT_OK)
     58       DeliverData(result);
     59   }
     60 }
     61 
     62 MojoResult DrainData::ReadData() {
     63   const void* buffer;
     64   uint32_t num_bytes = 0;
     65   MojoResult result = BeginReadDataRaw(
     66       handle_.get(), &buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
     67   if (result != MOJO_RESULT_OK)
     68     return result;
     69   const char* p = static_cast<const char*>(buffer);
     70   DataBuffer* data_buffer = new DataBuffer(p, p + num_bytes);
     71   data_buffers_.push_back(data_buffer);
     72   return EndReadDataRaw(handle_.get(), num_bytes);
     73 }
     74 
     75 void DrainData::DeliverData(MojoResult result) {
     76   if (!runner_) {
     77     delete this;
     78     return;
     79   }
     80 
     81   size_t total_bytes = 0;
     82   for (unsigned i = 0; i < data_buffers_.size(); i++)
     83     total_bytes += data_buffers_[i]->size();
     84 
     85   // Create a total_bytes length ArrayBuffer return value.
     86   gin::Runner::Scope scope(runner_.get());
     87   v8::Handle<v8::ArrayBuffer> array_buffer =
     88       v8::ArrayBuffer::New(isolate_, total_bytes);
     89   gin::ArrayBuffer buffer;
     90   ConvertFromV8(isolate_, array_buffer, &buffer);
     91   CHECK_EQ(total_bytes, buffer.num_bytes());
     92 
     93   // Copy the data_buffers into the ArrayBuffer.
     94   char* array_buffer_ptr = static_cast<char*>(buffer.bytes());
     95   size_t offset = 0;
     96   for (size_t i = 0; i < data_buffers_.size(); i++) {
     97     size_t num_bytes = data_buffers_[i]->size();
     98     if (num_bytes == 0)
     99       continue;
    100     const char* data_buffer_ptr = &((*data_buffers_[i])[0]);
    101     memcpy(array_buffer_ptr + offset, data_buffer_ptr, num_bytes);
    102     offset += num_bytes;
    103   }
    104 
    105   // The "settled" value of the promise always includes all of the data
    106   // that was read before either an error occurred or the remote pipe handle
    107   // was closed. The latter is indicated by MOJO_RESULT_FAILED_PRECONDITION.
    108 
    109   v8::Handle<v8::Promise::Resolver> resolver(
    110       v8::Local<v8::Promise::Resolver>::New(isolate_, resolver_));
    111 
    112   gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate_);
    113   dictionary.Set("result", result);
    114   dictionary.Set("buffer", array_buffer);
    115   v8::Handle<v8::Value> settled_value(ConvertToV8(isolate_, dictionary));
    116 
    117   if (result == MOJO_RESULT_FAILED_PRECONDITION)
    118     resolver->Resolve(settled_value);
    119   else
    120     resolver->Reject(settled_value);
    121 
    122   delete this;
    123 }
    124 
    125 }  // namespace js
    126 }  // namespace edk
    127 }  // namespace mojo
    128