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