Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { MainThreadWebview } from '../../src/browser/vscode/api/main.thread.api.
import { MainThreadExtensionLog } from '../../src/browser/vscode/api/main.thread.log';
import { MainThreadStorage } from '../../src/browser/vscode/api/main.thread.storage';
import { ExtensionNodeServiceServerPath } from '../../src/common';
import { ExtHostAppConfig } from '../../src/common/ext.process';
import { MainThreadExtensionLogIdentifier } from '../../src/common/extension-log';
import { ExtHostAPIIdentifier, MainThreadAPIIdentifier } from '../../src/common/vscode';
import * as types from '../../src/common/vscode/ext-types';
Expand Down Expand Up @@ -69,6 +70,10 @@ describe('MainThreadExtensions Test Suites', () => {
token: IReporter,
useClass: DefaultReporter,
},
{
token: ExtHostAppConfig,
useValue: {},
},
);
const injector = createBrowserInjector(
[],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { MainThreadExtensionService } from '../../../../__mocks__/api/mainthread
import { MainThreadStorage } from '../../../../__mocks__/api/mathread.storage';
import { mockExtensionProps, mockExtensionProps2 } from '../../../../__mocks__/extensions';
import { createMockPairRPCProtocol } from '../../../../__mocks__/initRPCProtocol';
import { ExtHostAppConfig } from '../../../../src/common/ext.process';
import { ExtHostAPIIdentifier, IExtHostLocalization } from '../../../../src/common/vscode';
import ExtensionHostServiceImpl from '../../../../src/hosted/ext.host';

Expand All @@ -23,7 +24,7 @@ describe('Extension process test', () => {
injector = createBrowserInjector([]);
injector.addProviders(
{
token: AppConfig,
token: ExtHostAppConfig,
useValue: {
builtinCommands: [
{
Expand Down
33 changes: 32 additions & 1 deletion packages/extension/src/browser/extension-node.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { WSChannelHandler } from '@opensumi/ide-connection/lib/browser';
import { BaseConnection } from '@opensumi/ide-connection/lib/common/connection';
import {
AppConfig,
ContributionProvider,
Deferred,
Disposable,
DisposableStore,
IApplicationService,
IExtensionProps,
Expand All @@ -21,6 +23,7 @@ import {
} from '../common';
import { ActivatedExtensionJSON } from '../common/activator';
import { AbstractNodeExtProcessService } from '../common/extension.service';
import { IMainThreadExtenderService, MainThreadExtenderContribution } from '../common/main.thread.extender';
import { ExtHostAPIIdentifier } from '../common/vscode';
import { knownProtocols } from '../common/vscode/protocols';

Expand All @@ -37,7 +40,7 @@ export class NodeExtProcessService implements AbstractNodeExtProcessService<IExt
private readonly appConfig: AppConfig;

@Autowired(INJECTOR_TOKEN)
private readonly injector: Injector;
protected readonly injector: Injector;

@Autowired(ExtensionNodeServiceServerPath)
private readonly extensionNodeClient: IExtensionNodeClientService;
Expand All @@ -48,6 +51,12 @@ export class NodeExtProcessService implements AbstractNodeExtProcessService<IExt
@Autowired(WSChannelHandler)
private readonly channelHandler: WSChannelHandler;

@Autowired(IMainThreadExtenderService)
private readonly mainThreadExtenderService: IMainThreadExtenderService;

@Autowired(MainThreadExtenderContribution)
private readonly mainThreadExtenderContributionProvider: ContributionProvider<MainThreadExtenderContribution>;

private _apiFactoryDisposables = new DisposableStore();

public ready: Deferred<void> = new Deferred();
Expand Down Expand Up @@ -125,9 +134,31 @@ export class NodeExtProcessService implements AbstractNodeExtProcessService<IExt
this._apiFactoryDisposables.add(apiProxy);
this._apiFactoryDisposables.add(toDisposable(initNodeThreadAPIProxy(this.protocol, this.injector, this)));
this._apiFactoryDisposables.add(toDisposable(createSumiAPIFactory(this.protocol, this.injector)));
this._apiFactoryDisposables.add(this.createExternalSumiAPIFactory());
await apiProxy.setup();
}

/**
* register external main thread class
* @returns disposer
*/
private createExternalSumiAPIFactory() {
const disposer = new Disposable();
// register main thread extender contribution
const contributions = this.mainThreadExtenderContributionProvider.getContributions();
for (const contribution of contributions) {
contribution.registerMainThreadExtender(this.mainThreadExtenderService);
}
// instantiate this MainThreadExtenderClass
const extenders = this.mainThreadExtenderService.getMainThreadExtenders();
for (const extender of extenders) {
const service = this.injector.get(extender.serviceClass, [this.protocol]);
this.protocol.set(extender.identifier, service);
disposer.addDispose(service);
}
return disposer;
}

public async getActivatedExtensions(): Promise<ActivatedExtensionJSON[]> {
const proxy = await this.getProxy();
return await proxy.$getActivatedExtensions();
Expand Down
11 changes: 10 additions & 1 deletion packages/extension/src/browser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ import {
AbstractViewExtProcessService,
AbstractWorkerExtProcessService,
} from '../common/extension.service';
import {
IMainThreadExtenderService,
MainThreadExtenderContribution,
MainThreadExtenderService,
} from '../common/main.thread.extender';

import { ActivationEventServiceImpl } from './activation.service';
import { ExtCommandManagementImpl as ExtCommandManagementImpl } from './extension-command-management';
Expand All @@ -37,7 +42,7 @@ import { VSCodeContributesService, VSCodeContributesServiceToken } from './vscod

@Injectable()
export class ExtensionModule extends BrowserModule {
contributionProvider = [RequireInterceptorContribution];
contributionProvider = [RequireInterceptorContribution, MainThreadExtenderContribution];
providers: Provider[] = [
{
token: ExtensionService,
Expand Down Expand Up @@ -93,6 +98,10 @@ export class ExtensionModule extends BrowserModule {
token: SumiContributionsServiceToken,
useClass: SumiContributionsService,
},
{
token: IMainThreadExtenderService,
useClass: MainThreadExtenderService,
},
ExtensionCommandContribution,
ExtensionClientAppContribution,
BrowserRequireInterceptorContribution,
Expand Down
56 changes: 56 additions & 0 deletions packages/extension/src/common/ext.process.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { SumiApiExtenders } from './sumi';
import type { CommandHandler } from './vscode';
import type { ConstructorOf, Injector } from '@opensumi/di';
import type { ILogService, LogLevel } from '@opensumi/ide-core-common';
import type Stream from 'stream';

export interface IBuiltInCommand {
id: string;
handler: CommandHandler;
}

export interface CustomChildProcess {
stdin: Stream.Writable;
stdout: Stream.Readable;
kill: () => void;
}

export interface CustomChildProcessModule {
spawn(command: string, args: string | string[], options: any): CustomChildProcess;
}

export const ExtHostAppConfig = Symbol('ExtHostAppConfig');
export interface ExtHostAppConfig {
/**
* exthost log service class
*/
LogServiceClass?: ConstructorOf<ILogService>;
/**
* 插件日志自定义实现路径
*/
extLogServiceClassPath?: string;
logDir?: string;
logLevel?: LogLevel;
builtinCommands?: IBuiltInCommand[];
customDebugChildProcess?: CustomChildProcessModule;
/**
* 集成方自定义 vscode.version 版本
* 设置该参数可能会导致插件运行异常
* @type {string} 插件版本号
* @memberof ExtHostAppConfig
*/
customVSCodeEngineVersion?: string;
/**
* control rpcProtocol message timeout
* default -1,it means disable
*/
rpcMessageTimeout?: number;
/**
* register external sumi extension api
*/
sumiApiExtenders?: SumiApiExtenders;
}

export interface ExtProcessConfig extends ExtHostAppConfig {
injector?: Injector;
}
39 changes: 39 additions & 0 deletions packages/extension/src/common/main.thread.extender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Injectable } from '@opensumi/di';
import { IRPCProtocol, ProxyIdentifier } from '@opensumi/ide-connection';
import { Disposable, IDisposable } from '@opensumi/ide-core-common';

export interface IMainThreadExtender<T = any> {
identifier: ProxyIdentifier<T>;
serviceClass: new (rpcProtocol: IRPCProtocol) => T;
}

export const IMainThreadExtenderService = Symbol('IMainThreadExtenderService');
export interface IMainThreadExtenderService<T = any> {
registerMainThreadExtender(extender: IMainThreadExtender<T>): IDisposable;
getMainThreadExtenders(): IMainThreadExtender<T>[];
}

export const MainThreadExtenderContribution = Symbol('MainThreadExtenderContribution');

export interface MainThreadExtenderContribution {
registerMainThreadExtender(registry: IMainThreadExtenderService): void;
}

@Injectable()
export class MainThreadExtenderService<T> implements IMainThreadExtenderService<T> {
private readonly registry: IMainThreadExtender<T>[] = [];

registerMainThreadExtender(extender: IMainThreadExtender) {
this.registry.push(extender);
return Disposable.create(() => {
const index = this.registry.indexOf(extender);
if (index !== -1) {
this.registry.splice(index, 1);
}
});
}

getMainThreadExtenders() {
return this.registry;
}
}
27 changes: 26 additions & 1 deletion packages/extension/src/common/sumi/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { createExtHostContextProxyIdentifier, createMainContextProxyIdentifier } from '@opensumi/ide-connection';
import {
IRPCProtocol,
ProxyIdentifier,
createExtHostContextProxyIdentifier,
createMainContextProxyIdentifier,
} from '@opensumi/ide-connection';

import { IExtHostChatAgents, IMainThreadChatAgents } from './chat-agents';
import { IExtHostCommon, IMainThreadCommon } from './common';
Expand Down Expand Up @@ -27,3 +32,23 @@ export const ExtHostSumiAPIIdentifier = {
ExtHostIDEWindow: createExtHostContextProxyIdentifier<IExtHostIDEWindow>('ExtHostIDEWindow'),
ExtHostChatAgents: createExtHostContextProxyIdentifier<IExtHostChatAgents>('ExtHostChatAgents'),
};

/**
* sumi API extender
*/
export abstract class SumiApiExtender<T = any> {
constructor(protected rpcProtocol: IRPCProtocol) {}
/**
* create rpc service when main thread could call
*/
createRPCService?: () => [identifier: ProxyIdentifier<T>, service: T];
/**
* api factory
* can use rpc service to call main thread
*/
createApiFactory: (service?: T) => any;
}

export interface SumiApiExtenders extends Record<string, any> {
[api: string]: new (rpcProtocol: IRPCProtocol) => SumiApiExtender;
}
20 changes: 18 additions & 2 deletions packages/extension/src/hosted/api/sumi/ext.host.api.impl.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { IRPCProtocol } from '@opensumi/ide-connection';
import { IReporter, REPORT_HOST, ReporterService } from '@opensumi/ide-core-common';
import { IReporter, REPORT_HOST, ReporterService, isFunction } from '@opensumi/ide-core-common';

import { IExtensionHostService, IExtensionWorkerHost, WorkerHostAPIIdentifier } from '../../../common';
import { ExtHostSumiAPIIdentifier } from '../../../common/sumi';
import { ExtHostSumiAPIIdentifier, SumiApiExtenders } from '../../../common/sumi';
import { ExtHostAPIIdentifier, IExtensionDescription } from '../../../common/vscode';
import { ExtensionHostEditorService } from '../vscode/editor/editor.host';

Expand All @@ -21,6 +21,7 @@ export function createAPIFactory(
extensionService: IExtensionHostService | IExtensionWorkerHost,
type: string,
reporterEmitter: IReporter,
sumiApiExtenders: SumiApiExtenders = {},
) {
if (type === 'worker') {
rpcProtocol.set(WorkerHostAPIIdentifier.ExtWorkerHostExtensionService, extensionService);
Expand Down Expand Up @@ -58,6 +59,20 @@ export function createAPIFactory(
new ExtHostChatAgents(rpcProtocol),
) as ExtHostChatAgents;

const externalSumiApis = Object.keys(sumiApiExtenders).reduce((acc, key) => {
const SumiApiExtender = sumiApiExtenders[key];
const extender = new SumiApiExtender(rpcProtocol);
let rpcService;
// register external api rpc protocol
if (isFunction(extender.createRPCService)) {
const [identifier, service] = extender.createRPCService();
rpcService = service;
rpcProtocol.set(identifier, service);
}
acc[key] = extender.createApiFactory(rpcService);
return acc;
}, {});

return (extension: IExtensionDescription) => {
const reporter = new ReporterService(reporterEmitter, {
extensionId: extension.extensionId,
Expand All @@ -75,6 +90,7 @@ export function createAPIFactory(
commands: createCommandsApiFactory(extHostCommands, extHostEditors, extension),
toolbar: createToolbarAPIFactory(extension, extHostToolbar),
chat: createChatApiFactory(extension, extHostChatAgents),
...externalSumiApis,
};
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
IDebuggerContribution,
} from '@opensumi/ide-debug';

import { CustomChildProcessModule } from '../../../../common/ext.process';
import {
IExtHostCommands,
IExtHostDebugService,
Expand All @@ -25,7 +26,6 @@ import {
Uri,
} from '../../../../common/vscode/ext-types';
import { Breakpoint } from '../../../../common/vscode/models';
import { CustomChildProcessModule } from '../../../ext.process-base';

import { IDebugConfigurationProvider } from './common';
import { resolveDebugAdapterExecutable } from './extension-debug-adapter-excutable-resolver';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import net from 'net';

import { DebugAdapterForkExecutable, DebugStreamConnection } from '@opensumi/ide-debug';

import { CustomChildProcess, CustomChildProcessModule } from '../../../ext.process-base';
import { CustomChildProcess, CustomChildProcessModule } from '../../../../common/ext.process';

import { DirectDebugAdapter } from './abstract-debug-adapter-session';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DEFAULT_VSCODE_ENGINE_VERSION } from '@opensumi/ide-core-common/lib/con
import { OverviewRulerLane } from '@opensumi/ide-editor';

import { IExtensionHostService } from '../../../common';
import { ExtHostAppConfig } from '../../../common/ext.process';
import {
ExtHostAPIIdentifier,
IExtHostDebugService,
Expand All @@ -18,7 +19,6 @@ import { ViewColumn } from '../../../common/vscode/enums';
import * as extTypes from '../../../common/vscode/ext-types';
import * as fileSystemTypes from '../../../common/vscode/file-system';
import { IExtHostLocalization } from '../../../common/vscode/localization';
import { ExtHostAppConfig } from '../../ext.process-base';

import { ExtHostDebug, createDebugApiFactory } from './debug';
import { ExtensionDocumentDataManagerImpl } from './doc';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
validateConstraint,
} from '@opensumi/ide-core-common';

import { IBuiltInCommand } from '../../../common/ext.process';
import {
ArgumentProcessor,
CommandHandler,
Expand All @@ -26,7 +27,6 @@ import * as extHostTypeConverter from '../../../common/vscode/converter';
import { Disposable, Location, Position, Range } from '../../../common/vscode/ext-types';
import * as modes from '../../../common/vscode/model.api';
import { CommandDto } from '../../../common/vscode/scm';
import { IBuiltInCommand } from '../../ext.process-base';

import { ExtensionHostEditorService } from './editor/editor.host';
import { ApiCommand, ApiCommandResult, newCommands } from './ext.host.api.command';
Expand Down
Loading