You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
549 lines
17 KiB
549 lines
17 KiB
// 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;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// |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();
|
|
output.ptr.bind(new mojo.InterfacePtrInfo(pipe.handle0, 0));
|
|
return new mojo.InterfaceRequest(pipe.handle1);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Operations used to setup/configure an interface pointer. Exposed as the
|
|
// |ptr| field of generated interface pointer classes.
|
|
// |ptrInfoOrHandle| could be omitted and passed into bind() later.
|
|
function InterfacePtrController(interfaceType, ptrInfoOrHandle) {
|
|
this.version = 0;
|
|
|
|
this.interfaceType_ = interfaceType;
|
|
this.router_ = null;
|
|
this.interfaceEndpointClient_ = null;
|
|
this.proxy_ = null;
|
|
|
|
// |router_| and |interfaceEndpointClient_| are lazily initialized.
|
|
// |handle_| is valid between bind() and
|
|
// the initialization of |router_| and |interfaceEndpointClient_|.
|
|
this.handle_ = null;
|
|
|
|
if (ptrInfoOrHandle)
|
|
this.bind(ptrInfoOrHandle);
|
|
}
|
|
|
|
InterfacePtrController.prototype.bind = function(ptrInfoOrHandle) {
|
|
this.reset();
|
|
|
|
if (ptrInfoOrHandle instanceof mojo.InterfacePtrInfo) {
|
|
this.version = ptrInfoOrHandle.version;
|
|
this.handle_ = ptrInfoOrHandle.handle;
|
|
} else {
|
|
this.handle_ = ptrInfoOrHandle;
|
|
}
|
|
};
|
|
|
|
InterfacePtrController.prototype.isBound = function() {
|
|
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;
|
|
|
|
this.proxy_ = null;
|
|
}
|
|
if (this.handle_) {
|
|
this.handle_.close();
|
|
this.handle_ = null;
|
|
}
|
|
};
|
|
|
|
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.interfaceEndpointClient_.setConnectionErrorHandler(callback);
|
|
};
|
|
|
|
InterfacePtrController.prototype.passInterface = function() {
|
|
var result;
|
|
if (this.router_) {
|
|
// TODO(yzshen): Fix Router interface to support extracting handle.
|
|
result = new mojo.InterfacePtrInfo(
|
|
this.router_.connector_.handle_, this.version);
|
|
this.router_.connector_.handle_ = null;
|
|
} else {
|
|
// This also handles the case when this object is not bound.
|
|
result = new mojo.InterfacePtrInfo(this.handle_, this.version);
|
|
this.handle_ = null;
|
|
}
|
|
|
|
this.reset();
|
|
return result;
|
|
};
|
|
|
|
InterfacePtrController.prototype.getProxy = function() {
|
|
this.configureProxyIfNecessary_();
|
|
return this.proxy_;
|
|
};
|
|
|
|
InterfacePtrController.prototype.configureProxyIfNecessary_ = function() {
|
|
if (!this.handle_)
|
|
return;
|
|
|
|
this.router_ = new internal.Router(this.handle_, true);
|
|
this.handle_ = null;
|
|
|
|
this.interfaceEndpointClient_ = new internal.InterfaceEndpointClient(
|
|
this.router_.createLocalEndpointHandle(internal.kMasterInterfaceId));
|
|
|
|
this.interfaceEndpointClient_ .setPayloadValidators([
|
|
this.interfaceType_.validateResponse]);
|
|
this.proxy_ = new this.interfaceType_.proxyClass(
|
|
this.interfaceEndpointClient_);
|
|
};
|
|
|
|
InterfacePtrController.prototype.queryVersion = function() {
|
|
function onQueryVersion(version) {
|
|
this.version = version;
|
|
return version;
|
|
}
|
|
|
|
this.configureProxyIfNecessary_();
|
|
return this.interfaceEndpointClient_.queryVersion().then(
|
|
onQueryVersion.bind(this));
|
|
};
|
|
|
|
InterfacePtrController.prototype.requireVersion = function(version) {
|
|
this.configureProxyIfNecessary_();
|
|
|
|
if (this.version >= version) {
|
|
return;
|
|
}
|
|
this.version = version;
|
|
this.interfaceEndpointClient_.requireVersion(version);
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// |request| could be omitted and passed into bind() later.
|
|
//
|
|
// Example:
|
|
//
|
|
// // FooImpl implements mojom.Foo.
|
|
// function FooImpl() { ... }
|
|
// FooImpl.prototype.fooMethod1 = function() { ... }
|
|
// FooImpl.prototype.fooMethod2 = function() { ... }
|
|
//
|
|
// var fooPtr = new mojom.FooPtr();
|
|
// var request = makeRequest(fooPtr);
|
|
// var binding = new Binding(mojom.Foo, new FooImpl(), request);
|
|
// fooPtr.fooMethod1();
|
|
function Binding(interfaceType, impl, requestOrHandle) {
|
|
this.interfaceType_ = interfaceType;
|
|
this.impl_ = impl;
|
|
this.router_ = null;
|
|
this.interfaceEndpointClient_ = null;
|
|
this.stub_ = null;
|
|
|
|
if (requestOrHandle)
|
|
this.bind(requestOrHandle);
|
|
}
|
|
|
|
Binding.prototype.isBound = function() {
|
|
return this.router_ !== null;
|
|
};
|
|
|
|
Binding.prototype.createInterfacePtrAndBind = function() {
|
|
var ptr = new this.interfaceType_.ptrClass();
|
|
// TODO(yzshen): Set the version of the interface pointer.
|
|
this.bind(makeRequest(ptr));
|
|
return ptr;
|
|
};
|
|
|
|
Binding.prototype.bind = function(requestOrHandle) {
|
|
this.close();
|
|
|
|
var handle = requestOrHandle instanceof mojo.InterfaceRequest ?
|
|
requestOrHandle.handle : requestOrHandle;
|
|
if (!(handle instanceof MojoHandle))
|
|
return;
|
|
|
|
this.router_ = new internal.Router(handle);
|
|
|
|
this.stub_ = new this.interfaceType_.stubClass(this.impl_);
|
|
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.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.interfaceEndpointClient_.setConnectionErrorHandler(callback);
|
|
};
|
|
|
|
Binding.prototype.unbind = function() {
|
|
if (!this.isBound())
|
|
return new mojo.InterfaceRequest(null);
|
|
|
|
var result = new mojo.InterfaceRequest(this.router_.connector_.handle_);
|
|
this.router_.connector_.handle_ = null;
|
|
this.close();
|
|
return result;
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
function BindingSetEntry(bindingSet, interfaceType, bindingType, impl,
|
|
requestOrHandle, bindingId) {
|
|
this.bindingSet_ = bindingSet;
|
|
this.bindingId_ = bindingId;
|
|
this.binding_ = new bindingType(interfaceType, impl,
|
|
requestOrHandle);
|
|
|
|
this.binding_.setConnectionErrorHandler(function(reason) {
|
|
this.bindingSet_.onConnectionError(bindingId, reason);
|
|
}.bind(this));
|
|
}
|
|
|
|
BindingSetEntry.prototype.close = function() {
|
|
this.binding_.close();
|
|
};
|
|
|
|
function BindingSet(interfaceType) {
|
|
this.interfaceType_ = interfaceType;
|
|
this.nextBindingId_ = 0;
|
|
this.bindings_ = new Map();
|
|
this.errorHandler_ = null;
|
|
this.bindingType_ = Binding;
|
|
}
|
|
|
|
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_, this.bindingType_, 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, reason) {
|
|
this.bindings_.delete(bindingId);
|
|
|
|
if (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;
|
|
})();
|