| OLD | NEW |
| (Empty) |
| 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<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<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, | |
| 234 gin::Handle<HandleWrapper> handle) { | |
| 235 return (new DrainData(args->isolate(), handle->release()))->GetPromise(); | |
| 236 } | |
| 237 | |
| 238 gin::WrapperInfo g_wrapper_info = { gin::kEmbedderNativeGin }; | |
| 239 | |
| 240 } // namespace | |
| 241 | |
| 242 const char Core::kModuleName[] = "mojo/public/js/bindings/core"; | |
| 243 | |
| 244 v8::Local<v8::Value> Core::GetModule(v8::Isolate* isolate) { | |
| 245 gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); | |
| 246 v8::Local<v8::ObjectTemplate> templ = data->GetObjectTemplate( | |
| 247 &g_wrapper_info); | |
| 248 | |
| 249 if (templ.IsEmpty()) { | |
| 250 templ = gin::ObjectTemplateBuilder(isolate) | |
| 251 // TODO(mpcomplete): Should these just be methods on the JS Handle | |
| 252 // object? | |
| 253 .SetMethod("close", CloseHandle) | |
| 254 .SetMethod("wait", WaitHandle) | |
| 255 .SetMethod("waitMany", WaitMany) | |
| 256 .SetMethod("createMessagePipe", CreateMessagePipe) | |
| 257 .SetMethod("writeMessage", WriteMessage) | |
| 258 .SetMethod("readMessage", ReadMessage) | |
| 259 .SetMethod("createDataPipe", CreateDataPipe) | |
| 260 .SetMethod("writeData", WriteData) | |
| 261 .SetMethod("readData", ReadData) | |
| 262 .SetMethod("drainData", DoDrainData) | |
| 263 | |
| 264 .SetValue("RESULT_OK", MOJO_RESULT_OK) | |
| 265 .SetValue("RESULT_CANCELLED", MOJO_RESULT_CANCELLED) | |
| 266 .SetValue("RESULT_UNKNOWN", MOJO_RESULT_UNKNOWN) | |
| 267 .SetValue("RESULT_INVALID_ARGUMENT", MOJO_RESULT_INVALID_ARGUMENT) | |
| 268 .SetValue("RESULT_DEADLINE_EXCEEDED", MOJO_RESULT_DEADLINE_EXCEEDED) | |
| 269 .SetValue("RESULT_NOT_FOUND", MOJO_RESULT_NOT_FOUND) | |
| 270 .SetValue("RESULT_ALREADY_EXISTS", MOJO_RESULT_ALREADY_EXISTS) | |
| 271 .SetValue("RESULT_PERMISSION_DENIED", MOJO_RESULT_PERMISSION_DENIED) | |
| 272 .SetValue("RESULT_RESOURCE_EXHAUSTED", MOJO_RESULT_RESOURCE_EXHAUSTED) | |
| 273 .SetValue("RESULT_FAILED_PRECONDITION", MOJO_RESULT_FAILED_PRECONDITION) | |
| 274 .SetValue("RESULT_ABORTED", MOJO_RESULT_ABORTED) | |
| 275 .SetValue("RESULT_OUT_OF_RANGE", MOJO_RESULT_OUT_OF_RANGE) | |
| 276 .SetValue("RESULT_UNIMPLEMENTED", MOJO_RESULT_UNIMPLEMENTED) | |
| 277 .SetValue("RESULT_INTERNAL", MOJO_RESULT_INTERNAL) | |
| 278 .SetValue("RESULT_UNAVAILABLE", MOJO_RESULT_UNAVAILABLE) | |
| 279 .SetValue("RESULT_DATA_LOSS", MOJO_RESULT_DATA_LOSS) | |
| 280 .SetValue("RESULT_BUSY", MOJO_RESULT_BUSY) | |
| 281 .SetValue("RESULT_SHOULD_WAIT", MOJO_RESULT_SHOULD_WAIT) | |
| 282 | |
| 283 .SetValue("DEADLINE_INDEFINITE", MOJO_DEADLINE_INDEFINITE) | |
| 284 | |
| 285 .SetValue("HANDLE_SIGNAL_NONE", MOJO_HANDLE_SIGNAL_NONE) | |
| 286 .SetValue("HANDLE_SIGNAL_READABLE", MOJO_HANDLE_SIGNAL_READABLE) | |
| 287 .SetValue("HANDLE_SIGNAL_WRITABLE", MOJO_HANDLE_SIGNAL_WRITABLE) | |
| 288 | |
| 289 .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE", | |
| 290 MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE) | |
| 291 | |
| 292 .SetValue("WRITE_MESSAGE_FLAG_NONE", MOJO_WRITE_MESSAGE_FLAG_NONE) | |
| 293 | |
| 294 .SetValue("READ_MESSAGE_FLAG_NONE", MOJO_READ_MESSAGE_FLAG_NONE) | |
| 295 .SetValue("READ_MESSAGE_FLAG_MAY_DISCARD", | |
| 296 MOJO_READ_MESSAGE_FLAG_MAY_DISCARD) | |
| 297 | |
| 298 .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_NONE", | |
| 299 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE) | |
| 300 .SetValue("CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD", | |
| 301 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD) | |
| 302 | |
| 303 .SetValue("WRITE_DATA_FLAG_NONE", MOJO_WRITE_DATA_FLAG_NONE) | |
| 304 .SetValue("WRITE_DATA_FLAG_ALL_OR_NONE", | |
| 305 MOJO_WRITE_DATA_FLAG_ALL_OR_NONE) | |
| 306 | |
| 307 .SetValue("READ_DATA_FLAG_NONE", MOJO_READ_DATA_FLAG_NONE) | |
| 308 .SetValue("READ_DATA_FLAG_ALL_OR_NONE", | |
| 309 MOJO_READ_DATA_FLAG_ALL_OR_NONE) | |
| 310 .SetValue("READ_DATA_FLAG_DISCARD", MOJO_READ_DATA_FLAG_DISCARD) | |
| 311 .SetValue("READ_DATA_FLAG_QUERY", MOJO_READ_DATA_FLAG_QUERY) | |
| 312 .Build(); | |
| 313 | |
| 314 data->SetObjectTemplate(&g_wrapper_info, templ); | |
| 315 } | |
| 316 | |
| 317 return templ->NewInstance(); | |
| 318 } | |
| 319 | |
| 320 } // namespace js | |
| 321 } // namespace mojo | |
| OLD | NEW |