| OLD | NEW |
| (Empty) |
| 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/router", [ | |
| 6 "mojo/public/js/codec", | |
| 7 "mojo/public/js/core", | |
| 8 "mojo/public/js/connector", | |
| 9 "mojo/public/js/validator", | |
| 10 ], function(codec, core, connector, validator) { | |
| 11 | |
| 12 var Connector = connector.Connector; | |
| 13 var MessageReader = codec.MessageReader; | |
| 14 var Validator = validator.Validator; | |
| 15 | |
| 16 function Router(handle, connectorFactory) { | |
| 17 if (!core.isHandle(handle)) | |
| 18 throw new Error("Router constructor: Not a handle"); | |
| 19 if (connectorFactory === undefined) | |
| 20 connectorFactory = Connector; | |
| 21 this.connector_ = new connectorFactory(handle); | |
| 22 this.incomingReceiver_ = null; | |
| 23 this.nextRequestID_ = 0; | |
| 24 this.completers_ = new Map(); | |
| 25 this.payloadValidators_ = []; | |
| 26 | |
| 27 this.connector_.setIncomingReceiver({ | |
| 28 accept: this.handleIncomingMessage_.bind(this), | |
| 29 }); | |
| 30 this.connector_.setErrorHandler({ | |
| 31 onError: this.handleConnectionError_.bind(this), | |
| 32 }); | |
| 33 } | |
| 34 | |
| 35 Router.prototype.close = function() { | |
| 36 this.completers_.clear(); // Drop any responders. | |
| 37 this.connector_.close(); | |
| 38 }; | |
| 39 | |
| 40 Router.prototype.accept = function(message) { | |
| 41 this.connector_.accept(message); | |
| 42 }; | |
| 43 | |
| 44 Router.prototype.reject = function(message) { | |
| 45 // TODO(mpcomplete): no way to trasmit errors over a Connection. | |
| 46 }; | |
| 47 | |
| 48 Router.prototype.acceptAndExpectResponse = function(message) { | |
| 49 // Reserve 0 in case we want it to convey special meaning in the future. | |
| 50 var requestID = this.nextRequestID_++; | |
| 51 if (requestID == 0) | |
| 52 requestID = this.nextRequestID_++; | |
| 53 | |
| 54 message.setRequestID(requestID); | |
| 55 var result = this.connector_.accept(message); | |
| 56 if (!result) | |
| 57 return Promise.reject(Error("Connection error")); | |
| 58 | |
| 59 var completer = {}; | |
| 60 this.completers_.set(requestID, completer); | |
| 61 return new Promise(function(resolve, reject) { | |
| 62 completer.resolve = resolve; | |
| 63 completer.reject = reject; | |
| 64 }); | |
| 65 }; | |
| 66 | |
| 67 Router.prototype.setIncomingReceiver = function(receiver) { | |
| 68 this.incomingReceiver_ = receiver; | |
| 69 }; | |
| 70 | |
| 71 Router.prototype.setPayloadValidators = function(payloadValidators) { | |
| 72 this.payloadValidators_ = payloadValidators; | |
| 73 }; | |
| 74 | |
| 75 Router.prototype.encounteredError = function() { | |
| 76 return this.connector_.encounteredError(); | |
| 77 }; | |
| 78 | |
| 79 Router.prototype.handleIncomingMessage_ = function(message) { | |
| 80 var noError = validator.validationError.NONE; | |
| 81 var messageValidator = new Validator(message); | |
| 82 var err = messageValidator.validateMessageHeader(); | |
| 83 for (var i = 0; err === noError && i < this.payloadValidators_.length; ++i) | |
| 84 err = this.payloadValidators_[i](messageValidator); | |
| 85 | |
| 86 if (err == noError) | |
| 87 this.handleValidIncomingMessage_(message); | |
| 88 else | |
| 89 this.handleInvalidIncomingMessage_(message, err); | |
| 90 }; | |
| 91 | |
| 92 Router.prototype.handleValidIncomingMessage_ = function(message) { | |
| 93 if (message.expectsResponse()) { | |
| 94 if (this.incomingReceiver_) { | |
| 95 this.incomingReceiver_.acceptWithResponder(message, this); | |
| 96 } else { | |
| 97 // If we receive a request expecting a response when the client is not | |
| 98 // listening, then we have no choice but to tear down the pipe. | |
| 99 this.close(); | |
| 100 } | |
| 101 } else if (message.isResponse()) { | |
| 102 var reader = new MessageReader(message); | |
| 103 var requestID = reader.requestID; | |
| 104 var completer = this.completers_.get(requestID); | |
| 105 this.completers_.delete(requestID); | |
| 106 completer.resolve(message); | |
| 107 } else { | |
| 108 if (this.incomingReceiver_) | |
| 109 this.incomingReceiver_.accept(message); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 Router.prototype.handleInvalidIncomingMessage_ = function(message, error) { | |
| 114 this.close(); | |
| 115 } | |
| 116 | |
| 117 Router.prototype.handleConnectionError_ = function(result) { | |
| 118 this.completers_.forEach(function(value) { | |
| 119 value.reject(result); | |
| 120 }); | |
| 121 this.close(); | |
| 122 }; | |
| 123 | |
| 124 // The TestRouter subclass is only intended to be used in unit tests. | |
| 125 // It defeats valid message handling and delgates invalid message handling. | |
| 126 | |
| 127 function TestRouter(handle, connectorFactory) { | |
| 128 Router.call(this, handle, connectorFactory); | |
| 129 } | |
| 130 | |
| 131 TestRouter.prototype = Object.create(Router.prototype); | |
| 132 | |
| 133 TestRouter.prototype.handleValidIncomingMessage_ = function() { | |
| 134 }; | |
| 135 | |
| 136 TestRouter.prototype.handleInvalidIncomingMessage_ = | |
| 137 function(message, error) { | |
| 138 this.validationErrorHandler(error); | |
| 139 }; | |
| 140 | |
| 141 var exports = {}; | |
| 142 exports.Router = Router; | |
| 143 exports.TestRouter = TestRouter; | |
| 144 return exports; | |
| 145 }); | |
| OLD | NEW |