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