Skip to content

Let DI framework create MonitorService instances #1165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 8 additions & 20 deletions arduino-ide-extension/src/node/arduino-ide-backend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,26 +236,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(MonitorServiceFactory).toFactory(
({ container }) =>
(options: MonitorServiceFactoryOptions) => {
const logger = container.get<ILogger>(ILogger);

const monitorSettingsProvider = container.get<MonitorSettingsProvider>(
MonitorSettingsProvider
);

const webSocketProvider =
container.get<WebSocketProvider>(WebSocketProvider);

const { board, port, coreClientProvider, monitorID } = options;

return new MonitorService(
logger,
monitorSettingsProvider,
webSocketProvider,
board,
port,
coreClientProvider,
monitorID
);
const child = container.createChild();
child
.bind<MonitorServiceFactoryOptions>(MonitorServiceFactoryOptions)
.toConstantValue({
...options,
});
child.bind(MonitorService).toSelf();
return child.get<MonitorService>(MonitorService);
}
);

Expand Down
2 changes: 1 addition & 1 deletion arduino-ide-extension/src/node/core-client-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
1 change: 0 additions & 1 deletion arduino-ide-extension/src/node/monitor-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,6 @@ export class MonitorManager extends CoreClientAware {
board,
port,
monitorID,
coreClientProvider: this.coreClientProvider,
});
this.monitorServices.set(monitorID, monitor);
monitor.onDispose(
Expand Down
16 changes: 6 additions & 10 deletions arduino-ide-extension/src/node/monitor-service-factory.ts
Original file line number Diff line number Diff line change
@@ -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;
}
67 changes: 38 additions & 29 deletions arduino-ide-extension/src/node/monitor-service.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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 {
Expand All @@ -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 =
Expand All @@ -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<MonitorRequest, MonitorResponse> | null;
private duplex: ClientDuplexStream<MonitorRequest, MonitorResponse> | 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<void>();
private readonly onDisposeEmitter = new Emitter<void>();
readonly onDispose = this.onDisposeEmitter.event;

protected _initialized = new Deferred<void>();
protected creating: Deferred<Status>;

MAX_WRITE_TO_STREAM_TRIES = 10;
WRITE_TO_STREAM_TIMEOUT_MS = 30000;
private _initialized = new Deferred<void>();
private creating: Deferred<Status>;
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) {
Expand All @@ -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,
Expand Down Expand Up @@ -258,8 +267,8 @@ export class MonitorService extends CoreClientAware implements Disposable {
}

pollWriteToStream(request: MonitorRequest): Promise<boolean> {
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<MonitorRequest, MonitorResponse>) =>
Expand Down