Theia APIs——通过JSON

  • 时间:
  • 浏览:0
  • 来源:幸运快3_快3单双_幸运快3单双

上一篇:Theia APIs——事件

通过JSON-PRC进行通信

  在本节中,我将讲解如保创建后端服务并通过JSON-PRC来连接它。

  我将使用debug logging system作为例子来进行讲解。

概述

  本示例将用express框架创建另1个服务,因此通过websocket连接该服务。

注册服务

  首没能做的是将服务公开,没法 前端就能连接它。

  你前要创建另1个后端服务模块(类似于 logger-server-module.ts):

import { ContainerModule } from 'inversify';
import { ConnectionHandler, JsonRpcConnectionHandler } from "../../messaging/common";
import { ILoggerServer, ILoggerClient } from '../../application/common/logger-protocol';

export const loggerServerModule = new ContainerModule(bind => {
    bind(ConnectionHandler).toDynamicValue(ctx =>
        new JsonRpcConnectionHandler<ILoggerClient>("/services/logger", client => {
            const loggerServer = ctx.container.get<ILoggerServer>(ILoggerServer);
            loggerServer.setClient(client);
            return loggerServer;
        })
    ).inSingletonScope()
});

  亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 来全版看一下:

import { ConnectionHandler, JsonRpcConnectionHandler } from "../../messaging/common";

  一点行导入了JsonRpcConnectionHandler,这是另1个工厂类,亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 用它创建了另1个onConnection连接外理程序运行,它为后端通过JSON-RPC调用的对象创建另1个代理,并将另1个本地对象公开给JSON-RPC。

接下来亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 来看看具体的实现过程。

  ConnectionHandler是另1个简单的接口,它指定了连接的路径以及在连接创建时的行为。

  它是没法 的:

import { MessageConnection } from "vscode-jsonrpc";

export const ConnectionHandler = Symbol('ConnectionHandler');

export interface ConnectionHandler {
    readonly path: string;
    onConnection(connection: MessageConnection): void;
}
import { ILoggerServer, ILoggerClient } from '../../application/common/logger-protocol';

  文件logger-protocol.ts所含了服务器和客户端前要实现的接口。

  这里的服务器指的是将通过JSON-RPC调用的后端对象,而客户端指的是还前要接收来自后端对象的通知的对象。

  稍后亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 会全版介绍。

bind<ConnectionHandler>(ConnectionHandler).toDynamicValue(ctx => {

  这里有个地方很神奇,乍一看,它是另1个ConnectionHandler的实现。

  神奇之存在于,一点ConnectionHandler类型是绑定到messaging-module.ts文件中的ContributionProvider的。

  统统,当MessageingContribution启动时(调用onStart),它为所有绑定ConnectionHandlers创建另1个websocket连接。

  像没法 (来自messageing-mocule.ts):

constructor( @inject(ContributionProvider) @named(ConnectionHandler) protected readonly handlers: ContributionProvider<ConnectionHandler>) {
    }

    onStart(server: http.Server): void {
        for (const handler of this.handlers.getContributions()) {
            const path = handler.path;
            try {
                createServerWebSocketConnection({
                    server,
                    path
                }, connection => handler.onConnection(connection));
            } catch (error) {
                console.error(error)
            }
        }
    }

  要深入了解ContributionProvider,还前要参考

这里

  因此:

new JsonRpcConnectionHandler<ILoggerClient>("/services/logger", client => {

  亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 来看看一点类的实现做了那此事情:

export class JsonRpcConnectionHandler<T extends object> implements ConnectionHandler {
    constructor(
        readonly path: string,
        readonly targetFactory: (proxy: JsonRpcProxy<T>) => any
    ) { }

    onConnection(connection: MessageConnection): void {
        const factory = new JsonRpcProxyFactory<T>(this.path);
        const proxy = factory.createProxy();
        factory.target = this.targetFactory(proxy);
        factory.listen(connection);
    }
}

  亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 看一遍,这里通过ConnectionHandler类的扩展创建了另1个websocker连接,路径是"/services/logger"。

  让亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 来看看一点onConnection具体做了那此:

onConnection(connection: MessageConnection): void {
        const factory = new JsonRpcProxyFactory<T>(this.path);
        const proxy = factory.createProxy();
        factory.target = this.targetFactory(proxy);
        factory.listen(connection);

  亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 一行一行来看:

const factory = new JsonRpcProxyFactory<T>(this.path);

  上边一点行在路径"/services/logger"上创建了另1个JsonRpcProxy。

const proxy = factory.createProxy();

  因此,亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 从工厂创建了另1个代理对象,它将使用ILoggerClient接口来调用JSON-RPC连接的另一端。

factory.target = this.targetFactory(proxy);

  上边一点行将调用亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 在参数中传递的函数,统统:

client => {
            const loggerServer = ctx.container.get<ILoggerServer>(ILoggerServer);
            loggerServer.setClient(client);
            return loggerServer;
        }

  这里在loggerServer上设置客户端,本例中它用于向前端发送有关日志更改的通知。

  同去它返回loggerServer,用作在JSON-RPC上公开的对象。

factory.listen(connection);

  上边一点行将工厂连接到Connection。

  所含services/*路径的endpoints由webpack开发服务器提供,参见webpack.config.js

'/services/*': {
        target: 'ws://localhost:5000',
        ws: true
    },

连接到服务

  现在亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 不可能 有了另1个后端服务,让亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 来看看如保没法 端连接它。

  要做到一点点,你前要像下面没法 :

(来自logger-frontend-module.ts)

import { ContainerModule, Container } from 'inversify';
import { WebSocketConnectionProvider } from '../../messaging/browser/connection';
import { ILogger, LoggerFactory, LoggerOptions, Logger } from '../common/logger';
import { ILoggerServer } from '../common/logger-protocol';
import { LoggerWatcher } from '../common/logger-watcher';

export const loggerFrontendModule = new ContainerModule(bind => {
    bind(ILogger).to(Logger).inSingletonScope();
    bind(LoggerWatcher).toSelf().inSingletonScope();
    bind(ILoggerServer).toDynamicValue(ctx => {
        const loggerWatcher = ctx.container.get(LoggerWatcher);
        const connection = ctx.container.get(WebSocketConnectionProvider);
        return connection.createProxy<ILoggerServer>("/services/logger", loggerWatcher.getLoggerClient());
    }).inSingletonScope();
});

  其中最重要的几行:

bind(ILoggerServer).toDynamicValue(ctx => {
        const loggerWatcher = ctx.container.get(LoggerWatcher);
        const connection = ctx.container.get(WebSocketConnectionProvider);
        return connection.createProxy<ILoggerServer>("/services/logger", loggerWatcher.getLoggerClient());
    }).inSingletonScope();

  亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 一行一行来看:

const loggerWatcher = ctx.container.get(LoggerWatcher);

  一点行创建了另1个监听器,它通过loggerWatcher客户端从后端获取有关事件的通知(loggerWatcher.getLoggerClient())。

  不想了解更多有关事件如保在theia中工作的信息,还前要查看

这里

const connection = ctx.container.get(WebSocketConnectionProvider);

  上边一点行获得了另1个websocket连接,它将被用来创建另1个代理。

return connection.createProxy<ILoggerServer>("/services/logger", loggerWatcher.getLoggerClient());

  亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 将另1个本地对象作为第5个参数传入,用来外理来自远程对象的JSON-RPC消息。有时,本地对象依赖于代理,在代理实例化随后无法实例化。一点情况汇报下,代理接口应该实现JsonRpcServer,而本地对象应该作为客户端来提供。

export type JsonRpcServer<Client> = Disposable & {
    setClient(client: Client | undefined): void;
};

export interface ILoggerServer extends JsonRpcServery<ILoggerClient> {
    // ...
}

const serverProxy = connection.createProxy<ILoggerServer>("/services/logger");
const client = loggerWatcher.getLoggerClient();
serverProxy.setClient(client);

  统统,在最后一行,亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 将ILoggerServer接口绑定到JsonRpc代理。

  注意底层的调用:

createProxy<T extends object>(path: string, target?: object, options?: WebSocketOptions): T {
        const factory = new JsonRpcProxyFactory<T>(path, target);
        this.listen(factory, options);
        return factory.createProxy();
    }

  一点和后端的例子很像。

  你说歌词 你也注意到了,就连接而言,这里前端是服务器而后端是客户端,但对亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 的逻辑来说这不必重要。

  这里还有几点:

  • 在路径"logger"上创建JsonRpc代理。

  • 公开loggerWatcher.getLoggerClient()对象。

  • 返回ILoggerServer类型的代理。

  现在,ILoggerServer的实例通过JSON-RPC被代理到后端的LoggerServer对象。

在示例的前端和后端加载模块

  现在亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 不可能 有了那此模块,亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 前要将它们引入到亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 的示例中。亲戚亲戚亲戚让我们让我们让我们让我们让我们让我们 将使用浏览器作为示例,在electron中代码是相同的。

后端

  在examples/browser/src/backend/main.ts中,你前要像没法 来引用:

import { loggerServerModule } from 'theia-core/lib/application/node/logger-server-module';

  因此将其载入到主容器。

container.load(loggerServerModule);

前端

  在examples/browser/src/frontend/main.ts中,你前要像没法 来引用:

import { loggerFrontendModule } from 'theia-core/lib/application/browser/logger-frontend-module';
container.load(frontendLanguagesModule);

完成示例

   不可能 你想查看本文中提到的全版示例,还前要查看这里的

commit