Skip to content

Commit f701dd5

Browse files
committed
Refactor stream.ts
1 parent 9ee29af commit f701dd5

5 files changed

Lines changed: 178 additions & 213 deletions

File tree

src/vs/base/node/encoding.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,5 @@ export function detectEncodingByBOMFromBuffer(buffer: NodeBuffer, bytesRead: num
9191
* If no BOM is detected, null will be passed to callback.
9292
*/
9393
export function detectEncodingByBOM(file: string): TPromise<string> {
94-
return new TPromise((complete, error) => {
95-
stream.readExactlyByFile(file, 3, (err: Error, buffer: NodeBuffer, bytesRead: number) => {
96-
if (err) {
97-
error(err);
98-
} else {
99-
complete(detectEncodingByBOMFromBuffer(buffer, bytesRead));
100-
}
101-
});
102-
});
103-
94+
return stream.readExactlyByFile(file, 3).then(({buffer, bytesRead}) => detectEncodingByBOMFromBuffer(buffer, bytesRead));
10495
}

src/vs/base/node/mime.ts

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,37 +59,14 @@ export interface IMimeAndEncoding {
5959
}
6060

6161
function doDetectMimesFromStream(instream: streams.Readable): TPromise<IMimeAndEncoding> {
62-
return new TPromise((complete, error) =>
63-
stream.readExactlyByStream(instream, BUFFER_READ_MAX_LEN, (err, buffer, bytesRead) => {
64-
if (err) {
65-
error(error);
66-
} else {
67-
complete(detectMimeAndEncodingFromBuffer({ buffer, bytesRead }));
68-
}
69-
})
70-
);
62+
return stream.readExactlyByStream(instream, BUFFER_READ_MAX_LEN).then(detectMimeAndEncodingFromBuffer);
7163
}
7264

7365
function doDetectMimesFromFile(absolutePath: string): TPromise<IMimeAndEncoding> {
74-
return new TPromise((complete, error) =>
75-
stream.readExactlyByFile(absolutePath, BUFFER_READ_MAX_LEN, (err, buffer, bytesRead) => {
76-
if (err) {
77-
error(error);
78-
} else {
79-
complete(detectMimeAndEncodingFromBuffer({ buffer, bytesRead }));
80-
}
81-
})
82-
);
83-
}
84-
85-
86-
87-
export interface ReadResult {
88-
buffer: NodeBuffer;
89-
bytesRead: number;
66+
return stream.readExactlyByFile(absolutePath, BUFFER_READ_MAX_LEN).then(detectMimeAndEncodingFromBuffer);
9067
}
9168

92-
export function detectMimeAndEncodingFromBuffer({buffer, bytesRead}: ReadResult): IMimeAndEncoding {
69+
export function detectMimeAndEncodingFromBuffer({buffer, bytesRead}: stream.ReadResult): IMimeAndEncoding {
9370
let enc = encoding.detectEncodingByBOMFromBuffer(buffer, bytesRead);
9471

9572
// Detect 0 bytes to see if file is binary (ignore for UTF 16 though)

src/vs/base/node/stream.ts

Lines changed: 148 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -8,94 +8,105 @@
88
import fs = require('fs');
99
import stream = require('stream');
1010

11+
import { TPromise } from 'vs/base/common/winjs.base';
12+
13+
export interface ReadResult {
14+
buffer: NodeBuffer;
15+
bytesRead: number;
16+
}
17+
1118
/**
1219
* Reads up to total bytes from the provided stream.
1320
*/
14-
export function readExactlyByStream(stream: stream.Readable, totalBytes: number, callback: (err: Error, buffer: NodeBuffer, bytesRead: number) => void): void {
15-
let done = false;
16-
let buffer = new Buffer(totalBytes);
17-
let bytesRead = 0;
18-
19-
stream.on('data', (data: NodeBuffer) => {
20-
let bytesToRead = Math.min(totalBytes - bytesRead, data.length);
21-
data.copy(buffer, bytesRead, 0, bytesToRead);
22-
bytesRead += bytesToRead;
23-
24-
if (bytesRead === totalBytes) {
25-
stream.destroy(); // Will trigger the close event eventually
26-
}
27-
});
28-
29-
stream.on('error', (e: Error) => {
30-
if (!done) {
31-
done = true;
32-
callback(e, null, null);
33-
}
34-
});
35-
36-
let onSuccess = () => {
37-
if (!done) {
38-
done = true;
39-
callback(null, buffer, bytesRead);
40-
}
41-
};
42-
43-
stream.on('close', onSuccess);
21+
export function readExactlyByStream(stream: stream.Readable, totalBytes: number): TPromise<ReadResult> {
22+
return new TPromise((complete, error) => {
23+
let done = false;
24+
let buffer = new Buffer(totalBytes);
25+
let bytesRead = 0;
26+
27+
stream.on('data', (data: NodeBuffer) => {
28+
let bytesToRead = Math.min(totalBytes - bytesRead, data.length);
29+
data.copy(buffer, bytesRead, 0, bytesToRead);
30+
bytesRead += bytesToRead;
31+
32+
if (bytesRead === totalBytes) {
33+
stream.destroy(); // Will trigger the close event eventually
34+
}
35+
});
36+
37+
stream.on('error', (e: Error) => {
38+
if (!done) {
39+
done = true;
40+
error(e);
41+
}
42+
});
43+
44+
let onSuccess = () => {
45+
if (!done) {
46+
done = true;
47+
complete({ buffer, bytesRead });
48+
}
49+
};
50+
51+
stream.on('close', onSuccess);
52+
});
4453
}
4554

4655
/**
4756
* Reads totalBytes from the provided file.
4857
*/
49-
export function readExactlyByFile(file: string, totalBytes: number, callback: (error: Error, buffer: NodeBuffer, bytesRead: number) => void): void {
50-
fs.open(file, 'r', null, (err, fd) => {
51-
if (err) {
52-
return callback(err, null, 0);
53-
}
54-
55-
function end(err: Error, resultBuffer: NodeBuffer, bytesRead: number): void {
56-
fs.close(fd, (closeError: Error) => {
57-
if (closeError) {
58-
return callback(closeError, null, bytesRead);
59-
}
60-
61-
if (err && (<any>err).code === 'EISDIR') {
62-
return callback(err, null, bytesRead); // we want to bubble this error up (file is actually a folder)
63-
}
64-
65-
return callback(null, resultBuffer, bytesRead);
66-
});
67-
}
68-
69-
let buffer = new Buffer(totalBytes);
70-
let bytesRead = 0;
71-
let zeroAttempts = 0;
72-
function loop(): void {
73-
fs.read(fd, buffer, bytesRead, totalBytes - bytesRead, null, (err, moreBytesRead) => {
74-
if (err) {
75-
return end(err, null, 0);
76-
}
77-
78-
// Retry up to N times in case 0 bytes where read
79-
if (moreBytesRead === 0) {
80-
if (++zeroAttempts === 10) {
81-
return end(null, buffer, bytesRead);
82-
}
83-
84-
return loop();
85-
}
86-
87-
bytesRead += moreBytesRead;
88-
89-
if (bytesRead === totalBytes) {
90-
return end(null, buffer, bytesRead);
91-
}
92-
93-
return loop();
94-
});
95-
}
96-
97-
loop();
98-
});
58+
export function readExactlyByFile(file: string, totalBytes: number): TPromise<ReadResult> {
59+
return new TPromise((complete, error) => {
60+
fs.open(file, 'r', null, (err, fd) => {
61+
if (err) {
62+
return error(err);
63+
}
64+
65+
function end(err: Error, resultBuffer: NodeBuffer, bytesRead: number): void {
66+
fs.close(fd, (closeError: Error) => {
67+
if (closeError) {
68+
return error(closeError);
69+
}
70+
71+
if (err && (<any>err).code === 'EISDIR') {
72+
return error(err); // we want to bubble this error up (file is actually a folder)
73+
}
74+
75+
return complete({ buffer:resultBuffer, bytesRead });
76+
});
77+
}
78+
79+
let buffer = new Buffer(totalBytes);
80+
let bytesRead = 0;
81+
let zeroAttempts = 0;
82+
function loop(): void {
83+
fs.read(fd, buffer, bytesRead, totalBytes - bytesRead, null, (err, moreBytesRead) => {
84+
if (err) {
85+
return end(err, null, 0);
86+
}
87+
88+
// Retry up to N times in case 0 bytes where read
89+
if (moreBytesRead === 0) {
90+
if (++zeroAttempts === 10) {
91+
return end(null, buffer, bytesRead);
92+
}
93+
94+
return loop();
95+
}
96+
97+
bytesRead += moreBytesRead;
98+
99+
if (bytesRead === totalBytes) {
100+
return end(null, buffer, bytesRead);
101+
}
102+
103+
return loop();
104+
});
105+
}
106+
107+
loop();
108+
});
109+
});
99110
}
100111

101112
/**
@@ -107,59 +118,61 @@ export function readExactlyByFile(file: string, totalBytes: number, callback: (e
107118
* @param maximumBytesToRead The maximum number of bytes to read before giving up.
108119
* @param callback The finished callback.
109120
*/
110-
export function readToMatchingString(file: string, matchingString: string, chunkBytes: number, maximumBytesToRead: number, callback: (error: Error, result: string) => void): void {
111-
fs.open(file, 'r', null, (err, fd) => {
112-
if (err) {
113-
return callback(err, null);
114-
}
115-
116-
function end(err: Error, result: string): void {
117-
fs.close(fd, (closeError: Error) => {
118-
if (closeError) {
119-
return callback(closeError, null);
120-
}
121-
122-
if (err && (<any>err).code === 'EISDIR') {
123-
return callback(err, null); // we want to bubble this error up (file is actually a folder)
124-
}
125-
126-
return callback(null, result);
127-
});
128-
}
129-
130-
let buffer = new Buffer(maximumBytesToRead);
131-
let bytesRead = 0;
132-
let zeroAttempts = 0;
133-
function loop(): void {
134-
fs.read(fd, buffer, bytesRead, chunkBytes, null, (err, moreBytesRead) => {
135-
if (err) {
136-
return end(err, null);
137-
}
138-
139-
// Retry up to N times in case 0 bytes where read
140-
if (moreBytesRead === 0) {
141-
if (++zeroAttempts === 10) {
142-
return end(null, null);
143-
}
144-
145-
return loop();
146-
}
147-
148-
bytesRead += moreBytesRead;
149-
150-
const newLineIndex = buffer.indexOf(matchingString);
151-
if (newLineIndex >= 0) {
152-
return end(null, buffer.toString('utf8').substr(0, newLineIndex));
153-
}
154-
155-
if (bytesRead >= maximumBytesToRead) {
156-
return end(new Error(`Could not find ${matchingString} in first ${maximumBytesToRead} bytes of ${file}`), null);
157-
}
158-
159-
return loop();
160-
});
161-
}
162-
163-
loop();
164-
});
121+
export function readToMatchingString(file: string, matchingString: string, chunkBytes: number, maximumBytesToRead: number): TPromise<string> {
122+
return new TPromise((complete, error) =>
123+
fs.open(file, 'r', null, (err, fd) => {
124+
if (err) {
125+
return error(err);
126+
}
127+
128+
function end(err: Error, result: string): void {
129+
fs.close(fd, (closeError: Error) => {
130+
if (closeError) {
131+
return error(closeError);
132+
}
133+
134+
if (err && (<any>err).code === 'EISDIR') {
135+
return error(err); // we want to bubble this error up (file is actually a folder)
136+
}
137+
138+
return complete(result);
139+
});
140+
}
141+
142+
let buffer = new Buffer(maximumBytesToRead);
143+
let bytesRead = 0;
144+
let zeroAttempts = 0;
145+
function loop(): void {
146+
fs.read(fd, buffer, bytesRead, chunkBytes, null, (err, moreBytesRead) => {
147+
if (err) {
148+
return end(err, null);
149+
}
150+
151+
// Retry up to N times in case 0 bytes where read
152+
if (moreBytesRead === 0) {
153+
if (++zeroAttempts === 10) {
154+
return end(null, null);
155+
}
156+
157+
return loop();
158+
}
159+
160+
bytesRead += moreBytesRead;
161+
162+
const newLineIndex = buffer.indexOf(matchingString);
163+
if (newLineIndex >= 0) {
164+
return end(null, buffer.toString('utf8').substr(0, newLineIndex));
165+
}
166+
167+
if (bytesRead >= maximumBytesToRead) {
168+
return end(new Error(`Could not find ${matchingString} in first ${maximumBytesToRead} bytes of ${file}`), null);
169+
}
170+
171+
return loop();
172+
});
173+
}
174+
175+
loop();
176+
})
177+
);
165178
}

0 commit comments

Comments
 (0)