Home | History | Annotate | Download | only in js
      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 
      5 define("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