import * as grpc from 'grpc'; import { inject, injectable, postConstruct } from 'inversify'; import { ILogger } from '@theia/core/lib/common/logger'; import { MaybePromise } from '@theia/core/lib/common/types'; import { ConfigServiceImpl } from './config-service-impl'; import { ArduinoDaemonImpl } from './arduino-daemon-impl'; @injectable() export abstract class GrpcClientProvider { @inject(ILogger) protected readonly logger: ILogger; @inject(ArduinoDaemonImpl) protected readonly daemon: ArduinoDaemonImpl; @inject(ConfigServiceImpl) protected readonly configService: ConfigServiceImpl; protected _port: string | number | undefined; protected _client: C | undefined; @postConstruct() protected init(): void { const updateClient = () => { const cliConfig = this.configService.cliConfiguration; this.reconcileClient(cliConfig ? cliConfig.daemon.port : undefined); } this.configService.onConfigChange(updateClient); this.daemon.ready.then(updateClient); this.daemon.onDaemonStopped(() => { if (this._client) { this.close(this._client); } this._client = undefined; this._port = undefined; }) } async client(): Promise { try { await this.daemon.ready; return this._client; } catch (error) { return undefined; } } protected async reconcileClient(port: string | number | undefined): Promise { if (this._port === port) { return; // Nothing to do. } this._port = port; if (this._client) { this.close(this._client); this._client = undefined; } if (this._port) { try { const client = await this.createClient(this._port); this._client = client; } catch (error) { this.logger.error('Could create client for gRPC.', error) } } } protected abstract createClient(port: string | number): MaybePromise; protected abstract close(client: C): void; protected get channelOptions(): grpc.CallOptions { return { 'grpc.max_send_message_length': 512 * 1024 * 1024, 'grpc.max_receive_message_length': 512 * 1024 * 1024 }; } }