From 2a2d6b225d39989e2dceb3deae312e9b2db240f8 Mon Sep 17 00:00:00 2001 From: Ankush Tyagi Date: Fri, 20 Nov 2020 19:08:00 +0100 Subject: [PATCH] Add Preference settings for trace configuration Set the default values for the trace server preferences Read the trace server preference values and spawn the server from the path specified in the preferences fixes #191 fixes #184 Signed-off-by: Ankush Tyagi --- browser-app/package.json | 5 +- electron-app/package.json | 4 +- viewer-prototype/package.json | 96 +++++++++---------- .../src/browser/trace-server-bindings.ts | 15 +++ .../src/browser/trace-server-preference.ts | 30 ++++++ .../src/browser/trace-server-status.ts | 45 ++++++++- ...trace-server-url-provider-frontend-impl.ts | 13 ++- .../trace-viewer-frontend-module.ts | 15 ++- .../src/common/trace-server-config.ts | 15 +++ .../src/common/trace-server-url-provider.ts | 4 +- .../src/common/trace-viewer-environment.ts | 11 ++- viewer-prototype/src/node/index.ts | 2 + .../src/node/trace-server-backend-module.ts | 16 ++++ .../src/node/trace-server-service.ts | 14 +++ viewer-prototype/tsconfig.json | 10 +- 15 files changed, 226 insertions(+), 69 deletions(-) create mode 100644 viewer-prototype/src/browser/trace-server-bindings.ts create mode 100644 viewer-prototype/src/browser/trace-server-preference.ts create mode 100644 viewer-prototype/src/common/trace-server-config.ts create mode 100644 viewer-prototype/src/node/index.ts create mode 100644 viewer-prototype/src/node/trace-server-backend-module.ts create mode 100644 viewer-prototype/src/node/trace-server-service.ts diff --git a/browser-app/package.json b/browser-app/package.json index b3b2b3440..212412a7e 100644 --- a/browser-app/package.json +++ b/browser-app/package.json @@ -8,7 +8,10 @@ "config": { "applicationName": "Theia-Trace Example Application", "preferences": { - "editor.autoSave": "on" + "editor.autoSave": "on", + "trace-viewer.path" : "/trace-compass-server/tracecompass-server", + "trace-viewer.port" : 8080 + } } } diff --git a/electron-app/package.json b/electron-app/package.json index cc4b70041..df4786251 100644 --- a/electron-app/package.json +++ b/electron-app/package.json @@ -17,7 +17,9 @@ "config": { "applicationName": "Theia-Trace Example Application", "preferences": { - "editor.autoSave": "on" + "editor.autoSave": "on", + "trace-viewer.path" : "/trace-compass-server/tracecompass-server", + "trace-viewer.port" : 8080 } } } diff --git a/viewer-prototype/package.json b/viewer-prototype/package.json index 5251c3d92..810a6e692 100644 --- a/viewer-prototype/package.json +++ b/viewer-prototype/package.json @@ -1,49 +1,49 @@ { - "name": "theia-trace-viewer", - "private": "true", - "version": "0.0.0", - "description": "Trace Compass trace viewer Theia Extension", - "keywords": [ - "theia-extension" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/theia-ide/theia-trace-extension" - }, - "files": [ - "lib", - "src" - ], - "dependencies": { - "@trace-viewer/base": "0.0.0", - "@trace-viewer/react-components": "0.0.0", - "@theia/core": "latest", - "@theia/editor": "latest", - "@theia/filesystem": "latest" - }, - "devDependencies": { - "@typescript-eslint/eslint-plugin": "^3.4.0", - "@typescript-eslint/parser": "^3.4.0", - "eslint": "^7.3.0", - "eslint-plugin-import": "^2.21.2", - "eslint-plugin-no-null": "^1.0.2", - "eslint-plugin-react": "^7.20.0", - "rimraf": "latest", - "typescript": "latest" - }, - "scripts": { - "build": "tsc", - "clean": "rimraf lib", - "lint": "eslint .", - "prepare": "yarn run clean && yarn run build", - "test": "echo 'test'", - "watch": "tsc -w" - }, - "theiaExtensions": [ - { - "frontend": "lib/browser/trace-viewer/trace-viewer-frontend-module" - } - ] - } - + "name": "theia-trace-viewer", + "private": "true", + "version": "0.0.0", + "description": "Trace Compass trace viewer Theia Extension", + "keywords": [ + "theia-extension" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/theia-ide/theia-trace-extension" + }, + "files": [ + "lib", + "src" + ], + "dependencies": { + "@trace-viewer/base": "0.0.0", + "@trace-viewer/react-components": "0.0.0", + "@theia/core": "latest", + "@theia/editor": "latest", + "@theia/filesystem": "latest" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^3.4.0", + "@typescript-eslint/parser": "^3.4.0", + "eslint": "^7.3.0", + "eslint-plugin-import": "^2.21.2", + "eslint-plugin-no-null": "^1.0.2", + "eslint-plugin-react": "^7.20.0", + "rimraf": "latest", + "typescript": "latest" + }, + "scripts": { + "build": "tsc", + "clean": "rimraf lib", + "lint": "eslint .", + "prepare": "yarn run clean && yarn run build", + "test": "echo 'test'", + "watch": "tsc -w" + }, + "theiaExtensions": [ + { + "frontend": "lib/browser/trace-viewer/trace-viewer-frontend-module", + "backend": "lib/node/trace-server-backend-module" + } + ] +} \ No newline at end of file diff --git a/viewer-prototype/src/browser/trace-server-bindings.ts b/viewer-prototype/src/browser/trace-server-bindings.ts new file mode 100644 index 000000000..7d6118faf --- /dev/null +++ b/viewer-prototype/src/browser/trace-server-bindings.ts @@ -0,0 +1,15 @@ +import { interfaces } from 'inversify'; +import { PreferenceService, createPreferenceProxy, PreferenceContribution } from '@theia/core/lib/browser'; +import { TracePreferences, ServerSchema } from './trace-server-preference'; + +export function bindTraceServerPreferences(bind: interfaces.Bind): void { + bind(TracePreferences).toDynamicValue(ctx => { + const preferences = ctx.container.get(PreferenceService); + return createPreferenceProxy(preferences, ServerSchema); + }).inSingletonScope(); + + bind(PreferenceContribution).toConstantValue({ + schema: ServerSchema, + }); + +} diff --git a/viewer-prototype/src/browser/trace-server-preference.ts b/viewer-prototype/src/browser/trace-server-preference.ts new file mode 100644 index 000000000..0853f45a5 --- /dev/null +++ b/viewer-prototype/src/browser/trace-server-preference.ts @@ -0,0 +1,30 @@ +import { PreferenceSchema, PreferenceProxy, PreferenceScope } from '@theia/core/lib/browser'; + +export const TRACE_PATH = 'trace-viewer.path'; +export const TRACE_PORT = 'trace-viewer.port'; + +export const ServerSchema: PreferenceSchema = { + type: 'object', + properties: { + [TRACE_PATH]: { + 'type': 'string', + 'default': '', + 'description': 'The path to trace-server executable, e.g.: /usr/bin/', + }, + [TRACE_PORT]: { + 'type': 'number', + 'default': '', + 'description': 'Specify the port on which you want to execute the server.', + } + + }, + scope: PreferenceScope.Folder, +}; + +interface TracePreferenceContribution { + [TRACE_PATH]: string; + [TRACE_PORT]: number; +} + +export const TracePreferences = Symbol('TracePreferences'); +export type TracePreferences = PreferenceProxy; diff --git a/viewer-prototype/src/browser/trace-server-status.ts b/viewer-prototype/src/browser/trace-server-status.ts index 3ef554503..046ad0ddf 100644 --- a/viewer-prototype/src/browser/trace-server-status.ts +++ b/viewer-prototype/src/browser/trace-server-status.ts @@ -12,6 +12,9 @@ import { Disposable, DisposableCollection } from '@theia/core/lib//common'; import { ConnectionStatusService, ConnectionStatus, AbstractConnectionStatusService } from '@theia/core/lib/browser/connection-status-service'; import { TspClient } from 'tsp-typescript-client/lib/protocol/tsp-client'; import { TspClientProvider } from './tsp-client-provider'; +import { TraceServerConfigService } from '../common/trace-server-config'; +import { PreferenceService } from '@theia/core/lib/browser'; +import { TRACE_PATH, TRACE_PORT } from './trace-server-preference'; @injectable() export class TraceServerConnectionStatusService extends AbstractConnectionStatusService { @@ -52,6 +55,20 @@ export class TraceServerConnectionStatusService extends AbstractConnectionStatus @injectable() export class TraceServerConnectionStatusContribution extends DefaultFrontendApplicationContribution { + @inject(PreferenceService) protected readonly preferenceService: PreferenceService; + + private path: string | undefined; + private port: number | undefined; + + @postConstruct() + async init(): Promise { + + this.path = this.preferenceService.get(TRACE_PATH); + this.port = this.preferenceService.get(TRACE_PORT); + } + + @inject(TraceServerConfigService) protected readonly traceServerConfigService: TraceServerConfigService; + protected readonly toDisposeOnOnline = new DisposableCollection(); constructor( @@ -61,6 +78,9 @@ export class TraceServerConnectionStatusContribution extends DefaultFrontendAppl ) { super(); this.connectionStatusService.onStatusChange(state => this.onStateChange(state)); + if (this.connectionStatusService.currentStatus === ConnectionStatus.ONLINE) { + this.handleOnline(); + } } protected onStateChange(state: ConnectionStatus): void { @@ -80,15 +100,34 @@ export class TraceServerConnectionStatusContribution extends DefaultFrontendAppl protected handleOnline(): void { this.toDisposeOnOnline.dispose(); + this.statusBar.setElement(this.statusbarId, { + alignment: StatusBarAlignment.LEFT, + text: '$(fas fa-stop) Stop trace server', + tooltip: 'Click here to stop the trace server', + priority: 5003, + onclick: this.stopServer.bind(this) + }); + + } + + private async startServer() { + await this.traceServerConfigService.startTraceServer(this.path, this.port); + } + + private async stopServer() { + await this.traceServerConfigService.stopTraceServer(this.port); } protected handleOffline(): void { + this.toDisposeOnOnline.dispose(); this.statusBar.setElement(this.statusbarId, { alignment: StatusBarAlignment.LEFT, - text: 'Trace Server Offline', - tooltip: 'Cannot connect to trace server.', - priority: 5000 + text: '$(fas fa-play) Start trace server', + tooltip: 'Click here to start the trace server', + priority: 5001, + onclick: this.startServer.bind(this) }); + this.toDisposeOnOnline.push(Disposable.create(() => this.statusBar.removeElement(this.statusbarId))); document.body.classList.add('traceserver-mod-offline'); this.toDisposeOnOnline.push(Disposable.create(() => document.body.classList.remove('traceserver-mod-offline'))); diff --git a/viewer-prototype/src/browser/trace-server-url-provider-frontend-impl.ts b/viewer-prototype/src/browser/trace-server-url-provider-frontend-impl.ts index e7ea9fc76..b350b8bde 100644 --- a/viewer-prototype/src/browser/trace-server-url-provider-frontend-impl.ts +++ b/viewer-prototype/src/browser/trace-server-url-provider-frontend-impl.ts @@ -1,18 +1,23 @@ import { inject, injectable } from 'inversify'; import { TraceViewerEnvironment } from '../common/trace-viewer-environment'; -import { TraceServerUrlProvider, TRACE_SERVER_DEFAULT_URL } from '../common/trace-server-url-provider'; -import { FrontendApplicationContribution, FrontendApplication } from '@theia/core/lib/browser'; +import { TraceServerUrlProvider, TRACE_SERVER_DEFAULT_URL, TRACE_SERVER_DEFAULT_PORT } from '../common/trace-server-url-provider'; +import { FrontendApplicationContribution, FrontendApplication, PreferenceService } from '@theia/core/lib/browser'; +import { TRACE_PORT } from './trace-server-preference'; @injectable() export class TraceServerUrlProviderImpl implements TraceServerUrlProvider, FrontendApplicationContribution { protected _traceServerUrl: string; protected _listeners: ((url: string) => void)[]; + private port: string|undefined; constructor( - @inject(TraceViewerEnvironment) protected readonly traceViewerEnvironment: TraceViewerEnvironment + @inject(TraceViewerEnvironment) protected readonly traceViewerEnvironment: TraceViewerEnvironment, + @inject(PreferenceService) protected readonly preferenceService: PreferenceService + ) { - this._traceServerUrl = TRACE_SERVER_DEFAULT_URL; + this.port = this.preferenceService.get(TRACE_PORT); + this._traceServerUrl = TRACE_SERVER_DEFAULT_URL.replace(/{}/g,this.port?this.port:TRACE_SERVER_DEFAULT_PORT); this._listeners = []; } diff --git a/viewer-prototype/src/browser/trace-viewer/trace-viewer-frontend-module.ts b/viewer-prototype/src/browser/trace-viewer/trace-viewer-frontend-module.ts index ab79e981c..2f2cf8d4f 100644 --- a/viewer-prototype/src/browser/trace-viewer/trace-viewer-frontend-module.ts +++ b/viewer-prototype/src/browser/trace-viewer/trace-viewer-frontend-module.ts @@ -1,5 +1,5 @@ import { ContainerModule, Container } from 'inversify'; -import { WidgetFactory, OpenHandler, FrontendApplicationContribution, bindViewContribution } from '@theia/core/lib/browser'; +import { WidgetFactory, OpenHandler, FrontendApplicationContribution, bindViewContribution, WebSocketConnectionProvider } from '@theia/core/lib/browser'; import { TraceViewerWidget, TraceViewerWidgetOptions } from './trace-viewer'; import { TraceViewerContribution } from './trace-viewer-contribution'; import { TraceViewerEnvironment } from '../../common/trace-viewer-environment'; @@ -10,16 +10,14 @@ import 'ag-grid-community/dist/styles/ag-grid.css'; import 'ag-grid-community/dist/styles/ag-theme-balham-dark.css'; import 'react-grid-layout/css/styles.css'; import 'react-resizable/css/styles.css'; -// import 'semantic-ui-css/semantic.min.css'; import { TraceExplorerContribution } from '../trace-explorer/trace-explorer-contribution'; import { TRACE_EXPLORER_ID, TraceExplorerWidget } from '../trace-explorer/trace-explorer-widget'; import { TspClientProvider } from '../tsp-client-provider'; import { TheiaMessageManager } from '../theia-message-manager'; import { TraceServerConnectionStatusService, TraceServerConnectionStatusContribution } from '../../browser/trace-server-status'; import { TraceServerUrlProviderImpl } from '../trace-server-url-provider-frontend-impl'; -// import { TracePropertiesContribution } from '../trace-properties-view/trace-properties-view-contribution'; -// import { TracePropertiesWidget, TRACE_PROPERTIES_ID } from '../trace-properties-view/trace-properties-view-widget'; - +import { bindTraceServerPreferences } from '../trace-server-bindings'; +import { TraceServerConfigService, traceServerPath } from '../../common/trace-server-config'; export default new ContainerModule(bind => { bind(TraceViewerEnvironment).toSelf().inRequestScope(); @@ -53,11 +51,18 @@ export default new ContainerModule(bind => { createWidget: () => context.container.get(TraceExplorerWidget) })); + bind(TraceServerConfigService).toDynamicValue(ctx => { + const connection = ctx.container.get(WebSocketConnectionProvider); + return connection.createProxy(traceServerPath); + }).inSingletonScope(); + bind(TraceServerConnectionStatusService).toSelf().inSingletonScope(); bind(FrontendApplicationContribution).toService(TraceServerConnectionStatusService); bind(TraceServerConnectionStatusContribution).toSelf().inSingletonScope(); bind(FrontendApplicationContribution).toService(TraceServerConnectionStatusContribution); + bindTraceServerPreferences(bind); + // bindViewContribution(bind, TracePropertiesContribution); // bind(TracePropertiesWidget).toSelf(); // bind(WidgetFactory).toDynamicValue(context => ({ diff --git a/viewer-prototype/src/common/trace-server-config.ts b/viewer-prototype/src/common/trace-server-config.ts new file mode 100644 index 000000000..87197324e --- /dev/null +++ b/viewer-prototype/src/common/trace-server-config.ts @@ -0,0 +1,15 @@ + +export const traceServerPath = '/services/trace-server-config'; +export const TraceServerConfigService = Symbol('TraceServerConfigService'); +export interface TraceServerConfigService { + /** + * Spawn the trace server from a given path + */ + startTraceServer(path: string | undefined, port: number | undefined): Promise; + + /** + * Stop the trace server + */ + stopTraceServer(port: number | undefined): Promise; +} + diff --git a/viewer-prototype/src/common/trace-server-url-provider.ts b/viewer-prototype/src/common/trace-server-url-provider.ts index bf5666954..2b90f4dc2 100644 --- a/viewer-prototype/src/common/trace-server-url-provider.ts +++ b/viewer-prototype/src/common/trace-server-url-provider.ts @@ -1,5 +1,7 @@ export const TraceServerUrlProvider = Symbol('TraceServerUrlProvider'); -export const TRACE_SERVER_DEFAULT_URL = 'http://localhost:8080/tsp/api'; +export const TRACE_SERVER_DEFAULT_URL = 'http://localhost:{}/tsp/api'; +export const TRACE_SERVER_DEFAULT_PORT = '8080'; + export interface TraceServerUrlProvider { /** diff --git a/viewer-prototype/src/common/trace-viewer-environment.ts b/viewer-prototype/src/common/trace-viewer-environment.ts index da6a4f393..73fdac9d7 100644 --- a/viewer-prototype/src/common/trace-viewer-environment.ts +++ b/viewer-prototype/src/common/trace-viewer-environment.ts @@ -1,13 +1,18 @@ import { injectable, inject } from 'inversify'; import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; -import { TRACE_SERVER_DEFAULT_URL } from './trace-server-url-provider'; +import { TRACE_SERVER_DEFAULT_URL, TRACE_SERVER_DEFAULT_PORT } from './trace-server-url-provider'; +import { PreferenceService } from '@theia/core/lib/browser'; +import { TRACE_PORT } from '../browser/trace-server-preference'; @injectable() export class TraceViewerEnvironment { + private port: string | undefined; constructor( - @inject(EnvVariablesServer) protected readonly environments: EnvVariablesServer) { + @inject(EnvVariablesServer) protected readonly environments: EnvVariablesServer, + @inject(PreferenceService) protected readonly preferenceService: PreferenceService) { + this.port = this.preferenceService.get(TRACE_PORT); } protected _traceServerUrl: string | undefined; @@ -16,7 +21,7 @@ export class TraceViewerEnvironment { const traceServerUrl = await this.environments.getValue('TRACE_SERVER_URL'); this._traceServerUrl = traceServerUrl ? this.parseUrl(traceServerUrl.value || TRACE_SERVER_DEFAULT_URL) : TRACE_SERVER_DEFAULT_URL; } - return this._traceServerUrl; + return this._traceServerUrl.replace(/{}/g, this.port ? this.port : TRACE_SERVER_DEFAULT_PORT); } private parseUrl(url: string): string { diff --git a/viewer-prototype/src/node/index.ts b/viewer-prototype/src/node/index.ts new file mode 100644 index 000000000..81103d901 --- /dev/null +++ b/viewer-prototype/src/node/index.ts @@ -0,0 +1,2 @@ +export * from './trace-server-backend-module'; +export * from './trace-server-service'; diff --git a/viewer-prototype/src/node/trace-server-backend-module.ts b/viewer-prototype/src/node/trace-server-backend-module.ts new file mode 100644 index 000000000..834ef6136 --- /dev/null +++ b/viewer-prototype/src/node/trace-server-backend-module.ts @@ -0,0 +1,16 @@ +import { ContainerModule } from 'inversify'; +import { TraceServerServiceImpl } from './trace-server-service'; +import { ConnectionHandler, JsonRpcConnectionHandler } from '@theia/core/lib/common'; +import { traceServerPath } from '../common/trace-server-config'; +import { TraceServerConfigService } from '../common/trace-server-config'; + +export default new ContainerModule(bind => { + bind(TraceServerServiceImpl).toSelf().inSingletonScope(); + + bind(ConnectionHandler) + .toDynamicValue(ctx => new JsonRpcConnectionHandler( + traceServerPath, + () => ctx.container.get(TraceServerServiceImpl), + )).inSingletonScope(); + +}); diff --git a/viewer-prototype/src/node/trace-server-service.ts b/viewer-prototype/src/node/trace-server-service.ts new file mode 100644 index 000000000..0e2ea22d4 --- /dev/null +++ b/viewer-prototype/src/node/trace-server-service.ts @@ -0,0 +1,14 @@ +import { spawn, exec } from 'child_process'; +import { injectable } from 'inversify'; +import { TraceServerConfigService } from '../common/trace-server-config'; +@injectable() +export class TraceServerServiceImpl implements TraceServerConfigService { + + async startTraceServer(path: string | undefined, port: number | undefined): Promise { + spawn(`..${path}`, ['-vmargs', `-Dtraceserver.port=${port}`]); + } + + async stopTraceServer(port: number | undefined): Promise { + exec(`kill -9 $(lsof -t -i:${port})`); // FIXME: Better approach to kill the server at a given port + } +} diff --git a/viewer-prototype/tsconfig.json b/viewer-prototype/tsconfig.json index d1aaf9bc8..b2f6acaf6 100644 --- a/viewer-prototype/tsconfig.json +++ b/viewer-prototype/tsconfig.json @@ -9,7 +9,7 @@ "moduleResolution": "node", "skipLibCheck": true, "esModuleInterop": true, - "target": "ESNEXT", + "target": "es5", "jsx": "react", "lib": [ "es6", @@ -18,7 +18,11 @@ "sourceMap": true, "rootDir": "src", "outDir": "lib", - "types": ["node", "jest"] + "types": [ + "node", + "jest" + ], + "strictPropertyInitialization": false }, "include": [ "src" @@ -28,4 +32,4 @@ "**/*.spec.ts", "**/*.test.ts" ] -} +} \ No newline at end of file