diff --git a/arduino-ide-extension/src/node/arduino-ide-backend-module.ts b/arduino-ide-extension/src/node/arduino-ide-backend-module.ts index 1cf4f39af..386f6d31c 100644 --- a/arduino-ide-extension/src/node/arduino-ide-backend-module.ts +++ b/arduino-ide-extension/src/node/arduino-ide-backend-module.ts @@ -236,26 +236,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(MonitorServiceFactory).toFactory( ({ container }) => (options: MonitorServiceFactoryOptions) => { - const logger = container.get(ILogger); - - const monitorSettingsProvider = container.get( - MonitorSettingsProvider - ); - - const webSocketProvider = - container.get(WebSocketProvider); - - const { board, port, coreClientProvider, monitorID } = options; - - return new MonitorService( - logger, - monitorSettingsProvider, - webSocketProvider, - board, - port, - coreClientProvider, - monitorID - ); + const child = container.createChild(); + child + .bind(MonitorServiceFactoryOptions) + .toConstantValue({ + ...options, + }); + child.bind(MonitorService).toSelf(); + return child.get(MonitorService); } ); diff --git a/arduino-ide-extension/src/node/core-client-provider.ts b/arduino-ide-extension/src/node/core-client-provider.ts index 3258ef829..404b76421 100644 --- a/arduino-ide-extension/src/node/core-client-provider.ts +++ b/arduino-ide-extension/src/node/core-client-provider.ts @@ -397,7 +397,7 @@ export namespace CoreClientProvider { @injectable() export abstract class CoreClientAware { @inject(CoreClientProvider) - protected readonly coreClientProvider: CoreClientProvider; // TODO: should be `private`, fix injection in subclasses. (https://github.com/arduino/arduino-ide/issues/1161) + private readonly coreClientProvider: CoreClientProvider; /** * Returns with a promise that resolves when the core client is initialized and ready. */ diff --git a/arduino-ide-extension/src/node/monitor-manager.ts b/arduino-ide-extension/src/node/monitor-manager.ts index 6365f5423..a671a14c4 100644 --- a/arduino-ide-extension/src/node/monitor-manager.ts +++ b/arduino-ide-extension/src/node/monitor-manager.ts @@ -317,7 +317,6 @@ export class MonitorManager extends CoreClientAware { board, port, monitorID, - coreClientProvider: this.coreClientProvider, }); this.monitorServices.set(monitorID, monitor); monitor.onDispose( diff --git a/arduino-ide-extension/src/node/monitor-service-factory.ts b/arduino-ide-extension/src/node/monitor-service-factory.ts index 6f88cdb0f..73f3f8cae 100644 --- a/arduino-ide-extension/src/node/monitor-service-factory.ts +++ b/arduino-ide-extension/src/node/monitor-service-factory.ts @@ -1,20 +1,16 @@ -import { Board, Port } from '../common/protocol'; -import { CoreClientProvider } from './core-client-provider'; -import { MonitorService } from './monitor-service'; +import type { Board, Port } from '../common/protocol'; +import type { MonitorService } from './monitor-service'; export const MonitorServiceFactory = Symbol('MonitorServiceFactory'); export interface MonitorServiceFactory { - (options: { - board: Board; - port: Port; - monitorID: string; - coreClientProvider: CoreClientProvider; - }): MonitorService; + (options: MonitorServiceFactoryOptions): MonitorService; } +export const MonitorServiceFactoryOptions = Symbol( + 'MonitorServiceFactoryOptions' +); export interface MonitorServiceFactoryOptions { board: Board; port: Port; monitorID: string; - coreClientProvider: CoreClientProvider; } diff --git a/arduino-ide-extension/src/node/monitor-service.ts b/arduino-ide-extension/src/node/monitor-service.ts index 68303ca18..b9d844225 100644 --- a/arduino-ide-extension/src/node/monitor-service.ts +++ b/arduino-ide-extension/src/node/monitor-service.ts @@ -1,6 +1,6 @@ import { ClientDuplexStream } from '@grpc/grpc-js'; import { Disposable, Emitter, ILogger } from '@theia/core'; -import { inject, named } from '@theia/core/shared/inversify'; +import { inject, named, postConstruct } from '@theia/core/shared/inversify'; import { Board, Port, Status, Monitor } from '../common/protocol'; import { EnumerateMonitorPortSettingsRequest, @@ -10,7 +10,7 @@ import { MonitorRequest, MonitorResponse, } from './cli-protocol/cc/arduino/cli/commands/v1/monitor_pb'; -import { CoreClientAware, CoreClientProvider } from './core-client-provider'; +import { CoreClientAware } from './core-client-provider'; import { WebSocketProvider } from './web-socket/web-socket-provider'; import { Port as gRPCPort } from 'arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/port_pb'; import { @@ -19,6 +19,7 @@ import { MonitorSettingsProvider, } from './monitor-settings/monitor-settings-provider'; import { Deferred } from '@theia/core/lib/common/promise-util'; +import { MonitorServiceFactoryOptions } from './monitor-service-factory'; export const MonitorServiceName = 'monitor-service'; type DuplexHandlerKeys = @@ -33,55 +34,63 @@ interface DuplexHandler { callback: (...args: any) => void; } +const MAX_WRITE_TO_STREAM_TRIES = 10; +const WRITE_TO_STREAM_TIMEOUT_MS = 30000; + export class MonitorService extends CoreClientAware implements Disposable { + @inject(ILogger) + @named(MonitorServiceName) + private readonly logger: ILogger; + + @inject(MonitorSettingsProvider) + private readonly monitorSettingsProvider: MonitorSettingsProvider; + + @inject(WebSocketProvider) + private readonly webSocketProvider: WebSocketProvider; + // Bidirectional gRPC stream used to receive and send data from the running // pluggable monitor managed by the Arduino CLI. - protected duplex: ClientDuplexStream | null; + private duplex: ClientDuplexStream | null; // Settings used by the currently running pluggable monitor. // They can be freely modified while running. - protected settings: MonitorSettings = {}; + private settings: MonitorSettings = {}; // List of messages received from the running pluggable monitor. // These are flushed from time to time to the frontend. - protected messages: string[] = []; + private messages: string[] = []; // Handles messages received from the frontend via websocket. - protected onMessageReceived?: Disposable; + private onMessageReceived?: Disposable; // Sends messages to the frontend from time to time. - protected flushMessagesInterval?: NodeJS.Timeout; + private flushMessagesInterval?: NodeJS.Timeout; // Triggered each time the number of clients connected // to the this service WebSocket changes. - protected onWSClientsNumberChanged?: Disposable; + private onWSClientsNumberChanged?: Disposable; // Used to notify that the monitor is being disposed - protected readonly onDisposeEmitter = new Emitter(); + private readonly onDisposeEmitter = new Emitter(); readonly onDispose = this.onDisposeEmitter.event; - protected _initialized = new Deferred(); - protected creating: Deferred; - - MAX_WRITE_TO_STREAM_TRIES = 10; - WRITE_TO_STREAM_TIMEOUT_MS = 30000; + private _initialized = new Deferred(); + private creating: Deferred; + private readonly board: Board; + private readonly port: Port; + private readonly monitorID: string; constructor( - @inject(ILogger) - @named(MonitorServiceName) - protected readonly logger: ILogger, - @inject(MonitorSettingsProvider) - protected readonly monitorSettingsProvider: MonitorSettingsProvider, - @inject(WebSocketProvider) - protected readonly webSocketProvider: WebSocketProvider, - - private readonly board: Board, - private readonly port: Port, - protected override readonly coreClientProvider: CoreClientProvider, - private readonly monitorID: string + @inject(MonitorServiceFactoryOptions) options: MonitorServiceFactoryOptions ) { super(); + this.board = options.board; + this.port = options.port; + this.monitorID = options.monitorID; + } + @postConstruct() + protected init(): void { this.onWSClientsNumberChanged = this.webSocketProvider.onClientsNumberChanged(async (clients: number) => { if (clients === 0) { @@ -94,7 +103,7 @@ export class MonitorService extends CoreClientAware implements Disposable { this.updateClientsSettings(this.settings); }); - this.portMonitorSettings(port.protocol, board.fqbn!).then( + this.portMonitorSettings(this.port.protocol, this.board.fqbn!).then( async (settings) => { this.settings = { ...this.settings, @@ -258,8 +267,8 @@ export class MonitorService extends CoreClientAware implements Disposable { } pollWriteToStream(request: MonitorRequest): Promise { - let attemptsRemaining = this.MAX_WRITE_TO_STREAM_TRIES; - const writeTimeoutMs = this.WRITE_TO_STREAM_TIMEOUT_MS; + let attemptsRemaining = MAX_WRITE_TO_STREAM_TRIES; + const writeTimeoutMs = WRITE_TO_STREAM_TIMEOUT_MS; const createWriteToStreamExecutor = (duplex: ClientDuplexStream) =>