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 |