| 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 |