Skip to content
This repository has been archived by the owner on Jul 3, 2019. It is now read-only.

Commit

Permalink
Move IPC code to its own files
Browse files Browse the repository at this point in the history
Changes:

- add showContextQuickPick function to API
- add node-ipc library to package-lock.json file
  • Loading branch information
bkircher committed Jul 12, 2017
1 parent 85bf4b9 commit 7b23983
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 91 deletions.
5 changes: 3 additions & 2 deletions .vscode/cSpell.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
"words": [
"jsrdbg",
"debugadapter",
"dopaag"
"dopaag",
"appspace"
],
// flagWords - list of words to be always considered incorrect
// This is useful for offensive words and common spelling errors.
// For example "hte" should be "the"
"flagWords": [
"hte"
]
}
}
31 changes: 31 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

91 changes: 40 additions & 51 deletions src/debugSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import * as assert from 'assert';
import { connect, Socket } from 'net';
import { IPC } from 'node-ipc';
import { crypt_md5, SDSConnection } from 'node-sds';
import { ContinuedEvent, DebugSession, InitializedEvent, OutputEvent, StoppedEvent, TerminatedEvent } from 'vscode-debugadapter';
import { DebugProtocol } from 'vscode-debugprotocol';
import { AttachRequestArguments, CommonArguments, LaunchRequestArguments } from './config';
import { DebugConnection } from './connection';
import { ContextId } from './context';
import { FrameMap } from './frameMap';
import { DebugAdapterIPC } from './ipcClient';
import { Logger } from './log';
import { Breakpoint, Command, Response, StackFrame, Variable, variableValueToString } from './protocol';
import { LocalSource, SourceMap } from './sourceMap';
Expand Down Expand Up @@ -117,24 +117,6 @@ export class JanusDebugSession extends DebugSession {

this.config = 'launch';

let ipc = new IPC();
ipc.config.appspace = 'vscode-janus-debug.';
ipc.config.id = 'debug_adapter';
ipc.config.retry = 1500;
ipc.connectTo('sock', () => {
ipc.of.sock.on('connect', () => {
log.debug(`IPC: connected to extension`);

ipc.of.sock.emit('message', 'something');
});
ipc.of.sock.on('disconnect', () => {
log.debug(`IPC: disconnected`);
});
ipc.of.sock.on('message', (data) => {
log.debug(`got message from extension: ${data}`);
});
});

const sdsPort: number = args.applicationPort || 10000;
const debuggerPort = 8089;
const host: string = args.host || 'localhost';
Expand Down Expand Up @@ -163,6 +145,9 @@ export class JanusDebugSession extends DebugSession {
return;
}

const ipcClient = new DebugAdapterIPC();
await ipcClient.connect();

const sdsSocket = connect(sdsPort, host);
const sdsConnection = new SDSConnection(sdsSocket);

Expand Down Expand Up @@ -341,12 +326,15 @@ export class JanusDebugSession extends DebugSession {
});
}

protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void {
protected async attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): Promise<void> {
this.applyConfig(args);
log.info(`attachRequest`);

this.config = 'attach';

const ipcClient = new DebugAdapterIPC();
await ipcClient.connect();

const port: number = args.debuggerPort || 8089;
const host: string = args.host || 'localhost';
const socket = connect(port, host);
Expand All @@ -358,51 +346,50 @@ export class JanusDebugSession extends DebugSession {
const connection = new DebugConnection(socket);
this.connection = connection;

socket.on('connect', () => {
socket.on('connect', async () => {

// TCP connection established. It is important for this client that we first send a 'get_all_source_urls'
// request to the server. This way we have a list of all currently active contexts.

log.info(`attachRequest: connection to ${host}:${port} established. Testing...`);

const timeout = new Promise<void>((resolve, reject) => {
setTimeout(reject, args.timeout || 6000, "Operation timed out");
});
const request = connection.sendRequest(new Command('get_all_source_urls'), (res: Response): Promise<void> => {
try {

return new Promise<void>((resolve, reject) => {
await connection.sendRequest(new Command('get_all_source_urls'), (res: Response): Promise<void> => {

assert.notEqual(res, undefined);
return new Promise<void>(async (resolve, reject) => {

if (res.subtype === 'all_source_urls') {
log.info('attachRequest: ...looks good');
this.sourceMap.setAllRemoteUrls(res.content.urls);
resolve();
} else {
log.error(`attachRequest: error while connecting to ${host}:${port}`);
reject(`Error while connecting to ${host}:${port}`);
}
});
});
assert.notEqual(res, undefined);

// TODO: the timeout needs to be cancelled when the request is resolved, right? Anyway, use
// promised-timeout library for that
if (res.subtype === 'all_source_urls') {
log.info('attachRequest: ...looks good');
this.sourceMap.setAllRemoteUrls(res.content.urls);

Promise.race([request, timeout]).then(() => {
// Here we'd show the user the available contexts with something like
// await ipcClient.showContextQuickPick(res.content.urls);

// Tell the frontend that we are ready to set breakpoints and so on. The frontend will end the
// configuration sequence by calling 'configurationDone' request
log.debug(`sending InitializedEvent`);
this.sendEvent(new InitializedEvent());
this.debugConsole(`Debugger listening on ${host}:${port}`);
this.sendResponse(response);
resolve();
} else {
log.error(`attachRequest: error while connecting to ${host}:${port}`);
reject(`Error while connecting to ${host}:${port}`);
}
});
});

}).catch(reason => {
log.error(`attachRequest: ...failed. ${reason}`);

} catch (err) {
log.error(`attachRequest: ...failed. ${err}`);
response.success = false;
response.message = `Could not attach to remote process: ${reason}`;
this.sendResponse(response);
});
response.message = `Could not attach to remote process: ${err}`;
return this.sendResponse(response);
}

// Tell the frontend that we are ready to set breakpoints and so on. The frontend will end the
// configuration sequence by calling 'configurationDone' request
log.debug(`sending InitializedEvent`);
this.sendEvent(new InitializedEvent());
this.debugConsole(`Debugger listening on ${host}:${port}`);
this.sendResponse(response);
});

socket.on('close', (hadError: boolean) => {
Expand All @@ -428,6 +415,8 @@ export class JanusDebugSession extends DebugSession {
this.connection = undefined;
this.sendEvent(new TerminatedEvent());
});

await ipcClient.disconnect();
}

protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse,
Expand Down
42 changes: 4 additions & 38 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ import * as fs from 'fs';
import * as nodeDoc from 'node-documents-scripting';
import * as os from 'os';
import * as path from 'path';
import * as fs from 'fs';
import { IPC } from 'node-ipc';
import * as vscode from 'vscode';
import * as commands from './commands';
import { provideInitialConfigurations } from './config';
import { extend } from './helpers';
import { VSCodeExtensionIPC } from './ipcServer';
import { LogConfiguration, Logger } from './log';
import * as login from './login';
import { ServerConsole } from './serverConsole';
Expand All @@ -18,6 +17,7 @@ import { getVersion } from './version';

const DOCUMENTS_SETTINGS = 'documents-scripting-settings.json';

let ipcServer: VSCodeExtensionIPC;
let launchJsonWatcher: vscode.FileSystemWatcher;
let serverConsole: ServerConsole;
let runScriptChannel: vscode.OutputChannel;
Expand Down Expand Up @@ -130,31 +130,6 @@ function disconnectServerConsole(console: ServerConsole): void {
console.outputChannel.appendLine(`Disconnected from server`);
}

// We use a UNIX Domain or Windows socket, respectively, for having a
// communication channel from the debug adapter process back to the extension.
// Socket file path is usually /tmp/vscode-janus-debug.sock or so on Linux or
// macOS. This communication channel is outside of VS Code's debug protocol and
// allows us to show input boxes or use other parts of the VS Code extension
// API that would otherwise be unavailable to us in the debug adapter.

let ipc = new IPC();
ipc.config.appspace = 'vscode-janus-debug.';
ipc.config.id = 'sock';
ipc.config.retry = 1500;
ipc.config.silent = true;

function removeStaleSocket() {
ipc.disconnect('sock');
const staleSocket = `${ipc.config.socketRoot}${ipc.config.appspace}${ipc.config.id}`;
if (fs.existsSync(staleSocket)) {
try {
fs.unlinkSync(staleSocket);
} catch (err) {
// Swallow
}
}
}

export function activate(context: vscode.ExtensionContext): void {

// set up file logging
Expand All @@ -178,7 +153,6 @@ export function activate(context: vscode.ExtensionContext): void {
loginData.loadConfigFile(launchJson);
}


if (isFolderOpen) {
const outputChannel = vscode.window.createOutputChannel('Server Console');
outputChannel.appendLine('Extension activated');
Expand Down Expand Up @@ -230,16 +204,7 @@ export function activate(context: vscode.ExtensionContext): void {
});
}

ipc.serve(() => {
ipc.server.on('message', () => {
vscode.window.showInformationMessage('Served!');
});
});

ipc.server.start();

process.on('exit', removeStaleSocket);
process.on('uncaughtException', removeStaleSocket);
ipcServer = new VSCodeExtensionIPC();

context.subscriptions.push(
vscode.commands.registerCommand('extension.vscode-janus-debug.askForPassword', () => {
Expand Down Expand Up @@ -428,6 +393,7 @@ export function activate(context: vscode.ExtensionContext): void {
}

export function deactivate(): undefined {
ipcServer.dispose();
launchJsonWatcher.dispose();
serverConsole.hide();
serverConsole.dispose();
Expand Down
64 changes: 64 additions & 0 deletions src/ipcClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import ipc = require('node-ipc');
import { timeout } from 'promised-timeout';
import { Logger } from './log';

ipc.config.appspace = 'vscode-janus-debug.';
ipc.config.id = 'debug_adapter';
ipc.config.retry = 1500;

const log = Logger.create('DebugAdapterIPC');

/**
* Acts as the client in our communication.
*
* @export
* @class DebugAdapter
*/
export class DebugAdapterIPC {

public async connect() {
ipc.connectTo('sock', () => {

ipc.of.sock.on('connect', () => {
log.debug(`connected to VS Code extension`);
});

ipc.of.sock.on('disconnect', () => {
log.debug(`disconnected from VS Code extension`);
});

ipc.of.sock.on('contextChosen', this.contextChosenDefaultHandler);
});
}

public async disconnect(): Promise<void> {
ipc.disconnect('sock');
}

public async showContextQuickPick(contextList: string[]): Promise<string> {
log.debug(`showContextQuickPick ${JSON.stringify(contextList)}`);

const waitForResponse = timeout({
promise: new Promise<string>(resolve => {
ipc.of.sock.on('contextChosen', (contextLabel: string) => {
log.debug(`user picked '${contextLabel}'`);
resolve(contextLabel);
});
}),
time: 10000,
error: new Error('Request timed out'),
});
ipc.of.sock.emit('showContextQuickPick', contextList);
let result: string;
try {
result = await waitForResponse;
} finally {
ipc.of.sock.on('contextChosen', this.contextChosenDefaultHandler);
}
return result;
}

private contextChosenDefaultHandler(data: any) {
log.warn(`got 'contextChosen' message from VS Code extension but we haven't asked!`);
}
}
Loading

0 comments on commit 7b23983

Please sign in to comment.