Commit 0c641b54 authored by yzshen's avatar yzshen Committed by Commit bot

Mojo JS bindings: BindingSet support.

It also makes binding to a raw handle easier.

BUG=579646

Review-Url: https://codereview.chromium.org/2578333002
Cr-Commit-Position: refs/heads/master@{#438973}
parent 1bd8046a
......@@ -17,6 +17,7 @@ define([
.then(testReusable)
.then(testConnectionError)
.then(testUnbind)
.then(testBindingSet)
.then(function() {
this.result = "PASS";
gc.collectGarbage(); // should not crash
......@@ -118,4 +119,41 @@ define([
return promise;
}
function testBindingSet() {
var calc1 = new math.CalculatorPtr();
var calc2 = new math.CalculatorPtr();
var calcImpl = new CalculatorImpl();
var bindingSet = new bindings.BindingSet(math.Calculator);
expect(bindingSet.isEmpty()).toBeTruthy();
bindingSet.addBinding(calcImpl, bindings.makeRequest(calc1));
bindingSet.addBinding(calcImpl, bindings.makeRequest(calc2));
expect(bindingSet.isEmpty()).toBeFalsy();
var promise = calc1.add(3).then(function(response) {
expect(response.value).toBe(3);
return calc2.add(4);
}).then(function(response) {
expect(response.value).toBe(7);
var promiseOfConnectionError = new Promise(function(resolve, reject) {
bindingSet.setConnectionErrorHandler(function() {
resolve();
});
});
calc1.ptr.reset();
return promiseOfConnectionError;
}).then(function() {
return calc2.add(5);
}).then(function(response) {
expect(response.value).toBe(12);
bindingSet.closeAllBindings();
expect(bindingSet.isEmpty()).toBeTruthy();
return Promise.resolve();
});
return promise;
}
});
......@@ -5,11 +5,13 @@
define([
"gin/test/expect",
"mojo/public/js/bindings",
"mojo/public/js/core",
"mojo/public/interfaces/bindings/tests/math_calculator.mojom",
"mojo/public/js/threading",
"gc",
], function(expect,
bindings,
core,
math,
threading,
gc) {
......@@ -18,6 +20,7 @@ define([
.then(testReusable)
.then(testConnectionError)
.then(testPassInterface)
.then(testBindRawHandle)
.then(function() {
this.result = "PASS";
gc.collectGarbage(); // should not crash
......@@ -138,4 +141,20 @@ define([
return promise;
}
function testBindRawHandle() {
var pipe = core.createMessagePipe();
var calc = new math.CalculatorPtr(pipe.handle0);
var newCalc = null;
var calcBinding = new bindings.Binding(math.Calculator,
new CalculatorImpl(),
pipe.handle1);
var promise = calc.add(2).then(function(response) {
expect(response.value).toBe(2);
return Promise.resolve();
});
return promise;
}
});
......@@ -6,10 +6,9 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [
'console',
'mojo/edk/js/tests/js_to_cpp.mojom',
'mojo/public/js/bindings',
'mojo/public/js/connection',
'mojo/public/js/connector',
'mojo/public/js/core',
], function (console, jsToCpp, bindings, connection, connector, core) {
], function (console, jsToCpp, bindings, connector, core) {
var retainedJsSide;
var retainedJsSideStub;
var sampleData;
......@@ -22,11 +21,9 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [
};
function JsSideConnection() {
this.binding = new bindings.Binding(jsToCpp.JsSide, this);
}
JsSideConnection.prototype =
Object.create(jsToCpp.JsSide.stubClass.prototype);
JsSideConnection.prototype.setCppSide = function(cppSide) {
this.cppSide_ = cppSide;
this.cppSide_.startTest();
......@@ -220,9 +217,7 @@ define('mojo/edk/js/tests/js_to_cpp_tests', [
for (i = 0; i < sampleMessage.length; ++i) {
sampleMessage[i] = 255 - i;
}
retainedJsSideStub =
connection.bindHandleToStub(jsSideRequestHandle, jsToCpp.JsSide);
retainedJsSide = new JsSideConnection;
bindings.StubBindings(retainedJsSideStub).delegate = retainedJsSide;
retainedJsSide.binding.bind(jsSideRequestHandle);
};
});
......@@ -20,7 +20,8 @@ define("mojo/public/js/bindings", [
// Operations used to setup/configure an interface pointer. Exposed as the
// |ptr| field of generated interface pointer classes.
function InterfacePtrController(interfaceType) {
// |ptrInfoOrHandle| could be omitted and passed into bind() later.
function InterfacePtrController(interfaceType, ptrInfoOrHandle) {
this.version = 0;
this.interfaceType_ = interfaceType;
......@@ -28,13 +29,20 @@ define("mojo/public/js/bindings", [
// |connection_| is lazily initialized. |handle_| is valid between bind()
// and the initialization of |connection_|.
this.handle_ = null;
if (ptrInfoOrHandle)
this.bind(ptrInfoOrHandle);
}
InterfacePtrController.prototype.bind = function(interfacePtrInfo) {
InterfacePtrController.prototype.bind = function(ptrInfoOrHandle) {
this.reset();
this.version = interfacePtrInfo.version;
this.handle_ = interfacePtrInfo.handle;
if (ptrInfoOrHandle instanceof types.InterfacePtrInfo) {
this.version = ptrInfoOrHandle.version;
this.handle_ = ptrInfoOrHandle.handle;
} else {
this.handle_ = ptrInfoOrHandle;
}
};
InterfacePtrController.prototype.isBound = function() {
......@@ -101,8 +109,6 @@ define("mojo/public/js/bindings", [
// ---------------------------------------------------------------------------
// |request| could be omitted and passed into bind() later.
// NOTE: |impl| shouldn't hold a reference to this object, because that
// results in circular references.
//
// Example:
//
......@@ -115,13 +121,13 @@ define("mojo/public/js/bindings", [
// var request = makeRequest(fooPtr);
// var binding = new Binding(mojom.Foo, new FooImpl(), request);
// fooPtr.fooMethod1();
function Binding(interfaceType, impl, request) {
function Binding(interfaceType, impl, requestOrHandle) {
this.interfaceType_ = interfaceType;
this.impl_ = impl;
this.stub_ = null;
if (request)
this.bind(request);
if (requestOrHandle)
this.bind(requestOrHandle);
}
Binding.prototype.isBound = function() {
......@@ -135,11 +141,13 @@ define("mojo/public/js/bindings", [
return ptr;
}
Binding.prototype.bind = function(request) {
Binding.prototype.bind = function(requestOrHandle) {
this.close();
if (request.isValid()) {
this.stub_ = connection.bindHandleToStub(request.handle,
this.interfaceType_);
var handle = requestOrHandle instanceof types.InterfaceRequest ?
requestOrHandle.handle : requestOrHandle;
if (core.isHandle(handle)) {
this.stub_ = connection.bindHandleToStub(handle, this.interfaceType_);
connection.StubBindings(this.stub_).delegate = this.impl_;
}
};
......@@ -172,12 +180,65 @@ define("mojo/public/js/bindings", [
return result;
};
// ---------------------------------------------------------------------------
function BindingSetEntry(bindingSet, interfaceType, impl, requestOrHandle,
bindingId) {
this.bindingSet_ = bindingSet;
this.bindingId_ = bindingId;
this.binding_ = new Binding(interfaceType, impl, requestOrHandle);
this.binding_.setConnectionErrorHandler(
() => this.bindingSet_.onConnectionError(bindingId));
}
BindingSetEntry.prototype.close = function() {
this.binding_.close();
};
function BindingSet(interfaceType) {
this.interfaceType_ = interfaceType;
this.nextBindingId_ = 0;
this.bindings_ = new Map();
this.errorHandler_ = null;
}
BindingSet.prototype.isEmpty = function() {
return this.bindings_.size == 0;
};
BindingSet.prototype.addBinding = function(impl, requestOrHandle) {
this.bindings_.set(
this.nextBindingId_,
new BindingSetEntry(this, this.interfaceType_, impl, requestOrHandle,
this.nextBindingId_));
++this.nextBindingId_;
};
BindingSet.prototype.closeAllBindings = function() {
for (var entry of this.bindings_.values())
entry.close();
this.bindings_.clear();
};
BindingSet.prototype.setConnectionErrorHandler = function(callback) {
this.errorHandler_ = callback;
};
BindingSet.prototype.onConnectionError = function(bindingId) {
this.bindings_.delete(bindingId);
if (this.errorHandler_)
this.errorHandler_();
};
var exports = {};
exports.InterfacePtrInfo = types.InterfacePtrInfo;
exports.InterfaceRequest = types.InterfaceRequest;
exports.makeRequest = makeRequest;
exports.InterfacePtrController = InterfacePtrController;
exports.Binding = Binding;
exports.BindingSet = BindingSet;
// TODO(yzshen): Remove the following exports.
exports.EmptyProxy = connection.EmptyProxy;
......
......@@ -8,6 +8,9 @@ define("mojo/public/js/connection", [
"mojo/public/js/router",
], function(connector, core, router) {
// TODO(yzshen): This module should only be used by the JS bindings internally
// and it will be removed soon.
var Router = router.Router;
var TestConnector = connector.TestConnector;
var TestRouter = router.TestRouter;
......
......@@ -2,8 +2,9 @@
var k{{interface.name}}_{{method.name}}_Name = {{method.ordinal}};
{%- endfor %}
function {{interface.name}}Ptr() {
this.ptr = new bindings.InterfacePtrController({{interface.name}});
function {{interface.name}}Ptr(handleOrPtrInfo) {
this.ptr = new bindings.InterfacePtrController({{interface.name}},
handleOrPtrInfo);
}
function {{interface.name}}Proxy(receiver) {
......
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