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 part of bindings; | |
6 | |
7 class ProxyCloseException { | |
8 final String message; | |
9 ProxyCloseException(this.message); | |
10 String toString() => message; | |
11 } | |
12 | |
13 abstract class Proxy extends core.MojoEventStreamListener { | |
14 Map<int, Completer> _completerMap; | |
15 int _nextId = 0; | |
16 int _version = 0; | |
17 /// Version of this interface that the remote side supports. Updated when a | |
18 /// call to [queryVersion] or [requireVersion] is made. | |
19 int get version => _version; | |
20 | |
21 Proxy.fromEndpoint(core.MojoMessagePipeEndpoint endpoint) | |
22 : _completerMap = {}, | |
23 super.fromEndpoint(endpoint); | |
24 | |
25 Proxy.fromHandle(core.MojoHandle handle) | |
26 : _completerMap = {}, | |
27 super.fromHandle(handle); | |
28 | |
29 Proxy.unbound() | |
30 : _completerMap = {}, | |
31 super.unbound(); | |
32 | |
33 void handleResponse(ServiceMessage reader); | |
34 | |
35 void handleRead() { | |
36 // Query how many bytes are available. | |
37 var result = endpoint.query(); | |
38 assert(result.status.isOk || result.status.isResourceExhausted); | |
39 | |
40 // Read the data. | |
41 var bytes = new ByteData(result.bytesRead); | |
42 var handles = new List<core.MojoHandle>(result.handlesRead); | |
43 result = endpoint.read(bytes, result.bytesRead, handles); | |
44 assert(result.status.isOk || result.status.isResourceExhausted); | |
45 var message = new ServiceMessage.fromMessage(new Message(bytes, handles)); | |
46 if (ControlMessageHandler.isControlMessage(message)) { | |
47 _handleControlMessageResponse(message); | |
48 return; | |
49 } | |
50 handleResponse(message); | |
51 } | |
52 | |
53 void handleWrite() { | |
54 throw 'Unexpected write signal in proxy.'; | |
55 } | |
56 | |
57 @override | |
58 Future close({bool immediate: false}) { | |
59 for (var completer in _completerMap.values) { | |
60 completer.completeError(new ProxyCloseException('Proxy closed')); | |
61 } | |
62 _completerMap.clear(); | |
63 return super.close(immediate: immediate); | |
64 } | |
65 | |
66 void sendMessage(Struct message, int name) { | |
67 if (!isOpen) { | |
68 listen(); | |
69 } | |
70 var header = new MessageHeader(name); | |
71 var serviceMessage = message.serializeWithHeader(header); | |
72 endpoint.write(serviceMessage.buffer, | |
73 serviceMessage.buffer.lengthInBytes, serviceMessage.handles); | |
74 if (!endpoint.status.isOk) { | |
75 throw "message pipe write failed - ${endpoint.status}"; | |
76 } | |
77 } | |
78 | |
79 Future sendMessageWithRequestId(Struct message, int name, int id, int flags) { | |
80 if (!isOpen) { | |
81 listen(); | |
82 } | |
83 if (id == -1) { | |
84 id = _nextId++; | |
85 } | |
86 | |
87 var header = new MessageHeader.withRequestId(name, flags, id); | |
88 var serviceMessage = message.serializeWithHeader(header); | |
89 endpoint.write(serviceMessage.buffer, | |
90 serviceMessage.buffer.lengthInBytes, serviceMessage.handles); | |
91 if (!endpoint.status.isOk) { | |
92 throw "message pipe write failed - ${endpoint.status}"; | |
93 } | |
94 | |
95 var completer = new Completer(); | |
96 _completerMap[id] = completer; | |
97 return completer.future; | |
98 } | |
99 | |
100 // Need a getter for this for access in subclasses. | |
101 Map<int, Completer> get completerMap => _completerMap; | |
102 | |
103 String toString() { | |
104 var superString = super.toString(); | |
105 return "Proxy(${superString})"; | |
106 } | |
107 | |
108 /// Queries the max version that the remote side supports. | |
109 /// Updates [version]. | |
110 Future<int> queryVersion() async { | |
111 var params = new icm.RunMessageParams(); | |
112 params.reserved0 = 16; | |
113 params.reserved1 = 0; | |
114 params.queryVersion = new icm.QueryVersion(); | |
115 var response = await | |
116 sendMessageWithRequestId(params, | |
117 icm.kRunMessageId, | |
118 -1, | |
119 MessageHeader.kMessageExpectsResponse); | |
120 _version = response.queryVersionResult.version; | |
121 return _version; | |
122 } | |
123 | |
124 /// If the remote side doesn't support the [requiredVersion], it will close | |
125 /// its end of the message pipe asynchronously. This does nothing if it's | |
126 /// already known that the remote side supports [requiredVersion]. | |
127 /// Updates [version]. | |
128 void requireVersion(int requiredVersion) { | |
129 if (requiredVersion <= _version) { | |
130 // Already supported. | |
131 return; | |
132 } | |
133 | |
134 // If the remote end doesn't close the pipe, we know that it supports | |
135 // required version. | |
136 _version = requiredVersion; | |
137 | |
138 var params = new icm.RunOrClosePipeMessageParams(); | |
139 params.reserved0 = 16; | |
140 params.reserved1 = 0; | |
141 params.requireVersion = new icm.RequireVersion(); | |
142 params.requireVersion.version = requiredVersion; | |
143 // TODO(johnmccutchan): We've set _version above but if this sendMessage | |
144 // throws an exception we may not have sent the RunOrClose message. Should | |
145 // we reset _version in that case? | |
146 sendMessage(params, icm.kRunOrClosePipeMessageId); | |
147 } | |
148 | |
149 _handleControlMessageResponse(ServiceMessage message) { | |
150 // We only expect to see Run messages. | |
151 assert(message.header.type == icm.kRunMessageId); | |
152 var response = icm.RunResponseMessageParams.deserialize(message.payload); | |
153 if (!message.header.hasRequestId) { | |
154 throw 'Expected a message with a valid request Id.'; | |
155 } | |
156 Completer c = completerMap[message.header.requestId]; | |
157 if (c == null) { | |
158 throw 'Message had unknown request Id: ${message.header.requestId}'; | |
159 } | |
160 completerMap.remove(message.header.requestId); | |
161 assert(!c.isCompleted); | |
162 c.complete(response); | |
163 } | |
164 } | |
165 | |
166 // Generated Proxy classes implement this interface. | |
167 abstract class ProxyBase { | |
168 final Proxy impl = null; | |
169 final String name = null; | |
170 } | |
OLD | NEW |