Index: mojo/public/js/new_bindings/bindings.js |
diff --git a/mojo/public/js/new_bindings/bindings.js b/mojo/public/js/new_bindings/bindings.js |
index 5b3b66ecea59860482728b74a93cf70e2b207f0e..98213a825e1360f869a4bd49e6f7ae066c0ed773 100644 |
--- a/mojo/public/js/new_bindings/bindings.js |
+++ b/mojo/public/js/new_bindings/bindings.js |
@@ -1,14 +1,33 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
(function() { |
var internal = mojo.internal; |
+ |
// --------------------------------------------------------------------------- |
- function makeRequest(interfacePtr) { |
+ // |output| could be an interface pointer, InterfacePtrInfo or |
+ // AssociatedInterfacePtrInfo. |
+ function makeRequest(output) { |
+ if (output instanceof mojo.AssociatedInterfacePtrInfo) { |
+ var {handle0, handle1} = internal.createPairPendingAssociation(); |
+ output.interfaceEndpointHandle = handle0; |
+ output.version = 0; |
+ |
+ return new mojo.AssociatedInterfaceRequest(handle1); |
+ } |
+ |
+ if (output instanceof mojo.InterfacePtrInfo) { |
+ var pipe = Mojo.createMessagePipe(); |
+ output.handle = pipe.handle0; |
+ output.version = 0; |
+ |
+ return new mojo.InterfaceRequest(pipe.handle1); |
+ } |
+ |
var pipe = Mojo.createMessagePipe(); |
- interfacePtr.ptr.bind(new mojo.InterfacePtrInfo(pipe.handle0, 0)); |
+ output.ptr.bind(new mojo.InterfacePtrInfo(pipe.handle0, 0)); |
return new mojo.InterfaceRequest(pipe.handle1); |
} |
@@ -22,12 +41,13 @@ |
this.interfaceType_ = interfaceType; |
this.router_ = null; |
+ this.interfaceEndpointClient_ = null; |
this.proxy_ = null; |
- // |router_| is lazily initialized. |handle_| is valid between bind() and |
- // the initialization of |router_|. |
+ // |router_| and |interfaceEndpointClient_| are lazily initialized. |
+ // |handle_| is valid between bind() and |
+ // the initialization of |router_| and |interfaceEndpointClient_|. |
this.handle_ = null; |
- this.controlMessageProxy_ = null; |
if (ptrInfoOrHandle) |
this.bind(ptrInfoOrHandle); |
@@ -45,13 +65,17 @@ |
}; |
InterfacePtrController.prototype.isBound = function() { |
- return this.router_ !== null || this.handle_ !== null; |
+ return this.interfaceEndpointClient_ !== null || this.handle_ !== null; |
}; |
// Although users could just discard the object, reset() closes the pipe |
// immediately. |
InterfacePtrController.prototype.reset = function() { |
this.version = 0; |
+ if (this.interfaceEndpointClient_) { |
+ this.interfaceEndpointClient_.close(); |
+ this.interfaceEndpointClient_ = null; |
+ } |
if (this.router_) { |
this.router_.close(); |
this.router_ = null; |
@@ -64,13 +88,22 @@ |
} |
}; |
- InterfacePtrController.prototype.setConnectionErrorHandler |
- = function(callback) { |
+ InterfacePtrController.prototype.resetWithReason = function(reason) { |
+ if (this.isBound()) { |
+ this.configureProxyIfNecessary_(); |
+ this.interfaceEndpointClient_.close(reason); |
+ this.interfaceEndpointClient_ = null; |
+ } |
+ this.reset(); |
+ }; |
+ |
+ InterfacePtrController.prototype.setConnectionErrorHandler = function( |
+ callback) { |
if (!this.isBound()) |
throw new Error("Cannot set connection error handler if not bound."); |
this.configureProxyIfNecessary_(); |
- this.router_.setErrorHandler(callback); |
+ this.interfaceEndpointClient_.setConnectionErrorHandler(callback); |
}; |
InterfacePtrController.prototype.passInterface = function() { |
@@ -95,22 +128,25 @@ |
return this.proxy_; |
}; |
- InterfacePtrController.prototype.enableTestingMode = function() { |
+ InterfacePtrController.prototype.waitForNextMessageForTesting = function() { |
this.configureProxyIfNecessary_(); |
- return this.router_.enableTestingMode(); |
+ this.router_.waitForNextMessageForTesting(); |
}; |
InterfacePtrController.prototype.configureProxyIfNecessary_ = function() { |
if (!this.handle_) |
return; |
- this.router_ = new internal.Router(this.handle_); |
+ this.router_ = new internal.Router(this.handle_, true); |
this.handle_ = null; |
- this.router_ .setPayloadValidators([this.interfaceType_.validateResponse]); |
- this.controlMessageProxy_ = new internal.ControlMessageProxy(this.router_); |
+ this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient( |
+ this.router_.createLocalEndpointHandle(internal.kMasterInterfaceId)); |
- this.proxy_ = new this.interfaceType_.proxyClass(this.router_); |
+ this.interfaceEndpointClient_ .setPayloadValidators([ |
+ this.interfaceType_.validateResponse]); |
+ this.proxy_ = new this.interfaceType_.proxyClass( |
+ this.interfaceEndpointClient_); |
}; |
InterfacePtrController.prototype.queryVersion = function() { |
@@ -120,7 +156,7 @@ |
} |
this.configureProxyIfNecessary_(); |
- return this.controlMessageProxy_.queryVersion().then( |
+ return this.interfaceEndpointClient_.queryVersion().then( |
onQueryVersion.bind(this)); |
}; |
@@ -131,7 +167,7 @@ |
return; |
} |
this.version = version; |
- this.controlMessageProxy_.requireVersion(version); |
+ this.interfaceEndpointClient_.requireVersion(version); |
}; |
// --------------------------------------------------------------------------- |
@@ -153,6 +189,7 @@ |
this.interfaceType_ = interfaceType; |
this.impl_ = impl; |
this.router_ = null; |
+ this.interfaceEndpointClient_ = null; |
this.stub_ = null; |
if (requestOrHandle) |
@@ -168,7 +205,7 @@ |
// TODO(yzshen): Set the version of the interface pointer. |
this.bind(makeRequest(ptr)); |
return ptr; |
- } |
+ }; |
Binding.prototype.bind = function(requestOrHandle) { |
this.close(); |
@@ -178,26 +215,44 @@ |
if (!(handle instanceof MojoHandle)) |
return; |
+ this.router_ = new internal.Router(handle); |
+ |
this.stub_ = new this.interfaceType_.stubClass(this.impl_); |
- this.router_ = new internal.Router(handle, this.interfaceType_.kVersion); |
- this.router_.setIncomingReceiver(this.stub_); |
- this.router_ .setPayloadValidators([this.interfaceType_.validateRequest]); |
+ this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient( |
+ this.router_.createLocalEndpointHandle(internal.kMasterInterfaceId), |
+ this.stub_, this.interfaceType_.kVersion); |
+ |
+ this.interfaceEndpointClient_ .setPayloadValidators([ |
+ this.interfaceType_.validateRequest]); |
}; |
Binding.prototype.close = function() { |
if (!this.isBound()) |
return; |
+ if (this.interfaceEndpointClient_) { |
+ this.interfaceEndpointClient_.close(); |
+ this.interfaceEndpointClient_ = null; |
+ } |
+ |
this.router_.close(); |
this.router_ = null; |
this.stub_ = null; |
}; |
- Binding.prototype.setConnectionErrorHandler |
- = function(callback) { |
- if (!this.isBound()) |
+ Binding.prototype.closeWithReason = function(reason) { |
+ if (this.interfaceEndpointClient_) { |
+ this.interfaceEndpointClient_.close(reason); |
+ this.interfaceEndpointClient_ = null; |
+ } |
+ this.close(); |
+ }; |
+ |
+ Binding.prototype.setConnectionErrorHandler = function(callback) { |
+ if (!this.isBound()) { |
throw new Error("Cannot set connection error handler if not bound."); |
- this.router_.setErrorHandler(callback); |
+ } |
+ this.interfaceEndpointClient_.setConnectionErrorHandler(callback); |
}; |
Binding.prototype.unbind = function() { |
@@ -210,20 +265,21 @@ |
return result; |
}; |
- Binding.prototype.enableTestingMode = function() { |
- return this.router_.enableTestingMode(); |
+ Binding.prototype.waitForNextMessageForTesting = function() { |
+ this.router_.waitForNextMessageForTesting(); |
}; |
// --------------------------------------------------------------------------- |
- function BindingSetEntry(bindingSet, interfaceType, impl, requestOrHandle, |
- bindingId) { |
+ function BindingSetEntry(bindingSet, interfaceType, bindingType, impl, |
+ requestOrHandle, bindingId) { |
this.bindingSet_ = bindingSet; |
this.bindingId_ = bindingId; |
- this.binding_ = new Binding(interfaceType, impl, requestOrHandle); |
+ this.binding_ = new bindingType(interfaceType, impl, |
+ requestOrHandle); |
- this.binding_.setConnectionErrorHandler(function() { |
- this.bindingSet_.onConnectionError(bindingId); |
+ this.binding_.setConnectionErrorHandler(function(reason) { |
+ this.bindingSet_.onConnectionError(bindingId, reason); |
}.bind(this)); |
} |
@@ -236,6 +292,7 @@ |
this.nextBindingId_ = 0; |
this.bindings_ = new Map(); |
this.errorHandler_ = null; |
+ this.bindingType_ = Binding; |
} |
BindingSet.prototype.isEmpty = function() { |
@@ -245,8 +302,8 @@ |
BindingSet.prototype.addBinding = function(impl, requestOrHandle) { |
this.bindings_.set( |
this.nextBindingId_, |
- new BindingSetEntry(this, this.interfaceType_, impl, requestOrHandle, |
- this.nextBindingId_)); |
+ new BindingSetEntry(this, this.interfaceType_, this.bindingType_, impl, |
+ requestOrHandle, this.nextBindingId_)); |
++this.nextBindingId_; |
}; |
@@ -260,15 +317,240 @@ |
this.errorHandler_ = callback; |
}; |
- BindingSet.prototype.onConnectionError = function(bindingId) { |
+ BindingSet.prototype.onConnectionError = function(bindingId, reason) { |
this.bindings_.delete(bindingId); |
if (this.errorHandler_) |
- this.errorHandler_(); |
+ this.errorHandler_(reason); |
}; |
+ // --------------------------------------------------------------------------- |
+ |
+ // Operations used to setup/configure an associated interface pointer. |
+ // Exposed as |ptr| field of generated associated interface pointer classes. |
+ // |associatedPtrInfo| could be omitted and passed into bind() later. |
+ // |
+ // Example: |
+ // // IntegerSenderImpl implements mojom.IntegerSender |
+ // function IntegerSenderImpl() { ... } |
+ // IntegerSenderImpl.prototype.echo = function() { ... } |
+ // |
+ // // IntegerSenderConnectionImpl implements mojom.IntegerSenderConnection |
+ // function IntegerSenderConnectionImpl() { |
+ // this.senderBinding_ = null; |
+ // } |
+ // IntegerSenderConnectionImpl.prototype.getSender = function( |
+ // associatedRequest) { |
+ // this.senderBinding_ = new AssociatedBinding(mojom.IntegerSender, |
+ // new IntegerSenderImpl(), |
+ // associatedRequest); |
+ // } |
+ // |
+ // var integerSenderConnection = new mojom.IntegerSenderConnectionPtr(); |
+ // var integerSenderConnectionBinding = new Binding( |
+ // mojom.IntegerSenderConnection, |
+ // new IntegerSenderConnectionImpl(), |
+ // mojo.makeRequest(integerSenderConnection)); |
+ // |
+ // // A locally-created associated interface pointer can only be used to |
+ // // make calls when the corresponding associated request is sent over |
+ // // another interface (either the master interface or another |
+ // // associated interface). |
+ // var associatedInterfacePtrInfo = new AssociatedInterfacePtrInfo(); |
+ // var associatedRequest = makeRequest(interfacePtrInfo); |
+ // |
+ // integerSenderConnection.getSender(associatedRequest); |
+ // |
+ // // Create an associated interface and bind the associated handle. |
+ // var integerSender = new mojom.AssociatedIntegerSenderPtr(); |
+ // integerSender.ptr.bind(associatedInterfacePtrInfo); |
+ // integerSender.echo(); |
+ |
+ function AssociatedInterfacePtrController(interfaceType, associatedPtrInfo) { |
+ this.version = 0; |
+ |
+ this.interfaceType_ = interfaceType; |
+ this.interfaceEndpointClient_ = null; |
+ this.proxy_ = null; |
+ |
+ if (associatedPtrInfo) { |
+ this.bind(associatedPtrInfo); |
+ } |
+ } |
+ |
+ AssociatedInterfacePtrController.prototype.bind = function( |
+ associatedPtrInfo) { |
+ this.reset(); |
+ this.version = associatedPtrInfo.version; |
+ |
+ this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient( |
+ associatedPtrInfo.interfaceEndpointHandle); |
+ |
+ this.interfaceEndpointClient_ .setPayloadValidators([ |
+ this.interfaceType_.validateResponse]); |
+ this.proxy_ = new this.interfaceType_.proxyClass( |
+ this.interfaceEndpointClient_); |
+ }; |
+ |
+ AssociatedInterfacePtrController.prototype.isBound = function() { |
+ return this.interfaceEndpointClient_ !== null; |
+ }; |
+ |
+ AssociatedInterfacePtrController.prototype.reset = function() { |
+ this.version = 0; |
+ if (this.interfaceEndpointClient_) { |
+ this.interfaceEndpointClient_.close(); |
+ this.interfaceEndpointClient_ = null; |
+ } |
+ if (this.proxy_) { |
+ this.proxy_ = null; |
+ } |
+ }; |
+ |
+ AssociatedInterfacePtrController.prototype.resetWithReason = function( |
+ reason) { |
+ if (this.isBound()) { |
+ this.interfaceEndpointClient_.close(reason); |
+ this.interfaceEndpointClient_ = null; |
+ } |
+ this.reset(); |
+ }; |
+ |
+ // Indicates whether an error has been encountered. If true, method calls |
+ // on this interface will be dropped (and may already have been dropped). |
+ AssociatedInterfacePtrController.prototype.getEncounteredError = function() { |
+ return this.interfaceEndpointClient_ ? |
+ this.interfaceEndpointClient_.getEncounteredError() : false; |
+ }; |
+ |
+ AssociatedInterfacePtrController.prototype.setConnectionErrorHandler = |
+ function(callback) { |
+ if (!this.isBound()) { |
+ throw new Error("Cannot set connection error handler if not bound."); |
+ } |
+ |
+ this.interfaceEndpointClient_.setConnectionErrorHandler(callback); |
+ }; |
+ |
+ AssociatedInterfacePtrController.prototype.passInterface = function() { |
+ if (!this.isBound()) { |
+ return new mojo.AssociatedInterfacePtrInfo(null); |
+ } |
+ |
+ var result = new mojo.AssociatedInterfacePtrInfo( |
+ this.interfaceEndpointClient_.passHandle(), this.version); |
+ this.reset(); |
+ return result; |
+ }; |
+ |
+ AssociatedInterfacePtrController.prototype.getProxy = function() { |
+ return this.proxy_; |
+ }; |
+ |
+ AssociatedInterfacePtrController.prototype.queryVersion = function() { |
+ function onQueryVersion(version) { |
+ this.version = version; |
+ return version; |
+ } |
+ |
+ return this.interfaceEndpointClient_.queryVersion().then( |
+ onQueryVersion.bind(this)); |
+ }; |
+ |
+ AssociatedInterfacePtrController.prototype.requireVersion = function( |
+ version) { |
+ if (this.version >= version) { |
+ return; |
+ } |
+ this.version = version; |
+ this.interfaceEndpointClient_.requireVersion(version); |
+ }; |
+ |
+ // --------------------------------------------------------------------------- |
+ |
+ // |associatedInterfaceRequest| could be omitted and passed into bind() |
+ // later. |
+ function AssociatedBinding(interfaceType, impl, associatedInterfaceRequest) { |
+ this.interfaceType_ = interfaceType; |
+ this.impl_ = impl; |
+ this.interfaceEndpointClient_ = null; |
+ this.stub_ = null; |
+ |
+ if (associatedInterfaceRequest) { |
+ this.bind(associatedInterfaceRequest); |
+ } |
+ } |
+ |
+ AssociatedBinding.prototype.isBound = function() { |
+ return this.interfaceEndpointClient_ !== null; |
+ }; |
+ |
+ AssociatedBinding.prototype.bind = function(associatedInterfaceRequest) { |
+ this.close(); |
+ |
+ this.stub_ = new this.interfaceType_.stubClass(this.impl_); |
+ this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient( |
+ associatedInterfaceRequest.interfaceEndpointHandle, this.stub_, |
+ this.interfaceType_.kVersion); |
+ |
+ this.interfaceEndpointClient_ .setPayloadValidators([ |
+ this.interfaceType_.validateRequest]); |
+ }; |
+ |
+ |
+ AssociatedBinding.prototype.close = function() { |
+ if (!this.isBound()) { |
+ return; |
+ } |
+ |
+ if (this.interfaceEndpointClient_) { |
+ this.interfaceEndpointClient_.close(); |
+ this.interfaceEndpointClient_ = null; |
+ } |
+ |
+ this.stub_ = null; |
+ }; |
+ |
+ AssociatedBinding.prototype.closeWithReason = function(reason) { |
+ if (this.interfaceEndpointClient_) { |
+ this.interfaceEndpointClient_.close(reason); |
+ this.interfaceEndpointClient_ = null; |
+ } |
+ this.close(); |
+ }; |
+ |
+ AssociatedBinding.prototype.setConnectionErrorHandler = function(callback) { |
+ if (!this.isBound()) { |
+ throw new Error("Cannot set connection error handler if not bound."); |
+ } |
+ this.interfaceEndpointClient_.setConnectionErrorHandler(callback); |
+ }; |
+ |
+ AssociatedBinding.prototype.unbind = function() { |
+ if (!this.isBound()) { |
+ return new mojo.AssociatedInterfaceRequest(null); |
+ } |
+ |
+ var result = new mojo.AssociatedInterfaceRequest( |
+ this.interfaceEndpointClient_.passHandle()); |
+ this.close(); |
+ return result; |
+ }; |
+ |
+ // --------------------------------------------------------------------------- |
+ |
+ function AssociatedBindingSet(interfaceType) { |
+ mojo.BindingSet.call(this, interfaceType); |
+ this.bindingType_ = AssociatedBinding; |
+ } |
+ |
+ AssociatedBindingSet.prototype = Object.create(BindingSet.prototype); |
+ AssociatedBindingSet.prototype.constructor = AssociatedBindingSet; |
mojo.makeRequest = makeRequest; |
+ mojo.AssociatedInterfacePtrController = AssociatedInterfacePtrController; |
+ mojo.AssociatedBinding = AssociatedBinding; |
+ mojo.AssociatedBindingSet = AssociatedBindingSet; |
mojo.Binding = Binding; |
mojo.BindingSet = BindingSet; |
mojo.InterfacePtrController = InterfacePtrController; |