Home | History | Annotate | Download | only in bindings
      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/bindings/connector", [
      6   "mojo/public/js/bindings/buffer",
      7   "mojo/public/js/bindings/codec",
      8   "mojo/public/js/bindings/core",
      9   "mojo/public/js/bindings/support",
     10 ], function(buffer, codec, core, support) {
     11 
     12   function Connector(handle) {
     13     this.handle_ = handle;
     14     this.dropWrites_ = false;
     15     this.error_ = false;
     16     this.incomingReceiver_ = null;
     17     this.readWaitCookie_ = null;
     18     this.errorHandler_ = null;
     19 
     20     this.waitToReadMore_();
     21   }
     22 
     23   Connector.prototype.close = function() {
     24     if (this.readWaitCookie_) {
     25       support.cancelWait(this.readWaitCookie_);
     26       this.readWaitCookie_ = null;
     27     }
     28     if (this.handle_ != null) {
     29       core.close(this.handle_);
     30       this.handle_ = null;
     31     }
     32   };
     33 
     34   Connector.prototype.accept = function(message) {
     35     if (this.error_)
     36       return false;
     37 
     38     if (this.dropWrites_)
     39       return true;
     40 
     41     var result = core.writeMessage(this.handle_,
     42                                    new Uint8Array(message.buffer.arrayBuffer),
     43                                    message.handles,
     44                                    core.WRITE_MESSAGE_FLAG_NONE);
     45     switch (result) {
     46       case core.RESULT_OK:
     47         // The handles were successfully transferred, so we don't own them
     48         // anymore.
     49         message.handles = [];
     50         break;
     51       case core.RESULT_FAILED_PRECONDITION:
     52         // There's no point in continuing to write to this pipe since the other
     53         // end is gone. Avoid writing any future messages. Hide write failures
     54         // from the caller since we'd like them to continue consuming any
     55         // backlog of incoming messages before regarding the message pipe as
     56         // closed.
     57         this.dropWrites_ = true;
     58         break;
     59       default:
     60         // This particular write was rejected, presumably because of bad input.
     61         // The pipe is not necessarily in a bad state.
     62         return false;
     63     }
     64     return true;
     65   };
     66 
     67   Connector.prototype.setIncomingReceiver = function(receiver) {
     68     this.incomingReceiver_ = receiver;
     69   };
     70 
     71   Connector.prototype.setErrorHandler = function(handler) {
     72     this.errorHandler_ = handler;
     73   };
     74 
     75   Connector.prototype.encounteredError = function() {
     76     return this.error_;
     77   };
     78 
     79   Connector.prototype.waitToReadMore_ = function() {
     80     this.readWaitCookie_ = support.asyncWait(this.handle_,
     81                                              core.HANDLE_SIGNAL_READABLE,
     82                                              this.readMore_.bind(this));
     83   };
     84 
     85   Connector.prototype.readMore_ = function(result) {
     86     for (;;) {
     87       var read = core.readMessage(this.handle_,
     88                                   core.READ_MESSAGE_FLAG_NONE);
     89       if (read.result == core.RESULT_SHOULD_WAIT) {
     90         this.waitToReadMore_();
     91         return;
     92       }
     93       if (read.result != core.RESULT_OK) {
     94         this.error_ = true;
     95         if (this.errorHandler_)
     96           this.errorHandler_.onError(read.result);
     97         return;
     98       }
     99       var messageBuffer = new buffer.Buffer(read.buffer);
    100       var message = new codec.Message(messageBuffer, read.handles);
    101       if (this.incomingReceiver_) {
    102           this.incomingReceiver_.accept(message);
    103       }
    104     }
    105   };
    106 
    107   // The TestConnector subclass is only intended to be used in unit tests. It
    108   // enables delivering a message to the pipe's handle without an async wait.
    109 
    110   function TestConnector(handle) {
    111     Connector.call(this, handle);
    112   }
    113 
    114   TestConnector.prototype = Object.create(Connector.prototype);
    115 
    116   TestConnector.prototype.waitToReadMore_ = function() {
    117   };
    118 
    119   TestConnector.prototype.deliverMessage = function() {
    120     this.readMore_(core.RESULT_OK);
    121   }
    122 
    123   var exports = {};
    124   exports.Connector = Connector;
    125   exports.TestConnector = TestConnector;
    126   return exports;
    127 });
    128