Let DI framework create MonitorService instances

Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
Akos Kitta 2022-07-11 09:12:28 +02:00 committed by Akos Kitta
parent f4a68e793e
commit 7fed8febf1
5 changed files with 53 additions and 61 deletions

View File

@ -236,26 +236,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(MonitorServiceFactory).toFactory( bind(MonitorServiceFactory).toFactory(
({ container }) => ({ container }) =>
(options: MonitorServiceFactoryOptions) => { (options: MonitorServiceFactoryOptions) => {
const logger = container.get<ILogger>(ILogger); const child = container.createChild();
child
const monitorSettingsProvider = container.get<MonitorSettingsProvider>( .bind<MonitorServiceFactoryOptions>(MonitorServiceFactoryOptions)
MonitorSettingsProvider .toConstantValue({
); ...options,
});
const webSocketProvider = child.bind(MonitorService).toSelf();
container.get<WebSocketProvider>(WebSocketProvider); return child.get<MonitorService>(MonitorService);
const { board, port, coreClientProvider, monitorID } = options;
return new MonitorService(
logger,
monitorSettingsProvider,
webSocketProvider,
board,
port,
coreClientProvider,
monitorID
);
} }
); );

View File

@ -397,7 +397,7 @@ export namespace CoreClientProvider {
@injectable() @injectable()
export abstract class CoreClientAware { export abstract class CoreClientAware {
@inject(CoreClientProvider) @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. * Returns with a promise that resolves when the core client is initialized and ready.
*/ */

View File

@ -317,7 +317,6 @@ export class MonitorManager extends CoreClientAware {
board, board,
port, port,
monitorID, monitorID,
coreClientProvider: this.coreClientProvider,
}); });
this.monitorServices.set(monitorID, monitor); this.monitorServices.set(monitorID, monitor);
monitor.onDispose( monitor.onDispose(

View File

@ -1,20 +1,16 @@
import { Board, Port } from '../common/protocol'; import type { Board, Port } from '../common/protocol';
import { CoreClientProvider } from './core-client-provider'; import type { MonitorService } from './monitor-service';
import { MonitorService } from './monitor-service';
export const MonitorServiceFactory = Symbol('MonitorServiceFactory'); export const MonitorServiceFactory = Symbol('MonitorServiceFactory');
export interface MonitorServiceFactory { export interface MonitorServiceFactory {
(options: { (options: MonitorServiceFactoryOptions): MonitorService;
board: Board;
port: Port;
monitorID: string;
coreClientProvider: CoreClientProvider;
}): MonitorService;
} }
export const MonitorServiceFactoryOptions = Symbol(
'MonitorServiceFactoryOptions'
);
export interface MonitorServiceFactoryOptions { export interface MonitorServiceFactoryOptions {
board: Board; board: Board;
port: Port; port: Port;
monitorID: string; monitorID: string;
coreClientProvider: CoreClientProvider;
} }

View File

@ -1,6 +1,6 @@
import { ClientDuplexStream } from '@grpc/grpc-js'; import { ClientDuplexStream } from '@grpc/grpc-js';
import { Disposable, Emitter, ILogger } from '@theia/core'; 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 { Board, Port, Status, Monitor } from '../common/protocol';
import { import {
EnumerateMonitorPortSettingsRequest, EnumerateMonitorPortSettingsRequest,
@ -10,7 +10,7 @@ import {
MonitorRequest, MonitorRequest,
MonitorResponse, MonitorResponse,
} from './cli-protocol/cc/arduino/cli/commands/v1/monitor_pb'; } 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 { 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 { Port as gRPCPort } from 'arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/port_pb';
import { import {
@ -19,6 +19,7 @@ import {
MonitorSettingsProvider, MonitorSettingsProvider,
} from './monitor-settings/monitor-settings-provider'; } from './monitor-settings/monitor-settings-provider';
import { Deferred } from '@theia/core/lib/common/promise-util'; import { Deferred } from '@theia/core/lib/common/promise-util';
import { MonitorServiceFactoryOptions } from './monitor-service-factory';
export const MonitorServiceName = 'monitor-service'; export const MonitorServiceName = 'monitor-service';
type DuplexHandlerKeys = type DuplexHandlerKeys =
@ -33,55 +34,63 @@ interface DuplexHandler {
callback: (...args: any) => void; 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 { 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 // Bidirectional gRPC stream used to receive and send data from the running
// pluggable monitor managed by the Arduino CLI. // pluggable monitor managed by the Arduino CLI.
protected duplex: ClientDuplexStream<MonitorRequest, MonitorResponse> | null; private duplex: ClientDuplexStream<MonitorRequest, MonitorResponse> | null;
// Settings used by the currently running pluggable monitor. // Settings used by the currently running pluggable monitor.
// They can be freely modified while running. // They can be freely modified while running.
protected settings: MonitorSettings = {}; private settings: MonitorSettings = {};
// List of messages received from the running pluggable monitor. // List of messages received from the running pluggable monitor.
// These are flushed from time to time to the frontend. // These are flushed from time to time to the frontend.
protected messages: string[] = []; private messages: string[] = [];
// Handles messages received from the frontend via websocket. // Handles messages received from the frontend via websocket.
protected onMessageReceived?: Disposable; private onMessageReceived?: Disposable;
// Sends messages to the frontend from time to time. // 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 // Triggered each time the number of clients connected
// to the this service WebSocket changes. // to the this service WebSocket changes.
protected onWSClientsNumberChanged?: Disposable; private onWSClientsNumberChanged?: Disposable;
// Used to notify that the monitor is being disposed // Used to notify that the monitor is being disposed
protected readonly onDisposeEmitter = new Emitter<void>(); private readonly onDisposeEmitter = new Emitter<void>();
readonly onDispose = this.onDisposeEmitter.event; readonly onDispose = this.onDisposeEmitter.event;
protected _initialized = new Deferred<void>(); private _initialized = new Deferred<void>();
protected creating: Deferred<Status>; private creating: Deferred<Status>;
private readonly board: Board;
MAX_WRITE_TO_STREAM_TRIES = 10; private readonly port: Port;
WRITE_TO_STREAM_TIMEOUT_MS = 30000; private readonly monitorID: string;
constructor( constructor(
@inject(ILogger) @inject(MonitorServiceFactoryOptions) options: MonitorServiceFactoryOptions
@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
) { ) {
super(); super();
this.board = options.board;
this.port = options.port;
this.monitorID = options.monitorID;
}
@postConstruct()
protected init(): void {
this.onWSClientsNumberChanged = this.onWSClientsNumberChanged =
this.webSocketProvider.onClientsNumberChanged(async (clients: number) => { this.webSocketProvider.onClientsNumberChanged(async (clients: number) => {
if (clients === 0) { if (clients === 0) {
@ -94,7 +103,7 @@ export class MonitorService extends CoreClientAware implements Disposable {
this.updateClientsSettings(this.settings); this.updateClientsSettings(this.settings);
}); });
this.portMonitorSettings(port.protocol, board.fqbn!).then( this.portMonitorSettings(this.port.protocol, this.board.fqbn!).then(
async (settings) => { async (settings) => {
this.settings = { this.settings = {
...this.settings, ...this.settings,
@ -258,8 +267,8 @@ export class MonitorService extends CoreClientAware implements Disposable {
} }
pollWriteToStream(request: MonitorRequest): Promise<boolean> { pollWriteToStream(request: MonitorRequest): Promise<boolean> {
let attemptsRemaining = this.MAX_WRITE_TO_STREAM_TRIES; let attemptsRemaining = MAX_WRITE_TO_STREAM_TRIES;
const writeTimeoutMs = this.WRITE_TO_STREAM_TIMEOUT_MS; const writeTimeoutMs = WRITE_TO_STREAM_TIMEOUT_MS;
const createWriteToStreamExecutor = const createWriteToStreamExecutor =
(duplex: ClientDuplexStream<MonitorRequest, MonitorResponse>) => (duplex: ClientDuplexStream<MonitorRequest, MonitorResponse>) =>