OLD | NEW |
| (Empty) |
1 // Copyright (c) 2016, 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 import 'dart:io'; | |
6 import 'dart:typed_data'; | |
7 | |
8 /// Groups stdin input into messages by interpreting it as | |
9 /// base-128 encoded lengths interleaved with raw data. | |
10 /// | |
11 /// The base-128 encoding is in little-endian order, with the high bit set on | |
12 /// all bytes but the last. This was chosen since it's the same as the | |
13 /// base-128 encoding used by protobufs, so it allows a modest amount of code | |
14 /// reuse at the other end of the protocol. | |
15 /// | |
16 /// Possible future improvements to consider (should a debugging need arise): | |
17 /// - Put a magic number at the beginning of the stream. | |
18 /// - Use a guard byte between messages to sanity check that the encoder and | |
19 /// decoder agree on the encoding of lengths. | |
20 class MessageGrouper { | |
21 final _state = new _MessageGrouperState(); | |
22 final Stdin _stdin; | |
23 | |
24 MessageGrouper(this._stdin); | |
25 | |
26 /// Blocks until the next full message is received, and then returns it. | |
27 /// | |
28 /// Returns null at end of file. | |
29 List<int> get next { | |
30 var message; | |
31 while (message == null) { | |
32 var nextByte = _stdin.readByteSync(); | |
33 if (nextByte == -1) return null; | |
34 message = _state.handleInput(nextByte); | |
35 } | |
36 return message; | |
37 } | |
38 } | |
39 | |
40 /// State held by the [MessageGrouper] while waiting for additional data to | |
41 /// arrive. | |
42 class _MessageGrouperState { | |
43 /// `true` means we are waiting to receive bytes of base-128 encoded length. | |
44 /// Some bytes of length may have been received already. | |
45 /// | |
46 /// `false` means we are waiting to receive more bytes of message data. Some | |
47 /// bytes of message data may have been received already. | |
48 bool waitingForLength = true; | |
49 | |
50 /// If [waitingForLength] is `true`, the decoded value of the length bytes | |
51 /// received so far (if any). If [waitingForLength] is `false`, the decoded | |
52 /// length that was most recently received. | |
53 int length = 0; | |
54 | |
55 /// If [waitingForLength] is `true`, the amount by which the next received | |
56 /// length byte must be left-shifted; otherwise undefined. | |
57 int lengthShift = 0; | |
58 | |
59 /// If [waitingForLength] is `false`, a [Uint8List] which is ready to receive | |
60 /// message data. Otherwise null. | |
61 Uint8List message; | |
62 | |
63 /// If [waitingForLength] is `false`, the number of message bytes that have | |
64 /// been received so far. Otherwise zero. | |
65 int numMessageBytesReceived; | |
66 | |
67 _MessageGrouperState() { | |
68 reset(); | |
69 } | |
70 | |
71 /// Handle one byte at a time. | |
72 /// | |
73 /// Returns a [List<int>] of message bytes if [byte] was the last byte in a | |
74 /// message, otherwise returns [null]. | |
75 List<int> handleInput(int byte) { | |
76 if (waitingForLength) { | |
77 length |= (byte & 0x7f) << lengthShift; | |
78 if ((byte & 0x80) == 0) { | |
79 waitingForLength = false; | |
80 message = new Uint8List(length); | |
81 if (length == 0) { | |
82 // There is no message data to wait for, so just go ahead and deliver
the | |
83 // empty message. | |
84 var messageToReturn = message; | |
85 reset(); | |
86 return messageToReturn; | |
87 } | |
88 } else { | |
89 lengthShift += 7; | |
90 } | |
91 } else { | |
92 message[numMessageBytesReceived] = byte; | |
93 numMessageBytesReceived++; | |
94 if (numMessageBytesReceived == length) { | |
95 var messageToReturn = message; | |
96 reset(); | |
97 return messageToReturn; | |
98 } | |
99 } | |
100 return null; | |
101 } | |
102 | |
103 /// Reset the state so that we are ready to receive the next base-128 encoded | |
104 /// length. | |
105 void reset() { | |
106 waitingForLength = true; | |
107 length = 0; | |
108 lengthShift = 0; | |
109 message = null; | |
110 numMessageBytesReceived = 0; | |
111 } | |
112 } | |
OLD | NEW |