From f701dd508d69a8262b28f73ebfe24d4e43232e76 Mon Sep 17 00:00:00 2001 From: katainaka0503 Date: Wed, 1 Mar 2017 09:16:22 +0900 Subject: [PATCH] Refactor stream.ts --- src/vs/base/node/encoding.ts | 11 +- src/vs/base/node/mime.ts | 29 +-- src/vs/base/node/stream.ts | 231 +++++++++--------- src/vs/base/test/node/stream/stream.test.ts | 55 ++--- .../services/backup/node/backupFileService.ts | 13 +- 5 files changed, 152 insertions(+), 187 deletions(-) diff --git a/src/vs/base/node/encoding.ts b/src/vs/base/node/encoding.ts index 7c77aeccdbb..5ff845143de 100644 --- a/src/vs/base/node/encoding.ts +++ b/src/vs/base/node/encoding.ts @@ -91,14 +91,5 @@ export function detectEncodingByBOMFromBuffer(buffer: NodeBuffer, bytesRead: num * If no BOM is detected, null will be passed to callback. */ export function detectEncodingByBOM(file: string): TPromise { - return new TPromise((complete, error) => { - stream.readExactlyByFile(file, 3, (err: Error, buffer: NodeBuffer, bytesRead: number) => { - if (err) { - error(err); - } else { - complete(detectEncodingByBOMFromBuffer(buffer, bytesRead)); - } - }); - }); - + return stream.readExactlyByFile(file, 3).then(({buffer, bytesRead}) => detectEncodingByBOMFromBuffer(buffer, bytesRead)); } \ No newline at end of file diff --git a/src/vs/base/node/mime.ts b/src/vs/base/node/mime.ts index 94f9c7def70..975867a36ab 100644 --- a/src/vs/base/node/mime.ts +++ b/src/vs/base/node/mime.ts @@ -59,37 +59,14 @@ export interface IMimeAndEncoding { } function doDetectMimesFromStream(instream: streams.Readable): TPromise { - return new TPromise((complete, error) => - stream.readExactlyByStream(instream, BUFFER_READ_MAX_LEN, (err, buffer, bytesRead) => { - if (err) { - error(error); - } else { - complete(detectMimeAndEncodingFromBuffer({ buffer, bytesRead })); - } - }) - ); + return stream.readExactlyByStream(instream, BUFFER_READ_MAX_LEN).then(detectMimeAndEncodingFromBuffer); } function doDetectMimesFromFile(absolutePath: string): TPromise { - return new TPromise((complete, error) => - stream.readExactlyByFile(absolutePath, BUFFER_READ_MAX_LEN, (err, buffer, bytesRead) => { - if (err) { - error(error); - } else { - complete(detectMimeAndEncodingFromBuffer({ buffer, bytesRead })); - } - }) - ); + return stream.readExactlyByFile(absolutePath, BUFFER_READ_MAX_LEN).then(detectMimeAndEncodingFromBuffer); } - - -export interface ReadResult { - buffer: NodeBuffer; - bytesRead: number; -} - -export function detectMimeAndEncodingFromBuffer({buffer, bytesRead}: ReadResult): IMimeAndEncoding { +export function detectMimeAndEncodingFromBuffer({buffer, bytesRead}: stream.ReadResult): IMimeAndEncoding { let enc = encoding.detectEncodingByBOMFromBuffer(buffer, bytesRead); // Detect 0 bytes to see if file is binary (ignore for UTF 16 though) diff --git a/src/vs/base/node/stream.ts b/src/vs/base/node/stream.ts index ee23b7037c8..463ce02831f 100644 --- a/src/vs/base/node/stream.ts +++ b/src/vs/base/node/stream.ts @@ -8,94 +8,105 @@ import fs = require('fs'); import stream = require('stream'); +import { TPromise } from 'vs/base/common/winjs.base'; + +export interface ReadResult { + buffer: NodeBuffer; + bytesRead: number; +} + /** * Reads up to total bytes from the provided stream. */ -export function readExactlyByStream(stream: stream.Readable, totalBytes: number, callback: (err: Error, buffer: NodeBuffer, bytesRead: number) => void): void { - let done = false; - let buffer = new Buffer(totalBytes); - let bytesRead = 0; +export function readExactlyByStream(stream: stream.Readable, totalBytes: number): TPromise { + return new TPromise((complete, error) => { + let done = false; + let buffer = new Buffer(totalBytes); + let bytesRead = 0; - stream.on('data', (data: NodeBuffer) => { - let bytesToRead = Math.min(totalBytes - bytesRead, data.length); - data.copy(buffer, bytesRead, 0, bytesToRead); - bytesRead += bytesToRead; + stream.on('data', (data: NodeBuffer) => { + let bytesToRead = Math.min(totalBytes - bytesRead, data.length); + data.copy(buffer, bytesRead, 0, bytesToRead); + bytesRead += bytesToRead; - if (bytesRead === totalBytes) { - stream.destroy(); // Will trigger the close event eventually - } - }); + if (bytesRead === totalBytes) { + stream.destroy(); // Will trigger the close event eventually + } + }); - stream.on('error', (e: Error) => { - if (!done) { - done = true; - callback(e, null, null); - } - }); + stream.on('error', (e: Error) => { + if (!done) { + done = true; + error(e); + } + }); - let onSuccess = () => { - if (!done) { - done = true; - callback(null, buffer, bytesRead); - } - }; + let onSuccess = () => { + if (!done) { + done = true; + complete({ buffer, bytesRead }); + } + }; - stream.on('close', onSuccess); + stream.on('close', onSuccess); + }); } /** * Reads totalBytes from the provided file. */ -export function readExactlyByFile(file: string, totalBytes: number, callback: (error: Error, buffer: NodeBuffer, bytesRead: number) => void): void { - fs.open(file, 'r', null, (err, fd) => { - if (err) { - return callback(err, null, 0); - } +export function readExactlyByFile(file: string, totalBytes: number): TPromise { + return new TPromise((complete, error) => { + fs.open(file, 'r', null, (err, fd) => { + if (err) { + return error(err); + } - function end(err: Error, resultBuffer: NodeBuffer, bytesRead: number): void { - fs.close(fd, (closeError: Error) => { - if (closeError) { - return callback(closeError, null, bytesRead); - } + function end(err: Error, resultBuffer: NodeBuffer, bytesRead: number): void { + fs.close(fd, (closeError: Error) => { + if (closeError) { + return error(closeError); + } - if (err && (err).code === 'EISDIR') { - return callback(err, null, bytesRead); // we want to bubble this error up (file is actually a folder) - } + if (err && (err).code === 'EISDIR') { + return error(err); // we want to bubble this error up (file is actually a folder) + } - return callback(null, resultBuffer, bytesRead); - }); - } + return complete({ buffer:resultBuffer, bytesRead }); + }); + } - let buffer = new Buffer(totalBytes); - let bytesRead = 0; - let zeroAttempts = 0; - function loop(): void { - fs.read(fd, buffer, bytesRead, totalBytes - bytesRead, null, (err, moreBytesRead) => { - if (err) { - return end(err, null, 0); - } + let buffer = new Buffer(totalBytes); + let bytesRead = 0; + let zeroAttempts = 0; + function loop(): void { + fs.read(fd, buffer, bytesRead, totalBytes - bytesRead, null, (err, moreBytesRead) => { + if (err) { + return end(err, null, 0); + } - // Retry up to N times in case 0 bytes where read - if (moreBytesRead === 0) { - if (++zeroAttempts === 10) { - return end(null, buffer, bytesRead); - } + // Retry up to N times in case 0 bytes where read + if (moreBytesRead === 0) { + if (++zeroAttempts === 10) { + return end(null, buffer, bytesRead); + } - return loop(); - } + return loop(); + } - bytesRead += moreBytesRead; + bytesRead += moreBytesRead; - if (bytesRead === totalBytes) { - return end(null, buffer, bytesRead); - } + if (bytesRead === totalBytes) { + return end(null, buffer, bytesRead); + } - return loop(); - }); - } + return loop(); + }); + } - loop(); - }); + loop(); + }); + }); } /** @@ -107,59 +118,61 @@ export function readExactlyByFile(file: string, totalBytes: number, callback: (e * @param maximumBytesToRead The maximum number of bytes to read before giving up. * @param callback The finished callback. */ -export function readToMatchingString(file: string, matchingString: string, chunkBytes: number, maximumBytesToRead: number, callback: (error: Error, result: string) => void): void { - fs.open(file, 'r', null, (err, fd) => { - if (err) { - return callback(err, null); - } +export function readToMatchingString(file: string, matchingString: string, chunkBytes: number, maximumBytesToRead: number): TPromise { + return new TPromise((complete, error) => + fs.open(file, 'r', null, (err, fd) => { + if (err) { + return error(err); + } - function end(err: Error, result: string): void { - fs.close(fd, (closeError: Error) => { - if (closeError) { - return callback(closeError, null); - } + function end(err: Error, result: string): void { + fs.close(fd, (closeError: Error) => { + if (closeError) { + return error(closeError); + } - if (err && (err).code === 'EISDIR') { - return callback(err, null); // we want to bubble this error up (file is actually a folder) - } + if (err && (err).code === 'EISDIR') { + return error(err); // we want to bubble this error up (file is actually a folder) + } - return callback(null, result); - }); - } + return complete(result); + }); + } - let buffer = new Buffer(maximumBytesToRead); - let bytesRead = 0; - let zeroAttempts = 0; - function loop(): void { - fs.read(fd, buffer, bytesRead, chunkBytes, null, (err, moreBytesRead) => { - if (err) { - return end(err, null); - } + let buffer = new Buffer(maximumBytesToRead); + let bytesRead = 0; + let zeroAttempts = 0; + function loop(): void { + fs.read(fd, buffer, bytesRead, chunkBytes, null, (err, moreBytesRead) => { + if (err) { + return end(err, null); + } - // Retry up to N times in case 0 bytes where read - if (moreBytesRead === 0) { - if (++zeroAttempts === 10) { - return end(null, null); - } + // Retry up to N times in case 0 bytes where read + if (moreBytesRead === 0) { + if (++zeroAttempts === 10) { + return end(null, null); + } - return loop(); - } + return loop(); + } - bytesRead += moreBytesRead; + bytesRead += moreBytesRead; - const newLineIndex = buffer.indexOf(matchingString); - if (newLineIndex >= 0) { - return end(null, buffer.toString('utf8').substr(0, newLineIndex)); - } + const newLineIndex = buffer.indexOf(matchingString); + if (newLineIndex >= 0) { + return end(null, buffer.toString('utf8').substr(0, newLineIndex)); + } - if (bytesRead >= maximumBytesToRead) { - return end(new Error(`Could not find ${matchingString} in first ${maximumBytesToRead} bytes of ${file}`), null); - } + if (bytesRead >= maximumBytesToRead) { + return end(new Error(`Could not find ${matchingString} in first ${maximumBytesToRead} bytes of ${file}`), null); + } - return loop(); - }); - } + return loop(); + }); + } - loop(); - }); + loop(); + }) + ); } \ No newline at end of file diff --git a/src/vs/base/test/node/stream/stream.test.ts b/src/vs/base/test/node/stream/stream.test.ts index 504d565c4db..2826ef443da 100644 --- a/src/vs/base/test/node/stream/stream.test.ts +++ b/src/vs/base/test/node/stream/stream.test.ts @@ -11,72 +11,61 @@ import fs = require('fs'); import stream = require('vs/base/node/stream'); suite('Stream', () => { - test('readExactlyByFile - ANSI', function (done: () => void) { + test('readExactlyByFile - ANSI', function (done: (err?) => void) { const file = require.toUrl('./fixtures/file.css'); - stream.readExactlyByFile(file, 10, (error: Error, buffer: NodeBuffer, count: number) => { - assert.equal(error, null); - assert.equal(count, 10); + stream.readExactlyByFile(file, 10).then(({buffer, bytesRead}) => { + assert.equal(bytesRead, 10); assert.equal(buffer.toString(), '/*--------'); - done(); - }); + }, done); }); - test('readExactlyByFile - empty', function (done: () => void) { + test('readExactlyByFile - empty', function (done: (err?: any) => void) { const file = require.toUrl('./fixtures/empty.txt'); - stream.readExactlyByFile(file, 10, (error: Error, buffer: NodeBuffer, count: number) => { - assert.equal(error, null); - assert.equal(count, 0); - + stream.readExactlyByFile(file, 10).then(({bytesRead}) => { + assert.equal(bytesRead, 0); done(); - }); + }, done); }); - test('readExactlyByStream - ANSI', function (done: () => void) { + test('readExactlyByStream - ANSI', function (done: (err?: any) => void) { const file = require.toUrl('./fixtures/file.css'); - stream.readExactlyByStream(fs.createReadStream(file), 10, (error: Error, buffer: NodeBuffer, count: number) => { - assert.equal(error, null); - assert.equal(count, 10); + stream.readExactlyByStream(fs.createReadStream(file), 10).then(({buffer, bytesRead}) => { + assert.equal(bytesRead, 10); assert.equal(buffer.toString(), '/*--------'); - done(); - }); + }, done); }); - test('readExactlyByStream - empty', function (done: () => void) { + test('readExactlyByStream - empty', function (done: (err?: any) => void) { const file = require.toUrl('./fixtures/empty.txt'); - stream.readExactlyByStream(fs.createReadStream(file), 10, (error: Error, buffer: NodeBuffer, count: number) => { - assert.equal(error, null); - assert.equal(count, 0); - + stream.readExactlyByStream(fs.createReadStream(file), 10).then(({bytesRead}) => { + assert.equal(bytesRead, 0); done(); - }); + }, done); }); - test('readToMatchingString - ANSI', function (done: () => void) { + test('readToMatchingString - ANSI', function (done: (err?: any) => void) { const file = require.toUrl('./fixtures/file.css'); - stream.readToMatchingString(file, '\n', 10, 100, (error: Error, result: string) => { - assert.equal(error, null); + stream.readToMatchingString(file, '\n', 10, 100).then ((result: string) => { // \r may be present on Windows assert.equal(result.replace('\r', ''), '/*---------------------------------------------------------------------------------------------'); - done(); - }); + }, done); }); - test('readToMatchingString - empty', function (done: () => void) { + test('readToMatchingString - empty', function (done: (err?: any) => void) { const file = require.toUrl('./fixtures/empty.txt'); - stream.readToMatchingString(file, '\n', 10, 100, (error: Error, result: string) => { - assert.equal(error, null); + stream.readToMatchingString(file, '\n', 10, 100).then((result: string) => { assert.equal(result, null); done(); - }); + }, done); }); }); \ No newline at end of file diff --git a/src/vs/workbench/services/backup/node/backupFileService.ts b/src/vs/workbench/services/backup/node/backupFileService.ts index 3b2e6cacd66..72310201af1 100644 --- a/src/vs/workbench/services/backup/node/backupFileService.ts +++ b/src/vs/workbench/services/backup/node/backupFileService.ts @@ -229,15 +229,10 @@ export class BackupFileService implements IBackupFileService { const readPromises: TPromise[] = []; model.get().forEach(fileBackup => { - readPromises.push(new TPromise((c, e) => { - readToMatchingString(fileBackup.fsPath, BackupFileService.META_MARKER, 2000, 10000, (error, result) => { - if (result === null) { - e(error); - } - - c(Uri.parse(result)); - }); - })); + readPromises.push( + readToMatchingString(fileBackup.fsPath, BackupFileService.META_MARKER, 2000, 10000) + .then(Uri.parse) + ); }); return TPromise.join(readPromises);