1645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Copyright 2014 The Chromium Authors. All rights reserved.
2645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// Use of this source code is governed by a BSD-style license that can be
3645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez// found in the LICENSE file.
4645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
5645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/edk/js/drain_data.h"
6645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
7645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stddef.h>
8645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include <stdint.h>
9645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
10645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "base/bind.h"
11645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "gin/array_buffer.h"
12645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "gin/converter.h"
13645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "gin/dictionary.h"
14645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "gin/per_context_data.h"
15645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "gin/per_isolate_data.h"
16645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez#include "mojo/public/cpp/system/core.h"
17645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
18645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace mojo {
19645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace edk {
20645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chaveznamespace js {
21645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
22645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezDrainData::DrainData(v8::Isolate* isolate, mojo::Handle handle)
23645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    : isolate_(isolate), handle_(DataPipeConsumerHandle(handle.value())) {
24645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  v8::Handle<v8::Context> context(isolate_->GetCurrentContext());
25645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  runner_ = gin::PerContextData::From(context)->runner()->GetWeakPtr();
26645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
27645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  WaitForData();
28645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
29645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
30645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezv8::Handle<v8::Value> DrainData::GetPromise() {
31645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK(resolver_.IsEmpty());
32645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  v8::Handle<v8::Promise::Resolver> resolver(
33645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      v8::Promise::Resolver::New(isolate_));
34645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  resolver_.Reset(isolate_, resolver);
35645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return resolver->GetPromise();
36645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
37645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
38645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezDrainData::~DrainData() {
39645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  resolver_.Reset();
40645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
41645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
42645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid DrainData::WaitForData() {
43645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  handle_watcher_.Start(
44645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      handle_.get(), MOJO_HANDLE_SIGNAL_READABLE,
45645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      base::Bind(&DrainData::DataReady, base::Unretained(this)));
46645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
47645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
48645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid DrainData::DataReady(MojoResult result) {
49645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (result != MOJO_RESULT_OK) {
50645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    DeliverData(result);
51645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
52645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
53645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  while (result == MOJO_RESULT_OK) {
54645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    result = ReadData();
55645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (result == MOJO_RESULT_SHOULD_WAIT)
56645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      WaitForData();
57645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    else if (result != MOJO_RESULT_OK)
58645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      DeliverData(result);
59645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
60645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
61645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
62645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector ChavezMojoResult DrainData::ReadData() {
63645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const void* buffer;
64645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  uint32_t num_bytes = 0;
65645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  MojoResult result = BeginReadDataRaw(
66645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      handle_.get(), &buffer, &num_bytes, MOJO_READ_DATA_FLAG_NONE);
67645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (result != MOJO_RESULT_OK)
68645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return result;
69645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  const char* p = static_cast<const char*>(buffer);
70645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  DataBuffer* data_buffer = new DataBuffer(p, p + num_bytes);
71645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  data_buffers_.push_back(data_buffer);
72645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  return EndReadDataRaw(handle_.get(), num_bytes);
73645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
74645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
75645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavezvoid DrainData::DeliverData(MojoResult result) {
76645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (!runner_) {
77645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    delete this;
78645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    return;
79645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
80645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
81645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t total_bytes = 0;
82645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (unsigned i = 0; i < data_buffers_.size(); i++)
83645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    total_bytes += data_buffers_[i]->size();
84645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
85645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Create a total_bytes length ArrayBuffer return value.
86645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  gin::Runner::Scope scope(runner_.get());
87645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  v8::Handle<v8::ArrayBuffer> array_buffer =
88645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      v8::ArrayBuffer::New(isolate_, total_bytes);
89645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  gin::ArrayBuffer buffer;
90645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  ConvertFromV8(isolate_, array_buffer, &buffer);
91645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  CHECK_EQ(total_bytes, buffer.num_bytes());
92645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
93645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // Copy the data_buffers into the ArrayBuffer.
94645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  char* array_buffer_ptr = static_cast<char*>(buffer.bytes());
95645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  size_t offset = 0;
96645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  for (size_t i = 0; i < data_buffers_.size(); i++) {
97645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    size_t num_bytes = data_buffers_[i]->size();
98645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    if (num_bytes == 0)
99645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      continue;
100645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    const char* data_buffer_ptr = &((*data_buffers_[i])[0]);
101645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    memcpy(array_buffer_ptr + offset, data_buffer_ptr, num_bytes);
102645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    offset += num_bytes;
103645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  }
104645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
105645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // The "settled" value of the promise always includes all of the data
106645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // that was read before either an error occurred or the remote pipe handle
107645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  // was closed. The latter is indicated by MOJO_RESULT_FAILED_PRECONDITION.
108645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
109645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  v8::Handle<v8::Promise::Resolver> resolver(
110645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez      v8::Local<v8::Promise::Resolver>::New(isolate_, resolver_));
111645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
112645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(isolate_);
113645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  dictionary.Set("result", result);
114645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  dictionary.Set("buffer", array_buffer);
115645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  v8::Handle<v8::Value> settled_value(ConvertToV8(isolate_, dictionary));
116645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
117645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  if (result == MOJO_RESULT_FAILED_PRECONDITION)
118645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    resolver->Resolve(settled_value);
119645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  else
120645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez    resolver->Reject(settled_value);
121645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
122645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez  delete this;
123645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}
124645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez
125645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace js
126645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace edk
127645501c2ab19a559ce82a1d5a29ced159a4c30fbLuis Hector Chavez}  // namespace mojo
128