Skip to content
This repository has been archived by the owner on Apr 4, 2023. It is now read-only.

Commit

Permalink
CHE-11954: Add che.registerTaskRunner Theia Plugin API
Browse files Browse the repository at this point in the history
  • Loading branch information
vinokurig committed Dec 29, 2018
1 parent c5cfc7e commit 3294ae6
Show file tree
Hide file tree
Showing 13 changed files with 380 additions and 5 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
yarn-error.log
.DS_Store
.idea

1 change: 1 addition & 0 deletions extensions/eclipse-che-theia-plugin-ext/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"dependencies": {
"@theia/core": "0.3.17",
"@theia/plugin-ext": "0.3.17",
"@theia/task": "0.3.17",
"@eclipse-che/plugin": "^0.0.1-1544617370",
"@eclipse-che/workspace-client": "^0.0.1-1545387823"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import { injectable, interfaces } from 'inversify';
import { PLUGIN_RPC_CONTEXT } from '../common/che-protocol';
import { CheApiMainImpl } from './che-api-main-impl';
import { CheVariablesMainImpl } from './che-variables-main';
import { CheTaskMainImpl } from './che-task-main';

@injectable()
export class CheApiProvider implements MainPluginApiProvider {

initialize(rpc: RPCProtocol, container: interfaces.Container): void {
rpc.set(PLUGIN_RPC_CONTEXT.CHE_API_MAIN, new CheApiMainImpl(container));
rpc.set(PLUGIN_RPC_CONTEXT.CHE_VARIABLES_MAIN, new CheVariablesMainImpl(container, rpc));
rpc.set(PLUGIN_RPC_CONTEXT.CHE_TASK_MAIN, new CheTaskMainImpl(container, rpc));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,15 @@
import { ContainerModule } from 'inversify';
import { MainPluginApiProvider } from '@theia/plugin-ext/lib/common/plugin-ext-api-contribution';
import { CheApiProvider } from './che-api-provider';
import { CheApiService, CHE_API_SERVICE_PATH } from '../common/che-protocol';
import {
CHE_API_SERVICE_PATH,
CHE_TASK_SERVICE_PATH,
CheApiService,
CheTaskClient,
CheTaskService
} from '../common/che-protocol';
import { WebSocketConnectionProvider } from '@theia/core/lib/browser';
import { CheTaskClientImpl } from './che-task-client';

export default new ContainerModule(bind => {
bind(CheApiProvider).toSelf().inSingletonScope();
Expand All @@ -22,4 +29,11 @@ export default new ContainerModule(bind => {
const provider = ctx.container.get(WebSocketConnectionProvider);
return provider.createProxy<CheApiService>(CHE_API_SERVICE_PATH);
}).inSingletonScope();

bind(CheTaskClient).to(CheTaskClientImpl).inSingletonScope();
bind(CheTaskService).toDynamicValue(ctx => {
const provider = ctx.container.get(WebSocketConnectionProvider);
const client: CheTaskClient = ctx.container.get(CheTaskClient);
return provider.createProxy<CheTaskService>(CHE_TASK_SERVICE_PATH, client);
}).inSingletonScope();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*********************************************************************
* Copyright (c) 2018 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
import { CheTaskClient } from '../common/che-protocol';
import { Emitter, Event } from '@theia/core';
import { injectable } from 'inversify';
import { TaskConfiguration, TaskInfo } from '@eclipse-che/plugin';

@injectable()
export class CheTaskClientImpl implements CheTaskClient {
private readonly onKillEventEmitter: Emitter<number>;
private taskInfoHandler: ((id: number) => Promise<TaskInfo>) | undefined;
private runTaskHandler: ((config: TaskConfiguration, ctx?: string) => Promise<void>) | undefined;
constructor() {
this.onKillEventEmitter = new Emitter<number>();
}

async runTask(taskConfig: TaskConfiguration, ctx?: string): Promise<void> {
if (this.runTaskHandler) {
return await this.runTaskHandler(taskConfig, ctx);
}
}

async getTaskInfo(id: number): Promise<TaskInfo | undefined> {
if (this.taskInfoHandler) {
return await this.taskInfoHandler(id);
}
}

get onKillEvent(): Event<number> {
return this.onKillEventEmitter.event;
}

async killTask(id: number): Promise<void> {
this.onKillEventEmitter.fire(id);
}

setTaskInfoHandler(handler: (id: number) => Promise<TaskInfo>) {
this.taskInfoHandler = handler;
}

setRunTaskHandler(handler: (config: TaskConfiguration, ctx?: string) => Promise<void>) {
this.runTaskHandler = handler;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*********************************************************************
* Copyright (c) 2018 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
import { CheTask, CheTaskMain, CheTaskService, CheTaskClient, PLUGIN_RPC_CONTEXT } from '../common/che-protocol';
import { RPCProtocol } from '@theia/plugin-ext/lib/api/rpc-protocol';
import { interfaces, injectable } from 'inversify';

@injectable()
export class CheTaskMainImpl implements CheTaskMain{
private readonly delegate: CheTaskService;
private readonly cheTaskClient: CheTaskClient;
constructor(container: interfaces.Container, rpc: RPCProtocol) {
const proxy: CheTask = rpc.getProxy(PLUGIN_RPC_CONTEXT.CHE_TASK);
this.delegate = container.get(CheTaskService);
this.cheTaskClient = container.get(CheTaskClient);
this.cheTaskClient.onKillEvent(id => {
proxy.$killTask(id);
});
this.cheTaskClient.setTaskInfoHandler(id => proxy.$getTaskInfo(id));
this.cheTaskClient.setRunTaskHandler((config, ctx) => proxy.$runTask(config, ctx));
}
async $registerTaskRunner(type: string): Promise<void> {
return await this.delegate.registerTaskRunner(type);
}

async $disposeTaskRunner(type: string): Promise<void> {
await this.delegate.disposeTaskRunner(type);
}
}
35 changes: 35 additions & 0 deletions extensions/eclipse-che-theia-plugin-ext/src/common/che-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import { ProxyIdentifier, createProxyIdentifier } from '@theia/plugin-ext/lib/api/rpc-protocol';
import * as che from '@eclipse-che/plugin';
import { Event, JsonRpcServer } from '@theia/core';

export interface CheApiPlugin {
}
Expand All @@ -31,6 +32,19 @@ export interface CheVariablesMain {
$resolve(value: string): Promise<string | undefined>;
}

export interface CheTask {
registerTaskRunner(type: string, runner: che.TaskRunner): Promise<che.Disposable>;
$runTask(config: che.TaskConfiguration, ctx?: string): Promise<void>;
$killTask(id: number): Promise<void>;
$getTaskInfo(id: number): Promise<che.TaskInfo | undefined>;
}

export const CheTaskMain = Symbol('CheTaskMain');
export interface CheTaskMain {
$registerTaskRunner(type: string): Promise<void>;
$disposeTaskRunner(type: string): Promise<void>;
}

export interface Variable {
name: string,
description: string,
Expand Down Expand Up @@ -285,6 +299,8 @@ export const PLUGIN_RPC_CONTEXT = {
CHE_API_MAIN: <ProxyIdentifier<CheApiMain>>createProxyIdentifier<CheApiMain>('CheApiMain'),
CHE_VARIABLES: <ProxyIdentifier<CheVariables>>createProxyIdentifier<CheVariables>('CheVariables'),
CHE_VARIABLES_MAIN: <ProxyIdentifier<CheVariablesMain>>createProxyIdentifier<CheVariablesMain>('CheVariablesMain'),
CHE_TASK: <ProxyIdentifier<CheTask>>createProxyIdentifier<CheTask>('CheTask'),
CHE_TASK_MAIN: <ProxyIdentifier<CheTaskMain>>createProxyIdentifier<CheTaskMain>('CheTaskMain'),
};

// Theia RPC protocol
Expand All @@ -300,3 +316,22 @@ export interface CheApiService {
getFactoryById(factoryId: string): Promise<FactoryDto>;

}

export const CHE_TASK_SERVICE_PATH = '/che-task-service';

export const CheTaskService = Symbol('CheTaskService');
export interface CheTaskService extends JsonRpcServer<CheTaskClient>{
registerTaskRunner(type: string): Promise<void>;
disposeTaskRunner(type: string): Promise<void>;
disconnectClient(client: CheTaskClient): void;
}

export const CheTaskClient = Symbol('CheTaskClient');
export interface CheTaskClient {
runTask(taskConfig: che.TaskConfiguration, ctx?: string): Promise<void>;
killTask(id: number): Promise<void>;
getTaskInfo(id: number): Promise<che.TaskInfo | undefined>;
setTaskInfoHandler(func: (id: number) => Promise<che.TaskInfo | undefined>): void;
setRunTaskHandler(func: (config: che.TaskConfiguration, ctx?: string) => Promise<void>): void;
onKillEvent: Event<number>
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,14 @@ import { ChePluginApiContribution } from './che-plugin-script-service';
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
import { ConnectionHandler, JsonRpcConnectionHandler } from '@theia/core';
import { CheApiServiceImpl } from './che-api-service';
import { CheApiService, CHE_API_SERVICE_PATH } from '../common/che-protocol';
import {
CHE_API_SERVICE_PATH,
CHE_TASK_SERVICE_PATH,
CheApiService,
CheTaskClient,
CheTaskService
} from '../common/che-protocol';
import {CheTaskServiceImpl} from "./che-task-service";

export default new ContainerModule(bind => {
bind(ChePluginApiProvider).toSelf().inSingletonScope();
Expand All @@ -30,4 +37,17 @@ export default new ContainerModule(bind => {
ctx.container.get(CheApiService)
)
).inSingletonScope();

bind(CheTaskService).toDynamicValue(ctx => new CheTaskServiceImpl(ctx.container)).inSingletonScope();
bind(ConnectionHandler).toDynamicValue(ctx =>
new JsonRpcConnectionHandler<CheTaskClient>(CHE_TASK_SERVICE_PATH, client => {
const server: CheTaskService = ctx.container.get(CheTaskService);
server.setClient(client);
client.onDidCloseConnection(() => {
server.disconnectClient(client);
});
return server;
}
)
).inSingletonScope();
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*********************************************************************
* Copyright (c) 2018 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
**********************************************************************/
import { CheTaskClient, CheTaskService } from '../common/che-protocol';
import { injectable, interfaces } from 'inversify';
import { Task, TaskManager, TaskOptions, TaskRunnerRegistry } from '@theia/task/lib/node'
import { Disposable, ILogger } from '@theia/core';
import { TaskConfiguration, TaskInfo } from '@theia/task/lib/common/task-protocol';

@injectable()
export class CheTaskServiceImpl implements CheTaskService {
private readonly runnerRegistry: TaskRunnerRegistry;
private readonly taskManager: TaskManager;
private readonly logger: ILogger;
private readonly disposableMap: Map<string, Disposable>;
private readonly clients: CheTaskClient[];
constructor(container: interfaces.Container) {
this.runnerRegistry = container.get(TaskRunnerRegistry);
this.taskManager = container.get(TaskManager);
this.logger = container.get(ILogger);
this.disposableMap = new Map();
this.clients = [];
}

async registerTaskRunner(type: string): Promise<void> {
const runner = {
async run(taskConfig: TaskConfiguration, ctx?: string): Promise<Task> {
return runTask(taskConfig, ctx);
}
};
this.disposableMap.set(type, this.runnerRegistry.registerRunner(type, runner));
const runTask = (config: TaskConfiguration, ctx?: string): Task => {
this.clients.forEach(client => client.runTask(config, ctx));
return new CheTask(this.taskManager, this.logger, { label: config.label, config }, this.clients);
};
}

dispose() {
// do nothing
}

setClient(client: CheTaskClient ){
this.clients.push(client);
}

async disposeTaskRunner(type: string): Promise<void> {
const disposable = this.disposableMap.get(type);
if (disposable) {
disposable.dispose();
}
}

async disconnectClient(client: CheTaskClient) {
const idx = this.clients.indexOf(client);
if (idx > -1) {
this.clients.splice(idx, 1);
}
}
}

class CheTask extends Task {
private readonly clients: CheTaskClient[];
constructor(taskManager: TaskManager,
logger: ILogger,
options: TaskOptions,
clients: CheTaskClient[]) {
super(taskManager, logger, options);
this.clients = clients;
}

getRuntimeInfo(): TaskInfo {
// for (const client of this.clients) {
// const taskInfo = await client.getTaskInfo(this.taskId);
// if (taskInfo) {
// return {
// taskId: this.taskId,
// terminalId: taskInfo.terminalId,
// ctx: taskInfo.ctx,
// config: taskInfo.config
// };
// }
// }
throw new Error('Information not found');
}

async kill(): Promise<void> {
this.clients.forEach(client => client.killTask(this.taskId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@ import {
import { CheApiPluginImpl } from './che-workspace';
import { CheVariablesImpl } from './che-variables-impl';
import { PLUGIN_RPC_CONTEXT } from '../common/che-protocol';
import { CheTaskImpl } from './che-task-impl';
export interface ApiFactory {
(plugin: Plugin): typeof che;
}

export function createAPIFactory(rpc: RPCProtocol): ApiFactory {
const chePluginImpl = new CheApiPluginImpl(rpc);
const cheVariablesImpl = rpc.set(PLUGIN_RPC_CONTEXT.CHE_VARIABLES, new CheVariablesImpl(rpc));
const cheTaskImpl = rpc.set(PLUGIN_RPC_CONTEXT.CHE_TASK, new CheTaskImpl(rpc));

return function (plugin: Plugin): typeof che {
const ws: typeof che.workspace = {
Expand Down Expand Up @@ -82,10 +84,17 @@ export function createAPIFactory(rpc: RPCProtocol): ApiFactory {
}
};

const task: typeof che.task = {
registerTaskRunner(type: string, runner: che.TaskRunner): Promise<che.Disposable> {
return cheTaskImpl.registerTaskRunner(type, runner);
}
};

return <typeof che>{
workspace: ws,
factory,
variables: variable
variables: variable,
task
};
};
}
Loading

0 comments on commit 3294ae6

Please sign in to comment.