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