| // 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 InterfaceEndpointClient(interfaceEndpointHandle, receiver, |
| interfaceVersion) { |
| this.controller_ = null; |
| this.encounteredError_ = false; |
| this.handle_ = interfaceEndpointHandle; |
| this.incomingReceiver_ = receiver; |
| |
| if (interfaceVersion !== undefined) { |
| this.controlMessageHandler_ = new internal.ControlMessageHandler( |
| interfaceVersion); |
| } else { |
| this.controlMessageProxy_ = new internal.ControlMessageProxy(this); |
| } |
| |
| this.nextRequestID_ = 0; |
| this.completers_ = new Map(); |
| this.payloadValidators_ = []; |
| this.connectionErrorHandler_ = null; |
| |
| if (interfaceEndpointHandle.pendingAssociation()) { |
| interfaceEndpointHandle.setAssociationEventHandler( |
| this.onAssociationEvent.bind(this)); |
| } else { |
| this.initControllerIfNecessary_(); |
| } |
| } |
| |
| InterfaceEndpointClient.prototype.initControllerIfNecessary_ = function() { |
| if (this.controller_ || this.handle_.pendingAssociation()) { |
| return; |
| } |
| |
| this.controller_ = this.handle_.groupController().attachEndpointClient( |
| this.handle_, this); |
| }; |
| |
| InterfaceEndpointClient.prototype.onAssociationEvent = function( |
| associationEvent) { |
| if (associationEvent === internal.AssociationEvent.ASSOCIATED) { |
| this.initControllerIfNecessary_(); |
| } else if (associationEvent === |
| internal.AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION) { |
| setTimeout(this.notifyError.bind(this, this.handle_.disconnectReason()), |
| 0); |
| } |
| }; |
| |
| InterfaceEndpointClient.prototype.passHandle = function() { |
| if (!this.handle_.isValid()) { |
| return new internal.InterfaceEndpointHandle(); |
| } |
| |
| // Used to clear the previously set callback. |
| this.handle_.setAssociationEventHandler(undefined); |
| |
| if (this.controller_) { |
| this.controller_ = null; |
| this.handle_.groupController().detachEndpointClient(this.handle_); |
| } |
| var handle = this.handle_; |
| this.handle_ = null; |
| return handle; |
| }; |
| |
| InterfaceEndpointClient.prototype.close = function(reason) { |
| var handle = this.passHandle(); |
| handle.reset(reason); |
| }; |
| |
| InterfaceEndpointClient.prototype.accept = function(message) { |
| if (message.associatedEndpointHandles.length > 0) { |
| message.serializeAssociatedEndpointHandles( |
| this.handle_.groupController()); |
| } |
| |
| if (this.encounteredError_) { |
| return false; |
| } |
| |
| this.initControllerIfNecessary_(); |
| return this.controller_.sendMessage(message); |
| }; |
| |
| InterfaceEndpointClient.prototype.acceptAndExpectResponse = function( |
| message) { |
| if (message.associatedEndpointHandles.length > 0) { |
| message.serializeAssociatedEndpointHandles( |
| this.handle_.groupController()); |
| } |
| |
| if (this.encounteredError_) { |
| return Promise.reject(); |
| } |
| |
| this.initControllerIfNecessary_(); |
| |
| // Reserve 0 in case we want it to convey special meaning in the future. |
| var requestID = this.nextRequestID_++; |
| if (requestID === 0) |
| requestID = this.nextRequestID_++; |
| |
| message.setRequestID(requestID); |
| var result = this.controller_.sendMessage(message); |
| if (!result) |
| return Promise.reject(Error("Connection error")); |
| |
| var completer = {}; |
| this.completers_.set(requestID, completer); |
| return new Promise(function(resolve, reject) { |
| completer.resolve = resolve; |
| completer.reject = reject; |
| }); |
| }; |
| |
| InterfaceEndpointClient.prototype.setPayloadValidators = function( |
| payloadValidators) { |
| this.payloadValidators_ = payloadValidators; |
| }; |
| |
| InterfaceEndpointClient.prototype.setIncomingReceiver = function(receiver) { |
| this.incomingReceiver_ = receiver; |
| }; |
| |
| InterfaceEndpointClient.prototype.setConnectionErrorHandler = function( |
| handler) { |
| this.connectionErrorHandler_ = handler; |
| }; |
| |
| InterfaceEndpointClient.prototype.handleIncomingMessage = function(message, |
| messageValidator) { |
| var noError = internal.validationError.NONE; |
| var err = noError; |
| for (var i = 0; err === noError && i < this.payloadValidators_.length; ++i) |
| err = this.payloadValidators_[i](messageValidator); |
| |
| if (err == noError) { |
| return this.handleValidIncomingMessage_(message); |
| } else { |
| internal.reportValidationError(err); |
| return false; |
| } |
| }; |
| |
| InterfaceEndpointClient.prototype.handleValidIncomingMessage_ = function( |
| message) { |
| if (internal.isTestingMode()) { |
| return true; |
| } |
| |
| if (this.encounteredError_) { |
| return false; |
| } |
| |
| var ok = false; |
| |
| if (message.expectsResponse()) { |
| if (internal.isInterfaceControlMessage(message) && |
| this.controlMessageHandler_) { |
| ok = this.controlMessageHandler_.acceptWithResponder(message, this); |
| } else if (this.incomingReceiver_) { |
| ok = this.incomingReceiver_.acceptWithResponder(message, this); |
| } |
| } else if (message.isResponse()) { |
| var reader = new internal.MessageReader(message); |
| var requestID = reader.requestID; |
| var completer = this.completers_.get(requestID); |
| if (completer) { |
| this.completers_.delete(requestID); |
| completer.resolve(message); |
| ok = true; |
| } else { |
| console.log("Unexpected response with request ID: " + requestID); |
| } |
| } else { |
| if (internal.isInterfaceControlMessage(message) && |
| this.controlMessageHandler_) { |
| ok = this.controlMessageHandler_.accept(message); |
| } else if (this.incomingReceiver_) { |
| ok = this.incomingReceiver_.accept(message); |
| } |
| } |
| return ok; |
| }; |
| |
| InterfaceEndpointClient.prototype.notifyError = function(reason) { |
| if (this.encounteredError_) { |
| return; |
| } |
| this.encounteredError_ = true; |
| |
| this.completers_.forEach(function(value) { |
| value.reject(); |
| }); |
| this.completers_.clear(); // Drop any responders. |
| |
| if (this.connectionErrorHandler_) { |
| this.connectionErrorHandler_(reason); |
| } |
| }; |
| |
| InterfaceEndpointClient.prototype.queryVersion = function() { |
| return this.controlMessageProxy_.queryVersion(); |
| }; |
| |
| InterfaceEndpointClient.prototype.requireVersion = function(version) { |
| this.controlMessageProxy_.requireVersion(version); |
| }; |
| |
| InterfaceEndpointClient.prototype.getEncounteredError = function() { |
| return this.encounteredError_; |
| }; |
| |
| internal.InterfaceEndpointClient = InterfaceEndpointClient; |
| })(); |