OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 class _SocketInputStream implements InputStream { | |
6 _SocketInputStream(Socket socket) : _socket = socket { | |
7 if (_socket._closed) _closed = true; | |
8 _socket.onClosed = _onClosed; | |
9 } | |
10 | |
11 List<int> read([int len]) { | |
12 int bytesToRead = available(); | |
13 if (bytesToRead == 0) return null; | |
14 if (len !== null) { | |
15 if (len <= 0) { | |
16 throw new StreamException("Illegal length $len"); | |
17 } else if (bytesToRead > len) { | |
18 bytesToRead = len; | |
19 } | |
20 } | |
21 List<int> buffer = new Uint8List(bytesToRead); | |
22 int bytesRead = _socket.readList(buffer, 0, bytesToRead); | |
23 if (bytesRead == 0) { | |
24 // On MacOS when reading from a tty Ctrl-D will result in one | |
25 // byte reported as available. Attempting to read it out will | |
26 // result in zero bytes read. When that happens there is no data | |
27 // which is indicated by a null return value. | |
28 return null; | |
29 } else if (bytesRead < bytesToRead) { | |
30 List<int> newBuffer = new Uint8List(bytesRead); | |
31 newBuffer.setRange(0, bytesRead, buffer); | |
32 return newBuffer; | |
33 } else { | |
34 return buffer; | |
35 } | |
36 } | |
37 | |
38 int readInto(List<int> buffer, [int offset = 0, int len]) { | |
39 if (_closed) return null; | |
40 if (len === null) len = buffer.length; | |
41 if (offset < 0) throw new StreamException("Illegal offset $offset"); | |
42 if (len < 0) throw new StreamException("Illegal length $len"); | |
43 return _socket.readList(buffer, offset, len); | |
44 } | |
45 | |
46 int available() => _socket.available(); | |
47 | |
48 void pipe(OutputStream output, {bool close: true}) { | |
49 _pipe(this, output, close: close); | |
50 } | |
51 | |
52 void close() { | |
53 if (!_closed) { | |
54 _socket.close(); | |
55 } | |
56 } | |
57 | |
58 bool get closed => _closed; | |
59 | |
60 void set onData(void callback()) { | |
61 _socket._onData = callback; | |
62 } | |
63 | |
64 void set onClosed(void callback()) { | |
65 _clientCloseHandler = callback; | |
66 _socket._onClosed = _onClosed; | |
67 } | |
68 | |
69 void set onError(void callback(e)) { | |
70 _onError = callback; | |
71 } | |
72 | |
73 void _onClosed() { | |
74 _closed = true; | |
75 if (_clientCloseHandler !== null) { | |
76 _clientCloseHandler(); | |
77 } | |
78 } | |
79 | |
80 void _onSocketError(e) { | |
81 close(); | |
82 if (_onError != null) { | |
83 _onError(e); | |
84 return true; | |
85 } else { | |
86 return false; | |
87 } | |
88 } | |
89 | |
90 Socket _socket; | |
91 bool _closed = false; | |
92 Function _clientCloseHandler; | |
93 Function _onError; | |
94 } | |
95 | |
96 | |
97 class _SocketOutputStream | |
98 extends _BaseOutputStream implements OutputStream { | |
99 _SocketOutputStream(Socket socket) | |
100 : _socket = socket, _pendingWrites = new _BufferList(); | |
101 | |
102 bool write(List<int> buffer, [bool copyBuffer = true]) { | |
103 return _write(buffer, 0, buffer.length, copyBuffer); | |
104 } | |
105 | |
106 bool writeFrom(List<int> buffer, [int offset = 0, int len]) { | |
107 return _write( | |
108 buffer, offset, (len == null) ? buffer.length - offset : len, true); | |
109 } | |
110 | |
111 void flush() { | |
112 // Nothing to do on a socket output stream. | |
113 } | |
114 | |
115 void close() { | |
116 if (_closing && _closed) return; | |
117 if (!_pendingWrites.isEmpty) { | |
118 // Mark the socket for close when all data is written. | |
119 _closing = true; | |
120 _socket._onWrite = _onWrite; | |
121 } else { | |
122 // Close the socket for writing. | |
123 _socket._closeWrite(); | |
124 _closed = true; | |
125 // Invoke the callback asynchronously. | |
126 new Timer(0, (t) { | |
127 if (_onClosed != null) _onClosed(); | |
128 }); | |
129 } | |
130 } | |
131 | |
132 void destroy() { | |
133 _socket.onWrite = null; | |
134 _pendingWrites.clear(); | |
135 _socket.close(); | |
136 _closed = true; | |
137 } | |
138 | |
139 bool get closed => _closed; | |
140 | |
141 void set onNoPendingWrites(void callback()) { | |
142 _onNoPendingWrites = callback; | |
143 if (_onNoPendingWrites != null) { | |
144 _socket._onWrite = _onWrite; | |
145 } | |
146 } | |
147 | |
148 void set onClosed(void callback()) { | |
149 _onClosed = callback; | |
150 } | |
151 | |
152 bool _write(List<int> buffer, int offset, int len, bool copyBuffer) { | |
153 if (_closing || _closed) throw new StreamException("Stream closed"); | |
154 int bytesWritten = 0; | |
155 if (_pendingWrites.isEmpty) { | |
156 // If nothing is buffered write as much as possible and buffer | |
157 // the rest. | |
158 bytesWritten = _socket.writeList(buffer, offset, len); | |
159 if (bytesWritten == len) return true; | |
160 } | |
161 | |
162 // Place remaining data on the pending writes queue. | |
163 int notWrittenOffset = offset + bytesWritten; | |
164 if (copyBuffer) { | |
165 List<int> newBuffer = | |
166 buffer.getRange(notWrittenOffset, len - bytesWritten); | |
167 _pendingWrites.add(newBuffer); | |
168 } else { | |
169 assert(offset + len == buffer.length); | |
170 _pendingWrites.add(buffer, notWrittenOffset); | |
171 } | |
172 _socket._onWrite = _onWrite; | |
173 return false; | |
174 } | |
175 | |
176 void _onWrite() { | |
177 // Write as much buffered data to the socket as possible. | |
178 while (!_pendingWrites.isEmpty) { | |
179 List<int> buffer = _pendingWrites.first; | |
180 int offset = _pendingWrites.index; | |
181 int bytesToWrite = buffer.length - offset; | |
182 int bytesWritten; | |
183 try { | |
184 bytesWritten = _socket.writeList(buffer, offset, bytesToWrite); | |
185 } catch (e) { | |
186 _pendingWrites.clear(); | |
187 _onSocketError(e); | |
188 return; | |
189 } | |
190 _pendingWrites.removeBytes(bytesWritten); | |
191 if (bytesWritten < bytesToWrite) { | |
192 _socket._onWrite = _onWrite; | |
193 return; | |
194 } | |
195 } | |
196 | |
197 // All buffered data was written. | |
198 if (_closing) { | |
199 _socket._closeWrite(); | |
200 _closed = true; | |
201 if (_onClosed != null) { | |
202 _onClosed(); | |
203 } | |
204 } else { | |
205 if (_onNoPendingWrites != null) _onNoPendingWrites(); | |
206 } | |
207 if (_onNoPendingWrites == null) { | |
208 _socket._onWrite = null; | |
209 } else { | |
210 _socket._onWrite = _onWrite; | |
211 } | |
212 } | |
213 | |
214 bool _onSocketError(e) { | |
215 close(); | |
216 if (_onError != null) { | |
217 _onError(e); | |
218 return true; | |
219 } else { | |
220 return false; | |
221 } | |
222 } | |
223 | |
224 Socket _socket; | |
225 _BufferList _pendingWrites; | |
226 Function _onNoPendingWrites; | |
227 Function _onClosed; | |
228 bool _closing = false; | |
229 bool _closed = false; | |
230 } | |
OLD | NEW |