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.
5 #include "mojo/bindings/js/core.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"
27 MojoResult
CloseHandle(gin::Handle
<HandleWrapper
> handle
) {
28 if (!handle
->get().is_valid())
29 return MOJO_RESULT_INVALID_ARGUMENT
;
31 return MOJO_RESULT_OK
;
34 MojoResult
WaitHandle(mojo::Handle handle
,
35 MojoHandleSignals signals
,
36 MojoDeadline deadline
) {
37 return MojoWait(handle
.value(), signals
, deadline
);
41 const std::vector
<mojo::Handle
>& handles
,
42 const std::vector
<MojoHandleSignals
>& signals
,
43 MojoDeadline deadline
) {
44 return mojo::WaitMany(handles
, signals
, deadline
);
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
);
51 MojoHandle handle0
= MOJO_HANDLE_INVALID
;
52 MojoHandle handle1
= MOJO_HANDLE_INVALID
;
53 MojoResult result
= MOJO_RESULT_OK
;
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
)) {
71 result
= MojoCreateMessagePipe(&options
, &handle0
, &handle1
);
76 CHECK_EQ(MOJO_RESULT_OK
, result
);
78 dictionary
.Set("result", result
);
79 dictionary
.Set("handle0", mojo::Handle(handle0
));
80 dictionary
.Set("handle1", mojo::Handle(handle1
));
84 MojoResult
WriteMessage(
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(),
94 static_cast<uint32_t>(buffer
.num_bytes()),
95 raw_handles
.empty() ? NULL
: &raw_handles
[0],
96 static_cast<uint32_t>(raw_handles
.size()),
98 // MojoWriteMessage takes ownership of the handles upon success, so
100 if (rv
== MOJO_RESULT_OK
) {
101 for (size_t i
= 0; i
< handles
.size(); ++i
)
102 ignore_result(handles
[i
]->release());
107 gin::Dictionary
ReadMessage(const gin::Arguments
& args
,
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
);
120 v8::Handle
<v8::ArrayBuffer
> array_buffer
=
121 v8::ArrayBuffer::New(args
.isolate(), num_bytes
);
122 std::vector
<mojo::Handle
> handles(num_handles
);
124 gin::ArrayBuffer buffer
;
125 ConvertFromV8(args
.isolate(), array_buffer
, &buffer
);
126 CHECK(buffer
.num_bytes() == num_bytes
);
128 result
= MojoReadMessage(handle
.value(),
131 handles
.empty() ? NULL
:
132 reinterpret_cast<MojoHandle
*>(&handles
[0]),
136 CHECK(buffer
.num_bytes() == num_bytes
);
137 CHECK(handles
.size() == num_handles
);
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
);
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
);
150 MojoHandle producer_handle
= MOJO_HANDLE_INVALID
;
151 MojoHandle consumer_handle
= MOJO_HANDLE_INVALID
;
152 MojoResult result
= MOJO_RESULT_OK
;
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
)) {
172 result
= MojoCreateDataPipe(&options
, &producer_handle
, &consumer_handle
);
177 CHECK_EQ(MOJO_RESULT_OK
, result
);
179 dictionary
.Set("result", result
);
180 dictionary
.Set("producerHandle", mojo::Handle(producer_handle
));
181 dictionary
.Set("consumerHandle", mojo::Handle(consumer_handle
));
185 gin::Dictionary
WriteData(const gin::Arguments
& args
,
187 const gin::ArrayBufferView
& buffer
,
188 MojoWriteDataFlags flags
) {
189 uint32_t num_bytes
= static_cast<uint32_t>(buffer
.num_bytes());
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
);
198 gin::Dictionary
ReadData(const gin::Arguments
& args
,
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
);
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());
216 result
= MojoReadData(handle
.value(), buffer
.bytes(), &num_bytes
, flags
);
217 CHECK_EQ(num_bytes
, buffer
.num_bytes());
219 gin::Dictionary dictionary
= gin::Dictionary::CreateEmpty(args
.isolate());
220 dictionary
.Set("result", result
);
221 dictionary
.Set("buffer", array_buffer
);
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.
233 v8::Handle
<v8::Value
> DoDrainData(gin::Arguments
* args
,
234 gin::Handle
<HandleWrapper
> handle
) {
235 return (new DrainData(args
->isolate(), handle
->release()))->GetPromise();
238 gin::WrapperInfo g_wrapper_info
= { gin::kEmbedderNativeGin
};
242 const char Core::kModuleName
[] = "mojo/public/js/bindings/core";
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(
249 if (templ
.IsEmpty()) {
250 templ
= gin::ObjectTemplateBuilder(isolate
)
251 // TODO(mpcomplete): Should these just be methods on the JS Handle
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
)
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
)
283 .SetValue("DEADLINE_INDEFINITE", MOJO_DEADLINE_INDEFINITE
)
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
)
289 .SetValue("CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE",
290 MOJO_CREATE_MESSAGE_PIPE_OPTIONS_FLAG_NONE
)
292 .SetValue("WRITE_MESSAGE_FLAG_NONE", MOJO_WRITE_MESSAGE_FLAG_NONE
)
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
)
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
)
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
)
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
)
314 data
->SetObjectTemplate(&g_wrapper_info
, templ
);
317 return templ
->NewInstance();