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/core.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "gin/arguments.h"
     10 #include "gin/array_buffer.h"
     11 #include "gin/converter.h"
     12 #include "gin/dictionary.h"
     13 #include "gin/function_template.h"
     14 #include "gin/handle.h"
     15 #include "gin/object_template_builder.h"
     16 #include "gin/per_isolate_data.h"
     17 #include "gin/public/wrapper_info.h"
     18 #include "gin/wrappable.h"
     19 #include "mojo/bindings/js/drain_data.h"
     20 #include "mojo/bindings/js/handle.h"
     21 
     22 namespace mojo {
     23 namespace js {
     24 
     25 namespace {
     26 
     27 MojoResult CloseHandle(gin::Handle<gin::HandleWrapper> handle) {
     28   if (!handle->get().is_valid())
     29     return MOJO_RESULT_INVALID_ARGUMENT;
     30   handle->Close();
     31   return MOJO_RESULT_OK;
     32 }
     33 
     34 MojoResult WaitHandle(mojo::Handle handle,
     35                       MojoHandleSignals signals,
     36                       MojoDeadline deadline) {
     37   return MojoWait(handle.value(), signals, deadline);
     38 }
     39 
     40 MojoResult WaitMany(
     41     const std::vector<mojo::Handle>& handles,
     42     const std::vector<MojoHandleSignals>& signals,
     43     MojoDeadline deadline) {
     44   return mojo::WaitMany(handles, signals, deadline);
     45 }
     46 
     47 gin::Dictionary CreateMessagePipe(const gin::Arguments& args) {
     48   gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
     49   dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
     50 
     51   MojoHandle handle0 = MOJO_HANDLE_INVALID;
     52   MojoHandle handle1 = MOJO_HANDLE_INVALID;
     53   MojoResult result = MOJO_RESULT_OK;
     54 
     55   v8::Handle<v8::Value> options_value = args.PeekNext();
     56   if (options_value.IsEmpty() || options_value->IsNull() ||
     57       options_value->IsUndefined()) {
     58     result = MojoCreateMessagePipe(NULL, &handle0, &handle1);
     59   } else if (options_value->IsObject()) {
     60     gin::Dictionary options_dict(args.isolate(), options_value->ToObject());
     61     MojoCreateMessagePipeOptions options;
     62     // For future struct_size, we can probably infer that from the presence of
     63     // properties in options_dict. For now, it's always 8.
     64     options.struct_size = 8;
     65     // Ideally these would be optional. But the interface makes it hard to
     66     // typecheck them then.
     67     if (!options_dict.Get("flags", &options.flags)) {
     68       return dictionary;
     69     }
     70 
     71     result = MojoCreateMessagePipe(&options, &handle0, &handle1);
     72   } else {
     73       return dictionary;
     74   }
     75 
     76   CHECK_EQ(MOJO_RESULT_OK, result);
     77 
     78   dictionary.Set("result", result);
     79   dictionary.Set("handle0", mojo::Handle(handle0));
     80   dictionary.Set("handle1", mojo::Handle(handle1));
     81   return dictionary;
     82 }
     83 
     84 MojoResult WriteMessage(
     85     mojo::Handle handle,
     86     const gin::ArrayBufferView& buffer,
     87     const std::vector<gin::Handle<gin::HandleWrapper> >& handles,
     88     MojoWriteMessageFlags flags) {
     89   std::vector<MojoHandle> raw_handles(handles.size());
     90   for (size_t i = 0; i < handles.size(); ++i)
     91     raw_handles[i] = handles[i]->get().value();
     92   MojoResult rv = MojoWriteMessage(handle.value(),
     93                           buffer.bytes(),
     94                           static_cast<uint32_t>(buffer.num_bytes()),
     95                           raw_handles.empty() ? NULL : &raw_handles[0],
     96                           static_cast<uint32_t>(raw_handles.size()),
     97                           flags);
     98   // MojoWriteMessage takes ownership of the handles upon success, so
     99   // release them here.
    100   if (rv == MOJO_RESULT_OK) {
    101     for (size_t i = 0; i < handles.size(); ++i)
    102       ignore_result(handles[i]->release());
    103   }
    104   return rv;
    105 }
    106 
    107 gin::Dictionary ReadMessage(const gin::Arguments& args,
    108                             mojo::Handle handle,
    109                             MojoReadMessageFlags flags) {
    110   uint32_t num_bytes = 0;
    111   uint32_t num_handles = 0;
    112   MojoResult result = MojoReadMessage(
    113       handle.value(), NULL, &num_bytes, NULL, &num_handles, flags);
    114   if (result != MOJO_RESULT_RESOURCE_EXHAUSTED) {
    115     gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
    116     dictionary.Set("result", result);
    117     return dictionary;
    118   }
    119 
    120   v8::Handle<v8::ArrayBuffer> array_buffer =
    121       v8::ArrayBuffer::New(args.isolate(), num_bytes);
    122   std::vector<mojo::Handle> handles(num_handles);
    123 
    124   gin::ArrayBuffer buffer;
    125   ConvertFromV8(args.isolate(), array_buffer, &buffer);
    126   CHECK(buffer.num_bytes() == num_bytes);
    127 
    128   result = MojoReadMessage(handle.value(),
    129                            buffer.bytes(),
    130                            &num_bytes,
    131                            handles.empty() ? NULL :
    132                                reinterpret_cast<MojoHandle*>(&handles[0]),
    133                            &num_handles,
    134                            flags);
    135 
    136   CHECK(buffer.num_bytes() == num_bytes);
    137   CHECK(handles.size() == num_handles);
    138 
    139   gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
    140   dictionary.Set("result", result);
    141   dictionary.Set("buffer", array_buffer);
    142   dictionary.Set("handles", handles);
    143   return dictionary;
    144 }
    145 
    146 gin::Dictionary CreateDataPipe(const gin::Arguments& args) {
    147   gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
    148   dictionary.Set("result", MOJO_RESULT_INVALID_ARGUMENT);
    149 
    150   MojoHandle producer_handle = MOJO_HANDLE_INVALID;
    151   MojoHandle consumer_handle = MOJO_HANDLE_INVALID;
    152   MojoResult result = MOJO_RESULT_OK;
    153 
    154   v8::Handle<v8::Value> options_value = args.PeekNext();
    155   if (options_value.IsEmpty() || options_value->IsNull() ||
    156       options_value->IsUndefined()) {
    157     result = MojoCreateDataPipe(NULL, &producer_handle, &consumer_handle);
    158   } else if (options_value->IsObject()) {
    159     gin::Dictionary options_dict(args.isolate(), options_value->ToObject());
    160     MojoCreateDataPipeOptions options;
    161     // For future struct_size, we can probably infer that from the presence of
    162     // properties in options_dict. For now, it's always 16.
    163     options.struct_size = 16;
    164     // Ideally these would be optional. But the interface makes it hard to
    165     // typecheck them then.
    166     if (!options_dict.Get("flags", &options.flags) ||
    167         !options_dict.Get("elementNumBytes", &options.element_num_bytes) ||
    168         !options_dict.Get("capacityNumBytes", &options.capacity_num_bytes)) {
    169       return dictionary;
    170     }
    171 
    172     result = MojoCreateDataPipe(&options, &producer_handle, &consumer_handle);
    173   } else {
    174     return dictionary;
    175   }
    176 
    177   CHECK_EQ(MOJO_RESULT_OK, result);
    178 
    179   dictionary.Set("result", result);
    180   dictionary.Set("producerHandle", mojo::Handle(producer_handle));
    181   dictionary.Set("consumerHandle", mojo::Handle(consumer_handle));
    182   return dictionary;
    183 }
    184 
    185 gin::Dictionary WriteData(const gin::Arguments& args,
    186                           mojo::Handle handle,
    187                           const gin::ArrayBufferView& buffer,
    188                           MojoWriteDataFlags flags) {
    189   uint32_t num_bytes = static_cast<uint32_t>(buffer.num_bytes());
    190   MojoResult result =
    191       MojoWriteData(handle.value(), buffer.bytes(), &num_bytes, flags);
    192   gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
    193   dictionary.Set("result", result);
    194   dictionary.Set("numBytes", num_bytes);
    195   return dictionary;
    196 }
    197 
    198 gin::Dictionary ReadData(const gin::Arguments& args,
    199                          mojo::Handle handle,
    200                          MojoReadDataFlags flags) {
    201   uint32_t num_bytes = 0;
    202   MojoResult result = MojoReadData(
    203       handle.value(), NULL, &num_bytes, MOJO_READ_DATA_FLAG_QUERY);
    204   if (result != MOJO_RESULT_OK) {
    205     gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
    206     dictionary.Set("result", result);
    207     return dictionary;
    208   }
    209 
    210   v8::Handle<v8::ArrayBuffer> array_buffer =
    211       v8::ArrayBuffer::New(args.isolate(), num_bytes);
    212   gin::ArrayBuffer buffer;
    213   ConvertFromV8(args.isolate(), array_buffer, &buffer);
    214   CHECK_EQ(num_bytes, buffer.num_bytes());
    215 
    216   result = MojoReadData(handle.value(), buffer.bytes(), &num_bytes, flags);
    217   CHECK_EQ(num_bytes, buffer.num_bytes());
    218 
    219   gin::Dictionary dictionary = gin::Dictionary::CreateEmpty(args.isolate());
    220   dictionary.Set("result", result);
    221   dictionary.Set("buffer", array_buffer);
    222   return dictionary;
    223 }
    224 
    225 // Asynchronously read all of the data available for the specified data pipe
    226 // consumer handle until the remote handle is closed or an error occurs. A
    227 // Promise is returned whose settled value is an object like this:
    228 // {result: core.RESULT_OK, buffer: dataArrayBuffer}. If the read failed,
    229 // then the Promise is rejected, the result will be the actual error code,
    230 // and the buffer will contain whatever was read before the error occurred.
    231 // The drainData data pipe handle argument is closed automatically.
    232 
    233 v8::Handle<v8::Value> DoDrainData(gin::Arguments* args, mojo::Handle handle) {
    234   return (new DrainData(args->isolate(), handle))->GetPromise();
    235 }
    236 
    237 gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin };
    238 
    239 }  // namespace
    240 
    241 const char Core::kModuleName[] = "mojo/public/js/bindings/core";
    242 
    243 v8::Local<v8::Value> Core::GetModule(v8::Isolate* isolate) {
    244   gin::PerIsolateData* data = gin::PerIsolateData::From(isolate);
    245   v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate(
    246       &g_wrapper_info);
    247 
    248   if (templ.IsEmpty()) {
    249      templ = gin::ObjectTemplateBuilder(isolate)
    250         // TODO(mpcomplete): Should these just be methods on the JS Handle
    251         // object?
    252         .SetMethod("close", CloseHandle)
    253         .SetMethod("wait", WaitHandle)
    254         .SetMethod("waitMany", WaitMany)
    255         .SetMethod("createMessagePipe", CreateMessagePipe)
    256         .SetMethod("writeMessage", WriteMessage)
    257         .SetMethod("readMessage", ReadMessage)
    258         .SetMethod("createDataPipe", CreateDataPipe)
    259         .SetMethod("writeData", WriteData)
    260         .SetMethod("readData", ReadData)
    261         .SetMethod("drainData", DoDrainData)
    262 
    263         .SetValue("RESULT_OK", MOJO_RESULT_OK)
    264         .SetValue("RESULT_CANCELLED", MOJO_RESULT_CANCELLED)
    265         .SetValue("RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN)
    266         .SetValue("RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT)
    267         .SetValue("RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED)
    268         .SetValue("RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND)
    269         .SetValue("RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS)
    270         .SetValue("RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED)
    271         .SetValue("RESULT_RESOURCE_EXHAUSTED", MOJO_RESULT_RESOURCE_EXHAUSTED)
    272         .SetValue("RESULT_FAILED_PRECONDITION", MOJO_RESULT_FAILED_PRECONDITION)
    273         .SetValue("RESULT_ABORTED", MOJO_RESULT_ABORTED)
    274         .SetValue("RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE)
    275         .SetValue("RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED)
    276         .SetValue("RESULT_INTERNAL", MOJO_RESULT_INTERNAL)
    277         .SetValue("RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE)
    278         .SetValue("RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS)
    279         .SetValue("RESULT_BUSY", MOJO_RESULT_BUSY)
    280         .SetValue("RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT)
    281 
    282         .SetValue("DEADLINE_INDEFINITE", MOJO_DEADLINE_INDEFINITE)
    283 
    284         .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE)
    285         .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE)
    286         .SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE)
    287 
    288         .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE",
    289                   MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE)
    290 
    291         .SetValue("WRITE_MESSAGE_FLAG_NONE", MOJO_WRITE_MESSAGE_FLAG_NONE)
    292 
    293         .SetValue("READ_MESSAGE_FLAG_NONE", MOJO_READ_MESSAGE_FLAG_NONE)
    294         .SetValue("READ_MESSAGE_FLAG_MAY_DISCARD",
    295                   MOJO_READ_MESSAGE_FLAG_MAY_DISCARD)
    296 
    297         .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_NONE",
    298                   MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE)
    299         .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD",
    300                   MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD)
    301 
    302         .SetValue("WRITE_DATA_FLAG_NONE", MOJO_WRITE_DATA_FLAG_NONE)
    303         .SetValue("WRITE_DATA_FLAG_ALL_OR_NONE",
    304                   MOJO_WRITE_DATA_FLAG_ALL_OR_NONE)
    305 
    306         .SetValue("READ_DATA_FLAG_NONE", MOJO_READ_DATA_FLAG_NONE)
    307         .SetValue("READ_DATA_FLAG_ALL_OR_NONE",
    308                   MOJO_READ_DATA_FLAG_ALL_OR_NONE)
    309         .SetValue("READ_DATA_FLAG_DISCARD", MOJO_READ_DATA_FLAG_DISCARD)
    310         .SetValue("READ_DATA_FLAG_QUERY", MOJO_READ_DATA_FLAG_QUERY)
    311         .Build();
    312 
    313     data->SetObjectTemplate(&g_wrapper_info, templ);
    314   }
    315 
    316   return templ->NewInstance();
    317 }
    318 
    319 }  // namespace js
    320 }  // namespace mojo
    321