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 |