Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(463)

Side by Side Diff: pkg/analysis_server/lib/src/channel/byte_stream_channel.dart

Issue 872633002: Use 'print' to send responses/notifications to the client. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Use non-blocking 'stdout', revert 'print' changes. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/analysis_server/doc/api.html ('k') | pkg/analysis_server/lib/src/server/stdio_server.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library channel.byte_stream; 5 library channel.byte_stream;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:convert'; 8 import 'dart:convert';
9 import 'dart:io'; 9 import 'dart:io';
10 10
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 return responseStream.firstWhere((Response response) => response.id == id); 54 return responseStream.firstWhere((Response response) => response.id == id);
55 } 55 }
56 } 56 }
57 57
58 /** 58 /**
59 * Instances of the class [ByteStreamServerChannel] implement a 59 * Instances of the class [ByteStreamServerChannel] implement a
60 * [ServerCommunicationChannel] that uses a stream and a sink (typically, 60 * [ServerCommunicationChannel] that uses a stream and a sink (typically,
61 * standard input and standard output) to communicate with clients. 61 * standard input and standard output) to communicate with clients.
62 */ 62 */
63 class ByteStreamServerChannel implements ServerCommunicationChannel { 63 class ByteStreamServerChannel implements ServerCommunicationChannel {
64 /** 64 final Stream _input;
65 * Value of [_outputState] indicating that there is no outstanding data in
66 * [_pendingOutput], and that the most recent flush of [_output] has
67 * completed.
68 */
69 static const int _STATE_IDLE = 0;
70
71 /**
72 * Value of [_outputState] indicating that there is outstanding data in
73 * [_pendingOutput], and that the most recent flush of [_output] has
74 * completed; therefore a microtask has been scheduled to send the data.
75 */
76 static const int _STATE_MICROTASK_PENDING = 1;
77
78 /**
79 * Value of [_outputState] indicating that data has been sent to the
80 * [_output] stream and flushed, but the flush has not completed, so we must
81 * wait for it to complete before sending more data. There may or may not be
82 * outstanding data in [_pendingOutput].
83 */
84 static const int _STATE_FLUSH_PENDING = 2;
85
86 final Stream input;
87 65
88 final IOSink _output; 66 final IOSink _output;
89 67
90 /** 68 /**
91 * The instrumentation service that is to be used by this analysis server. 69 * The instrumentation service that is to be used by this analysis server.
92 */ 70 */
93 final InstrumentationService instrumentationService; 71 final InstrumentationService _instrumentationService;
94 72
95 /** 73 /**
96 * Completer that will be signalled when the input stream is closed. 74 * Completer that will be signalled when the input stream is closed.
97 */ 75 */
98 final Completer _closed = new Completer(); 76 final Completer _closed = new Completer();
99 77
100 /** 78 /**
101 * State of the output stream (see constants above).
102 */
103 int _outputState = _STATE_IDLE;
104
105 /**
106 * List of strings that need to be sent to [_output] at the next available
107 * opportunity.
108 */
109 List<String> _pendingOutput = <String>[];
110
111 /**
112 * True if [close] has been called. 79 * True if [close] has been called.
113 */ 80 */
114 bool _closeRequested = false; 81 bool _closeRequested = false;
115 82
116 ByteStreamServerChannel(this.input, this._output, 83 ByteStreamServerChannel(this._input, this._output,
117 this.instrumentationService); 84 this._instrumentationService);
118 85
119 /** 86 /**
120 * Future that will be completed when the input stream is closed. 87 * Future that will be completed when the input stream is closed.
121 */ 88 */
122 Future get closed { 89 Future get closed {
123 return _closed.future; 90 return _closed.future;
124 } 91 }
125 92
126 @override 93 @override
127 void close() { 94 void close() {
128 if (!_closeRequested) { 95 if (!_closeRequested) {
129 _closeRequested = true; 96 _closeRequested = true;
130 if (_outputState == _STATE_IDLE) { 97 assert(!_closed.isCompleted);
131 assert(!_closed.isCompleted); 98 _closed.complete();
132 _closed.complete();
133 } else {
134 // Nothing to do. [_flushCompleted] will call _closed.complete() after
135 // the flush completes.
136 }
137 } 99 }
138 } 100 }
139 101
140 @override 102 @override
141 void listen(void onRequest(Request request), {Function onError, void 103 void listen(void onRequest(Request request), {Function onError, void
142 onDone()}) { 104 onDone()}) {
143 input.transform( 105 _input.transform(
144 (new Utf8Codec()).decoder).transform( 106 (new Utf8Codec()).decoder).transform(
145 new LineSplitter()).listen( 107 new LineSplitter()).listen(
146 (String data) => _readRequest(data, onRequest), 108 (String data) => _readRequest(data, onRequest),
147 onError: onError, 109 onError: onError,
148 onDone: () { 110 onDone: () {
149 close(); 111 close();
150 onDone(); 112 onDone();
151 }); 113 });
152 } 114 }
153 115
154 @override 116 @override
155 void sendNotification(Notification notification) { 117 void sendNotification(Notification notification) {
156 // Don't send any further notifications after the communication channel is 118 // Don't send any further notifications after the communication channel is
157 // closed. 119 // closed.
158 if (_closeRequested) { 120 if (_closeRequested) {
159 return; 121 return;
160 } 122 }
161 ServerCommunicationChannel.ToJson.start(); 123 ServerCommunicationChannel.ToJson.start();
162 String jsonEncoding = JSON.encode(notification.toJson()); 124 String jsonEncoding = JSON.encode(notification.toJson());
163 ServerCommunicationChannel.ToJson.stop(); 125 ServerCommunicationChannel.ToJson.stop();
164 _outputLine(jsonEncoding); 126 _outputLine(jsonEncoding);
165 instrumentationService.logNotification(jsonEncoding); 127 _instrumentationService.logNotification(jsonEncoding);
166 } 128 }
167 129
168 @override 130 @override
169 void sendResponse(Response response) { 131 void sendResponse(Response response) {
170 // Don't send any further responses after the communication channel is 132 // Don't send any further responses after the communication channel is
171 // closed. 133 // closed.
172 if (_closeRequested) { 134 if (_closeRequested) {
173 return; 135 return;
174 } 136 }
175 ServerCommunicationChannel.ToJson.start(); 137 ServerCommunicationChannel.ToJson.start();
176 String jsonEncoding = JSON.encode(response.toJson()); 138 String jsonEncoding = JSON.encode(response.toJson());
177 ServerCommunicationChannel.ToJson.stop(); 139 ServerCommunicationChannel.ToJson.stop();
178 _outputLine(jsonEncoding); 140 _outputLine(jsonEncoding);
179 instrumentationService.logResponse(jsonEncoding); 141 _instrumentationService.logResponse(jsonEncoding);
180 }
181
182 /**
183 * Callback invoked after a flush of [_output] completes. Closes the stream
184 * if necessary. Otherwise schedules additional pending output.
185 */
186 void _flushCompleted(_) {
187 assert(_outputState == _STATE_FLUSH_PENDING);
188 if (_pendingOutput.isNotEmpty) {
189 _output.write(_pendingOutput.join());
190 _output.flush().then(_flushCompleted);
191 _pendingOutput.clear();
192 // Since we've done another flush, stay in _STATE_FLUSH_PENDING.
193 } else {
194 _outputState = _STATE_IDLE;
195 if (_closeRequested) {
196 assert(!_closed.isCompleted);
197 _closed.complete();
198 }
199 }
200 }
201
202 /**
203 * Microtask that writes pending output to the output stream and flushes it.
204 */
205 void _microtask() {
206 assert(_outputState == _STATE_MICROTASK_PENDING);
207 _output.write(_pendingOutput.join());
208 _output.flush().then(_flushCompleted);
209 _pendingOutput.clear();
210 _outputState = _STATE_FLUSH_PENDING;
211 } 142 }
212 143
213 /** 144 /**
214 * Send the string [s] to [_output] followed by a newline. 145 * Send the string [s] to [_output] followed by a newline.
215 */ 146 */
216 void _outputLine(String s) { 147 void _outputLine(String s) {
217 _pendingOutput.add(s); 148 stdout.writeln(s);
Paul Berry 2015/01/23 21:26:00 Did you mean to do _output.writeln()?
218 _pendingOutput.add('\n');
219 if (_outputState == _STATE_IDLE) {
220 // Don't send the output just yet; schedule a microtask to do it, so that
221 // if caller decides to output additional lines, they will get sent in
222 // the same call to _output.write().
223 new Future.microtask(_microtask);
224 _outputState = _STATE_MICROTASK_PENDING;
225 }
226 } 149 }
227 150
228 /** 151 /**
229 * Read a request from the given [data] and use the given function to handle 152 * Read a request from the given [data] and use the given function to handle
230 * the request. 153 * the request.
231 */ 154 */
232 void _readRequest(Object data, void onRequest(Request request)) { 155 void _readRequest(Object data, void onRequest(Request request)) {
233 // Ignore any further requests after the communication channel is closed. 156 // Ignore any further requests after the communication channel is closed.
234 if (_closed.isCompleted) { 157 if (_closed.isCompleted) {
235 return; 158 return;
236 } 159 }
237 instrumentationService.logRequest(data); 160 _instrumentationService.logRequest(data);
238 // Parse the string as a JSON descriptor and process the resulting 161 // Parse the string as a JSON descriptor and process the resulting
239 // structure as a request. 162 // structure as a request.
240 ServerCommunicationChannel.FromJson.start(); 163 ServerCommunicationChannel.FromJson.start();
241 Request request = new Request.fromString(data); 164 Request request = new Request.fromString(data);
242 ServerCommunicationChannel.FromJson.stop(); 165 ServerCommunicationChannel.FromJson.stop();
243 if (request == null) { 166 if (request == null) {
244 sendResponse(new Response.invalidRequestFormat()); 167 sendResponse(new Response.invalidRequestFormat());
245 return; 168 return;
246 } 169 }
247 onRequest(request); 170 onRequest(request);
248 } 171 }
249 } 172 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/doc/api.html ('k') | pkg/analysis_server/lib/src/server/stdio_server.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698