| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 part of bindings; | 5 part of bindings; |
| 6 | 6 |
| 7 /// Generated StubControl classes implement this interface. | 7 /// Generated StubControl classes implement this interface. |
| 8 /// StubControl objects are accessible through the [ctrl] field on Stubs. | 8 /// StubControl objects are accessible through the [ctrl] field on Stubs. |
| 9 abstract class StubControl<T> implements StubMessageHandler { | 9 abstract class StubControl<T> implements StubMessageHandler { |
| 10 // TODO(zra): This is only used by ApplicationConnection.requestService(), so | 10 // TODO(zra): This is only used by ApplicationConnection.requestService(), so |
| (...skipping 25 matching lines...) Expand all Loading... |
| 36 /// ctrl.impl. If a Mojo interface has a method 'impl', its name will be | 36 /// ctrl.impl. If a Mojo interface has a method 'impl', its name will be |
| 37 /// mangled to be 'impl_'. | 37 /// mangled to be 'impl_'. |
| 38 T get impl => ctrl.impl; | 38 T get impl => ctrl.impl; |
| 39 set impl(T impl) { | 39 set impl(T impl) { |
| 40 ctrl.impl = impl; | 40 ctrl.impl = impl; |
| 41 } | 41 } |
| 42 } | 42 } |
| 43 | 43 |
| 44 abstract class StubMessageHandler extends core.MojoEventHandler | 44 abstract class StubMessageHandler extends core.MojoEventHandler |
| 45 implements MojoInterfaceControl { | 45 implements MojoInterfaceControl { |
| 46 int _outstandingResponseFutures = 0; | |
| 47 bool _isClosing = false; | |
| 48 Completer _closeCompleter; | |
| 49 | |
| 50 StubMessageHandler.fromEndpoint(core.MojoMessagePipeEndpoint endpoint, | 46 StubMessageHandler.fromEndpoint(core.MojoMessagePipeEndpoint endpoint, |
| 51 {bool autoBegin: true}) | 47 {bool autoBegin: true}) |
| 52 : super.fromEndpoint(endpoint, autoBegin: autoBegin); | 48 : super.fromEndpoint(endpoint, autoBegin: autoBegin); |
| 53 | 49 |
| 54 StubMessageHandler.fromHandle(core.MojoHandle handle, {bool autoBegin: true}) | 50 StubMessageHandler.fromHandle(core.MojoHandle handle, {bool autoBegin: true}) |
| 55 : super.fromHandle(handle, autoBegin: autoBegin); | 51 : super.fromHandle(handle, autoBegin: autoBegin); |
| 56 | 52 |
| 57 StubMessageHandler.unbound() : super.unbound(); | 53 StubMessageHandler.unbound() : super.unbound(); |
| 58 | 54 |
| 59 /// Generated StubControl classes implement this method to route messages to | 55 /// Generated StubControl classes implement this method to route messages to |
| 60 /// the correct implementation method. | 56 /// the correct implementation method. |
| 61 dynamic handleMessage(ServiceMessage message); | 57 void handleMessage(ServiceMessage message); |
| 62 | 58 |
| 63 /// Generated StubControl classes implement this getter to return the version | 59 /// Generated StubControl classes implement this getter to return the version |
| 64 /// of the mojom interface for which the bindings are generated. | 60 /// of the mojom interface for which the bindings are generated. |
| 65 int get version; | 61 int get version; |
| 66 | 62 |
| 67 @override | 63 @override |
| 68 void handleRead() { | 64 void handleRead() { |
| 69 var result = endpoint.queryAndRead(); | 65 var result = endpoint.queryAndRead(); |
| 70 if ((result.data == null) || (result.dataLength == 0)) { | 66 if ((result.data == null) || (result.dataLength == 0)) { |
| 71 throw new MojoCodecError('Unexpected empty message or error: $result'); | 67 throw new MojoCodecError('Unexpected empty message or error: $result'); |
| 72 } | 68 } |
| 73 | 69 |
| 74 // Prepare the response. | |
| 75 var message; | |
| 76 var response; | |
| 77 try { | 70 try { |
| 78 message = new ServiceMessage.fromMessage(new Message(result.data, | 71 var message = new ServiceMessage.fromMessage(new Message(result.data, |
| 79 result.handles, result.dataLength, result.handlesLength)); | 72 result.handles, result.dataLength, result.handlesLength)); |
| 80 response = _isClosing ? null : handleMessage(message); | 73 handleMessage(message); |
| 81 } catch (e) { | 74 } catch (e) { |
| 82 if (result.handles != null) { | 75 if (result.handles != null) { |
| 83 result.handles.forEach((h) => h.close()); | 76 result.handles.forEach((h) => h.close()); |
| 84 } | 77 } |
| 85 rethrow; | 78 rethrow; |
| 86 } | 79 } |
| 87 | |
| 88 // If there's a response, send it. | |
| 89 if (response != null) { | |
| 90 if (response is Future) { | |
| 91 _outstandingResponseFutures++; | |
| 92 response.then((response) { | |
| 93 _outstandingResponseFutures--; | |
| 94 return response; | |
| 95 }).then(_sendResponse); | |
| 96 } else { | |
| 97 _sendResponse(response); | |
| 98 } | |
| 99 } else if (_isClosing && (_outstandingResponseFutures == 0)) { | |
| 100 // We are closing, there is no response to send for this message, and | |
| 101 // there are no outstanding response futures. Do the close now. | |
| 102 super.close().then((_) { | |
| 103 if (_isClosing) { | |
| 104 _isClosing = false; | |
| 105 _closeCompleter.complete(null); | |
| 106 _closeCompleter = null; | |
| 107 } | |
| 108 }); | |
| 109 } | |
| 110 } | 80 } |
| 111 | 81 |
| 112 @override | 82 @override |
| 113 void handleWrite() { | 83 void handleWrite() { |
| 114 throw 'Unexpected write signal in client.'; | 84 throw 'Unexpected write signal in client.'; |
| 115 } | 85 } |
| 116 | 86 |
| 117 // NB: |immediate| should only be true when calling close() while handling an | 87 /// Called by generated handleMessage functions in implementations. |
| 118 // exception thrown from handleRead(), e.g. when we receive a malformed | 88 void sendResponse(Message response) { |
| 119 // message, or when we have received the PEER_CLOSED event. | 89 if (isOpen) { |
| 120 @override | 90 endpoint.write( |
| 121 Future close({bool immediate: false}) { | 91 response.buffer, response.buffer.lengthInBytes, response.handles); |
| 122 if (isOpen && | 92 // FailedPrecondition is only used to indicate that the other end of |
| 123 !immediate && | 93 // the pipe has been closed. We can ignore the close here and wait for |
| 124 !isPeerClosed && | 94 // the PeerClosed signal on the event stream. |
| 125 (isInHandler || (_outstandingResponseFutures > 0))) { | 95 assert((endpoint.status == core.MojoResult.kOk) || |
| 126 // Either close() is being called from within handleRead() or | 96 (endpoint.status == core.MojoResult.kFailedPrecondition)); |
| 127 // handleWrite(), or close() is being called while there are outstanding | |
| 128 // response futures. Defer the actual close until all response futures | |
| 129 // have been resolved. | |
| 130 _isClosing = true; | |
| 131 _closeCompleter = new Completer(); | |
| 132 return _closeCompleter.future; | |
| 133 } else { | |
| 134 return super.close(immediate: immediate).then((_) { | |
| 135 if (_isClosing) { | |
| 136 _isClosing = false; | |
| 137 _closeCompleter.complete(null); | |
| 138 _closeCompleter = null; | |
| 139 } | |
| 140 }); | |
| 141 } | 97 } |
| 142 } | 98 } |
| 143 | 99 |
| 144 Message buildResponse(Struct response, int name) { | 100 Message buildResponse(Struct response, int name) { |
| 145 var header = new MessageHeader(name); | 101 var header = new MessageHeader(name); |
| 146 return response.serializeWithHeader(header); | 102 return response.serializeWithHeader(header); |
| 147 } | 103 } |
| 148 | 104 |
| 149 Message buildResponseWithId(Struct response, int name, int id, int flags) { | 105 Message buildResponseWithId(Struct response, int name, int id, int flags) { |
| 150 var header = new MessageHeader.withRequestId(name, flags, id); | 106 var header = new MessageHeader.withRequestId(name, flags, id); |
| 151 return response.serializeWithHeader(header); | 107 return response.serializeWithHeader(header); |
| 152 } | 108 } |
| 153 | 109 |
| 154 @override | 110 @override |
| 155 String toString() { | 111 String toString() { |
| 156 var superString = super.toString(); | 112 var superString = super.toString(); |
| 157 return "StubMessageHandler(${superString})"; | 113 return "StubMessageHandler(${superString})"; |
| 158 } | 114 } |
| 159 | 115 |
| 160 /// Returns a service description, which exposes the mojom type information | 116 /// Returns a service description, which exposes the mojom type information |
| 161 /// of the service being stubbed. | 117 /// of the service being stubbed. |
| 162 /// Note: The description is null or incomplete if type info is unavailable. | 118 /// Note: The description is null or incomplete if type info is unavailable. |
| 163 service_describer.ServiceDescription get description => null; | 119 service_describer.ServiceDescription get description => null; |
| 164 | |
| 165 void _sendResponse(Message response) { | |
| 166 if (isOpen) { | |
| 167 endpoint.write( | |
| 168 response.buffer, response.buffer.lengthInBytes, response.handles); | |
| 169 // FailedPrecondition is only used to indicate that the other end of | |
| 170 // the pipe has been closed. We can ignore the close here and wait for | |
| 171 // the PeerClosed signal on the event stream. | |
| 172 assert((endpoint.status == core.MojoResult.kOk) || | |
| 173 (endpoint.status == core.MojoResult.kFailedPrecondition)); | |
| 174 if (_isClosing && (_outstandingResponseFutures == 0)) { | |
| 175 // This was the final response future for which we needed to send | |
| 176 // a response. It is safe to close. | |
| 177 super.close().then((_) { | |
| 178 if (_isClosing) { | |
| 179 _isClosing = false; | |
| 180 _closeCompleter.complete(null); | |
| 181 _closeCompleter = null; | |
| 182 } | |
| 183 }); | |
| 184 } | |
| 185 } | |
| 186 } | |
| 187 } | 120 } |
| OLD | NEW |