183 lines
5.5 KiB
JavaScript
183 lines
5.5 KiB
JavaScript
// 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;
|
|
|
|
var AssociationEvent = {
|
|
// The interface has been associated with a message pipe.
|
|
ASSOCIATED: 'associated',
|
|
// The peer of this object has been closed before association.
|
|
PEER_CLOSED_BEFORE_ASSOCIATION: 'peer_closed_before_association'
|
|
};
|
|
|
|
function State(interfaceId, associatedGroupController) {
|
|
if (interfaceId === undefined) {
|
|
interfaceId = internal.kInvalidInterfaceId;
|
|
}
|
|
|
|
this.interfaceId = interfaceId;
|
|
this.associatedGroupController = associatedGroupController;
|
|
this.pendingAssociation = false;
|
|
this.disconnectReason = null;
|
|
this.peerState_ = null;
|
|
this.associationEventHandler_ = null;
|
|
}
|
|
|
|
State.prototype.initPendingState = function(peer) {
|
|
this.pendingAssociation = true;
|
|
this.peerState_ = peer;
|
|
};
|
|
|
|
State.prototype.isValid = function() {
|
|
return this.pendingAssociation ||
|
|
internal.isValidInterfaceId(this.interfaceId);
|
|
};
|
|
|
|
State.prototype.close = function(disconnectReason) {
|
|
var cachedGroupController;
|
|
var cachedPeerState;
|
|
var cachedId = internal.kInvalidInterfaceId;
|
|
|
|
if (!this.pendingAssociation) {
|
|
if (internal.isValidInterfaceId(this.interfaceId)) {
|
|
cachedGroupController = this.associatedGroupController;
|
|
this.associatedGroupController = null;
|
|
cachedId = this.interfaceId;
|
|
this.interfaceId = internal.kInvalidInterfaceId;
|
|
}
|
|
} else {
|
|
this.pendingAssociation = false;
|
|
cachedPeerState = this.peerState_;
|
|
this.peerState_ = null;
|
|
}
|
|
|
|
if (cachedGroupController) {
|
|
cachedGroupController.closeEndpointHandle(cachedId,
|
|
disconnectReason);
|
|
} else if (cachedPeerState) {
|
|
cachedPeerState.onPeerClosedBeforeAssociation(disconnectReason);
|
|
}
|
|
};
|
|
|
|
State.prototype.runAssociationEventHandler = function(associationEvent) {
|
|
if (this.associationEventHandler_) {
|
|
var handler = this.associationEventHandler_;
|
|
this.associationEventHandler_ = null;
|
|
handler(associationEvent);
|
|
}
|
|
};
|
|
|
|
State.prototype.setAssociationEventHandler = function(handler) {
|
|
if (!this.pendingAssociation &&
|
|
!internal.isValidInterfaceId(this.interfaceId)) {
|
|
return;
|
|
}
|
|
|
|
if (!handler) {
|
|
this.associationEventHandler_ = null;
|
|
return;
|
|
}
|
|
|
|
this.associationEventHandler_ = handler;
|
|
if (!this.pendingAssociation) {
|
|
setTimeout(this.runAssociationEventHandler.bind(this,
|
|
AssociationEvent.ASSOCIATED), 0);
|
|
} else if (!this.peerState_) {
|
|
setTimeout(this.runAssociationEventHandler.bind(this,
|
|
AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION), 0);
|
|
}
|
|
};
|
|
|
|
State.prototype.notifyAssociation = function(interfaceId,
|
|
peerGroupController) {
|
|
var cachedPeerState = this.peerState_;
|
|
this.peerState_ = null;
|
|
|
|
this.pendingAssociation = false;
|
|
|
|
if (cachedPeerState) {
|
|
cachedPeerState.onAssociated(interfaceId, peerGroupController);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
|
|
State.prototype.onAssociated = function(interfaceId,
|
|
associatedGroupController) {
|
|
if (!this.pendingAssociation) {
|
|
return;
|
|
}
|
|
|
|
this.pendingAssociation = false;
|
|
this.peerState_ = null;
|
|
this.interfaceId = interfaceId;
|
|
this.associatedGroupController = associatedGroupController;
|
|
this.runAssociationEventHandler(AssociationEvent.ASSOCIATED);
|
|
};
|
|
|
|
State.prototype.onPeerClosedBeforeAssociation = function(disconnectReason) {
|
|
if (!this.pendingAssociation) {
|
|
return;
|
|
}
|
|
|
|
this.peerState_ = null;
|
|
this.disconnectReason = disconnectReason;
|
|
|
|
this.runAssociationEventHandler(
|
|
AssociationEvent.PEER_CLOSED_BEFORE_ASSOCIATION);
|
|
};
|
|
|
|
function createPairPendingAssociation() {
|
|
var handle0 = new InterfaceEndpointHandle();
|
|
var handle1 = new InterfaceEndpointHandle();
|
|
handle0.state_.initPendingState(handle1.state_);
|
|
handle1.state_.initPendingState(handle0.state_);
|
|
return {handle0: handle0, handle1: handle1};
|
|
}
|
|
|
|
function InterfaceEndpointHandle(interfaceId, associatedGroupController) {
|
|
this.state_ = new State(interfaceId, associatedGroupController);
|
|
}
|
|
|
|
InterfaceEndpointHandle.prototype.isValid = function() {
|
|
return this.state_.isValid();
|
|
};
|
|
|
|
InterfaceEndpointHandle.prototype.pendingAssociation = function() {
|
|
return this.state_.pendingAssociation;
|
|
};
|
|
|
|
InterfaceEndpointHandle.prototype.id = function() {
|
|
return this.state_.interfaceId;
|
|
};
|
|
|
|
InterfaceEndpointHandle.prototype.groupController = function() {
|
|
return this.state_.associatedGroupController;
|
|
};
|
|
|
|
InterfaceEndpointHandle.prototype.disconnectReason = function() {
|
|
return this.state_.disconnectReason;
|
|
};
|
|
|
|
InterfaceEndpointHandle.prototype.setAssociationEventHandler = function(
|
|
handler) {
|
|
this.state_.setAssociationEventHandler(handler);
|
|
};
|
|
|
|
InterfaceEndpointHandle.prototype.notifyAssociation = function(interfaceId,
|
|
peerGroupController) {
|
|
return this.state_.notifyAssociation(interfaceId, peerGroupController);
|
|
};
|
|
|
|
InterfaceEndpointHandle.prototype.reset = function(reason) {
|
|
this.state_.close(reason);
|
|
this.state_ = new State();
|
|
};
|
|
|
|
internal.AssociationEvent = AssociationEvent;
|
|
internal.InterfaceEndpointHandle = InterfaceEndpointHandle;
|
|
internal.createPairPendingAssociation = createPairPendingAssociation;
|
|
})();
|