-
Notifications
You must be signed in to change notification settings - Fork 30k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cli: allow installation as a service from the UI
- When turning on remote tunnel access, a quickpick is now shown asking users whether it should be installed as a service or just run in the session. - Picking the service install will install the tunnel as a service on the machine, and start it. - Turning off remote tunnel access will uninstall the service only if we were the ones to install it. - This involved some refactoring to add extra state to the RemoteTunnelService. There's now a "mode" that includes the previous "session" and reflects the desired end state. - I also did a cleanup with a `StreamSplitter` to ensure output of the CLI gets read line-by-line. This was depended upon by the remote tunnel service code, but it's not actually guaranteed. - Changes in the CLI: allow setting the tunnel name while installing the service, and make both service un/installation and renames idempotent. Closes #184663
- Loading branch information
1 parent
4529b4a
commit 22425c5
Showing
10 changed files
with
473 additions
and
181 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
import { Transform } from 'stream'; | ||
import { binaryIndexOf } from 'vs/base/common/buffer'; | ||
|
||
/** | ||
* A Transform stream that splits the input on the "splitter" substring. | ||
* The resulting chunks will contain (and trail with) the splitter match. | ||
* The last chunk when the stream ends will be emitted even if a splitter | ||
* is not encountered. | ||
*/ | ||
export class StreamSplitter extends Transform { | ||
private buffer: Buffer | undefined; | ||
private readonly splitter: Buffer | number; | ||
private readonly spitterLen: number; | ||
|
||
constructor(splitter: string | number | Buffer) { | ||
super(); | ||
if (typeof splitter === 'number') { | ||
this.splitter = splitter; | ||
this.spitterLen = 1; | ||
} else { | ||
const buf = Buffer.isBuffer(splitter) ? splitter : Buffer.from(splitter); | ||
this.splitter = buf.length === 1 ? buf[0] : buf; | ||
this.spitterLen = buf.length; | ||
} | ||
} | ||
|
||
override _transform(chunk: Buffer, _encoding: string, callback: (error?: Error | null, data?: any) => void): void { | ||
if (!this.buffer) { | ||
this.buffer = chunk; | ||
} else { | ||
this.buffer = Buffer.concat([this.buffer, chunk]); | ||
} | ||
|
||
let offset = 0; | ||
while (offset < this.buffer.length) { | ||
const index = typeof this.splitter === 'number' | ||
? this.buffer.indexOf(this.splitter, offset) | ||
: binaryIndexOf(this.buffer, this.splitter, offset); | ||
if (index === -1) { | ||
break; | ||
} | ||
|
||
this.push(this.buffer.slice(offset, index + this.spitterLen)); | ||
offset = index + this.spitterLen; | ||
} | ||
|
||
this.buffer = offset === this.buffer.length ? undefined : this.buffer.slice(offset); | ||
callback(); | ||
} | ||
|
||
override _flush(callback: (error?: Error | null, data?: any) => void): void { | ||
if (this.buffer) { | ||
this.push(this.buffer); | ||
} | ||
|
||
callback(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
|
||
import { Writable } from 'stream'; | ||
import * as assert from 'assert'; | ||
import { StreamSplitter } from 'vs/base/node/nodeStreams'; | ||
|
||
suite('StreamSplitter', () => { | ||
test('should split a stream on a single character splitter', (done) => { | ||
const chunks: string[] = []; | ||
const splitter = new StreamSplitter('\n'); | ||
const writable = new Writable({ | ||
write(chunk, _encoding, callback) { | ||
chunks.push(chunk.toString()); | ||
callback(); | ||
}, | ||
}); | ||
|
||
splitter.pipe(writable); | ||
splitter.write('hello\nwor'); | ||
splitter.write('ld\n'); | ||
splitter.write('foo\nbar\nz'); | ||
splitter.end(() => { | ||
assert.deepStrictEqual(chunks, ['hello\n', 'world\n', 'foo\n', 'bar\n', 'z']); | ||
done(); | ||
}); | ||
}); | ||
|
||
test('should split a stream on a multi-character splitter', (done) => { | ||
const chunks: string[] = []; | ||
const splitter = new StreamSplitter('---'); | ||
const writable = new Writable({ | ||
write(chunk, _encoding, callback) { | ||
chunks.push(chunk.toString()); | ||
callback(); | ||
}, | ||
}); | ||
|
||
splitter.pipe(writable); | ||
splitter.write('hello---wor'); | ||
splitter.write('ld---'); | ||
splitter.write('foo---bar---z'); | ||
splitter.end(() => { | ||
assert.deepStrictEqual(chunks, ['hello---', 'world---', 'foo---', 'bar---', 'z']); | ||
done(); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.