• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/connector", [
6  "mojo/public/js/buffer",
7  "mojo/public/js/codec",
8  "mojo/public/js/core",
9  "mojo/public/js/support",
10], function(buffer, codec, core, support) {
11
12  function Connector(handle) {
13    if (!core.isHandle(handle))
14      throw new Error("Connector: not a handle " + handle);
15    this.handle_ = handle;
16    this.dropWrites_ = false;
17    this.error_ = false;
18    this.incomingReceiver_ = null;
19    this.readWatcher_ = null;
20    this.errorHandler_ = null;
21
22    if (handle) {
23      this.readWatcher_ = support.watch(handle,
24                                        core.HANDLE_SIGNAL_READABLE,
25                                        this.readMore_.bind(this));
26    }
27  }
28
29  Connector.prototype.close = function() {
30    if (this.readWatcher_) {
31      support.cancelWatch(this.readWatcher_);
32      this.readWatcher_ = null;
33    }
34    if (this.handle_ != null) {
35      core.close(this.handle_);
36      this.handle_ = null;
37    }
38  };
39
40  Connector.prototype.accept = function(message) {
41    if (this.error_)
42      return false;
43
44    if (this.dropWrites_)
45      return true;
46
47    var result = core.writeMessage(this.handle_,
48                                   new Uint8Array(message.buffer.arrayBuffer),
49                                   message.handles,
50                                   core.WRITE_MESSAGE_FLAG_NONE);
51    switch (result) {
52      case core.RESULT_OK:
53        // The handles were successfully transferred, so we don't own them
54        // anymore.
55        message.handles = [];
56        break;
57      case core.RESULT_FAILED_PRECONDITION:
58        // There's no point in continuing to write to this pipe since the other
59        // end is gone. Avoid writing any future messages. Hide write failures
60        // from the caller since we'd like them to continue consuming any
61        // backlog of incoming messages before regarding the message pipe as
62        // closed.
63        this.dropWrites_ = true;
64        break;
65      default:
66        // This particular write was rejected, presumably because of bad input.
67        // The pipe is not necessarily in a bad state.
68        return false;
69    }
70    return true;
71  };
72
73  Connector.prototype.setIncomingReceiver = function(receiver) {
74    this.incomingReceiver_ = receiver;
75  };
76
77  Connector.prototype.setErrorHandler = function(handler) {
78    this.errorHandler_ = handler;
79  };
80
81  Connector.prototype.encounteredError = function() {
82    return this.error_;
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 (this.handle_ == null) // The connector has been closed.
90        return;
91      if (read.result == core.RESULT_SHOULD_WAIT)
92        return;
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  // doesn't automatically listen for input messages. Instead, you need to
109  // call waitForNextMessage to block and wait for the next incoming message.
110  function TestConnector(handle) {
111    Connector.call(this, handle);
112  }
113
114  TestConnector.prototype = Object.create(Connector.prototype);
115
116  TestConnector.prototype.waitForNextMessage = function() {
117    var wait = core.wait(this.handle_, core.HANDLE_SIGNAL_READABLE,
118                         core.DEADLINE_INDEFINITE);
119    this.readMore_(wait.result);
120  }
121
122  var exports = {};
123  exports.Connector = Connector;
124  exports.TestConnector = TestConnector;
125  return exports;
126});
127