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 abstract class Interface { | 7 abstract class Interface { |
8 core.MojoMessagePipeEndpoint _endpoint; | 8 core.MojoMessagePipeEndpoint _endpoint; |
9 core.MojoHandle _handle; | 9 core.MojoHandle _handle; |
10 List _sendQueue; | 10 List _sendQueue; |
11 bool _isOpen; | 11 bool _isOpen; |
12 | 12 |
13 Message handleMessage(MessageReader reader); | 13 Future<Message> handleMessage(MessageReader reader); |
14 | 14 |
15 Interface(this._endpoint) { | 15 Interface(core.MojoMessagePipeEndpoint endpoint) : |
| 16 _endpoint = endpoint, |
| 17 _sendQueue = [], |
| 18 _handle = new core.MojoHandle(endpoint.handle), |
| 19 _isOpen = false; |
| 20 |
| 21 Interface.fromHandle(int handle) { |
| 22 _endpoint = |
| 23 new core.MojoMessagePipeEndpoint(new core.RawMojoHandle(handle)); |
16 _sendQueue = []; | 24 _sendQueue = []; |
17 _handle = new core.MojoHandle(_endpoint.handle); | 25 _handle = new core.MojoHandle(_endpoint.handle); |
18 _isOpen = false; | 26 _isOpen = false; |
19 } | 27 } |
20 | 28 |
| 29 void _doRead() { |
| 30 assert(_handle.readyRead); |
| 31 |
| 32 // Query how many bytes are available. |
| 33 var result = _endpoint.query(); |
| 34 if (!result.status.isOk && !result.status.isResourceExhausted) { |
| 35 // If something else happens, it means the handle wasn't really ready |
| 36 // for reading, which indicates a bug in MojoHandle or the |
| 37 // handle watcher. |
| 38 throw "message pipe query failed: ${result.status} for $_handle"; |
| 39 } |
| 40 |
| 41 // Read the data and view as a message. |
| 42 var bytes = new ByteData(result.bytesRead); |
| 43 var handles = new List<core.RawMojoHandle>(result.handlesRead); |
| 44 result = _endpoint.read(bytes, result.bytesRead, handles); |
| 45 if (!result.status.isOk && !result.status.isResourceExhausted) { |
| 46 // If something else happens, it means the handle wasn't really ready |
| 47 // for reading, which indicates a bug in MojoHandle or the |
| 48 // handle watcher. |
| 49 throw "message pipe read failed: ${result.status}"; |
| 50 } |
| 51 var message = new Message(bytes, handles); |
| 52 var reader = new MessageReader(message); |
| 53 |
| 54 // Prepare the response. |
| 55 var responseFuture = handleMessage(reader); |
| 56 |
| 57 // If there's a response, queue it up for sending. |
| 58 if (responseFuture != null) { |
| 59 responseFuture.then((response) { |
| 60 _sendQueue.add(response); |
| 61 if (_sendQueue.length == 1) { |
| 62 _handle.enableWriteEvents(); |
| 63 } |
| 64 }); |
| 65 } |
| 66 } |
| 67 |
| 68 void _doWrite() { |
| 69 if (_sendQueue.length > 0) { |
| 70 assert(_handle.readyWrite); |
| 71 var responseMessage = _sendQueue.removeAt(0); |
| 72 _endpoint.write(responseMessage.buffer, |
| 73 responseMessage.buffer.lengthInBytes, |
| 74 responseMessage.handles); |
| 75 if (!_endpoint.status.isOk) { |
| 76 throw "message pipe write failed: ${_endpoint.status}"; |
| 77 } |
| 78 } |
| 79 } |
| 80 |
21 StreamSubscription<int> listen() { | 81 StreamSubscription<int> listen() { |
22 _isOpen = true; | 82 _isOpen = true; |
23 return _handle.listen((int mojoSignal) { | 83 return _handle.listen((List<int> event) { |
24 if (core.MojoHandleSignals.isReadable(mojoSignal)) { | 84 var signalsWatched = new core.MojoHandleSignals(event[0]); |
25 // Query how many bytes are available. | 85 var signalsReceived = new core.MojoHandleSignals(event[1]); |
26 var result = _endpoint.query(); | 86 if (signalsReceived.isPeerClosed) { |
27 if (!result.status.isOk && !result.status.isResourceExhausted) { | 87 close(); |
28 // If something else happens, it means the handle wasn't really ready | 88 return; |
29 // for reading, which indicates a bug in MojoHandle or the | 89 } |
30 // event listener. | |
31 throw new Exception("message pipe query failed: ${result.status}"); | |
32 } | |
33 | 90 |
34 // Read the data and view as a message. | 91 if (signalsReceived.isReadable) { |
35 var bytes = new ByteData(result.bytesRead); | 92 _doRead(); |
36 var handles = new List<core.RawMojoHandle>(result.handlesRead); | 93 } |
37 result = _endpoint.read(bytes, result.bytesRead, handles); | |
38 if (!result.status.isOk && !result.status.isResourceExhausted) { | |
39 // If something else happens, it means the handle wasn't really ready | |
40 // for reading, which indicates a bug in MojoHandle or the | |
41 // event listener. | |
42 throw new Exception("message pipe read failed: ${result.status}"); | |
43 } | |
44 var message = new Message(bytes, handles); | |
45 var reader = new MessageReader(message); | |
46 | 94 |
47 // Prepare the response. | 95 if (signalsReceived.isWritable) { |
48 var responseMessage = handleMessage(reader); | 96 _doWrite(); |
49 // If there's a response, queue it up for sending. | |
50 if (responseMessage != null) { | |
51 _sendQueue.add(responseMessage); | |
52 if ((_sendQueue.length > 0) && !_handle.writeEnabled()) { | |
53 _handle.enableWriteEvents(); | |
54 } | |
55 } | |
56 } | 97 } |
57 if (core.MojoHandleSignals.isWritable(mojoSignal)) { | 98 |
58 if (_sendQueue.length > 0) { | 99 if (_sendQueue.length == 0) { |
59 var responseMessage = _sendQueue.removeAt(0); | 100 var withoutWritable = signalsWatched - core.MojoHandleSignals.WRITABLE; |
60 _endpoint.write(responseMessage.buffer, | 101 _handle.enableSignals(withoutWritable); |
61 responseMessage.buffer.lengthInBytes, | 102 } else { |
62 responseMessage.handles); | 103 _handle.enableSignals(signalsWatched); |
63 if (!_endpoint.status.isOk) { | |
64 throw new Exception("message pipe write failed"); | |
65 } | |
66 } | |
67 if ((_sendQueue.length == 0) && _handle.writeEnabled()) { | |
68 _handle.disableWriteEvents(); | |
69 } | |
70 } | |
71 if (core.MojoHandleSignals.isNone(mojoSignal)) { | |
72 // The handle watcher will send MojoHandleSignals.NONE when the other | |
73 // endpoint of the pipe is closed. | |
74 _handle.close(); | |
75 } | 104 } |
76 }); | 105 }); |
77 } | 106 } |
78 | 107 |
| 108 void close() { |
| 109 if (_isOpen) { |
| 110 _handle.close(); |
| 111 _isOpen = false; |
| 112 _handle = null; |
| 113 } |
| 114 } |
| 115 |
79 Message buildResponse(Type t, int name, Object response) { | 116 Message buildResponse(Type t, int name, Object response) { |
80 var builder = new MessageBuilder(name, align(getEncodedSize(t))); | 117 var builder = new MessageBuilder(name, align(getEncodedSize(t))); |
81 builder.encodeStruct(t, response); | 118 builder.encodeStruct(t, response); |
82 return builder.finish(); | 119 return builder.finish(); |
83 } | 120 } |
84 | 121 |
85 Message buildResponseWithID( | 122 Message buildResponseWithID( |
86 Type t, int name, int id, int flags, Object response) { | 123 Type t, int name, int id, int flags, Object response) { |
87 var builder = new MessageWithRequestIDBuilder( | 124 var builder = new MessageWithRequestIDBuilder( |
88 name, align(getEncodedSize(t)), id, flags); | 125 name, align(getEncodedSize(t)), id, flags); |
89 builder.encodeStruct(t, response); | 126 builder.encodeStruct(t, response); |
90 return builder.finish(); | 127 return builder.finish(); |
91 } | 128 } |
92 | 129 |
93 void enqueueMessage(Type t, int name, Object msg) { | 130 void enqueueMessage(Type t, int name, Object msg) { |
94 var builder = new MessageBuilder(name, align(getEncodedSize(t))); | 131 var builder = new MessageBuilder(name, align(getEncodedSize(t))); |
95 builder.encodeStruct(t, msg); | 132 builder.encodeStruct(t, msg); |
96 var message = builder.finish(); | 133 var message = builder.finish(); |
97 _sendQueue.add(message); | 134 _sendQueue.add(message); |
98 if (!_handle.writeEnabled()) { | 135 _handle.enableWriteEvents(); |
99 _handle.enableWriteEvents(); | |
100 } | |
101 } | 136 } |
102 | 137 |
103 Future enqueueMessageWithRequestID(Type t, int name, int id, Object msg) { | 138 Future enqueueMessageWithRequestID(Type t, int name, int id, Object msg) { |
104 throw new Exception("The client Mixin should not expect a response"); | 139 // TODO(zra): Is this correct? |
| 140 throw "The client interface should not expect a response"; |
105 } | 141 } |
106 | 142 |
107 bool get isOpen => _isOpen; | 143 bool get isOpen => _isOpen; |
| 144 core.MojoMessagePipeEndpoint get endpoint => _endpoint; |
108 } | 145 } |
OLD | NEW |