From c9db693cc6838fce09d9a0ea70e2ecb58f70ad7a Mon Sep 17 00:00:00 2001 From: Dustin Campbell Date: Wed, 9 Nov 2016 12:52:59 -0800 Subject: [PATCH] Get server working again --- src/features/status.ts | 10 +-- src/omnisharp/{queue.ts => requestQueue.ts} | 46 ++++++++----- src/omnisharp/server.ts | 72 +++++++++++---------- 3 files changed, 70 insertions(+), 58 deletions(-) rename src/omnisharp/{queue.ts => requestQueue.ts} (77%) diff --git a/src/features/status.ts b/src/features/status.ts index 371f5e1..19086fe 100644 --- a/src/features/status.ts +++ b/src/features/status.ts @@ -278,17 +278,11 @@ function showMessageSoon() { function forwardOutput(server: OmniSharpServer) { const logChannel = server.getChannel(); - const timing200Pattern = /^\[INFORMATION:OmniSharp.Middleware.LoggingMiddleware\] \/\w+: 200 \d+ms/; function forward(message: string) { - // strip stuff like: /codecheck: 200 339ms - if(!timing200Pattern.test(message)) { - logChannel.append(message); - } + logChannel.append(message); } return vscode.Disposable.from( - server.onStdout(forward), server.onStderr(forward)); -} - +} \ No newline at end of file diff --git a/src/omnisharp/queue.ts b/src/omnisharp/requestQueue.ts similarity index 77% rename from src/omnisharp/queue.ts rename to src/omnisharp/requestQueue.ts index 426cda2..2fb0b69 100644 --- a/src/omnisharp/queue.ts +++ b/src/omnisharp/requestQueue.ts @@ -7,11 +7,13 @@ import { Logger } from '../logger'; import * as protocol from './protocol'; import * as prioritization from './prioritization'; -interface Request { +export interface Request { command: string; data?: any; onSuccess(value: any): void; onError(err: any): void; + startTime?: number; + endTime?: number; } /** @@ -20,37 +22,47 @@ interface Request { */ class RequestQueue { private _pending: Request[] = []; - private _waiting: Map = new Map(); + private _waiting: Map = new Map(); public constructor( private _name: string, private _maxSize: number, private _logger: Logger, - private _makeRequest: (request: Request) => protocol.WireProtocol.RequestPacket) { + private _makeRequest: (request: Request) => number) { } /** * Enqueue a new request. */ public enqueue(request: Request) { - this._logger.appendLine(`Enqueuing request for ${request.command}.`); + this._logger.appendLine(`Enqueue request for ${request.command}.`); this._pending.push(request); } - public dequeue(seq: number) { - return this._waiting.delete(seq); + /** + * Dequeue a request that has completed. + */ + public dequeue(id: number) { + const request = this._waiting.get(id); + + if (request) { + this._waiting.delete(id); + this._logger.appendLine(`Dequeue request for ${request.command}.`); + } + + return request; } - public delete(request: Request) { + public cancelRequest(request: Request) { let index = this._pending.indexOf(request); if (index !== -1) { this._pending.splice(index, 1); - // Do something better here. - let err = new Error('Canceled'); - err.message = 'Canceled'; - request.onError(err); + // Note: This calls reject() on the promise returned by OmniSharpServer.makeRequest + request.onError(new Error(`Pending request cancelled: ${request.command}`)); } + + // TODO: Handle cancellation of a request already waiting on the OmniSharp server. } /** @@ -79,8 +91,10 @@ class RequestQueue { for (let i = 0; i < slots && this._pending.length > 0; i++) { const item = this._pending.shift(); - const request = this._makeRequest(item); - this._waiting.set(request.Seq, request); + item.startTime = Date.now(); + + const id = this._makeRequest(item); + this._waiting.set(id, item); if (this.isFull()) { return; @@ -89,7 +103,7 @@ class RequestQueue { } } -export class Queue { +export class RequestQueueCollection { private _logger: Logger; private _isProcessing: boolean; private _priorityQueue: RequestQueue; @@ -99,7 +113,7 @@ export class Queue { public constructor( logger: Logger, concurrency: number, - makeRequest: (request: Request) => protocol.WireProtocol.RequestPacket + makeRequest: (request: Request) => number ) { this._priorityQueue = new RequestQueue('Priority', 1, logger, makeRequest); this._normalQueue = new RequestQueue('Normal', concurrency, logger, makeRequest); @@ -132,7 +146,7 @@ export class Queue { public cancelRequest(request: Request) { const queue = this.getQueue(request.command); - queue.delete(request); + queue.cancelRequest(request); } public drain() { diff --git a/src/omnisharp/server.ts b/src/omnisharp/server.ts index d02714d..696a2da 100644 --- a/src/omnisharp/server.ts +++ b/src/omnisharp/server.ts @@ -3,21 +3,19 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import {EventEmitter} from 'events'; -import {ChildProcess, exec} from 'child_process'; -import {dirname} from 'path'; -import {ReadLine, createInterface} from 'readline'; -import {launchOmniSharp} from './launcher'; -import * as protocol from './protocol'; -import {Options} from './options'; -import {Logger} from '../logger'; -import {DelayTracker} from './delayTracker'; -import {LaunchTarget, findLaunchTargets} from './launcher'; -import {PlatformInformation} from '../platform'; -import { Queue } from './queue'; +import { EventEmitter } from 'events'; +import { ChildProcess, exec } from 'child_process'; +import { ReadLine, createInterface } from 'readline'; +import { launchOmniSharp } from './launcher'; +import { Options } from './options'; +import { Logger } from '../logger'; +import { DelayTracker } from './delayTracker'; +import { LaunchTarget, findLaunchTargets } from './launcher'; +import { PlatformInformation } from '../platform'; +import { Request, RequestQueueCollection } from './requestQueue'; import TelemetryReporter from 'vscode-extension-telemetry'; +import * as path from 'path'; +import * as protocol from './protocol'; import * as vscode from 'vscode'; enum ServerState { @@ -26,13 +24,6 @@ enum ServerState { Stopped } -interface Request { - command: string; - data?: any; - onSuccess(value: any): void; - onError(err: any): void; -} - module Events { export const StateChanged = 'stateChanged'; @@ -79,7 +70,7 @@ export class OmniSharpServer { private _eventBus = new EventEmitter(); private _state: ServerState = ServerState.Stopped; private _launchTarget: LaunchTarget; - private _requestQueue: Queue; + private _requestQueue: RequestQueueCollection; private _channel: vscode.OutputChannel; private _logger: Logger; @@ -93,7 +84,7 @@ export class OmniSharpServer { this._channel = vscode.window.createOutputChannel('OmniSharp Log'); this._logger = new Logger(message => this._channel.append(message)); - this._requestQueue = new Queue(this._logger, 8, request => this._makeRequest(request)); + this._requestQueue = new RequestQueueCollection(this._logger, 8, request => this._makeRequest(request)); } public isRunning(): boolean { @@ -124,9 +115,9 @@ export class OmniSharpServer { private _reportTelemetry() { const delayTrackers = this._delayTrackers; - for (const path in delayTrackers) { - const tracker = delayTrackers[path]; - const eventName = 'omnisharp' + path; + for (const requestName in delayTrackers) { + const tracker = delayTrackers[requestName]; + const eventName = 'omnisharp' + requestName; if (tracker.hasMeasures()) { const measures = tracker.getMeasures(); tracker.clearMeasures(); @@ -237,7 +228,7 @@ export class OmniSharpServer { this._launchTarget = launchTarget; const solutionPath = launchTarget.target; - const cwd = dirname(solutionPath); + const cwd = path.dirname(solutionPath); let args = [ '-s', solutionPath, '--hostPID', process.pid.toString(), @@ -473,6 +464,7 @@ export class OmniSharpServer { if (listener) { listener.dispose(); } + clearTimeout(handle); resolve(); }); @@ -523,24 +515,25 @@ export class OmniSharpServer { } private _handleResponsePacket(packet: protocol.WireProtocol.ResponsePacket) { - if (!this._requestQueue.dequeue(packet.Command, packet.Request_seq)) { + const request = this._requestQueue.dequeue(packet.Command, packet.Request_seq); + + if (!request) { this._logger.appendLine(`Received response for ${packet.Command} but could not find request.`); return; } if (packet.Success) { - // Handle success + request.onSuccess(packet.Body); } else { - // Handle failure + request.onError(packet.Message || packet.Body); } } private _handleEventPacket(packet: protocol.WireProtocol.EventPacket): void { if (packet.Event === 'log') { - // handle log events const entry = <{ LogLevel: string; Name: string; Message: string; }>packet.Body; - this._logger.appendLine(`[${entry.LogLevel}:${entry.Name}] ${entry.Message}`); + this._logOutput(entry.LogLevel, entry.Name, entry.Message); } else { // fwd all other events @@ -558,10 +551,21 @@ export class OmniSharpServer { Arguments: request.data }; - console.log(`Making request: ${request.command} (${id})`); + this._logger.appendLine(`Making request: ${request.command} (${id})`); this._serverProcess.stdin.write(JSON.stringify(requestPacket) + '\n'); - return requestPacket; + return id; + } + + private _logOutput(logLevel: string, name: string, message: string) { + const timing200Pattern = /^\[INFORMATION:OmniSharp.Middleware.LoggingMiddleware\] \/[\/\w]+: 200 \d+ms/; + + const output = `[${logLevel}:${name}] ${message}`; + + // strip stuff like: /codecheck: 200 339ms + if (!timing200Pattern.test(output)) { + this._logger.appendLine(output); + } } }