1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5define("mojo/public/js/connection", [ 6 "mojo/public/js/bindings", 7 "mojo/public/js/connector", 8 "mojo/public/js/core", 9 "mojo/public/js/router", 10], function(bindings, connector, core, router) { 11 12 var Router = router.Router; 13 var EmptyProxy = bindings.EmptyProxy; 14 var EmptyStub = bindings.EmptyStub; 15 var ProxyBindings = bindings.ProxyBindings; 16 var StubBindings = bindings.StubBindings; 17 var TestConnector = connector.TestConnector; 18 var TestRouter = router.TestRouter; 19 20 // TODO(hansmuller): the proxy receiver_ property should be receiver$ 21 22 function BaseConnection(localStub, remoteProxy, router) { 23 this.router_ = router; 24 this.local = localStub; 25 this.remote = remoteProxy; 26 27 this.router_.setIncomingReceiver(localStub); 28 this.router_.setErrorHandler(function() { 29 if (StubBindings(this.local) && 30 StubBindings(this.local).connectionErrorHandler) 31 StubBindings(this.local).connectionErrorHandler(); 32 }.bind(this)); 33 if (this.remote) 34 this.remote.receiver_ = router; 35 36 // Validate incoming messages: remote responses and local requests. 37 var validateRequest = localStub && localStub.validator; 38 var validateResponse = remoteProxy && remoteProxy.validator; 39 var payloadValidators = []; 40 if (validateRequest) 41 payloadValidators.push(validateRequest); 42 if (validateResponse) 43 payloadValidators.push(validateResponse); 44 this.router_.setPayloadValidators(payloadValidators); 45 } 46 47 BaseConnection.prototype.close = function() { 48 this.router_.close(); 49 this.router_ = null; 50 this.local = null; 51 this.remote = null; 52 }; 53 54 BaseConnection.prototype.encounteredError = function() { 55 return this.router_.encounteredError(); 56 }; 57 58 function Connection( 59 handle, localFactory, remoteFactory, routerFactory, connectorFactory) { 60 var routerClass = routerFactory || Router; 61 var router = new routerClass(handle, connectorFactory); 62 var remoteProxy = remoteFactory && new remoteFactory(router); 63 var localStub = localFactory && new localFactory(remoteProxy); 64 BaseConnection.call(this, localStub, remoteProxy, router); 65 } 66 67 Connection.prototype = Object.create(BaseConnection.prototype); 68 69 // The TestConnection subclass is only intended to be used in unit tests. 70 function TestConnection(handle, localFactory, remoteFactory) { 71 Connection.call(this, 72 handle, 73 localFactory, 74 remoteFactory, 75 TestRouter, 76 TestConnector); 77 } 78 79 TestConnection.prototype = Object.create(Connection.prototype); 80 81 // Return a handle for a message pipe that's connected to a proxy 82 // for remoteInterface. Used by generated code for outgoing interface& 83 // (request) parameters: the caller is given the generated proxy via 84 // |proxyCallback(proxy)| and the generated code sends the handle 85 // returned by this function. 86 function bindProxy(proxyCallback, remoteInterface) { 87 var messagePipe = core.createMessagePipe(); 88 if (messagePipe.result != core.RESULT_OK) 89 throw new Error("createMessagePipe failed " + messagePipe.result); 90 91 var proxy = new remoteInterface.proxyClass; 92 var router = new Router(messagePipe.handle0); 93 var connection = new BaseConnection(undefined, proxy, router); 94 ProxyBindings(proxy).connection = connection; 95 if (proxyCallback) 96 proxyCallback(proxy); 97 98 return messagePipe.handle1; 99 } 100 101 // Return a handle for a message pipe that's connected to a stub for 102 // localInterface. Used by generated code for outgoing interface 103 // parameters: the caller is given the generated stub via 104 // |stubCallback(stub)| and the generated code sends the handle 105 // returned by this function. The caller is responsible for managing 106 // the lifetime of the stub and for setting it's implementation 107 // delegate with: StubBindings(stub).delegate = myImpl; 108 function bindImpl(stubCallback, localInterface) { 109 var messagePipe = core.createMessagePipe(); 110 if (messagePipe.result != core.RESULT_OK) 111 throw new Error("createMessagePipe failed " + messagePipe.result); 112 113 var stub = new localInterface.stubClass; 114 var router = new Router(messagePipe.handle0); 115 var connection = new BaseConnection(stub, undefined, router); 116 StubBindings(stub).connection = connection; 117 if (stubCallback) 118 stubCallback(stub); 119 120 return messagePipe.handle1; 121 } 122 123 // Return a remoteInterface proxy for handle. Used by generated code 124 // for converting incoming interface parameters to proxies. 125 function bindHandleToProxy(handle, remoteInterface) { 126 if (!core.isHandle(handle)) 127 throw new Error("Not a handle " + handle); 128 129 var proxy = new remoteInterface.proxyClass; 130 var router = new Router(handle); 131 var connection = new BaseConnection(undefined, proxy, router); 132 ProxyBindings(proxy).connection = connection; 133 return proxy; 134 } 135 136 // Return a localInterface stub for handle. Used by generated code 137 // for converting incoming interface& request parameters to localInterface 138 // stubs. The caller can specify the stub's implementation of localInterface 139 // like this: StubBindings(stub).delegate = myStubImpl. 140 function bindHandleToStub(handle, localInterface) { 141 if (!core.isHandle(handle)) 142 throw new Error("Not a handle " + handle); 143 144 var stub = new localInterface.stubClass; 145 var router = new Router(handle); 146 var connection = new BaseConnection(stub, undefined, router); 147 StubBindings(stub).connection = connection; 148 return stub; 149 } 150 151 /** 152 * Creates a messape pipe and links one end of the pipe to the given object. 153 * @param {!Object} obj The object to create a handle for. Must be a subclass 154 * of an auto-generated stub class. 155 * @return {!MojoHandle} The other (not yet connected) end of the message 156 * pipe. 157 */ 158 function bindStubDerivedImpl(obj) { 159 var pipe = core.createMessagePipe(); 160 var router = new Router(pipe.handle0); 161 var connection = new BaseConnection(obj, undefined, router); 162 obj.connection = connection; 163 return pipe.handle1; 164 } 165 166 var exports = {}; 167 exports.Connection = Connection; 168 exports.TestConnection = TestConnection; 169 170 exports.bindProxy = bindProxy; 171 exports.bindImpl = bindImpl; 172 exports.bindHandleToProxy = bindHandleToProxy; 173 exports.bindHandleToStub = bindHandleToStub; 174 exports.bindStubDerivedImpl = bindStubDerivedImpl; 175 return exports; 176}); 177