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 |