import { inject, injectable, postConstruct } from '@theia/core/shared/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 | Error | undefined; @postConstruct() protected init(): void { const updateClient = () => { this.reconcileClient(); }; this.configService.onConfigChange(updateClient); this.daemon.ready.then(updateClient); this.daemon.onDaemonStopped(() => { if (this._client && !(this._client instanceof Error)) { this.close(this._client); } this._client = undefined; this._port = undefined; }); } async client(): Promise { try { await this.daemon.ready; return this._client; } catch (error) { return error; } } protected async reconcileClient(): Promise { const port = await this.daemon.getPort(); if (this._port === port) { return; // Nothing to do. } this._port = port; if (this._client && !(this._client instanceof Error)) { 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 not create client for gRPC.', error); this._client = error; } } } protected abstract createClient(port: string | number): MaybePromise; protected abstract close(client: C): void; protected get channelOptions(): Record { const pjson = require('../../package.json') || { version: '0.0.0' }; return { 'grpc.max_send_message_length': 512 * 1024 * 1024, 'grpc.max_receive_message_length': 512 * 1024 * 1024, 'grpc.primary_user_agent': `arduino-ide/${pjson.version}`, }; } }