Commit 6c653757 authored by Scott Graham's avatar Scott Graham Committed by Commit Bot

Fuchsia: Implement request<Interface> in FIDL/JS

Fairly basic and the connection must be manually torn down for now, but
allows requesting an interface implemention from the JS side.

Bug: 883496
Change-Id: I8367fd50097403ee2f9911657afbabdd8d461a41
Reviewed-on: https://chromium-review.googlesource.com/c/1324929
Commit-Queue: Scott Graham <scottmg@chromium.org>
Reviewed-by: default avatarWez <wez@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606663}
parent d96b4d74
...@@ -402,7 +402,7 @@ function %(name)s(%(param_names)s) { ...@@ -402,7 +402,7 @@ function %(name)s(%(param_names)s) {
compound = _ParseCompoundIdentifier(t.identifier) compound = _ParseCompoundIdentifier(t.identifier)
name = _CompileCompoundIdentifier(compound) name = _CompileCompoundIdentifier(compound)
return name + ('_Nullable' if t.nullable else '') return name + ('_Nullable' if t.nullable else '')
elif t.kind == fidl.TypeKind.HANDLE: elif t.kind == fidl.TypeKind.HANDLE or t.kind == fidl.TypeKind.REQUEST:
return 'Handle' return 'Handle'
elif t.kind == fidl.TypeKind.ARRAY: elif t.kind == fidl.TypeKind.ARRAY:
element_ttname = self._CompileType(t.element_type) element_ttname = self._CompileType(t.element_type)
...@@ -545,6 +545,30 @@ function %(proxy_name)s() { ...@@ -545,6 +545,30 @@ function %(proxy_name)s() {
this.channel = channel; this.channel = channel;
}; };
%(proxy_name)s.prototype.$is_bound = function() {
return this.channel != $ZX_HANDLE_INVALID;
};
%(proxy_name)s.prototype.$request = function() {
if (this.$is_bound())
throw "Proxy already bound";
var pair = $ZxChannelCreate();
if (pair.status != $ZX_OK)
throw "ChannelPair creation failed";
this.channel = pair.first;
return pair.second;
};
%(proxy_name)s.prototype.$close = function() {
if (!this.$is_bound())
return;
var status = $zx_handle_close(this.channel);
if (status !== $ZX_OK) {
throw "close handle failed";
}
this.channel = $ZX_HANDLE_INVALID;
};
''' % { ''' % {
'name': name, 'name': name,
'proxy_name': proxy_name 'proxy_name': proxy_name
......
...@@ -189,6 +189,22 @@ v8::Local<v8::Promise> ZxObjectWaitOne(gin::Arguments* args) { ...@@ -189,6 +189,22 @@ v8::Local<v8::Promise> ZxObjectWaitOne(gin::Arguments* args) {
return v8::Local<v8::Promise>(); return v8::Local<v8::Promise>();
} }
v8::Local<v8::Value> ZxChannelCreate(gin::Arguments* args) {
zx_handle_t channel0, channel1;
zx_status_t status = zx_channel_create(0, &channel0, &channel1);
if (status != ZX_OK) {
return gin::DataObjectBuilder(args->isolate())
.Set("status", status)
.Build();
}
return gin::DataObjectBuilder(args->isolate())
.Set("status", status)
.Set("first", channel0)
.Set("second", channel1)
.Build();
}
zx_status_t ZxChannelWrite(gin::Arguments* args) { zx_status_t ZxChannelWrite(gin::Arguments* args) {
zx_handle_t handle; zx_handle_t handle;
if (!args->GetNext(&handle)) { if (!args->GetNext(&handle)) {
...@@ -350,10 +366,18 @@ ZxBindings::ZxBindings(v8::Isolate* isolate, v8::Local<v8::Object> global) ...@@ -350,10 +366,18 @@ ZxBindings::ZxBindings(v8::Isolate* isolate, v8::Local<v8::Object> global)
gin::StringToSymbol(isolate, "$ZxObjectWaitOne"), gin::StringToSymbol(isolate, "$ZxObjectWaitOne"),
gin::CreateFunctionTemplate(isolate, base::BindRepeating(ZxObjectWaitOne)) gin::CreateFunctionTemplate(isolate, base::BindRepeating(ZxObjectWaitOne))
->GetFunction()); ->GetFunction());
global->Set(
gin::StringToSymbol(isolate, "$zx_handle_close"),
gin::CreateFunctionTemplate(isolate, base::BindRepeating(zx_handle_close))
->GetFunction());
SET_CONSTANT(ZX_HANDLE_INVALID); SET_CONSTANT(ZX_HANDLE_INVALID);
SET_CONSTANT(ZX_TIME_INFINITE); SET_CONSTANT(ZX_TIME_INFINITE);
// Channel APIs. // Channel APIs.
global->Set(gin::StringToSymbol(isolate, "$ZxChannelCreate"),
gin::CreateFunctionTemplate(isolate,
base::BindRepeating(&ZxChannelCreate))
->GetFunction());
global->Set( global->Set(
gin::StringToSymbol(isolate, "$ZxChannelWrite"), gin::StringToSymbol(isolate, "$ZxChannelWrite"),
gin::CreateFunctionTemplate(isolate, base::BindRepeating(&ZxChannelWrite)) gin::CreateFunctionTemplate(isolate, base::BindRepeating(&ZxChannelWrite))
......
...@@ -197,6 +197,23 @@ class BindingsSetupHelper { ...@@ -197,6 +197,23 @@ class BindingsSetupHelper {
DISALLOW_COPY_AND_ASSIGN(BindingsSetupHelper); DISALLOW_COPY_AND_ASSIGN(BindingsSetupHelper);
}; };
class AnotherInterfaceImpl : public fidljstest::AnotherInterface {
public:
AnotherInterfaceImpl(
fidl::InterfaceRequest<fidljstest::AnotherInterface> request)
: binding_(this, std::move(request)) {}
~AnotherInterfaceImpl() override = default;
void TimesTwo(int32_t a, TimesTwoCallback callback) override {
callback(a * 2);
}
private:
fidl::Binding<fidljstest::AnotherInterface> binding_;
DISALLOW_COPY_AND_ASSIGN(AnotherInterfaceImpl);
};
class TestolaImpl : public fidljstest::Testola { class TestolaImpl : public fidljstest::Testola {
public: public:
TestolaImpl() { TestolaImpl() {
...@@ -493,6 +510,12 @@ class TestolaImpl : public fidljstest::Testola { ...@@ -493,6 +510,12 @@ class TestolaImpl : public fidljstest::Testola {
response_callbacks_.clear(); response_callbacks_.clear();
} }
void GetAnother(
fidl::InterfaceRequest<fidljstest::AnotherInterface> request) override {
another_interface_impl_ =
std::make_unique<AnotherInterfaceImpl>(std::move(request));
}
private: private:
bool was_do_something_called_ = false; bool was_do_something_called_ = false;
int32_t received_int_ = -1; int32_t received_int_ = -1;
...@@ -505,6 +528,7 @@ class TestolaImpl : public fidljstest::Testola { ...@@ -505,6 +528,7 @@ class TestolaImpl : public fidljstest::Testola {
zx_handle_t unowned_log_handle_; zx_handle_t unowned_log_handle_;
bool did_receive_union_ = false; bool did_receive_union_ = false;
bool did_get_vectors_of_string_ = false; bool did_get_vectors_of_string_ = false;
std::unique_ptr<AnotherInterfaceImpl> another_interface_impl_;
DISALLOW_COPY_AND_ASSIGN(TestolaImpl); DISALLOW_COPY_AND_ASSIGN(TestolaImpl);
}; };
...@@ -1269,6 +1293,40 @@ TEST_F(FidlGenJsTest, VectorOfHandle) { ...@@ -1269,6 +1293,40 @@ TEST_F(FidlGenJsTest, VectorOfHandle) {
EXPECT_EQ(zx_handle_close(result_vmo1), ZX_OK); EXPECT_EQ(zx_handle_close(result_vmo1), ZX_OK);
} }
TEST_F(FidlGenJsTest, RequestInterface) {
v8::Isolate* isolate = instance_->isolate();
BindingsSetupHelper helper(isolate);
TestolaImpl testola_impl;
fidl::Binding<fidljstest::Testola> binding(&testola_impl);
binding.Bind(std::move(helper.server()));
std::string source = R"(
var proxy = new TestolaProxy();
proxy.$bind(testHandle);
var another_proxy = new AnotherInterfaceProxy();
proxy.GetAnother(another_proxy.$request());
this.is_bound = another_proxy.$is_bound();
another_proxy.TimesTwo(456).then(resp => {
this.result = resp;
// TODO(crbug.com/883496): Handle created by $request() must be manually
// closed for now to avoid leaking it.
another_proxy.$close();
}).catch((e) => log('FAILED: ' + e));
// Use the original interface to make sure we didn't break its connection.
proxy.PrintInt(789);
)";
helper.runner().Run(source, "test.js");
base::RunLoop().RunUntilIdle();
EXPECT_EQ(helper.Get<int>("result"), 456 * 2);
EXPECT_EQ(testola_impl.received_int(), 789);
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
base::TestSuite test_suite(argc, argv); base::TestSuite test_suite(argc, argv);
......
...@@ -100,6 +100,10 @@ struct AfterPreviousReference { ...@@ -100,6 +100,10 @@ struct AfterPreviousReference {
int32 an_int; int32 an_int;
}; };
interface AnotherInterface {
1: TimesTwo(int32 a) -> (int32 b);
};
interface Testola { interface Testola {
1: DoSomething(); 1: DoSomething();
...@@ -133,4 +137,6 @@ interface Testola { ...@@ -133,4 +137,6 @@ interface Testola {
14: PassVectorOfVMO(VectorOfHandleToVMO input) 14: PassVectorOfVMO(VectorOfHandleToVMO input)
-> (VectorOfHandleToVMO output); -> (VectorOfHandleToVMO output);
15: GetAnother(request<AnotherInterface> another);
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment