deploy: current vibn theia state
Made-with: Cursor
This commit is contained in:
107
packages/debug/src/node/debug-adapter-factory.ts
Normal file
107
packages/debug/src/node/debug-adapter-factory.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 Red Hat, Inc. and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// Some entities copied and modified from https://github.com/Microsoft/vscode-debugadapter-node/blob/master/adapter/src/protocol.ts
|
||||
|
||||
import * as net from 'net';
|
||||
import { injectable, inject } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
RawProcessFactory,
|
||||
ProcessManager,
|
||||
RawProcess,
|
||||
RawForkOptions,
|
||||
RawProcessOptions
|
||||
} from '@theia/process/lib/node';
|
||||
import {
|
||||
DebugAdapterExecutable,
|
||||
DebugAdapterSession,
|
||||
DebugAdapterSessionFactory,
|
||||
DebugAdapterFactory,
|
||||
DebugAdapterForkExecutable,
|
||||
DebugAdapter
|
||||
} from '../common/debug-model';
|
||||
import { DebugAdapterSessionImpl } from '../common/debug-adapter-session';
|
||||
import { environment } from '@theia/core/shared/@theia/application-package';
|
||||
import { ProcessDebugAdapter, SocketDebugAdapter } from './stream-debug-adapter';
|
||||
import { isObject } from '@theia/core/lib/common';
|
||||
|
||||
/**
|
||||
* [DebugAdapterFactory](#DebugAdapterFactory) implementation based on
|
||||
* launching the debug adapter as separate process.
|
||||
*/
|
||||
@injectable()
|
||||
export class LaunchBasedDebugAdapterFactory implements DebugAdapterFactory {
|
||||
@inject(RawProcessFactory)
|
||||
protected readonly processFactory: RawProcessFactory;
|
||||
@inject(ProcessManager)
|
||||
protected readonly processManager: ProcessManager;
|
||||
|
||||
start(executable: DebugAdapterExecutable): DebugAdapter {
|
||||
const process = this.childProcess(executable);
|
||||
|
||||
if (!process.process) {
|
||||
throw new Error(`Could not start debug adapter process: ${JSON.stringify(executable)}`);
|
||||
}
|
||||
|
||||
// FIXME: propagate onError + onExit
|
||||
const provider = new ProcessDebugAdapter(process.process);
|
||||
return provider;
|
||||
}
|
||||
|
||||
private childProcess(executable: DebugAdapterExecutable): RawProcess {
|
||||
const isForkOptions = (forkOptions: unknown): forkOptions is RawForkOptions =>
|
||||
isObject(forkOptions) && 'modulePath' in forkOptions;
|
||||
|
||||
const processOptions: RawProcessOptions | RawForkOptions = { ...executable };
|
||||
const options: { stdio: (string | number)[], env?: object, execArgv?: string[] } = { stdio: ['pipe', 'pipe', 2] };
|
||||
|
||||
if (isForkOptions(processOptions)) {
|
||||
options.stdio.push('ipc');
|
||||
options.env = environment.electron.runAsNodeEnv();
|
||||
options.execArgv = (executable as DebugAdapterForkExecutable).execArgv;
|
||||
}
|
||||
|
||||
processOptions.options = options;
|
||||
return this.processFactory(processOptions);
|
||||
}
|
||||
|
||||
connect(debugServerPort: number): DebugAdapter {
|
||||
const socket = net.createConnection(debugServerPort);
|
||||
// FIXME: propagate socket.on('error', ...) + socket.on('close', ...)
|
||||
|
||||
const provider = new SocketDebugAdapter(socket);
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [DebugAdapterSessionFactory](#DebugAdapterSessionFactory) implementation.
|
||||
*/
|
||||
@injectable()
|
||||
export class DebugAdapterSessionFactoryImpl implements DebugAdapterSessionFactory {
|
||||
|
||||
get(sessionId: string, debugAdapter: DebugAdapter): DebugAdapterSession {
|
||||
return new DebugAdapterSessionImpl(
|
||||
sessionId,
|
||||
debugAdapter
|
||||
);
|
||||
}
|
||||
}
|
||||
106
packages/debug/src/node/debug-adapter-session-manager.ts
Normal file
106
packages/debug/src/node/debug-adapter-session-manager.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 Red Hat, Inc. and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { UUID } from '@theia/core/shared/@lumino/coreutils';
|
||||
import { injectable, inject } from '@theia/core/shared/inversify';
|
||||
import { MessagingService } from '@theia/core/lib/node/messaging/messaging-service';
|
||||
|
||||
import { DebugAdapterPath, ForwardingDebugChannel } from '../common/debug-service';
|
||||
import { DebugConfiguration } from '../common/debug-configuration';
|
||||
import { DebugAdapterSession, DebugAdapterSessionFactory, DebugAdapterFactory } from '../common/debug-model';
|
||||
import { DebugAdapterContributionRegistry } from '../common/debug-adapter-contribution-registry';
|
||||
|
||||
/**
|
||||
* Debug adapter session manager.
|
||||
*/
|
||||
@injectable()
|
||||
export class DebugAdapterSessionManager implements MessagingService.Contribution {
|
||||
protected readonly sessions = new Map<string, DebugAdapterSession>();
|
||||
|
||||
@inject(DebugAdapterSessionFactory)
|
||||
protected readonly debugAdapterSessionFactory: DebugAdapterSessionFactory;
|
||||
|
||||
@inject(DebugAdapterFactory)
|
||||
protected readonly debugAdapterFactory: DebugAdapterFactory;
|
||||
|
||||
configure(service: MessagingService): void {
|
||||
service.registerChannelHandler(`${DebugAdapterPath}/:id`, ({ id }: { id: string }, wsChannel) => {
|
||||
const session = this.find(id);
|
||||
if (!session) {
|
||||
wsChannel.close();
|
||||
return;
|
||||
}
|
||||
session.start(new ForwardingDebugChannel(wsChannel));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new [debug adapter session](#DebugAdapterSession).
|
||||
* @param config The [DebugConfiguration](#DebugConfiguration)
|
||||
* @returns The debug adapter session
|
||||
*/
|
||||
async create(config: DebugConfiguration, registry: DebugAdapterContributionRegistry): Promise<DebugAdapterSession> {
|
||||
const sessionId = UUID.uuid4();
|
||||
|
||||
let communicationProvider;
|
||||
if ('debugServer' in config) {
|
||||
communicationProvider = this.debugAdapterFactory.connect(config.debugServer);
|
||||
} else {
|
||||
const executable = await registry.provideDebugAdapterExecutable(config);
|
||||
communicationProvider = this.debugAdapterFactory.start(executable);
|
||||
}
|
||||
|
||||
const sessionFactory = registry.debugAdapterSessionFactory(config.type) || this.debugAdapterSessionFactory;
|
||||
const session = sessionFactory.get(sessionId, communicationProvider);
|
||||
this.sessions.set(sessionId, session);
|
||||
|
||||
if (config.parentSession) {
|
||||
const parentSession = this.sessions.get(config.parentSession.id);
|
||||
if (parentSession) {
|
||||
session.parentSession = parentSession;
|
||||
}
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes [debug adapter session](#DebugAdapterSession) from the list of the instantiated sessions.
|
||||
* Is invoked when session is terminated and isn't needed anymore.
|
||||
* @param sessionId The session identifier
|
||||
*/
|
||||
remove(sessionId: string): void {
|
||||
this.sessions.delete(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the debug adapter session by its id.
|
||||
* Returning the value 'undefined' means the session isn't found.
|
||||
* @param sessionId The session identifier
|
||||
* @returns The debug adapter session
|
||||
*/
|
||||
find(sessionId: string): DebugAdapterSession | undefined {
|
||||
return this.sessions.get(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all instantiated debug adapter sessions.
|
||||
* @returns An array of debug adapter sessions
|
||||
*/
|
||||
getAll(): IterableIterator<DebugAdapterSession> {
|
||||
return this.sessions.values();
|
||||
}
|
||||
}
|
||||
57
packages/debug/src/node/debug-backend-module.ts
Normal file
57
packages/debug/src/node/debug-backend-module.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 Red Hat, Inc. and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { bindContributionProvider } from '@theia/core/lib/common';
|
||||
import { ContainerModule } from '@theia/core/shared/inversify';
|
||||
import {
|
||||
DebugPath,
|
||||
DebugService
|
||||
} from '../common/debug-service';
|
||||
import {
|
||||
LaunchBasedDebugAdapterFactory,
|
||||
DebugAdapterSessionFactoryImpl
|
||||
} from './debug-adapter-factory';
|
||||
import { MessagingService } from '@theia/core/lib/node/messaging/messaging-service';
|
||||
import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connection-container-module';
|
||||
import {
|
||||
DebugAdapterContribution,
|
||||
DebugAdapterSessionFactory,
|
||||
DebugAdapterFactory
|
||||
} from '../common/debug-model';
|
||||
import { DebugServiceImpl } from './debug-service-impl';
|
||||
import { DebugAdapterContributionRegistry } from '../common/debug-adapter-contribution-registry';
|
||||
import { DebugAdapterSessionManager } from './debug-adapter-session-manager';
|
||||
import { bindDebugPreferences } from '../common/debug-preferences';
|
||||
import { bindLaunchPreferences } from '../common/launch-preferences';
|
||||
|
||||
const debugConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
bindContributionProvider(bind, DebugAdapterContribution);
|
||||
bind(DebugAdapterContributionRegistry).toSelf().inSingletonScope();
|
||||
|
||||
bind(DebugService).to(DebugServiceImpl).inSingletonScope();
|
||||
bindBackendService(DebugPath, DebugService);
|
||||
});
|
||||
|
||||
export default new ContainerModule(bind => {
|
||||
bind(ConnectionContainerModule).toConstantValue(debugConnectionModule);
|
||||
|
||||
bind(DebugAdapterSessionFactory).to(DebugAdapterSessionFactoryImpl).inSingletonScope();
|
||||
bind(DebugAdapterFactory).to(LaunchBasedDebugAdapterFactory).inSingletonScope();
|
||||
bind(DebugAdapterSessionManager).toSelf().inSingletonScope();
|
||||
bind(MessagingService.Contribution).toService(DebugAdapterSessionManager);
|
||||
bindDebugPreferences(bind);
|
||||
bindLaunchPreferences(bind);
|
||||
});
|
||||
119
packages/debug/src/node/debug-service-impl.ts
Normal file
119
packages/debug/src/node/debug-service-impl.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2018 Red Hat, Inc. and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { injectable, inject } from '@theia/core/shared/inversify';
|
||||
import { DebugConfiguration } from '../common/debug-configuration';
|
||||
import { DebugService, DebuggerDescription } from '../common/debug-service';
|
||||
import { IJSONSchema, IJSONSchemaSnippet } from '@theia/core/lib/common/json-schema';
|
||||
import { CommandIdVariables } from '@theia/variable-resolver/lib/common/variable-types';
|
||||
import { DebugAdapterSessionManager } from './debug-adapter-session-manager';
|
||||
import { DebugAdapterContributionRegistry } from '../common/debug-adapter-contribution-registry';
|
||||
import { Event } from '@theia/core';
|
||||
|
||||
/**
|
||||
* DebugService implementation.
|
||||
*/
|
||||
@injectable()
|
||||
export class DebugServiceImpl implements DebugService {
|
||||
|
||||
@inject(DebugAdapterSessionManager)
|
||||
protected readonly sessionManager: DebugAdapterSessionManager;
|
||||
|
||||
@inject(DebugAdapterContributionRegistry)
|
||||
protected readonly registry: DebugAdapterContributionRegistry;
|
||||
|
||||
get onDidChangeDebugConfigurationProviders(): Event<void> {
|
||||
return Event.None;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.terminateDebugSession();
|
||||
}
|
||||
|
||||
async debugTypes(): Promise<string[]> {
|
||||
return this.registry.debugTypes();
|
||||
}
|
||||
|
||||
getDebuggersForLanguage(language: string): Promise<DebuggerDescription[]> {
|
||||
return this.registry.getDebuggersForLanguage(language);
|
||||
}
|
||||
|
||||
getSchemaAttributes(debugType: string): Promise<IJSONSchema[]> {
|
||||
return this.registry.getSchemaAttributes(debugType);
|
||||
}
|
||||
|
||||
getConfigurationSnippets(): Promise<IJSONSchemaSnippet[]> {
|
||||
return this.registry.getConfigurationSnippets();
|
||||
}
|
||||
|
||||
async provideDebuggerVariables(debugType: string): Promise<CommandIdVariables> {
|
||||
// TODO: Support resolution of variables map through Theia extensions?
|
||||
return {};
|
||||
}
|
||||
|
||||
async provideDebugConfigurations(debugType: string, workspaceFolderUri?: string): Promise<DebugConfiguration[]> {
|
||||
return this.registry.provideDebugConfigurations(debugType, workspaceFolderUri);
|
||||
}
|
||||
async provideDynamicDebugConfigurations(): Promise<Record<string, DebugConfiguration[]>> {
|
||||
// TODO: Support dynamic debug configurations through Theia extensions?
|
||||
return {};
|
||||
}
|
||||
fetchDynamicDebugConfiguration(name: string, type: string, folder?: string): Promise<DebugConfiguration | undefined> {
|
||||
// TODO: Support dynamic debug configurations through Theia extensions?
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
async resolveDebugConfiguration(config: DebugConfiguration, workspaceFolderUri?: string): Promise<DebugConfiguration> {
|
||||
return this.registry.resolveDebugConfiguration(config, workspaceFolderUri);
|
||||
}
|
||||
async resolveDebugConfigurationWithSubstitutedVariables(config: DebugConfiguration, workspaceFolderUri?: string): Promise<DebugConfiguration> {
|
||||
return this.registry.resolveDebugConfigurationWithSubstitutedVariables(config, workspaceFolderUri);
|
||||
}
|
||||
|
||||
protected readonly sessions = new Set<string>();
|
||||
async createDebugSession(config: DebugConfiguration, _workspaceFolderUri?: string): Promise<string> {
|
||||
const session = await this.sessionManager.create(config, this.registry);
|
||||
this.sessions.add(session.id);
|
||||
return session.id;
|
||||
}
|
||||
|
||||
async terminateDebugSession(sessionId?: string): Promise<void> {
|
||||
if (sessionId) {
|
||||
await this.doStop(sessionId);
|
||||
} else {
|
||||
const promises: Promise<void>[] = [];
|
||||
const sessions = [...this.sessions];
|
||||
this.sessions.clear();
|
||||
for (const session of sessions) {
|
||||
promises.push((async () => {
|
||||
try {
|
||||
await this.doStop(session);
|
||||
} catch (e) {
|
||||
console.error('terminateDebugSession failed:', e);
|
||||
}
|
||||
})());
|
||||
}
|
||||
await Promise.all(promises);
|
||||
}
|
||||
}
|
||||
protected async doStop(sessionId: string): Promise<void> {
|
||||
const debugSession = this.sessionManager.find(sessionId);
|
||||
if (debugSession) {
|
||||
this.sessionManager.remove(sessionId);
|
||||
this.sessions.delete(sessionId);
|
||||
await debugSession.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
126
packages/debug/src/node/stream-debug-adapter.ts
Normal file
126
packages/debug/src/node/stream-debug-adapter.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
// *****************************************************************************
|
||||
// Copyright (C) 2021 Red Hat, Inc. and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// http://www.eclipse.org/legal/epl-2.0.
|
||||
//
|
||||
// This Source Code may also be made available under the following Secondary
|
||||
// Licenses when the conditions for such availability set forth in the Eclipse
|
||||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
||||
// with the GNU Classpath Exception which is available at
|
||||
// https://www.gnu.org/software/classpath/license.html.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
||||
// *****************************************************************************
|
||||
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { ChildProcess } from 'child_process';
|
||||
import * as stream from 'stream';
|
||||
import * as net from 'net';
|
||||
import { DebugAdapter } from '../common/debug-model';
|
||||
|
||||
abstract class StreamDebugAdapter extends DisposableCollection {
|
||||
private messageReceivedEmitter = new Emitter<string>();
|
||||
onMessageReceived: Event<string> = this.messageReceivedEmitter.event;
|
||||
private errorEmitter = new Emitter<Error>();
|
||||
onError: Event<Error> = this.errorEmitter.event;
|
||||
private closeEmitter = new Emitter<void>();
|
||||
onClose: Event<void> = this.closeEmitter.event;
|
||||
|
||||
// these constants are for the message header, see: https://microsoft.github.io/debug-adapter-protocol/overview#header-part
|
||||
private static TWO_CRLF = '\r\n\r\n';
|
||||
private static CONTENT_LENGTH = 'Content-Length';
|
||||
private contentLength: number = -1;
|
||||
private buffer: Buffer = Buffer.alloc(0);
|
||||
|
||||
constructor(private fromAdapter: stream.Readable, private toAdapter: stream.Writable) {
|
||||
super();
|
||||
|
||||
this.fromAdapter.on('data', (data: Buffer) => this.handleData(data));
|
||||
this.fromAdapter.on('close', () => this.handleClosed()); // FIXME pass a proper exit code
|
||||
this.fromAdapter.on('error', error => this.errorEmitter.fire(error));
|
||||
this.toAdapter.on('error', error => this.errorEmitter.fire(error));
|
||||
}
|
||||
|
||||
handleClosed(): void {
|
||||
this.closeEmitter.fire();
|
||||
}
|
||||
|
||||
send(message: string): void {
|
||||
const msg = `${StreamDebugAdapter.CONTENT_LENGTH}: ${Buffer.byteLength(message, 'utf8')}${StreamDebugAdapter.TWO_CRLF}${message}`;
|
||||
|
||||
this.toAdapter.write(msg, 'utf8');
|
||||
}
|
||||
|
||||
protected handleData(data: Buffer): void {
|
||||
this.buffer = Buffer.concat([this.buffer, data]);
|
||||
|
||||
while (true) {
|
||||
if (this.contentLength >= 0) {
|
||||
if (this.buffer.length >= this.contentLength) {
|
||||
const message = this.buffer.toString('utf8', 0, this.contentLength);
|
||||
this.buffer = this.buffer.slice(this.contentLength);
|
||||
this.contentLength = -1;
|
||||
|
||||
if (message.length > 0) {
|
||||
this.messageReceivedEmitter.fire(message);
|
||||
}
|
||||
continue; // there may be more complete messages to process
|
||||
}
|
||||
} else {
|
||||
let idx = this.buffer.indexOf(StreamDebugAdapter.CONTENT_LENGTH);
|
||||
if (idx > 0) {
|
||||
// log unrecognized output
|
||||
const output = this.buffer.slice(0, idx);
|
||||
console.log(output.toString('utf-8'));
|
||||
|
||||
this.buffer = this.buffer.slice(idx);
|
||||
}
|
||||
|
||||
idx = this.buffer.indexOf(StreamDebugAdapter.TWO_CRLF);
|
||||
if (idx !== -1) {
|
||||
const header = this.buffer.toString('utf8', 0, idx);
|
||||
const lines = header.split('\r\n');
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const pair = lines[i].split(/: +/);
|
||||
if (pair[0] === StreamDebugAdapter.CONTENT_LENGTH) {
|
||||
this.contentLength = +pair[1];
|
||||
}
|
||||
}
|
||||
this.buffer = this.buffer.slice(idx + StreamDebugAdapter.TWO_CRLF.length);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ProcessDebugAdapter extends StreamDebugAdapter implements DebugAdapter {
|
||||
protected readonly process: ChildProcess;
|
||||
constructor(process: ChildProcess) {
|
||||
super(process.stdout!, process.stdin!);
|
||||
this.process = process;
|
||||
}
|
||||
|
||||
async stop(): Promise<void> {
|
||||
this.process.kill();
|
||||
this.process.stdin?.end();
|
||||
}
|
||||
}
|
||||
|
||||
export class SocketDebugAdapter extends StreamDebugAdapter implements DebugAdapter {
|
||||
private readonly socket: net.Socket;
|
||||
constructor(socket: net.Socket) {
|
||||
super(socket, socket);
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
stop(): Promise<void> {
|
||||
return new Promise<void>(resolve => {
|
||||
this.socket.end(() => resolve());
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user