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 Jan 2, 2019
1 parent c46138c commit 13e7f37
Show file tree
Hide file tree
Showing 12 changed files with 379 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
yarn-error.log
.DS_Store
.idea
7 changes: 7 additions & 0 deletions browser-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "$name$",
"version": "$version$",
"dependencies": {
$END$
}
}
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: ((id: number, config: TaskConfiguration, ctx?: string) => Promise<void>) | undefined;
constructor() {
this.onKillEventEmitter = new Emitter<number>();
}

async runTask(id: number, taskConfig: TaskConfiguration, ctx?: string): Promise<void> {
if (this.runTaskHandler) {
return await this.runTaskHandler(id, 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: (id: number, config: TaskConfiguration, ctx?: string) => Promise<void>) {
this.runTaskHandler = handler;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*********************************************************************
* 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((id, config, ctx) => proxy.$runTask(id, config, ctx));
}
$registerTaskRunner(type: string): Promise<void> {
return this.delegate.registerTaskRunner(type);
}

$disposeTaskRunner(type: string): Promise<void> {
return this.delegate.disposeTaskRunner(type);
}
}
37 changes: 37 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,21 @@ export interface CheVariablesMain {
$resolve(value: string): Promise<string | undefined>;
}

export interface CheTask {
registerTaskRunner(type: string, runner: che.TaskRunner): Promise<che.Disposable>;
fireTaskExited(id: number): Promise<void>;
$runTask(id: number, config: che.TaskConfiguration, ctx?: string): Promise<void>;
$killTask(id: number): 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 +301,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 +318,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(id: number, 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: (id: number, 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,15 @@ 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();
});
102 changes: 102 additions & 0 deletions extensions/eclipse-che-theia-plugin-ext/src/node/che-task-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*********************************************************************
* 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[];
private taskId: number;
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 = [];
this.taskId = 0;
}

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 = async (config: TaskConfiguration, ctx?: string): Promise<Task> => {
const id = this.taskId ++;
for (const client of this.clients) {
await client.runTask(id, config, ctx);
}
return new CheTask(id, 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(id: number,
taskManager: TaskManager,
logger: ILogger,
options: TaskOptions,
clients: CheTaskClient[]) {
super(taskManager, logger, options);
this.clients = clients;
this.taskId = id;
}

async getRuntimeInfo(): Promise<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,20 @@ 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);
},
fireTaskExited(id: number): Promise<void> {
return cheTaskImpl.fireTaskExited(id);
}
};

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

0 comments on commit 13e7f37

Please sign in to comment.