mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-07-07 19:36:33 +00:00
ATL-374: Refactored the Output services.
Signed-off-by: Akos Kitta <kittaakos@typefox.io>
This commit is contained in:
parent
f26dae185b
commit
5f5193932f
@ -2,13 +2,13 @@
|
||||
import { VariableContribution, VariableRegistry, Variable } from '@theia/variable-resolver/lib/browser';
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { BoardsServiceClientImpl } from 'arduino-ide-extension/lib/browser/boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from 'arduino-ide-extension/lib/browser/boards/boards-service-provider';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoVariableResolver implements VariableContribution {
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceProvider: BoardsServiceProvider;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService
|
||||
@ -27,7 +27,7 @@ export class ArduinoVariableResolver implements VariableContribution {
|
||||
}
|
||||
|
||||
protected async resolveFqbn(): Promise<string | undefined> {
|
||||
const { boardsConfig } = this.boardsServiceClient;
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
if (!boardsConfig || !boardsConfig.selectedBoard) {
|
||||
this.messageService.error('No board selected. Please select a board for debugging.');
|
||||
return undefined;
|
||||
@ -36,7 +36,7 @@ export class ArduinoVariableResolver implements VariableContribution {
|
||||
}
|
||||
|
||||
protected async resolvePort(): Promise<string | undefined> {
|
||||
const { boardsConfig } = this.boardsServiceClient;
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
if (!boardsConfig || !boardsConfig.selectedPort) {
|
||||
return undefined;
|
||||
}
|
||||
|
@ -1,53 +0,0 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { ArduinoDaemonClient } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoDaemonClientImpl implements ArduinoDaemonClient {
|
||||
|
||||
@inject(ILogger)
|
||||
protected readonly logger: ILogger;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
|
||||
protected readonly onStartedEmitter = new Emitter<void>();
|
||||
protected readonly onStoppedEmitter = new Emitter<void>();
|
||||
protected _isRunning = false;
|
||||
|
||||
notifyStopped(): void {
|
||||
if (this._isRunning) {
|
||||
this._isRunning = false;
|
||||
this.onStoppedEmitter.fire();
|
||||
this.info('The CLI daemon process has stopped.');
|
||||
}
|
||||
}
|
||||
|
||||
notifyStarted(): void {
|
||||
if (!this._isRunning) {
|
||||
this._isRunning = true;
|
||||
this.onStartedEmitter.fire();
|
||||
this.info('The CLI daemon process has started.');
|
||||
}
|
||||
}
|
||||
|
||||
get onDaemonStarted(): Event<void> {
|
||||
return this.onStartedEmitter.event;
|
||||
}
|
||||
|
||||
get onDaemonStopped(): Event<void> {
|
||||
return this.onStoppedEmitter.event;
|
||||
}
|
||||
|
||||
get isRunning(): boolean {
|
||||
return this._isRunning;
|
||||
}
|
||||
|
||||
protected info(message: string): void {
|
||||
this.messageService.info(message, { timeout: 3000 });
|
||||
this.logger.info(message);
|
||||
}
|
||||
|
||||
}
|
@ -24,7 +24,7 @@ import { TerminalMenus } from '@theia/terminal/lib/browser/terminal-frontend-con
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import * as React from 'react';
|
||||
import { MainMenuManager } from '../common/main-menu-manager';
|
||||
import { BoardsService, BoardsServiceClient, CoreService, Port, SketchesService, ToolOutputServiceClient, ExecutableService } from '../common/protocol';
|
||||
import { BoardsService, CoreService, Port, SketchesService, ExecutableService } from '../common/protocol';
|
||||
import { ArduinoDaemon } from '../common/protocol/arduino-daemon';
|
||||
import { ConfigService } from '../common/protocol/config-service';
|
||||
import { FileSystemExt } from '../common/protocol/filesystem-ext';
|
||||
@ -32,7 +32,7 @@ import { ArduinoCommands } from './arduino-commands';
|
||||
import { BoardsConfig } from './boards/boards-config';
|
||||
import { BoardsConfigDialog } from './boards/boards-config-dialog';
|
||||
import { BoardsDataStore } from './boards/boards-data-store';
|
||||
import { BoardsServiceClientImpl } from './boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from './boards/boards-service-provider';
|
||||
import { BoardsToolBarItem } from './boards/boards-toolbar-item';
|
||||
import { EditorMode } from './editor-mode';
|
||||
import { ArduinoMenus } from './menu/arduino-menus';
|
||||
@ -44,6 +44,9 @@ import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted
|
||||
import { FileService } from '@theia/filesystem/lib/browser/file-service';
|
||||
|
||||
const debounce = require('lodash.debounce');
|
||||
import { OutputService } from '../common/protocol/output-service';
|
||||
import { NotificationCenter } from './notification-center';
|
||||
import { Settings } from './contributions/settings';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoFrontendContribution implements FrontendApplicationContribution,
|
||||
@ -61,15 +64,8 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
@inject(CoreService)
|
||||
protected readonly coreService: CoreService;
|
||||
|
||||
@inject(ToolOutputServiceClient)
|
||||
protected readonly toolOutputServiceClient: ToolOutputServiceClient;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
|
||||
|
||||
// Unused but do not remove it. It's required by DI, otherwise `init` method is not called.
|
||||
@inject(BoardsServiceClient)
|
||||
protected readonly boardsServiceClient: BoardsServiceClient;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(SelectionService)
|
||||
protected readonly selectionService: SelectionService;
|
||||
@ -151,6 +147,13 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
|
||||
@inject(ExecutableService)
|
||||
protected executableService: ExecutableService;
|
||||
@inject(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected invalidConfigPopup: Promise<void | 'No' | 'Yes' | undefined> | undefined;
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
@ -198,6 +201,21 @@ export class ArduinoFrontendContribution implements FrontendApplicationContribut
|
||||
}
|
||||
}
|
||||
});
|
||||
this.notificationCenter.onConfigChanged(({ config }) => {
|
||||
if (config) {
|
||||
this.invalidConfigPopup = undefined;
|
||||
} else {
|
||||
if (!this.invalidConfigPopup) {
|
||||
this.invalidConfigPopup = this.messageService.error(`Your CLI configuration is invalid. Do you want to correct it now?`, 'No', 'Yes')
|
||||
.then(answer => {
|
||||
if (answer === 'Yes') {
|
||||
this.commandRegistry.executeCommand(Settings.Commands.OPEN_CLI_CONFIG.id)
|
||||
}
|
||||
this.invalidConfigPopup = undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected startLanguageServer = debounce((fqbn: string, name: string | undefined) => this.doStartLanguageServer(fqbn, name));
|
||||
|
@ -8,17 +8,14 @@ import { WebSocketConnectionProvider } from '@theia/core/lib/browser/messaging/w
|
||||
import { FrontendApplicationContribution, FrontendApplication as TheiaFrontendApplication } from '@theia/core/lib/browser/frontend-application'
|
||||
import { LibraryListWidget } from './library/library-list-widget';
|
||||
import { ArduinoFrontendContribution } from './arduino-frontend-contribution';
|
||||
import { LibraryServiceServer, LibraryServiceServerPath } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath, BoardsServiceClient } from '../common/protocol/boards-service';
|
||||
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath } from '../common/protocol/boards-service';
|
||||
import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service';
|
||||
import { SketchesServiceClientImpl } from '../common/protocol/sketches-service-client-impl';
|
||||
import { CoreService, CoreServicePath, CoreServiceClient } from '../common/protocol/core-service';
|
||||
import { CoreService, CoreServicePath } from '../common/protocol/core-service';
|
||||
import { BoardsListWidget } from './boards/boards-list-widget';
|
||||
import { BoardsListWidgetFrontendContribution } from './boards/boards-widget-frontend-contribution';
|
||||
import { ToolOutputServiceClient } from '../common/protocol/tool-output-service';
|
||||
import { ToolOutputService } from '../common/protocol/tool-output-service';
|
||||
import { ToolOutputServiceClientImpl } from './tool-output/client-service-impl';
|
||||
import { BoardsServiceClientImpl } from './boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from './boards/boards-service-provider';
|
||||
import { WorkspaceService as TheiaWorkspaceService } from '@theia/workspace/lib/browser/workspace-service';
|
||||
import { WorkspaceService } from './theia/workspace/workspace-service';
|
||||
import { OutlineViewContribution as TheiaOutlineViewContribution } from '@theia/outline-view/lib/browser/outline-view-contribution';
|
||||
@ -50,7 +47,7 @@ import { SearchInWorkspaceFrontendContribution } from './theia/search-in-workspa
|
||||
import { LibraryListWidgetFrontendContribution } from './library/library-widget-frontend-contribution';
|
||||
import { MonitorServiceClientImpl } from './monitor/monitor-service-client-impl';
|
||||
import { MonitorServicePath, MonitorService, MonitorServiceClient } from '../common/protocol/monitor-service';
|
||||
import { ConfigService, ConfigServicePath, ConfigServiceClient } from '../common/protocol/config-service';
|
||||
import { ConfigService, ConfigServicePath } from '../common/protocol/config-service';
|
||||
import { MonitorWidget } from './monitor/monitor-widget';
|
||||
import { MonitorViewContribution } from './monitor/monitor-view-contribution';
|
||||
import { MonitorConnection } from './monitor/monitor-connection';
|
||||
@ -67,8 +64,7 @@ import { EditorMode } from './editor-mode';
|
||||
import { ListItemRenderer } from './widgets/component-list/list-item-renderer';
|
||||
import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution';
|
||||
import { MonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service';
|
||||
import { ArduinoDaemonClientImpl } from './arduino-daemon-client-impl';
|
||||
import { ArduinoDaemonClient, ArduinoDaemonPath, ArduinoDaemon } from '../common/protocol/arduino-daemon';
|
||||
import { ArduinoDaemonPath, ArduinoDaemon } from '../common/protocol/arduino-daemon';
|
||||
import { EditorManager as TheiaEditorManager } from '@theia/editor/lib/browser';
|
||||
import { EditorManager } from './theia/editor/editor-manager';
|
||||
import { FrontendConnectionStatusService, ApplicationConnectionStatusContribution } from './theia/core/connection-status-service';
|
||||
@ -76,8 +72,6 @@ import {
|
||||
FrontendConnectionStatusService as TheiaFrontendConnectionStatusService,
|
||||
ApplicationConnectionStatusContribution as TheiaApplicationConnectionStatusContribution
|
||||
} from '@theia/core/lib/browser/connection-status-service';
|
||||
import { ConfigServiceClientImpl } from './config-service-client-impl';
|
||||
import { CoreServiceClientImpl } from './core-service-client-impl';
|
||||
import { BoardsDataMenuUpdater } from './boards/boards-data-menu-updater';
|
||||
import { BoardsDataStore } from './boards/boards-data-store';
|
||||
import { ILogger } from '@theia/core';
|
||||
@ -116,7 +110,6 @@ import { OutputWidget } from './theia/output/output-widget';
|
||||
import { BurnBootloader } from './contributions/burn-bootloader';
|
||||
import { ExamplesServicePath, ExamplesService } from '../common/protocol/examples-service';
|
||||
import { BuiltInExamples, LibraryExamples } from './contributions/examples';
|
||||
import { LibraryServiceProvider } from './library/library-service-provider';
|
||||
import { IncludeLibrary } from './contributions/include-library';
|
||||
import { OutputChannelManager as TheiaOutputChannelManager } from '@theia/output/lib/common/output-channel';
|
||||
import { OutputChannelManager } from './theia/output/output-channel';
|
||||
@ -124,6 +117,10 @@ import { OutputChannelRegistryMainImpl as TheiaOutputChannelRegistryMainImpl, Ou
|
||||
import { ExecutableService, ExecutableServicePath } from '../common/protocol';
|
||||
import { MonacoTextModelService as TheiaMonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service';
|
||||
import { MonacoTextModelService } from './theia/monaco/monaco-text-model-service';
|
||||
import { OutputServiceImpl } from './output-service-impl';
|
||||
import { OutputServicePath, OutputService } from '../common/protocol/output-service';
|
||||
import { NotificationCenter } from './notification-center';
|
||||
import { NotificationServicePath, NotificationServiceServer } from '../common/protocol';
|
||||
|
||||
const ElementQueries = require('css-element-queries/src/ElementQueries');
|
||||
|
||||
@ -153,8 +150,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ListItemRenderer).toSelf().inSingletonScope();
|
||||
|
||||
// Library service
|
||||
bind(LibraryServiceProvider).toSelf().inSingletonScope();
|
||||
bind(LibraryServiceServer).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServiceServerPath)).inSingletonScope();
|
||||
bind(LibraryService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, LibraryServicePath)).inSingletonScope();
|
||||
|
||||
// Library list widget
|
||||
bind(LibraryListWidget).toSelf();
|
||||
@ -170,34 +166,13 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(SketchesServiceClientImpl).toSelf().inSingletonScope();
|
||||
|
||||
// Config service
|
||||
bind(ConfigService).toDynamicValue(context => {
|
||||
const connection = context.container.get(WebSocketConnectionProvider);
|
||||
const client = context.container.get(ConfigServiceClientImpl);
|
||||
return connection.createProxy(ConfigServicePath, client);
|
||||
}).inSingletonScope();
|
||||
bind(ConfigServiceClientImpl).toSelf().inSingletonScope();
|
||||
bind(ConfigServiceClient).toDynamicValue(context => {
|
||||
const client = context.container.get(ConfigServiceClientImpl);
|
||||
WebSocketConnectionProvider.createProxy(context.container, ConfigServicePath, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
bind(ConfigService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ConfigServicePath)).inSingletonScope();
|
||||
|
||||
// Boards service
|
||||
bind(BoardsService).toDynamicValue(context => {
|
||||
const connection = context.container.get(WebSocketConnectionProvider);
|
||||
const client = context.container.get(BoardsServiceClientImpl);
|
||||
return connection.createProxy(BoardsServicePath, client);
|
||||
}).inSingletonScope();
|
||||
bind(BoardsService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, BoardsServicePath)).inSingletonScope();
|
||||
// Boards service client to receive and delegate notifications from the backend.
|
||||
bind(BoardsServiceClientImpl).toSelf().inSingletonScope();
|
||||
bind(FrontendApplicationContribution).toService(BoardsServiceClientImpl);
|
||||
bind(BoardsServiceClient).toDynamicValue(async context => {
|
||||
const client = context.container.get(BoardsServiceClientImpl);
|
||||
const service = context.container.get<BoardsService>(BoardsService);
|
||||
await client.init(service);
|
||||
WebSocketConnectionProvider.createProxy(context.container, BoardsServicePath, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
bind(BoardsServiceProvider).toSelf().inSingletonScope();
|
||||
bind(FrontendApplicationContribution).toService(BoardsServiceProvider);
|
||||
|
||||
// To be able to track, and update the menu based on the core settings (aka. board details) of the currently selected board.
|
||||
bind(FrontendApplicationContribution).to(BoardsDataMenuUpdater).inSingletonScope();
|
||||
@ -230,26 +205,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
})
|
||||
|
||||
// Core service
|
||||
bind(CoreService).toDynamicValue(context => {
|
||||
const connection = context.container.get(WebSocketConnectionProvider);
|
||||
const client = context.container.get(CoreServiceClientImpl);
|
||||
return connection.createProxy(CoreServicePath, client);
|
||||
}).inSingletonScope();
|
||||
// Core service client to receive and delegate notifications when the index or the library index has been updated.
|
||||
bind(CoreServiceClientImpl).toSelf().inSingletonScope();
|
||||
bind(CoreServiceClient).toDynamicValue(context => {
|
||||
const client = context.container.get(CoreServiceClientImpl);
|
||||
WebSocketConnectionProvider.createProxy(context.container, CoreServicePath, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
|
||||
// Tool output service client
|
||||
bind(ToolOutputServiceClientImpl).toSelf().inSingletonScope();
|
||||
bind(ToolOutputServiceClient).toDynamicValue(context => {
|
||||
const client = context.container.get(ToolOutputServiceClientImpl);
|
||||
WebSocketConnectionProvider.createProxy(context.container, ToolOutputService.SERVICE_PATH, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
bind(CoreService).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, CoreServicePath)).inSingletonScope();
|
||||
|
||||
// Serial monitor
|
||||
bind(MonitorModel).toSelf().inSingletonScope();
|
||||
@ -341,18 +297,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
bind(ShellLayoutRestorer).toSelf().inSingletonScope();
|
||||
rebind(TheiaShellLayoutRestorer).toService(ShellLayoutRestorer);
|
||||
|
||||
// Arduino daemon client. Receives notifications from the backend if the CLI daemon process has been restarted.
|
||||
bind(ArduinoDaemon).toDynamicValue(context => {
|
||||
const connection = context.container.get(WebSocketConnectionProvider);
|
||||
const client = context.container.get(ArduinoDaemonClientImpl);
|
||||
return connection.createProxy(ArduinoDaemonPath, client);
|
||||
}).inSingletonScope();
|
||||
bind(ArduinoDaemonClientImpl).toSelf().inSingletonScope();
|
||||
bind(ArduinoDaemonClient).toDynamicValue(context => {
|
||||
const client = context.container.get(ArduinoDaemonClientImpl);
|
||||
WebSocketConnectionProvider.createProxy(context.container, ArduinoDaemonPath, client);
|
||||
return client;
|
||||
}).inSingletonScope();
|
||||
bind(ArduinoDaemon).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, ArduinoDaemonPath)).inSingletonScope();
|
||||
|
||||
// File-system extension
|
||||
bind(FileSystemExt).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, FileSystemExtPath)).inSingletonScope();
|
||||
@ -379,4 +324,13 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
Contribution.configure(bind, BuiltInExamples);
|
||||
Contribution.configure(bind, LibraryExamples);
|
||||
Contribution.configure(bind, IncludeLibrary);
|
||||
|
||||
bind(OutputServiceImpl).toSelf().inSingletonScope().onActivation(({ container }, outputService) => {
|
||||
WebSocketConnectionProvider.createProxy(container, OutputServicePath, outputService);
|
||||
return outputService;
|
||||
});
|
||||
bind(OutputService).toService(OutputServiceImpl);
|
||||
|
||||
bind(NotificationCenter).toSelf().inSingletonScope();
|
||||
bind(NotificationServiceServer).toDynamicValue(context => WebSocketConnectionProvider.createProxy(context.container, NotificationServicePath)).inSingletonScope();
|
||||
});
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
|
||||
import { BoardsService, Board } from '../../common/protocol/boards-service';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsService, BoardsPackage } from '../../common/protocol/boards-service';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
import { BoardsListWidgetFrontendContribution } from './boards-widget-frontend-contribution';
|
||||
import { InstallationProgressDialog } from '../widgets/progress-dialog';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
@ -20,8 +20,8 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(BoardsListWidgetFrontendContribution)
|
||||
protected readonly boardsManagerFrontendContribution: BoardsListWidgetFrontendContribution;
|
||||
@ -36,7 +36,7 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution {
|
||||
if (selectedBoard) {
|
||||
this.boardsService.search({}).then(packages => {
|
||||
const candidates = packages
|
||||
.filter(pkg => pkg.boards.some(board => Board.sameAs(board, selectedBoard)))
|
||||
.filter(pkg => BoardsPackage.contains(selectedBoard, pkg))
|
||||
.filter(({ installable, installedVersion }) => installable && !installedVersion);
|
||||
for (const candidate of candidates) {
|
||||
// tslint:disable-next-line:max-line-length
|
||||
|
@ -4,9 +4,8 @@ import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { ReactWidget, Message } from '@theia/core/lib/browser';
|
||||
import { BoardsService } from '../../common/protocol/boards-service';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { CoreServiceClientImpl } from '../core-service-client-impl';
|
||||
import { ArduinoDaemonClientImpl } from '../arduino-daemon-client-impl';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class BoardsConfigDialogWidget extends ReactWidget {
|
||||
@ -14,14 +13,11 @@ export class BoardsConfigDialogWidget extends ReactWidget {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(CoreServiceClientImpl)
|
||||
protected readonly coreServiceClient: CoreServiceClientImpl;
|
||||
|
||||
@inject(ArduinoDaemonClientImpl)
|
||||
protected readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected readonly onBoardConfigChangedEmitter = new Emitter<BoardsConfig.Config>();
|
||||
readonly onBoardConfigChanged = this.onBoardConfigChangedEmitter.event;
|
||||
@ -44,10 +40,8 @@ export class BoardsConfigDialogWidget extends ReactWidget {
|
||||
protected render(): React.ReactNode {
|
||||
return <div className='selectBoardContainer'>
|
||||
<BoardsConfig
|
||||
boardsService={this.boardsService}
|
||||
boardsServiceClient={this.boardsServiceClient}
|
||||
coreServiceClient={this.coreServiceClient}
|
||||
daemonClient={this.daemonClient}
|
||||
boardsServiceProvider={this.boardsServiceClient}
|
||||
notificationCenter={this.notificationCenter}
|
||||
onConfigChange={this.fireConfigChanged}
|
||||
onFocusNodeSet={this.setFocusNode} />
|
||||
</div>;
|
||||
|
@ -4,7 +4,7 @@ import { AbstractDialog, DialogProps, Widget, DialogError } from '@theia/core/li
|
||||
import { BoardsService } from '../../common/protocol/boards-service';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { BoardsConfigDialogWidget } from './boards-config-dialog-widget';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
|
||||
@injectable()
|
||||
export class BoardsConfigDialogProps extends DialogProps {
|
||||
@ -19,8 +19,8 @@ export class BoardsConfigDialog extends AbstractDialog<BoardsConfig.Config> {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
protected config: BoardsConfig.Config = {};
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
import * as React from 'react';
|
||||
import { DisposableCollection } from '@theia/core';
|
||||
import { BoardsService, Board, Port, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { CoreServiceClientImpl } from '../core-service-client-impl';
|
||||
import { ArduinoDaemonClientImpl } from '../arduino-daemon-client-impl';
|
||||
import { notEmpty } from '@theia/core/lib/common/objects';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { Board, Port, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
import { MaybePromise } from '@theia/core';
|
||||
|
||||
export namespace BoardsConfig {
|
||||
|
||||
@ -13,10 +14,8 @@ export namespace BoardsConfig {
|
||||
}
|
||||
|
||||
export interface Props {
|
||||
readonly boardsService: BoardsService;
|
||||
readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
readonly coreServiceClient: CoreServiceClientImpl;
|
||||
readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
readonly boardsServiceProvider: BoardsServiceProvider;
|
||||
readonly notificationCenter: NotificationCenter;
|
||||
readonly onConfigChange: (config: Config) => void;
|
||||
readonly onFocusNodeSet: (element: HTMLElement | undefined) => void;
|
||||
}
|
||||
@ -70,7 +69,7 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
|
||||
constructor(props: BoardsConfig.Props) {
|
||||
super(props);
|
||||
|
||||
const { boardsConfig } = props.boardsServiceClient;
|
||||
const { boardsConfig } = props.boardsServiceProvider;
|
||||
this.state = {
|
||||
searchResults: [],
|
||||
knownPorts: [],
|
||||
@ -82,18 +81,17 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
|
||||
|
||||
componentDidMount() {
|
||||
this.updateBoards();
|
||||
this.props.boardsService.getAvailablePorts().then(ports => this.updatePorts(ports));
|
||||
const { boardsServiceClient, coreServiceClient, daemonClient } = this.props;
|
||||
this.updatePorts(this.props.boardsServiceProvider.availableBoards.map(({ port }) => port).filter(notEmpty));
|
||||
this.toDispose.pushAll([
|
||||
boardsServiceClient.onAttachedBoardsChanged(event => this.updatePorts(event.newState.ports, AttachedBoardsChangeEvent.diff(event).detached.ports)),
|
||||
boardsServiceClient.onBoardsConfigChanged(({ selectedBoard, selectedPort }) => {
|
||||
this.props.notificationCenter.onAttachedBoardsChanged(event => this.updatePorts(event.newState.ports, AttachedBoardsChangeEvent.diff(event).detached.ports)),
|
||||
this.props.boardsServiceProvider.onBoardsConfigChanged(({ selectedBoard, selectedPort }) => {
|
||||
this.setState({ selectedBoard, selectedPort }, () => this.fireConfigChanged());
|
||||
}),
|
||||
boardsServiceClient.onBoardsPackageInstalled(() => this.updateBoards(this.state.query)),
|
||||
boardsServiceClient.onBoardsPackageUninstalled(() => this.updateBoards(this.state.query)),
|
||||
coreServiceClient.onIndexUpdated(() => this.updateBoards(this.state.query)),
|
||||
daemonClient.onDaemonStarted(() => this.updateBoards(this.state.query)),
|
||||
daemonClient.onDaemonStopped(() => this.setState({ searchResults: [] }))
|
||||
this.props.notificationCenter.onPlatformInstalled(() => this.updateBoards(this.state.query)),
|
||||
this.props.notificationCenter.onPlatformUninstalled(() => this.updateBoards(this.state.query)),
|
||||
this.props.notificationCenter.onIndexUpdated(() => this.updateBoards(this.state.query)),
|
||||
this.props.notificationCenter.onDaemonStarted(() => this.updateBoards(this.state.query)),
|
||||
this.props.notificationCenter.onDaemonStopped(() => this.setState({ searchResults: [] }))
|
||||
]);
|
||||
}
|
||||
|
||||
@ -127,14 +125,14 @@ export class BoardsConfig extends React.Component<BoardsConfig.Props, BoardsConf
|
||||
}
|
||||
|
||||
protected queryBoards = (options: { query?: string } = {}): Promise<Array<Board & { packageName: string }>> => {
|
||||
return this.props.boardsServiceClient.searchBoards(options);
|
||||
return this.props.boardsServiceProvider.searchBoards(options);
|
||||
}
|
||||
|
||||
protected get availablePorts(): Promise<Port[]> {
|
||||
return this.props.boardsService.getAvailablePorts();
|
||||
protected get availablePorts(): MaybePromise<Port[]> {
|
||||
return this.props.boardsServiceProvider.availableBoards.map(({ port }) => port).filter(notEmpty);
|
||||
}
|
||||
|
||||
protected queryPorts = async (availablePorts: Promise<Port[]> = this.availablePorts) => {
|
||||
protected queryPorts = async (availablePorts: MaybePromise<Port[]> = this.availablePorts) => {
|
||||
const ports = await availablePorts;
|
||||
return { knownPorts: ports.sort(Port.compare) };
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { inject, injectable } from 'inversify';
|
||||
import { CommandRegistry } from '@theia/core/lib/common/command';
|
||||
import { MenuModelRegistry, MenuNode } from '@theia/core/lib/common/menu';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from './boards-service-provider';
|
||||
import { Board, ConfigOption, Programmer } from '../../common/protocol';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
|
||||
import { BoardsDataStore } from './boards-data-store';
|
||||
@ -25,8 +25,8 @@ export class BoardsDataMenuUpdater implements FrontendApplicationContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
|
||||
protected readonly toDisposeOnBoardChange = new DisposableCollection();
|
||||
|
@ -5,8 +5,8 @@ import { MaybePromise } from '@theia/core/lib/common/types';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { FrontendApplicationContribution, LocalStorageService } from '@theia/core/lib/browser';
|
||||
import { notEmpty } from '../../common/utils';
|
||||
import { BoardsServiceClientImpl } from './boards-service-client-impl';
|
||||
import { BoardsService, ConfigOption, Installable, BoardDetails, Programmer } from '../../common/protocol';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
@ -18,8 +18,8 @@ export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
@inject(LocalStorageService)
|
||||
protected readonly storageService: LocalStorageService;
|
||||
@ -27,7 +27,7 @@ export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
protected readonly onChangedEmitter = new Emitter<void>();
|
||||
|
||||
onStart(): void {
|
||||
this.boardsServiceClient.onBoardsPackageInstalled(async ({ item }) => {
|
||||
this.notificationCenter.onPlatformInstalled(async ({ item }) => {
|
||||
const { installedVersion: version } = item;
|
||||
if (!version) {
|
||||
return;
|
||||
@ -76,7 +76,8 @@ export class BoardsDataStore implements FrontendApplicationContribution {
|
||||
const key = this.getStorageKey(fqbn, version);
|
||||
let data = await this.storageService.getData<BoardsDataStore.Data | undefined>(key, undefined);
|
||||
if (data) {
|
||||
if (data.programmers !== undefined) { // to be backward compatible. We did not save the `programmers` into the `localStorage`.
|
||||
// If `configOptions` is empty we rather reload the data. See arduino/arduino-cli#954 and arduino/arduino-cli#955.
|
||||
if (data.configOptions.length && data.programmers !== undefined) { // to be backward compatible. We did not save the `programmers` into the `localStorage`.
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { BoardsPackage, BoardsService } from '../../common/protocol/boards-service';
|
||||
import { ListWidget } from '../widgets/component-list/list-widget';
|
||||
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
||||
@ -24,4 +24,13 @@ export class BoardsListWidget extends ListWidget<BoardsPackage> {
|
||||
});
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
super.init();
|
||||
this.toDispose.pushAll([
|
||||
this.notificationCenter.onPlatformInstalled(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onPlatformUninstalled(() => this.refresh(undefined)),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -10,14 +10,12 @@ import {
|
||||
Board,
|
||||
BoardsService,
|
||||
BoardsPackage,
|
||||
InstalledEvent,
|
||||
UninstalledEvent,
|
||||
BoardsServiceClient,
|
||||
AttachedBoardsChangeEvent
|
||||
} from '../../common/protocol';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { naturalCompare } from '../../common/utils';
|
||||
import { compareAnything } from '../theia/monaco/comparers';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
interface BoardMatch {
|
||||
readonly board: Board & Readonly<{ packageName: string }>;
|
||||
@ -25,7 +23,7 @@ interface BoardMatch {
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApplicationContribution {
|
||||
export class BoardsServiceProvider implements FrontendApplicationContribution {
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
@ -36,9 +34,12 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
|
||||
@inject(StorageService)
|
||||
protected storageService: StorageService;
|
||||
|
||||
protected readonly onBoardsPackageInstalledEmitter = new Emitter<InstalledEvent<BoardsPackage>>();
|
||||
protected readonly onBoardsPackageUninstalledEmitter = new Emitter<UninstalledEvent<BoardsPackage>>();
|
||||
protected readonly onAttachedBoardsChangedEmitter = new Emitter<AttachedBoardsChangeEvent>();
|
||||
@inject(BoardsService)
|
||||
protected boardsService: BoardsService;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected notificationCenter: NotificationCenter;
|
||||
|
||||
protected readonly onBoardsConfigChangedEmitter = new Emitter<BoardsConfig.Config>();
|
||||
protected readonly onAvailableBoardsChangedEmitter = new Emitter<AvailableBoard[]>();
|
||||
|
||||
@ -54,14 +55,7 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
|
||||
protected _attachedBoards: Board[] = []; // This does not contain the `Unknown` boards. They're visible from the available ports only.
|
||||
protected _availablePorts: Port[] = [];
|
||||
protected _availableBoards: AvailableBoard[] = [];
|
||||
protected boardsService: BoardsService;
|
||||
|
||||
/**
|
||||
* Event when the state of the attached/detached boards has changed. For instance, the user have detached a physical board.
|
||||
*/
|
||||
readonly onAttachedBoardsChanged = this.onAttachedBoardsChangedEmitter.event;
|
||||
readonly onBoardsPackageInstalled = this.onBoardsPackageInstalledEmitter.event;
|
||||
readonly onBoardsPackageUninstalled = this.onBoardsPackageUninstalledEmitter.event;
|
||||
/**
|
||||
* Unlike `onAttachedBoardsChanged` this even fires when the user modifies the selected board in the IDE.\
|
||||
* This even also fires, when the boards package was not available for the currently selected board,
|
||||
@ -72,33 +66,72 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
|
||||
readonly onBoardsConfigChanged = this.onBoardsConfigChangedEmitter.event;
|
||||
readonly onAvailableBoardsChanged = this.onAvailableBoardsChangedEmitter.event;
|
||||
|
||||
async onStart(): Promise<void> {
|
||||
return this.loadState();
|
||||
}
|
||||
onStart(): void {
|
||||
this.notificationCenter.onAttachedBoardsChanged(this.notifyAttachedBoardsChanged.bind(this));
|
||||
this.notificationCenter.onPlatformInstalled(this.notifyPlatformInstalled.bind(this));
|
||||
this.notificationCenter.onPlatformUninstalled(this.notifyPlatformUninstalled.bind(this));
|
||||
|
||||
/**
|
||||
* When the FE connects to the BE, the BE stets the known boards and ports.\
|
||||
* This is a DI workaround for not being able to inject the service into the client.
|
||||
*/
|
||||
async init(boardsService: BoardsService): Promise<void> {
|
||||
this.boardsService = boardsService;
|
||||
const [attachedBoards, availablePorts] = await Promise.all([
|
||||
Promise.all([
|
||||
this.boardsService.getAttachedBoards(),
|
||||
this.boardsService.getAvailablePorts()
|
||||
]);
|
||||
this._attachedBoards = attachedBoards;
|
||||
this._availablePorts = availablePorts;
|
||||
this.reconcileAvailableBoards().then(() => this.tryReconnect());
|
||||
this.boardsService.getAvailablePorts(),
|
||||
this.loadState()
|
||||
]).then(([attachedBoards, availablePorts]) => {
|
||||
this._attachedBoards = attachedBoards;
|
||||
this._availablePorts = availablePorts;
|
||||
this.reconcileAvailableBoards().then(() => this.tryReconnect());
|
||||
});
|
||||
}
|
||||
|
||||
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
|
||||
this.logger.info('Attached boards and available ports changed: ', JSON.stringify(event));
|
||||
protected notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
|
||||
if (!AttachedBoardsChangeEvent.isEmpty(event)) {
|
||||
this.logger.info('Attached boards and available ports changed:');
|
||||
this.logger.info(AttachedBoardsChangeEvent.toString(event));
|
||||
this.logger.info(`------------------------------------------`);
|
||||
}
|
||||
this._attachedBoards = event.newState.boards;
|
||||
this.onAttachedBoardsChangedEmitter.fire(event);
|
||||
this._availablePorts = event.newState.ports;
|
||||
this.reconcileAvailableBoards().then(() => this.tryReconnect());
|
||||
}
|
||||
|
||||
protected notifyPlatformInstalled(event: { item: BoardsPackage }): void {
|
||||
this.logger.info('Boards package installed: ', JSON.stringify(event));
|
||||
const { selectedBoard } = this.boardsConfig;
|
||||
const { installedVersion, id } = event.item;
|
||||
if (selectedBoard) {
|
||||
const installedBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (installedBoard && (!selectedBoard.fqbn || selectedBoard.fqbn === installedBoard.fqbn)) {
|
||||
this.logger.info(`Board package ${id}[${installedVersion}] was installed. Updating the FQBN of the currently selected ${selectedBoard.name} board. [FQBN: ${installedBoard.fqbn}]`);
|
||||
this.boardsConfig = {
|
||||
...this.boardsConfig,
|
||||
selectedBoard: installedBoard
|
||||
};
|
||||
return;
|
||||
}
|
||||
// Trigger a board re-set. See: https://github.com/arduino/arduino-cli/issues/954
|
||||
// E.g: install `adafruit:avr`, then select `adafruit:avr:adafruit32u4` board, and finally install the required `arduino:avr`
|
||||
this.boardsConfig = this.boardsConfig;
|
||||
}
|
||||
}
|
||||
|
||||
protected notifyPlatformUninstalled(event: { item: BoardsPackage }): void {
|
||||
this.logger.info('Boards package uninstalled: ', JSON.stringify(event));
|
||||
const { selectedBoard } = this.boardsConfig;
|
||||
if (selectedBoard && selectedBoard.fqbn) {
|
||||
const uninstalledBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (uninstalledBoard && uninstalledBoard.fqbn === selectedBoard.fqbn) {
|
||||
this.logger.info(`Board package ${event.item.id} was uninstalled. Discarding the FQBN of the currently selected ${selectedBoard.name} board.`);
|
||||
const selectedBoardWithoutFqbn = {
|
||||
name: selectedBoard.name
|
||||
// No FQBN
|
||||
};
|
||||
this.boardsConfig = {
|
||||
...this.boardsConfig,
|
||||
selectedBoard: selectedBoardWithoutFqbn
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected async tryReconnect(): Promise<boolean> {
|
||||
if (this.latestValidBoardsConfig && !this.canUploadTo(this.boardsConfig)) {
|
||||
for (const board of this.availableBoards.filter(({ state }) => state !== AvailableBoard.State.incomplete)) {
|
||||
@ -127,43 +160,6 @@ export class BoardsServiceClientImpl implements BoardsServiceClient, FrontendApp
|
||||
return false;
|
||||
}
|
||||
|
||||
notifyInstalled(event: InstalledEvent<BoardsPackage>): void {
|
||||
this.logger.info('Boards package installed: ', JSON.stringify(event));
|
||||
this.onBoardsPackageInstalledEmitter.fire(event);
|
||||
const { selectedBoard } = this.boardsConfig;
|
||||
const { installedVersion, id } = event.item;
|
||||
if (selectedBoard) {
|
||||
const installedBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (installedBoard && (!selectedBoard.fqbn || selectedBoard.fqbn === installedBoard.fqbn)) {
|
||||
this.logger.info(`Board package ${id}[${installedVersion}] was installed. Updating the FQBN of the currently selected ${selectedBoard.name} board. [FQBN: ${installedBoard.fqbn}]`);
|
||||
this.boardsConfig = {
|
||||
...this.boardsConfig,
|
||||
selectedBoard: installedBoard
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notifyUninstalled(event: UninstalledEvent<BoardsPackage>): void {
|
||||
this.logger.info('Boards package uninstalled: ', JSON.stringify(event));
|
||||
this.onBoardsPackageUninstalledEmitter.fire(event);
|
||||
const { selectedBoard } = this.boardsConfig;
|
||||
if (selectedBoard && selectedBoard.fqbn) {
|
||||
const uninstalledBoard = event.item.boards.find(({ name }) => name === selectedBoard.name);
|
||||
if (uninstalledBoard && uninstalledBoard.fqbn === selectedBoard.fqbn) {
|
||||
this.logger.info(`Board package ${event.item.id} was uninstalled. Discarding the FQBN of the currently selected ${selectedBoard.name} board.`);
|
||||
const selectedBoardWithoutFqbn = {
|
||||
name: selectedBoard.name
|
||||
// No FQBN
|
||||
};
|
||||
this.boardsConfig = {
|
||||
...this.boardsConfig,
|
||||
selectedBoard: selectedBoardWithoutFqbn
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set boardsConfig(config: BoardsConfig.Config) {
|
||||
this.doSetBoardsConfig(config);
|
||||
this.saveState().finally(() => this.reconcileAvailableBoards().finally(() => this.onBoardsConfigChangedEmitter.fire(this._boardsConfig)));
|
@ -5,7 +5,7 @@ import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { Port } from '../../common/protocol';
|
||||
import { BoardsConfig } from './boards-config';
|
||||
import { ArduinoCommands } from '../arduino-commands';
|
||||
import { BoardsServiceClientImpl, AvailableBoard } from './boards-service-client-impl';
|
||||
import { BoardsServiceProvider, AvailableBoard } from './boards-service-provider';
|
||||
|
||||
export interface BoardsDropDownListCoords {
|
||||
readonly top: number;
|
||||
@ -181,7 +181,7 @@ export class BoardsToolBarItem extends React.Component<BoardsToolBarItem.Props,
|
||||
export namespace BoardsToolBarItem {
|
||||
|
||||
export interface Props {
|
||||
readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
readonly boardsServiceClient: BoardsServiceProvider;
|
||||
readonly commands: CommandRegistry;
|
||||
}
|
||||
|
||||
|
@ -16,9 +16,9 @@ import {
|
||||
} from '@theia/core/lib/browser/quick-open';
|
||||
import { naturalCompare } from '../../../common/utils';
|
||||
import { BoardsService, Port, Board, ConfigOption, ConfigValue } from '../../../common/protocol';
|
||||
import { CoreServiceClientImpl } from '../../core-service-client-impl';
|
||||
import { BoardsDataStore } from '../boards-data-store';
|
||||
import { BoardsServiceClientImpl, AvailableBoard } from '../boards-service-client-impl';
|
||||
import { BoardsServiceProvider, AvailableBoard } from '../boards-service-provider';
|
||||
import { NotificationCenter } from '../../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenModel, QuickOpenHandler, CommandContribution, KeybindingContribution, Command {
|
||||
@ -38,14 +38,14 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(CoreServiceClientImpl)
|
||||
protected coreServiceClient: CoreServiceClientImpl;
|
||||
@inject(NotificationCenter)
|
||||
protected notificationCenter: NotificationCenter;
|
||||
|
||||
protected isOpen: boolean = false;
|
||||
protected currentQuery: string = '';
|
||||
@ -59,7 +59,7 @@ export class BoardsQuickOpenService implements QuickOpenContribution, QuickOpenM
|
||||
// `init` name is used by the `QuickOpenHandler`.
|
||||
@postConstruct()
|
||||
protected postConstruct(): void {
|
||||
this.coreServiceClient.onIndexUpdated(() => this.update(this.availableBoards));
|
||||
this.notificationCenter.onIndexUpdated(() => this.update(this.availableBoards));
|
||||
this.boardsServiceClient.onAvailableBoardsChanged(availableBoards => this.update(availableBoards));
|
||||
this.update(this.boardsServiceClient.availableBoards);
|
||||
}
|
||||
|
@ -1,52 +0,0 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { CommandService } from '@theia/core/lib/common/command';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { ConfigServiceClient, Config } from '../common/protocol';
|
||||
import { Settings } from './contributions/settings';
|
||||
|
||||
@injectable()
|
||||
export class ConfigServiceClientImpl implements ConfigServiceClient {
|
||||
|
||||
@inject(CommandService)
|
||||
protected readonly commandService: CommandService;
|
||||
|
||||
@inject(ILogger)
|
||||
protected readonly logger: ILogger;
|
||||
|
||||
@inject(MessageService)
|
||||
protected readonly messageService: MessageService;
|
||||
|
||||
protected readonly onConfigChangedEmitter = new Emitter<Config>();
|
||||
protected invalidConfigPopup: Promise<void | 'No' | 'Yes' | undefined> | undefined;
|
||||
|
||||
notifyConfigChanged(config: Config): void {
|
||||
this.invalidConfigPopup = undefined;
|
||||
this.info(`The CLI configuration has been successfully reloaded.`);
|
||||
this.onConfigChangedEmitter.fire(config);
|
||||
}
|
||||
|
||||
notifyInvalidConfig(): void {
|
||||
if (!this.invalidConfigPopup) {
|
||||
this.invalidConfigPopup = this.messageService.error(`Your CLI configuration is invalid. Do you want to correct it now?`, 'No', 'Yes')
|
||||
.then(answer => {
|
||||
if (answer === 'Yes') {
|
||||
this.commandService.executeCommand(Settings.Commands.OPEN_CLI_CONFIG.id)
|
||||
}
|
||||
this.invalidConfigPopup = undefined;
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
get onConfigChanged(): Event<Config> {
|
||||
return this.onConfigChangedEmitter.event;
|
||||
}
|
||||
|
||||
protected info(message: string): void {
|
||||
this.messageService.info(message, { timeout: 3000 });
|
||||
this.logger.info(message);
|
||||
}
|
||||
|
||||
}
|
@ -4,7 +4,7 @@ import { CoreService } from '../../common/protocol';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { MonitorConnection } from '../monitor/monitor-connection';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
@ -19,8 +19,8 @@ export class BurnBootloader extends SketchContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
|
@ -5,10 +5,10 @@ import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposa
|
||||
import { OpenSketch } from './open-sketch';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
import { LibraryServiceProvider } from '../library/library-service-provider';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { ExamplesService, ExampleContainer } from '../../common/protocol/examples-service';
|
||||
import { SketchContribution, CommandRegistry, MenuModelRegistry } from './contribution';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export abstract class Examples extends SketchContribution {
|
||||
@ -25,8 +25,8 @@ export abstract class Examples extends SketchContribution {
|
||||
@inject(ExamplesService)
|
||||
protected readonly examplesService: ExamplesService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
protected readonly toDispose = new DisposableCollection();
|
||||
|
||||
@ -113,15 +113,15 @@ export class BuiltInExamples extends Examples {
|
||||
@injectable()
|
||||
export class LibraryExamples extends Examples {
|
||||
|
||||
@inject(LibraryServiceProvider)
|
||||
protected readonly libraryServiceProvider: LibraryServiceProvider;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
|
||||
|
||||
onStart(): void {
|
||||
this.register(); // no `await`
|
||||
this.libraryServiceProvider.onLibraryPackageInstalled(() => this.register());
|
||||
this.libraryServiceProvider.onLibraryPackageUninstalled(() => this.register());
|
||||
this.notificationCenter.onLibraryInstalled(() => this.register());
|
||||
this.notificationCenter.onLibraryUninstalled(() => this.register());
|
||||
}
|
||||
|
||||
protected handleBoardChanged(fqbn: string | undefined): void {
|
||||
|
@ -6,12 +6,12 @@ import { EditorManager } from '@theia/editor/lib/browser';
|
||||
import { MenuModelRegistry, MenuPath } from '@theia/core/lib/common/menu';
|
||||
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { LibraryPackage, LibraryLocation } from '../../common/protocol';
|
||||
import { LibraryPackage, LibraryLocation, LibraryService } from '../../common/protocol';
|
||||
import { MainMenuManager } from '../../common/main-menu-manager';
|
||||
import { LibraryListWidget } from '../library/library-list-widget';
|
||||
import { LibraryServiceProvider } from '../library/library-service-provider';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { SketchContribution, Command, CommandRegistry } from './contribution';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class IncludeLibrary extends SketchContribution {
|
||||
@ -28,11 +28,14 @@ export class IncludeLibrary extends SketchContribution {
|
||||
@inject(EditorManager)
|
||||
protected readonly editorManager: EditorManager;
|
||||
|
||||
@inject(LibraryServiceProvider)
|
||||
protected readonly libraryServiceProvider: LibraryServiceProvider;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
@inject(LibraryService)
|
||||
protected readonly libraryService: LibraryService;
|
||||
|
||||
protected readonly queue = new PQueue({ autoStart: true, concurrency: 1 });
|
||||
protected readonly toDispose = new DisposableCollection();
|
||||
@ -40,8 +43,8 @@ export class IncludeLibrary extends SketchContribution {
|
||||
onStart(): void {
|
||||
this.updateMenuActions();
|
||||
this.boardsServiceClient.onBoardsConfigChanged(() => this.updateMenuActions())
|
||||
this.libraryServiceProvider.onLibraryPackageInstalled(() => this.updateMenuActions());
|
||||
this.libraryServiceProvider.onLibraryPackageUninstalled(() => this.updateMenuActions());
|
||||
this.notificationCenter.onLibraryInstalled(() => this.updateMenuActions());
|
||||
this.notificationCenter.onLibraryUninstalled(() => this.updateMenuActions());
|
||||
}
|
||||
|
||||
registerCommands(registry: CommandRegistry): void {
|
||||
@ -62,7 +65,7 @@ export class IncludeLibrary extends SketchContribution {
|
||||
const fqbn = this.boardsServiceClient.boardsConfig.selectedBoard?.fqbn;
|
||||
// Do not show board specific examples, when no board is selected.
|
||||
if (fqbn) {
|
||||
libraries.push(...await this.libraryServiceProvider.list({ fqbn }));
|
||||
libraries.push(...await this.libraryService.list({ fqbn }));
|
||||
}
|
||||
|
||||
// `Include Library` submenu
|
||||
|
@ -5,7 +5,7 @@ import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { MonitorConnection } from '../monitor/monitor-connection';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
@ -20,8 +20,8 @@ export class UploadSketch extends SketchContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
|
@ -4,7 +4,7 @@ import { CoreService } from '../../common/protocol';
|
||||
import { ArduinoMenus } from '../menu/arduino-menus';
|
||||
import { ArduinoToolbar } from '../toolbar/arduino-toolbar';
|
||||
import { BoardsDataStore } from '../boards/boards-data-store';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { SketchContribution, Command, CommandRegistry, MenuModelRegistry, KeybindingRegistry, TabBarToolbarRegistry } from './contribution';
|
||||
|
||||
@injectable()
|
||||
@ -16,8 +16,8 @@ export class VerifySketch extends SketchContribution {
|
||||
@inject(BoardsDataStore)
|
||||
protected readonly boardsDataStore: BoardsDataStore;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClientImpl: BoardsServiceProvider;
|
||||
|
||||
@inject(OutputChannelManager)
|
||||
protected readonly outputChannelManager: OutputChannelManager;
|
||||
|
@ -1,36 +0,0 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { LocalStorageService } from '@theia/core/lib/browser/storage-service';
|
||||
import { CoreServiceClient } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class CoreServiceClientImpl implements CoreServiceClient {
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
|
||||
@inject(MessageService)
|
||||
protected messageService: MessageService;
|
||||
|
||||
@inject(LocalStorageService)
|
||||
protected storageService: LocalStorageService;
|
||||
|
||||
protected readonly onIndexUpdatedEmitter = new Emitter<void>();
|
||||
|
||||
notifyIndexUpdated(): void {
|
||||
this.info('Index has been updated.');
|
||||
this.onIndexUpdatedEmitter.fire();
|
||||
}
|
||||
|
||||
get onIndexUpdated(): Event<void> {
|
||||
return this.onIndexUpdatedEmitter.event;
|
||||
}
|
||||
|
||||
protected info(message: string): void {
|
||||
this.messageService.info(message, { timeout: 3000 });
|
||||
this.logger.info(message);
|
||||
}
|
||||
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { LibraryPackage } from '../../common/protocol/library-service';
|
||||
import { injectable, postConstruct, inject } from 'inversify';
|
||||
import { LibraryPackage, LibraryService } from '../../common/protocol/library-service';
|
||||
import { ListWidget } from '../widgets/component-list/list-widget';
|
||||
import { ListItemRenderer } from '../widgets/component-list/list-item-renderer';
|
||||
import { LibraryServiceProvider } from './library-service-provider';
|
||||
|
||||
@injectable()
|
||||
export class LibraryListWidget extends ListWidget<LibraryPackage> {
|
||||
@ -11,7 +10,7 @@ export class LibraryListWidget extends ListWidget<LibraryPackage> {
|
||||
static WIDGET_LABEL = 'Library Manager';
|
||||
|
||||
constructor(
|
||||
@inject(LibraryServiceProvider) protected service: LibraryServiceProvider,
|
||||
@inject(LibraryService) protected service: LibraryService,
|
||||
@inject(ListItemRenderer) protected itemRenderer: ListItemRenderer<LibraryPackage>) {
|
||||
|
||||
super({
|
||||
@ -25,4 +24,13 @@ export class LibraryListWidget extends ListWidget<LibraryPackage> {
|
||||
});
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
super.init();
|
||||
this.toDispose.pushAll([
|
||||
this.notificationCenter.onLibraryInstalled(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onLibraryUninstalled(() => this.refresh(undefined)),
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,61 +0,0 @@
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { Searchable, InstalledEvent, UninstalledEvent } from '../../common/protocol';
|
||||
import { LibraryPackage, LibraryServiceServer, LibraryService } from '../../common/protocol/library-service';
|
||||
|
||||
@injectable()
|
||||
export class LibraryServiceProvider implements Required<LibraryService> {
|
||||
|
||||
@inject(LibraryServiceServer)
|
||||
protected readonly server: JsonRpcProxy<LibraryServiceServer>;
|
||||
|
||||
protected readonly onLibraryPackageInstalledEmitter = new Emitter<InstalledEvent<LibraryPackage>>();
|
||||
protected readonly onLibraryPackageUninstalledEmitter = new Emitter<UninstalledEvent<LibraryPackage>>();
|
||||
protected readonly toDispose = new DisposableCollection(
|
||||
this.onLibraryPackageInstalledEmitter,
|
||||
this.onLibraryPackageUninstalledEmitter
|
||||
);
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.server.setClient({
|
||||
notifyInstalled: event => this.onLibraryPackageInstalledEmitter.fire(event),
|
||||
notifyUninstalled: event => this.onLibraryPackageUninstalledEmitter.fire(event)
|
||||
});
|
||||
}
|
||||
|
||||
get onLibraryPackageInstalled(): Event<InstalledEvent<LibraryPackage>> {
|
||||
return this.onLibraryPackageInstalledEmitter.event;
|
||||
}
|
||||
|
||||
get onLibraryPackageUninstalled(): Event<InstalledEvent<LibraryPackage>> {
|
||||
return this.onLibraryPackageUninstalledEmitter.event;
|
||||
}
|
||||
|
||||
// #region remote library service API
|
||||
|
||||
async install(options: { item: LibraryPackage; version?: string | undefined; }): Promise<void> {
|
||||
return this.server.install(options);
|
||||
}
|
||||
|
||||
async list(options: LibraryService.List.Options): Promise<LibraryPackage[]> {
|
||||
return this.server.list(options);
|
||||
}
|
||||
|
||||
async uninstall(options: { item: LibraryPackage; }): Promise<void> {
|
||||
return this.server.uninstall(options);
|
||||
}
|
||||
|
||||
async search(options: Searchable.Options): Promise<LibraryPackage[]> {
|
||||
return this.server.search(options);
|
||||
}
|
||||
|
||||
// #endregion remote API
|
||||
|
||||
dispose(): void {
|
||||
this.toDispose.dispose();
|
||||
}
|
||||
|
||||
}
|
@ -4,11 +4,12 @@ import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state';
|
||||
import { MonitorService, MonitorConfig, MonitorError, Status, MonitorReadEvent } from '../../common/protocol/monitor-service';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
import { Port, Board, BoardsService, AttachedBoardsChangeEvent } from '../../common/protocol/boards-service';
|
||||
import { MonitorServiceClientImpl } from './monitor-service-client-impl';
|
||||
import { BoardsConfig } from '../boards/boards-config';
|
||||
import { MonitorModel } from './monitor-model';
|
||||
import { NotificationCenter } from '../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class MonitorConnection {
|
||||
@ -25,8 +26,11 @@ export class MonitorConnection {
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceProvider: BoardsServiceProvider;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
@inject(MessageService)
|
||||
protected messageService: MessageService;
|
||||
@ -110,11 +114,11 @@ export class MonitorConnection {
|
||||
}
|
||||
}
|
||||
});
|
||||
this.boardsServiceClient.onBoardsConfigChanged(this.handleBoardConfigChange.bind(this));
|
||||
this.boardsServiceClient.onAttachedBoardsChanged(event => {
|
||||
this.boardsServiceProvider.onBoardsConfigChanged(this.handleBoardConfigChange.bind(this));
|
||||
this.notificationCenter.onAttachedBoardsChanged(event => {
|
||||
if (this.autoConnect && this.connected) {
|
||||
const { boardsConfig } = this.boardsServiceClient;
|
||||
if (this.boardsServiceClient.canUploadTo(boardsConfig, { silent: false })) {
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
if (this.boardsServiceProvider.canUploadTo(boardsConfig, { silent: false })) {
|
||||
const { attached } = AttachedBoardsChangeEvent.diff(event);
|
||||
if (attached.boards.some(board => !!board.port && BoardsConfig.Config.sameAs(boardsConfig, board))) {
|
||||
const { selectedBoard: board, selectedPort: port } = boardsConfig;
|
||||
@ -128,7 +132,7 @@ export class MonitorConnection {
|
||||
// Handles the `baudRate` changes by reconnecting if required.
|
||||
this.monitorModel.onChange(({ property }) => {
|
||||
if (property === 'baudRate' && this.autoConnect && this.connected) {
|
||||
const { boardsConfig } = this.boardsServiceClient;
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
this.handleBoardConfigChange(boardsConfig);
|
||||
}
|
||||
});
|
||||
@ -154,7 +158,7 @@ export class MonitorConnection {
|
||||
// We have to make sure the previous boards config has been restored.
|
||||
// Otherwise, we might start the auto-connection without configured boards.
|
||||
this.applicationState.reachedState('started_contributions').then(() => {
|
||||
const { boardsConfig } = this.boardsServiceClient;
|
||||
const { boardsConfig } = this.boardsServiceProvider;
|
||||
this.handleBoardConfigChange(boardsConfig);
|
||||
});
|
||||
} else if (oldValue && !value) {
|
||||
@ -227,7 +231,7 @@ export class MonitorConnection {
|
||||
|
||||
protected async handleBoardConfigChange(boardsConfig: BoardsConfig.Config): Promise<void> {
|
||||
if (this.autoConnect) {
|
||||
if (this.boardsServiceClient.canUploadTo(boardsConfig, { silent: false })) {
|
||||
if (this.boardsServiceProvider.canUploadTo(boardsConfig, { silent: false })) {
|
||||
// Instead of calling `getAttachedBoards` and filtering for `AttachedSerialBoard` we have to check the available ports.
|
||||
// The connected board might be unknown. See: https://github.com/arduino/arduino-pro-ide/issues/127#issuecomment-563251881
|
||||
this.boardsService.getAvailablePorts().then(ports => {
|
||||
|
@ -2,7 +2,7 @@ import { injectable, inject } from 'inversify';
|
||||
import { Emitter, Event } from '@theia/core/lib/common/event';
|
||||
import { MonitorConfig } from '../../common/protocol/monitor-service';
|
||||
import { FrontendApplicationContribution, LocalStorageService } from '@theia/core/lib/browser';
|
||||
import { BoardsServiceClientImpl } from '../boards/boards-service-client-impl';
|
||||
import { BoardsServiceProvider } from '../boards/boards-service-provider';
|
||||
|
||||
@injectable()
|
||||
export class MonitorModel implements FrontendApplicationContribution {
|
||||
@ -12,8 +12,8 @@ export class MonitorModel implements FrontendApplicationContribution {
|
||||
@inject(LocalStorageService)
|
||||
protected readonly localStorageService: LocalStorageService;
|
||||
|
||||
@inject(BoardsServiceClientImpl)
|
||||
protected readonly boardsServiceClient: BoardsServiceClientImpl;
|
||||
@inject(BoardsServiceProvider)
|
||||
protected readonly boardsServiceClient: BoardsServiceProvider;
|
||||
|
||||
protected readonly onChangeEmitter: Emitter<MonitorModel.State.Change<keyof MonitorModel.State>>;
|
||||
protected _autoscroll: boolean;
|
||||
|
92
arduino-ide-extension/src/browser/notification-center.ts
Normal file
92
arduino-ide-extension/src/browser/notification-center.ts
Normal file
@ -0,0 +1,92 @@
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { Emitter } from '@theia/core/lib/common/event';
|
||||
import { JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application';
|
||||
import { NotificationServiceClient, NotificationServiceServer } from '../common/protocol/notification-service';
|
||||
import { AttachedBoardsChangeEvent, BoardsPackage, LibraryPackage, Config } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class NotificationCenter implements NotificationServiceClient, FrontendApplicationContribution {
|
||||
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly server: JsonRpcProxy<NotificationServiceServer>;
|
||||
|
||||
protected readonly indexUpdatedEmitter = new Emitter<void>();
|
||||
protected readonly daemonStartedEmitter = new Emitter<void>();
|
||||
protected readonly daemonStoppedEmitter = new Emitter<void>();
|
||||
protected readonly configChangedEmitter = new Emitter<{ config: Config | undefined }>();
|
||||
protected readonly platformInstalledEmitter = new Emitter<{ item: BoardsPackage }>();
|
||||
protected readonly platformUninstalledEmitter = new Emitter<{ item: BoardsPackage }>();
|
||||
protected readonly libraryInstalledEmitter = new Emitter<{ item: LibraryPackage }>();
|
||||
protected readonly libraryUninstalledEmitter = new Emitter<{ item: LibraryPackage }>();
|
||||
protected readonly attachedBoardsChangedEmitter = new Emitter<AttachedBoardsChangeEvent>();
|
||||
|
||||
protected readonly toDispose = new DisposableCollection(
|
||||
this.indexUpdatedEmitter,
|
||||
this.daemonStartedEmitter,
|
||||
this.daemonStoppedEmitter,
|
||||
this.configChangedEmitter,
|
||||
this.platformInstalledEmitter,
|
||||
this.platformUninstalledEmitter,
|
||||
this.libraryInstalledEmitter,
|
||||
this.libraryUninstalledEmitter,
|
||||
this.attachedBoardsChangedEmitter
|
||||
);
|
||||
|
||||
readonly onIndexUpdated = this.indexUpdatedEmitter.event;
|
||||
readonly onDaemonStarted = this.daemonStartedEmitter.event;
|
||||
readonly onDaemonStopped = this.daemonStoppedEmitter.event;
|
||||
readonly onConfigChanged = this.configChangedEmitter.event;
|
||||
readonly onPlatformInstalled = this.platformInstalledEmitter.event;
|
||||
readonly onPlatformUninstalled = this.platformUninstalledEmitter.event;
|
||||
readonly onLibraryInstalled = this.libraryInstalledEmitter.event;
|
||||
readonly onLibraryUninstalled = this.libraryUninstalledEmitter.event;
|
||||
readonly onAttachedBoardsChanged = this.attachedBoardsChangedEmitter.event;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.server.setClient(this);
|
||||
}
|
||||
|
||||
onStop(): void {
|
||||
this.toDispose.dispose();
|
||||
}
|
||||
|
||||
notifyIndexUpdated(): void {
|
||||
this.indexUpdatedEmitter.fire();
|
||||
}
|
||||
|
||||
notifyDaemonStarted(): void {
|
||||
this.daemonStartedEmitter.fire();
|
||||
}
|
||||
|
||||
notifyDaemonStopped(): void {
|
||||
this.daemonStoppedEmitter.fire();
|
||||
}
|
||||
|
||||
notifyConfigChanged(event: { config: Config | undefined }): void {
|
||||
this.configChangedEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyPlatformInstalled(event: { item: BoardsPackage }): void {
|
||||
this.platformInstalledEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyPlatformUninstalled(event: { item: BoardsPackage }): void {
|
||||
this.platformUninstalledEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyLibraryInstalled(event: { item: LibraryPackage }): void {
|
||||
this.libraryInstalledEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyLibraryUninstalled(event: { item: LibraryPackage }): void {
|
||||
this.libraryUninstalledEmitter.fire(event);
|
||||
}
|
||||
|
||||
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
|
||||
this.attachedBoardsChangedEmitter.fire(event);
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { OutputContribution } from '@theia/output/lib/browser/output-contribution';
|
||||
import { OutputChannelManager, OutputChannelSeverity } from '@theia/output/lib/common/output-channel';
|
||||
import { ToolOutputServiceClient, ToolOutputMessage } from '../../common/protocol/tool-output-service';
|
||||
import { OutputService, OutputMessage } from '../common/protocol/output-service';
|
||||
|
||||
@injectable()
|
||||
export class ToolOutputServiceClientImpl implements ToolOutputServiceClient {
|
||||
export class OutputServiceImpl implements OutputService {
|
||||
|
||||
@inject(OutputContribution)
|
||||
protected outputContribution: OutputContribution;
|
||||
@ -12,13 +12,12 @@ export class ToolOutputServiceClientImpl implements ToolOutputServiceClient {
|
||||
@inject(OutputChannelManager)
|
||||
protected outputChannelManager: OutputChannelManager;
|
||||
|
||||
onMessageReceived(message: ToolOutputMessage): void {
|
||||
const { tool, chunk } = message;
|
||||
const name = `Arduino: ${tool}`;
|
||||
const channel = this.outputChannelManager.getChannel(name);
|
||||
append(message: OutputMessage): void {
|
||||
const { name, chunk } = message;
|
||||
const channel = this.outputChannelManager.getChannel(`Arduino: ${name}`);
|
||||
// Zen-mode: we do not reveal the output for daemon messages.
|
||||
const show: Promise<any> = tool === 'daemon'
|
||||
// This will open and reveal the view but won't show it. You will see the toggle bottom panel on the status bar
|
||||
const show: Promise<any> = name === 'daemon'
|
||||
// This will open and reveal the view but won't show it. You will see the toggle bottom panel on the status bar.
|
||||
? this.outputContribution.openView({ activate: false, reveal: false })
|
||||
// This will open, reveal but do not activate the Output view.
|
||||
: Promise.resolve(channel.show({ preserveFocus: true }));
|
||||
@ -26,7 +25,7 @@ export class ToolOutputServiceClientImpl implements ToolOutputServiceClient {
|
||||
show.then(() => channel.append(chunk, this.toOutputSeverity(message)));
|
||||
}
|
||||
|
||||
private toOutputSeverity(message: ToolOutputMessage): OutputChannelSeverity {
|
||||
protected toOutputSeverity(message: OutputMessage): OutputChannelSeverity {
|
||||
if (message.severity) {
|
||||
switch (message.severity) {
|
||||
case 'error': return OutputChannelSeverity.Error
|
@ -6,20 +6,30 @@ import {
|
||||
ApplicationConnectionStatusContribution as TheiaApplicationConnectionStatusContribution,
|
||||
ConnectionStatus
|
||||
} from '@theia/core/lib/browser/connection-status-service';
|
||||
import { ArduinoDaemonClientImpl } from '../../arduino-daemon-client-impl';
|
||||
import { ArduinoDaemon } from '../../../common/protocol';
|
||||
import { NotificationCenter } from '../../notification-center';
|
||||
|
||||
@injectable()
|
||||
export class FrontendConnectionStatusService extends TheiaFrontendConnectionStatusService {
|
||||
|
||||
@inject(ArduinoDaemonClientImpl)
|
||||
protected readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
@inject(ArduinoDaemon)
|
||||
protected readonly daemon: ArduinoDaemon;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected isRunning = false;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
protected async init(): Promise<void> {
|
||||
this.schedulePing();
|
||||
try {
|
||||
this.isRunning = await this.daemon.isRunning();
|
||||
} catch { }
|
||||
this.notificationCenter.onDaemonStarted(() => this.isRunning = true);
|
||||
this.notificationCenter.onDaemonStopped(() => this.isRunning = false);
|
||||
this.wsConnectionProvider.onIncomingMessageActivity(() => {
|
||||
// natural activity
|
||||
this.updateStatus(this.daemonClient.isRunning);
|
||||
this.updateStatus(this.isRunning);
|
||||
this.schedulePing();
|
||||
});
|
||||
}
|
||||
@ -29,22 +39,35 @@ export class FrontendConnectionStatusService extends TheiaFrontendConnectionStat
|
||||
@injectable()
|
||||
export class ApplicationConnectionStatusContribution extends TheiaApplicationConnectionStatusContribution {
|
||||
|
||||
@inject(ArduinoDaemonClientImpl)
|
||||
protected readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
@inject(ArduinoDaemon)
|
||||
protected readonly daemon: ArduinoDaemon;
|
||||
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
protected isRunning = false;
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
try {
|
||||
this.isRunning = await this.daemon.isRunning();
|
||||
} catch { }
|
||||
this.notificationCenter.onDaemonStarted(() => this.isRunning = true);
|
||||
this.notificationCenter.onDaemonStopped(() => this.isRunning = false);
|
||||
}
|
||||
|
||||
protected onStateChange(state: ConnectionStatus): void {
|
||||
if (!this.daemonClient.isRunning && state === ConnectionStatus.ONLINE) {
|
||||
if (!this.isRunning && state === ConnectionStatus.ONLINE) {
|
||||
return;
|
||||
}
|
||||
super.onStateChange(state);
|
||||
}
|
||||
|
||||
protected handleOffline(): void {
|
||||
const { isRunning } = this.daemonClient;
|
||||
this.statusBar.setElement('connection-status', {
|
||||
alignment: StatusBarAlignment.LEFT,
|
||||
text: isRunning ? 'Offline' : '$(bolt) CLI Daemon Offline',
|
||||
tooltip: isRunning ? 'Cannot connect to the backend.' : 'Cannot connect to the CLI daemon.',
|
||||
text: this.isRunning ? 'Offline' : '$(bolt) CLI Daemon Offline',
|
||||
tooltip: this.isRunning ? 'Cannot connect to the backend.' : 'Cannot connect to the CLI daemon.',
|
||||
priority: 5000
|
||||
});
|
||||
this.toDisposeOnOnline.push(Disposable.create(() => this.statusBar.removeElement('connection-status')));
|
||||
|
@ -10,17 +10,13 @@ import { Searchable } from '../../../common/protocol/searchable';
|
||||
import { ArduinoComponent } from '../../../common/protocol/arduino-component';
|
||||
import { FilterableListContainer } from './filterable-list-container';
|
||||
import { ListItemRenderer } from './list-item-renderer';
|
||||
import { CoreServiceClientImpl } from '../../core-service-client-impl';
|
||||
import { ArduinoDaemonClientImpl } from '../../arduino-daemon-client-impl';
|
||||
import { NotificationCenter } from '../../notification-center';
|
||||
|
||||
@injectable()
|
||||
export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget {
|
||||
|
||||
@inject(CoreServiceClientImpl)
|
||||
protected readonly coreServiceClient: CoreServiceClientImpl;
|
||||
|
||||
@inject(ArduinoDaemonClientImpl)
|
||||
protected readonly daemonClient: ArduinoDaemonClientImpl;
|
||||
@inject(NotificationCenter)
|
||||
protected readonly notificationCenter: NotificationCenter;
|
||||
|
||||
/**
|
||||
* Do not touch or use it. It is for setting the focus on the `input` after the widget activation.
|
||||
@ -49,9 +45,9 @@ export abstract class ListWidget<T extends ArduinoComponent> extends ReactWidget
|
||||
protected init(): void {
|
||||
this.update();
|
||||
this.toDispose.pushAll([
|
||||
this.coreServiceClient.onIndexUpdated(() => this.refresh(undefined)),
|
||||
this.daemonClient.onDaemonStarted(() => this.refresh(undefined)),
|
||||
this.daemonClient.onDaemonStopped(() => this.refresh(undefined))
|
||||
this.notificationCenter.onIndexUpdated(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onDaemonStarted(() => this.refresh(undefined)),
|
||||
this.notificationCenter.onDaemonStopped(() => this.refresh(undefined))
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,5 @@
|
||||
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
|
||||
export const ArduinoDaemonClient = Symbol('ArduinoDaemonClient');
|
||||
export interface ArduinoDaemonClient {
|
||||
notifyStarted(): void;
|
||||
notifyStopped(): void;
|
||||
}
|
||||
|
||||
export const ArduinoDaemonPath = '/services/arduino-daemon';
|
||||
export const ArduinoDaemon = Symbol('ArduinoDaemon');
|
||||
export interface ArduinoDaemon extends JsonRpcServer<ArduinoDaemonClient> {
|
||||
export interface ArduinoDaemon {
|
||||
isRunning(): Promise<boolean>;
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { isWindows, isOSX } from '@theia/core/lib/common/os';
|
||||
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { naturalCompare } from './../utils';
|
||||
import { Searchable } from './searchable';
|
||||
import { Installable, InstallableClient } from './installable';
|
||||
import { Installable } from './installable';
|
||||
import { ArduinoComponent } from './arduino-component';
|
||||
|
||||
export interface AttachedBoardsChangeEvent {
|
||||
@ -11,6 +10,45 @@ export interface AttachedBoardsChangeEvent {
|
||||
}
|
||||
export namespace AttachedBoardsChangeEvent {
|
||||
|
||||
export function isEmpty(event: AttachedBoardsChangeEvent): boolean {
|
||||
const { detached, attached } = diff(event);
|
||||
return !!detached.boards.length && !!detached.ports.length && !!attached.boards.length && !!attached.ports.length;
|
||||
}
|
||||
|
||||
export function toString(event: AttachedBoardsChangeEvent): string {
|
||||
let rows: string[] = [];
|
||||
if (!isEmpty(event)) {
|
||||
const { attached, detached } = diff(event);
|
||||
const visitedAttachedPorts: Port[] = [];
|
||||
const visitedDetachedPorts: Port[] = [];
|
||||
for (const board of attached.boards) {
|
||||
const port = board.port ? ` on ${Port.toString(board.port, { useLabel: true })}` : '';
|
||||
rows.push(` - Attached board: ${Board.toString(board)}${port}`);
|
||||
if (board.port) {
|
||||
visitedAttachedPorts.push(board.port);
|
||||
}
|
||||
}
|
||||
for (const board of detached.boards) {
|
||||
const port = board.port ? ` from ${Port.toString(board.port, { useLabel: true })}` : '';
|
||||
rows.push(` - Detached board: ${Board.toString(board)}${port}`);
|
||||
if (board.port) {
|
||||
visitedDetachedPorts.push(board.port);
|
||||
}
|
||||
}
|
||||
for (const port of attached.ports) {
|
||||
if (!visitedAttachedPorts.find(p => Port.sameAs(port, p))) {
|
||||
rows.push(` - New port is available on ${Port.toString(port, { useLabel: true })}`);
|
||||
}
|
||||
}
|
||||
for (const port of detached.ports) {
|
||||
if (!visitedDetachedPorts.find(p => Port.sameAs(port, p))) {
|
||||
rows.push(` - Port is no longer available on ${Port.toString(port, { useLabel: true })}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rows.length ? rows.join('\n') : 'No changes.';
|
||||
}
|
||||
|
||||
export function diff(event: AttachedBoardsChangeEvent): Readonly<{
|
||||
attached: {
|
||||
boards: Board[],
|
||||
@ -45,14 +83,9 @@ export namespace AttachedBoardsChangeEvent {
|
||||
|
||||
}
|
||||
|
||||
export const BoardsServiceClient = Symbol('BoardsServiceClient');
|
||||
export interface BoardsServiceClient extends InstallableClient<BoardsPackage> {
|
||||
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void;
|
||||
}
|
||||
|
||||
export const BoardsServicePath = '/services/boards-service';
|
||||
export const BoardsService = Symbol('BoardsService');
|
||||
export interface BoardsService extends Installable<BoardsPackage>, Searchable<BoardsPackage>, JsonRpcServer<BoardsServiceClient> {
|
||||
export interface BoardsService extends Installable<BoardsPackage>, Searchable<BoardsPackage> {
|
||||
getAttachedBoards(): Promise<Board[]>;
|
||||
getAvailablePorts(): Promise<Port[]>;
|
||||
getBoardDetails(options: { fqbn: string }): Promise<BoardDetails>;
|
||||
@ -185,9 +218,24 @@ export interface BoardsPackage extends ArduinoComponent {
|
||||
readonly boards: Board[];
|
||||
}
|
||||
export namespace BoardsPackage {
|
||||
|
||||
export function equals(left: BoardsPackage, right: BoardsPackage): boolean {
|
||||
return left.id === right.id;
|
||||
}
|
||||
|
||||
export function contains(selectedBoard: Board, { id, boards }: BoardsPackage): boolean {
|
||||
if (boards.some(board => Board.sameAs(board, selectedBoard))) {
|
||||
return true;
|
||||
}
|
||||
if (selectedBoard.fqbn) {
|
||||
const [platform, architecture] = selectedBoard.fqbn.split(':');
|
||||
if (platform && architecture) {
|
||||
return `${platform}:${architecture}` === id;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export interface Board {
|
||||
|
@ -1,14 +1,6 @@
|
||||
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
|
||||
export const ConfigServiceClient = Symbol('ConfigServiceClient');
|
||||
export interface ConfigServiceClient {
|
||||
notifyConfigChanged(config: Config): void;
|
||||
notifyInvalidConfig(): void;
|
||||
}
|
||||
|
||||
export const ConfigServicePath = '/services/config-service';
|
||||
export const ConfigService = Symbol('ConfigService');
|
||||
export interface ConfigService extends JsonRpcServer<ConfigServiceClient> {
|
||||
export interface ConfigService {
|
||||
getVersion(): Promise<string>;
|
||||
getConfiguration(): Promise<Config>;
|
||||
getCliConfigFileUri(): Promise<string>;
|
||||
|
@ -1,14 +1,8 @@
|
||||
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { Programmer } from './boards-service';
|
||||
|
||||
export const CoreServiceClient = Symbol('CoreServiceClient');
|
||||
export interface CoreServiceClient {
|
||||
notifyIndexUpdated(): void;
|
||||
}
|
||||
|
||||
export const CoreServicePath = '/services/core-service';
|
||||
export const CoreService = Symbol('CoreService');
|
||||
export interface CoreService extends JsonRpcServer<CoreServiceClient> {
|
||||
export interface CoreService {
|
||||
compile(options: CoreService.Compile.Options): Promise<void>;
|
||||
upload(options: CoreService.Upload.Options): Promise<void>;
|
||||
burnBootloader(options: CoreService.Bootloader.Options): Promise<void>;
|
||||
|
@ -9,6 +9,7 @@ export * from './library-service';
|
||||
export * from './monitor-service';
|
||||
export * from './searchable';
|
||||
export * from './sketches-service';
|
||||
export * from './tool-output-service';
|
||||
export * from './examples-service';
|
||||
export * from './executable-service';
|
||||
export * from './output-service';
|
||||
export * from './notification-service';
|
||||
|
@ -1,17 +1,6 @@
|
||||
import { naturalCompare } from './../utils';
|
||||
import { ArduinoComponent } from './arduino-component';
|
||||
|
||||
export interface InstalledEvent<T extends ArduinoComponent> {
|
||||
readonly item: Readonly<T>;
|
||||
}
|
||||
export interface UninstalledEvent<T extends ArduinoComponent> {
|
||||
readonly item: Readonly<T>;
|
||||
}
|
||||
export interface InstallableClient<T extends ArduinoComponent> {
|
||||
notifyInstalled(event: InstalledEvent<T>): void
|
||||
notifyUninstalled(event: UninstalledEvent<T>): void
|
||||
}
|
||||
|
||||
export interface Installable<T extends ArduinoComponent> {
|
||||
/**
|
||||
* If `options.version` is specified, that will be installed. Otherwise, `item.availableVersions[0]`.
|
||||
|
@ -1,22 +1,13 @@
|
||||
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { Searchable } from './searchable';
|
||||
import { Installable } from './installable';
|
||||
import { ArduinoComponent } from './arduino-component';
|
||||
import { Installable, InstallableClient } from './installable';
|
||||
|
||||
export const LibraryServicePath = '/services/library-service';
|
||||
export const LibraryService = Symbol('LibraryService');
|
||||
export interface LibraryService extends Installable<LibraryPackage>, Searchable<LibraryPackage> {
|
||||
install(options: { item: LibraryPackage, version?: Installable.Version }): Promise<void>;
|
||||
list(options: LibraryService.List.Options): Promise<LibraryPackage[]>;
|
||||
}
|
||||
|
||||
export const LibraryServiceClient = Symbol('LibraryServiceClient');
|
||||
export interface LibraryServiceClient extends InstallableClient<LibraryPackage> {
|
||||
}
|
||||
|
||||
export const LibraryServiceServerPath = '/services/library-service-server';
|
||||
export const LibraryServiceServer = Symbol('LibraryServiceServer');
|
||||
export interface LibraryServiceServer extends LibraryService, JsonRpcServer<LibraryServiceClient> {
|
||||
}
|
||||
|
||||
export namespace LibraryService {
|
||||
export namespace List {
|
||||
export interface Options {
|
||||
@ -26,31 +17,38 @@ export namespace LibraryService {
|
||||
}
|
||||
|
||||
export enum LibraryLocation {
|
||||
|
||||
/**
|
||||
* In the `libraries` subdirectory of the Arduino IDE installation.
|
||||
*/
|
||||
IDE_BUILTIN = 0,
|
||||
|
||||
/**
|
||||
* In the `libraries` subdirectory of the user directory (sketchbook).
|
||||
*/
|
||||
USER = 1,
|
||||
|
||||
/**
|
||||
* In the `libraries` subdirectory of a platform.
|
||||
*/
|
||||
PLATFORM_BUILTIN = 2,
|
||||
|
||||
/**
|
||||
* When `LibraryLocation` is used in a context where a board is specified, this indicates the library is in the `libraries`
|
||||
* subdirectory of a platform referenced by the board's platform.
|
||||
*/
|
||||
REFERENCED_PLATFORM_BUILTIN = 3
|
||||
|
||||
}
|
||||
|
||||
export interface LibraryPackage extends ArduinoComponent {
|
||||
|
||||
/**
|
||||
* Same as [`Library#real_name`](https://arduino.github.io/arduino-cli/latest/rpc/commands/#library).
|
||||
* Should be used for the UI, and `name` is used to uniquely identify a library. It does not have an ID.
|
||||
*/
|
||||
readonly label: string;
|
||||
|
||||
/**
|
||||
* An array of string that should be included into the `ino` file if this library is used.
|
||||
* For example, including `SD` will prepend `#include <SD.h>` to the `ino` file. While including `Bridge`
|
||||
|
@ -0,0 +1,22 @@
|
||||
import { LibraryPackage } from './library-service';
|
||||
import { JsonRpcServer } from '@theia/core/lib/common/messaging/proxy-factory';
|
||||
import { BoardsPackage, AttachedBoardsChangeEvent } from './boards-service';
|
||||
import { Config } from './config-service';
|
||||
|
||||
export interface NotificationServiceClient {
|
||||
notifyIndexUpdated(): void;
|
||||
notifyDaemonStarted(): void;
|
||||
notifyDaemonStopped(): void;
|
||||
notifyConfigChanged(event: { config: Config | undefined }): void;
|
||||
notifyPlatformInstalled(event: { item: BoardsPackage }): void;
|
||||
notifyPlatformUninstalled(event: { item: BoardsPackage }): void;
|
||||
notifyLibraryInstalled(event: { item: LibraryPackage }): void;
|
||||
notifyLibraryUninstalled(event: { item: LibraryPackage }): void;
|
||||
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void;
|
||||
}
|
||||
|
||||
export const NotificationServicePath = '/services/notification-service';
|
||||
export const NotificationServiceServer = Symbol('NotificationServiceServer');
|
||||
export interface NotificationServiceServer extends Required<NotificationServiceClient>, JsonRpcServer<NotificationServiceClient> {
|
||||
disposeClient(client: NotificationServiceClient): void;
|
||||
}
|
11
arduino-ide-extension/src/common/protocol/output-service.ts
Normal file
11
arduino-ide-extension/src/common/protocol/output-service.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export interface OutputMessage {
|
||||
readonly name: string;
|
||||
readonly chunk: string;
|
||||
readonly severity?: 'error' | 'warning' | 'info';
|
||||
}
|
||||
|
||||
export const OutputServicePath = '/services/output-service';
|
||||
export const OutputService = Symbol('OutputService');
|
||||
export interface OutputService {
|
||||
append(message: OutputMessage): void;
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
import { JsonRpcServer } from '@theia/core';
|
||||
|
||||
export interface ToolOutputMessage {
|
||||
readonly tool: string;
|
||||
readonly chunk: string;
|
||||
readonly severity?: 'error' | 'warning' | 'info';
|
||||
}
|
||||
|
||||
export const ToolOutputServiceServer = Symbol('ToolOutputServiceServer');
|
||||
export interface ToolOutputServiceServer extends JsonRpcServer<ToolOutputServiceClient> {
|
||||
append(message: ToolOutputMessage): void;
|
||||
disposeClient(client: ToolOutputServiceClient): void;
|
||||
}
|
||||
|
||||
export const ToolOutputServiceClient = Symbol('ToolOutputServiceClient');
|
||||
export interface ToolOutputServiceClient {
|
||||
onMessageReceived(message: ToolOutputMessage): void;
|
||||
}
|
||||
|
||||
export namespace ToolOutputService {
|
||||
export const SERVICE_PATH = '/tool-output-service';
|
||||
}
|
@ -9,7 +9,7 @@ import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { environment } from '@theia/application-package/lib/environment';
|
||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
|
||||
import { ArduinoDaemon, ArduinoDaemonClient, ToolOutputServiceServer } from '../common/protocol';
|
||||
import { ArduinoDaemon, NotificationServiceServer } from '../common/protocol';
|
||||
import { DaemonLog } from './daemon-log';
|
||||
import { CLI_CONFIG } from './cli-config';
|
||||
import { getExecPath, spawnCommand } from './exec-util';
|
||||
@ -21,13 +21,12 @@ export class ArduinoDaemonImpl implements ArduinoDaemon, BackendApplicationContr
|
||||
@named('daemon')
|
||||
protected readonly logger: ILogger
|
||||
|
||||
@inject(ToolOutputServiceServer)
|
||||
protected readonly toolOutputService: ToolOutputServiceServer;
|
||||
|
||||
@inject(EnvVariablesServer)
|
||||
protected readonly envVariablesServer: EnvVariablesServer;
|
||||
|
||||
protected readonly clients: Array<ArduinoDaemonClient> = [];
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly notificationService: NotificationServiceServer;
|
||||
|
||||
protected readonly toDispose = new DisposableCollection();
|
||||
protected readonly onDaemonStartedEmitter = new Emitter<void>();
|
||||
protected readonly onDaemonStoppedEmitter = new Emitter<void>();
|
||||
@ -42,37 +41,6 @@ export class ArduinoDaemonImpl implements ArduinoDaemon, BackendApplicationContr
|
||||
this.startDaemon();
|
||||
}
|
||||
|
||||
onStop(): void {
|
||||
this.dispose();
|
||||
}
|
||||
|
||||
// JSON-RPC proxy
|
||||
|
||||
setClient(client: ArduinoDaemonClient | undefined): void {
|
||||
if (client) {
|
||||
if (this._running) {
|
||||
client.notifyStarted()
|
||||
} else {
|
||||
client.notifyStopped();
|
||||
}
|
||||
this.clients.push(client);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.toDispose.dispose();
|
||||
this.clients.length = 0;
|
||||
}
|
||||
|
||||
disposeClient(client: ArduinoDaemonClient): void {
|
||||
const index = this.clients.indexOf(client);
|
||||
if (index === -1) {
|
||||
this.logger.warn('Could not dispose client. It was not registered or was already disposed.');
|
||||
} else {
|
||||
this.clients.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Daemon API
|
||||
|
||||
async isRunning(): Promise<boolean> {
|
||||
@ -184,7 +152,7 @@ export class ArduinoDaemonImpl implements ArduinoDaemon, BackendApplicationContr
|
||||
if (code === 0 || signal === 'SIGINT' || signal === 'SIGKILL') {
|
||||
this.onData('Daemon has stopped.');
|
||||
} else {
|
||||
this.onData(`Daemon exited with ${typeof code === 'undefined' ? `signal '${signal}'` : `exit code: ${code}`}.`, { useOutput: false });
|
||||
this.onData(`Daemon exited with ${typeof code === 'undefined' ? `signal '${signal}'` : `exit code: ${code}`}.`);
|
||||
}
|
||||
});
|
||||
daemon.on('error', error => {
|
||||
@ -198,9 +166,7 @@ export class ArduinoDaemonImpl implements ArduinoDaemon, BackendApplicationContr
|
||||
this._running = true;
|
||||
this._ready.resolve();
|
||||
this.onDaemonStartedEmitter.fire();
|
||||
for (const client of this.clients) {
|
||||
client.notifyStarted();
|
||||
}
|
||||
this.notificationService.notifyDaemonStarted();
|
||||
}
|
||||
|
||||
protected fireDaemonStopped(): void {
|
||||
@ -211,15 +177,10 @@ export class ArduinoDaemonImpl implements ArduinoDaemon, BackendApplicationContr
|
||||
this._ready.reject(); // Reject all pending.
|
||||
this._ready = new Deferred<void>();
|
||||
this.onDaemonStoppedEmitter.fire();
|
||||
for (const client of this.clients) {
|
||||
client.notifyStopped();
|
||||
}
|
||||
this.notificationService.notifyDaemonStopped();
|
||||
}
|
||||
|
||||
protected onData(message: string, options: { useOutput: boolean } = { useOutput: true }): void {
|
||||
if (options.useOutput) {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: DaemonLog.toPrettyString(message) });
|
||||
}
|
||||
protected onData(message: string): void {
|
||||
DaemonLog.log(this.logger, message);
|
||||
}
|
||||
|
||||
|
@ -5,130 +5,169 @@ import { ContainerModule } from 'inversify';
|
||||
import { ArduinoDaemonImpl } from './arduino-daemon-impl';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
|
||||
import { LibraryServiceServerPath, LibraryServiceServer, LibraryServiceClient } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath, BoardsServiceClient } from '../common/protocol/boards-service';
|
||||
import { LibraryServiceServerImpl } from './library-service-server-impl';
|
||||
import { LibraryService, LibraryServicePath } from '../common/protocol/library-service';
|
||||
import { BoardsService, BoardsServicePath } from '../common/protocol/boards-service';
|
||||
import { LibraryServiceImpl } from './library-service-server-impl';
|
||||
import { BoardsServiceImpl } from './boards-service-impl';
|
||||
import { CoreServiceImpl } from './core-service-impl';
|
||||
import { CoreService, CoreServicePath, CoreServiceClient } from '../common/protocol/core-service';
|
||||
import { CoreService, CoreServicePath } from '../common/protocol/core-service';
|
||||
import { ConnectionContainerModule } from '@theia/core/lib/node/messaging/connection-container-module';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import { ToolOutputService, ToolOutputServiceClient, ToolOutputServiceServer } from '../common/protocol/tool-output-service';
|
||||
import { ConnectionHandler, JsonRpcConnectionHandler } from '@theia/core';
|
||||
import { ToolOutputServiceServerImpl } from './tool-output-service-impl';
|
||||
import { DefaultWorkspaceServerExt } from './default-workspace-server-ext';
|
||||
import { WorkspaceServer } from '@theia/workspace/lib/common';
|
||||
import { ConnectionHandler, JsonRpcConnectionHandler, JsonRpcProxy } from '@theia/core';
|
||||
import { DefaultWorkspaceServer } from './theia/workspace/default-workspace-server';
|
||||
import { WorkspaceServer as TheiaWorkspaceServer } from '@theia/workspace/lib/common';
|
||||
import { SketchesServiceImpl } from './sketches-service-impl';
|
||||
import { SketchesService, SketchesServicePath } from '../common/protocol/sketches-service';
|
||||
import { ConfigService, ConfigServicePath, ConfigServiceClient } from '../common/protocol/config-service';
|
||||
import { ArduinoDaemon, ArduinoDaemonPath, ArduinoDaemonClient } from '../common/protocol/arduino-daemon';
|
||||
import { ConfigService, ConfigServicePath } from '../common/protocol/config-service';
|
||||
import { ArduinoDaemon, ArduinoDaemonPath } from '../common/protocol/arduino-daemon';
|
||||
import { MonitorServiceImpl } from './monitor/monitor-service-impl';
|
||||
import { MonitorService, MonitorServicePath, MonitorServiceClient } from '../common/protocol/monitor-service';
|
||||
import { MonitorClientProvider } from './monitor/monitor-client-provider';
|
||||
import { ConfigServiceImpl } from './config-service-impl';
|
||||
import { ArduinoHostedPluginReader } from './arduino-plugin-reader';
|
||||
import { HostedPluginReader } from '@theia/plugin-ext/lib/hosted/node/plugin-reader';
|
||||
import { HostedPluginReader } from './theia/plugin-ext/plugin-reader';
|
||||
import { HostedPluginReader as TheiaHostedPluginReader } from '@theia/plugin-ext/lib/hosted/node/plugin-reader';
|
||||
import { ConfigFileValidator } from './config-file-validator';
|
||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import { ArduinoEnvVariablesServer } from './arduino-env-variables-server';
|
||||
import { EnvVariablesServer as TheiaEnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import { EnvVariablesServer } from './theia/env-variables/env-variables-server';
|
||||
import { NodeFileSystemExt } from './node-filesystem-ext';
|
||||
import { FileSystemExt, FileSystemExtPath } from '../common/protocol/filesystem-ext';
|
||||
import { ExamplesServiceImpl } from './examples-service-impl';
|
||||
import { ExamplesService, ExamplesServicePath } from '../common/protocol/examples-service';
|
||||
import { ExecutableService, ExecutableServicePath } from '../common/protocol/executable-service';
|
||||
import { ExecutableServiceImpl } from './executable-service-impl';
|
||||
import { OutputServicePath, OutputService } from '../common/protocol/output-service';
|
||||
import { NotificationServiceServerImpl } from './notification-service-server';
|
||||
import { NotificationServiceServer, NotificationServiceClient, NotificationServicePath } from '../common/protocol';
|
||||
|
||||
export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
rebind(EnvVariablesServer).to(ArduinoEnvVariablesServer).inSingletonScope();
|
||||
bind(ConfigFileValidator).toSelf().inSingletonScope();
|
||||
// XXX: The config service must start earlier than the daemon, hence the binding order does matter.
|
||||
// Shared config service
|
||||
bind(ConfigFileValidator).toSelf().inSingletonScope();
|
||||
bind(ConfigServiceImpl).toSelf().inSingletonScope();
|
||||
bind(ConfigService).toService(ConfigServiceImpl);
|
||||
// Note: The config service must start earlier than the daemon, hence the binding order of the BA contribution does matter.
|
||||
bind(BackendApplicationContribution).toService(ConfigServiceImpl);
|
||||
bind(ConnectionHandler).toDynamicValue(context =>
|
||||
new JsonRpcConnectionHandler<ConfigServiceClient>(ConfigServicePath, client => {
|
||||
const server = context.container.get<ConfigServiceImpl>(ConfigServiceImpl);
|
||||
server.setClient(client);
|
||||
client.onDidCloseConnection(() => server.disposeClient(client));
|
||||
return server;
|
||||
})
|
||||
).inSingletonScope();
|
||||
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(ConfigServicePath, () => context.container.get(ConfigService))).inSingletonScope();
|
||||
|
||||
// Shared daemon
|
||||
bind(ArduinoDaemonImpl).toSelf().inSingletonScope();
|
||||
bind(ArduinoDaemon).toService(ArduinoDaemonImpl);
|
||||
bind(BackendApplicationContribution).toService(ArduinoDaemonImpl);
|
||||
bind(ConnectionHandler).toDynamicValue(context =>
|
||||
new JsonRpcConnectionHandler<ArduinoDaemonClient>(ArduinoDaemonPath, async client => {
|
||||
const server = context.container.get<ArduinoDaemonImpl>(ArduinoDaemonImpl);
|
||||
server.setClient(client);
|
||||
client.onDidCloseConnection(() => server.disposeClient(client));
|
||||
return server;
|
||||
})
|
||||
).inSingletonScope();
|
||||
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(ArduinoDaemonPath, () => context.container.get(ArduinoDaemon))).inSingletonScope();
|
||||
|
||||
// Shared examples service
|
||||
bind(ExamplesServiceImpl).toSelf().inSingletonScope();
|
||||
bind(ExamplesService).toService(ExamplesServiceImpl);
|
||||
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(ExamplesServicePath, () => context.container.get(ExamplesService))).inSingletonScope();
|
||||
// Examples service. One per backend, each connected FE gets a proxy.
|
||||
bind(ConnectionContainerModule).toConstantValue(ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
// const ExamplesServiceProxy = Symbol('ExamplesServiceProxy');
|
||||
// bind(ExamplesServiceProxy).toDynamicValue(ctx => new Proxy(ctx.container.get(ExamplesService), {}));
|
||||
// bindBackendService(ExamplesServicePath, ExamplesServiceProxy);
|
||||
bind(ExamplesServiceImpl).toSelf().inSingletonScope();
|
||||
bind(ExamplesService).toService(ExamplesServiceImpl);
|
||||
bindBackendService(ExamplesServicePath, ExamplesService);
|
||||
}));
|
||||
|
||||
// Exposes the executable paths/URIs to the frontend
|
||||
bind(ExecutableServiceImpl).toSelf().inSingletonScope();
|
||||
bind(ExecutableService).toService(ExecutableServiceImpl);
|
||||
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(ExecutableServicePath, () => context.container.get(ExecutableService))).inSingletonScope();
|
||||
|
||||
// Library service
|
||||
bind(LibraryServiceServerImpl).toSelf().inSingletonScope();
|
||||
bind(LibraryServiceServer).toService(LibraryServiceServerImpl);
|
||||
bind(ConnectionHandler).toDynamicValue(context =>
|
||||
new JsonRpcConnectionHandler<LibraryServiceClient>(LibraryServiceServerPath, client => {
|
||||
const server = context.container.get<LibraryServiceServerImpl>(LibraryServiceServerImpl);
|
||||
server.setClient(client);
|
||||
client.onDidCloseConnection(() => server.dispose());
|
||||
return server;
|
||||
})
|
||||
).inSingletonScope();
|
||||
// Library service. Singleton per backend, each connected FE gets its proxy.
|
||||
bind(ConnectionContainerModule).toConstantValue(ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
// const LibraryServiceProxy = Symbol('LibraryServiceProxy');
|
||||
// bind(LibraryServiceProxy).toDynamicValue(ctx => new Proxy(ctx.container.get(LibraryService), {}));
|
||||
// bindBackendService(LibraryServicePath, LibraryServiceProxy);
|
||||
bind(LibraryServiceImpl).toSelf().inSingletonScope();
|
||||
bind(LibraryService).toService(LibraryServiceImpl);
|
||||
bindBackendService(LibraryServicePath, LibraryService);
|
||||
}));
|
||||
|
||||
// Shred sketches service
|
||||
bind(SketchesServiceImpl).toSelf().inSingletonScope();
|
||||
bind(SketchesService).toService(SketchesServiceImpl);
|
||||
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(SketchesServicePath, () => context.container.get(SketchesService))).inSingletonScope();
|
||||
|
||||
// Boards service
|
||||
const boardsServiceConnectionModule = ConnectionContainerModule.create(async ({ bind, bindBackendService }) => {
|
||||
// Boards service. One singleton per backend that does the board and port polling. Each connected FE gets its proxy.
|
||||
bind(ConnectionContainerModule).toConstantValue(ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
// const BoardsServiceProxy = Symbol('BoardsServiceProxy');
|
||||
// bind(BoardsServiceProxy).toDynamicValue(ctx => new Proxy(ctx.container.get(BoardsService), {}));
|
||||
// bindBackendService(BoardsServicePath, BoardsServiceProxy);
|
||||
bind(BoardsServiceImpl).toSelf().inSingletonScope();
|
||||
bind(BoardsService).toService(BoardsServiceImpl);
|
||||
bindBackendService<BoardsService, BoardsServiceClient>(BoardsServicePath, BoardsService, (service, client) => {
|
||||
service.setClient(client);
|
||||
bindBackendService<BoardsServiceImpl, JsonRpcProxy<object>>(BoardsServicePath, BoardsService, (service, client) => {
|
||||
client.onDidCloseConnection(() => service.dispose());
|
||||
return service;
|
||||
});
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(boardsServiceConnectionModule);
|
||||
}));
|
||||
|
||||
// Shared Arduino core client provider service for the backend.
|
||||
bind(CoreClientProvider).toSelf().inSingletonScope();
|
||||
|
||||
// Core service -> `verify` and `upload`. One per Theia connection.
|
||||
const connectionConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
// Core service -> `verify` and `upload`. Singleton per BE, each FE connection gets its proxy.
|
||||
bind(ConnectionContainerModule).toConstantValue(ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
// const CoreServiceProxy = Symbol('CoreServiceProxy');
|
||||
// bind(CoreServiceProxy).toDynamicValue(ctx => new Proxy(ctx.container.get(CoreService), {}));
|
||||
// bindBackendService(CoreServicePath, CoreServiceProxy);
|
||||
bind(CoreServiceImpl).toSelf().inSingletonScope();
|
||||
bind(CoreService).toService(CoreServiceImpl);
|
||||
bindBackendService(BoardsServicePath, BoardsService);
|
||||
bindBackendService<CoreService, CoreServiceClient>(CoreServicePath, CoreService, (service, client) => {
|
||||
bindBackendService(CoreServicePath, CoreService);
|
||||
}));
|
||||
|
||||
// #region Theia customizations
|
||||
|
||||
bind(DefaultWorkspaceServer).toSelf().inSingletonScope();
|
||||
rebind(TheiaWorkspaceServer).toService(DefaultWorkspaceServer);
|
||||
|
||||
bind(EnvVariablesServer).toSelf().inSingletonScope();
|
||||
rebind(TheiaEnvVariablesServer).toService(EnvVariablesServer);
|
||||
|
||||
bind(HostedPluginReader).toSelf().inSingletonScope();
|
||||
rebind(TheiaHostedPluginReader).toService(HostedPluginReader);
|
||||
|
||||
// #endregion Theia customizations
|
||||
|
||||
// Shared monitor client provider service for the backend.
|
||||
bind(MonitorClientProvider).toSelf().inSingletonScope();
|
||||
bind(MonitorServiceImpl).toSelf().inSingletonScope();
|
||||
bind(MonitorService).toService(MonitorServiceImpl);
|
||||
bind(ConnectionContainerModule).toConstantValue(ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
const MonitorServiceProxy = Symbol('MonitorServiceProxy');
|
||||
bind(MonitorServiceProxy).toDynamicValue(ctx => new Proxy(ctx.container.get(MonitorService), {}));
|
||||
bindBackendService<MonitorService, MonitorServiceClient>(MonitorServicePath, MonitorServiceProxy, (service, client) => {
|
||||
service.setClient(client);
|
||||
client.onDidCloseConnection(() => service.dispose());
|
||||
return service;
|
||||
});
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(connectionConnectionModule);
|
||||
}));
|
||||
|
||||
// Tool output service -> feedback from the daemon, compile and flash
|
||||
bind(ToolOutputServiceServerImpl).toSelf().inSingletonScope();
|
||||
bind(ToolOutputServiceServer).toService(ToolOutputServiceServerImpl);
|
||||
// Set up cpp extension
|
||||
if (!process.env.CPP_CLANGD_COMMAND) {
|
||||
const segments = ['..', '..', 'build'];
|
||||
if (os.platform() === 'win32') {
|
||||
segments.push('clangd.exe');
|
||||
} else {
|
||||
segments.push('bin');
|
||||
segments.push('clangd');
|
||||
}
|
||||
const clangdCommand = join(__dirname, ...segments);
|
||||
if (fs.existsSync(clangdCommand)) {
|
||||
process.env.CPP_CLANGD_COMMAND = clangdCommand;
|
||||
}
|
||||
}
|
||||
|
||||
// File-system extension for mapping paths to URIs
|
||||
bind(NodeFileSystemExt).toSelf().inSingletonScope();
|
||||
bind(FileSystemExt).toService(NodeFileSystemExt);
|
||||
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(FileSystemExtPath, () => context.container.get(FileSystemExt))).inSingletonScope();
|
||||
|
||||
// Output service per connection.
|
||||
bind(ConnectionContainerModule).toConstantValue(ConnectionContainerModule.create(({ bindFrontendService }) => {
|
||||
bindFrontendService(OutputServicePath, OutputService);
|
||||
}));
|
||||
|
||||
// Notify all connected frontend instances
|
||||
bind(NotificationServiceServerImpl).toSelf().inSingletonScope();
|
||||
bind(NotificationServiceServer).toService(NotificationServiceServerImpl);
|
||||
bind(ConnectionHandler).toDynamicValue(context =>
|
||||
new JsonRpcConnectionHandler<ToolOutputServiceClient>(ToolOutputService.SERVICE_PATH, client => {
|
||||
const server = context.container.get<ToolOutputServiceServer>(ToolOutputServiceServer);
|
||||
new JsonRpcConnectionHandler<NotificationServiceClient>(NotificationServicePath, client => {
|
||||
const server = context.container.get<NotificationServiceServer>(NotificationServiceServer);
|
||||
server.setClient(client);
|
||||
client.onDidCloseConnection(() => server.disposeClient(client));
|
||||
return server;
|
||||
@ -153,52 +192,10 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
|
||||
return parentLogger.child('config');
|
||||
}).inSingletonScope().whenTargetNamed('config');
|
||||
|
||||
// Default workspace server extension to initialize and use a fallback workspace.
|
||||
// If nothing was set previously.
|
||||
bind(DefaultWorkspaceServerExt).toSelf().inSingletonScope();
|
||||
rebind(WorkspaceServer).toService(DefaultWorkspaceServerExt);
|
||||
|
||||
// Shared monitor client provider service for the backend.
|
||||
bind(MonitorClientProvider).toSelf().inSingletonScope();
|
||||
|
||||
// Connection scoped service for the serial monitor.
|
||||
const monitorServiceConnectionModule = ConnectionContainerModule.create(({ bind, bindBackendService }) => {
|
||||
bind(MonitorServiceImpl).toSelf().inSingletonScope();
|
||||
bind(MonitorService).toService(MonitorServiceImpl);
|
||||
bindBackendService<MonitorService, MonitorServiceClient>(MonitorServicePath, MonitorService, (service, client) => {
|
||||
service.setClient(client);
|
||||
client.onDidCloseConnection(() => service.dispose());
|
||||
return service;
|
||||
});
|
||||
});
|
||||
bind(ConnectionContainerModule).toConstantValue(monitorServiceConnectionModule);
|
||||
|
||||
// Logger for the monitor service.
|
||||
bind(ILogger).toDynamicValue(ctx => {
|
||||
const parentLogger = ctx.container.get<ILogger>(ILogger);
|
||||
return parentLogger.child('monitor-service');
|
||||
}).inSingletonScope().whenTargetNamed('monitor-service');
|
||||
|
||||
// Set up cpp extension
|
||||
if (!process.env.CPP_CLANGD_COMMAND) {
|
||||
const segments = ['..', '..', 'build'];
|
||||
if (os.platform() === 'win32') {
|
||||
segments.push('clangd.exe');
|
||||
} else {
|
||||
segments.push('bin');
|
||||
segments.push('clangd');
|
||||
}
|
||||
const clangdCommand = join(__dirname, ...segments);
|
||||
if (fs.existsSync(clangdCommand)) {
|
||||
process.env.CPP_CLANGD_COMMAND = clangdCommand;
|
||||
}
|
||||
}
|
||||
|
||||
bind(ArduinoHostedPluginReader).toSelf().inSingletonScope();
|
||||
rebind(HostedPluginReader).toService(ArduinoHostedPluginReader);
|
||||
|
||||
// File-system extension for mapping paths to URIs
|
||||
bind(NodeFileSystemExt).toSelf().inSingletonScope();
|
||||
bind(FileSystemExt).toService(NodeFileSystemExt);
|
||||
bind(ConnectionHandler).toDynamicValue(context => new JsonRpcConnectionHandler(FileSystemExtPath, () => context.container.get(FileSystemExt))).inSingletonScope();
|
||||
});
|
||||
|
@ -1,19 +1,22 @@
|
||||
import { injectable, inject, postConstruct, named } from 'inversify';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { BoardsService, BoardsPackage, Board, BoardsServiceClient, Port, BoardDetails, Tool, ConfigOption, ConfigValue, Programmer } from '../common/protocol';
|
||||
import {
|
||||
BoardsService,
|
||||
BoardsPackage, Board, Port, BoardDetails, Tool, ConfigOption, ConfigValue, Programmer, OutputService, NotificationServiceServer, AttachedBoardsChangeEvent
|
||||
} from '../common/protocol';
|
||||
import {
|
||||
PlatformSearchReq, PlatformSearchResp, PlatformInstallReq, PlatformInstallResp, PlatformListReq,
|
||||
PlatformListResp, Platform, PlatformUninstallResp, PlatformUninstallReq
|
||||
} from './cli-protocol/commands/core_pb';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import { BoardListReq, BoardListResp, BoardDetailsReq, BoardDetailsResp } from './cli-protocol/commands/board_pb';
|
||||
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
|
||||
import { Installable } from '../common/protocol/installable';
|
||||
import { ListProgrammersAvailableForUploadReq, ListProgrammersAvailableForUploadResp } from './cli-protocol/commands/upload_pb';
|
||||
import { Disposable } from '@theia/core/lib/common/disposable';
|
||||
|
||||
@injectable()
|
||||
export class BoardsServiceImpl implements BoardsService {
|
||||
export class BoardsServiceImpl implements BoardsService, Disposable {
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
@ -25,8 +28,11 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
@inject(ToolOutputServiceServer)
|
||||
protected readonly toolOutputService: ToolOutputServiceServer;
|
||||
@inject(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly notificationService: NotificationServiceServer;
|
||||
|
||||
protected discoveryInitialized = false;
|
||||
protected discoveryTimer: NodeJS.Timer | undefined;
|
||||
@ -38,7 +44,6 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
protected attachedBoards: Board[] = [];
|
||||
protected availablePorts: Port[] = [];
|
||||
protected started = new Deferred<void>();
|
||||
protected client: BoardsServiceClient | undefined;
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
@ -49,19 +54,19 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
const update = (oldBoards: Board[], newBoards: Board[], oldPorts: Port[], newPorts: Port[], message: string) => {
|
||||
this.attachedBoards = newBoards;
|
||||
this.availablePorts = newPorts;
|
||||
this.discoveryLogger.info(`${message} - Discovered boards: ${JSON.stringify(newBoards)} and available ports: ${JSON.stringify(newPorts)}`);
|
||||
if (this.client) {
|
||||
this.client.notifyAttachedBoardsChanged({
|
||||
oldState: {
|
||||
boards: oldBoards,
|
||||
ports: oldPorts
|
||||
},
|
||||
newState: {
|
||||
boards: newBoards,
|
||||
ports: newPorts
|
||||
}
|
||||
});
|
||||
}
|
||||
const event = {
|
||||
oldState: {
|
||||
boards: oldBoards,
|
||||
ports: oldPorts
|
||||
},
|
||||
newState: {
|
||||
boards: newBoards,
|
||||
ports: newPorts
|
||||
}
|
||||
};
|
||||
this.discoveryLogger.info(`${message}`);
|
||||
this.discoveryLogger.info(`${AttachedBoardsChangeEvent.toString(event)}`);
|
||||
this.notificationService.notifyAttachedBoardsChanged(event);
|
||||
}
|
||||
const sortedBoards = boards.sort(Board.compare);
|
||||
const sortedPorts = ports.sort(Port.compare);
|
||||
@ -103,16 +108,13 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
setClient(client: BoardsServiceClient | undefined): void {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.logger.info('>>> Disposing boards service...');
|
||||
if (this.discoveryTimer !== undefined) {
|
||||
this.logger.info('>>> Disposing the boards discovery...');
|
||||
clearInterval(this.discoveryTimer);
|
||||
this.logger.info('<<< Disposed the boards discovery.');
|
||||
}
|
||||
this.client = undefined;
|
||||
this.logger.info('<<< Disposed boards service.');
|
||||
}
|
||||
|
||||
@ -213,14 +215,28 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
const detailsReq = new BoardDetailsReq();
|
||||
detailsReq.setInstance(instance);
|
||||
detailsReq.setFqbn(fqbn);
|
||||
const detailsResp = await new Promise<BoardDetailsResp>((resolve, reject) => client.boardDetails(detailsReq, (err, resp) => {
|
||||
const detailsResp = await new Promise<BoardDetailsResp | undefined>((resolve, reject) => client.boardDetails(detailsReq, (err, resp) => {
|
||||
if (err) {
|
||||
// Required cores are not installed manually: https://github.com/arduino/arduino-cli/issues/954
|
||||
if (err.message.indexOf('missing platform release') !== -1 && err.message.indexOf('referenced by board') !== -1) {
|
||||
resolve(undefined);
|
||||
return;
|
||||
}
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
resolve(resp);
|
||||
}));
|
||||
|
||||
if (!detailsResp) {
|
||||
return {
|
||||
fqbn,
|
||||
configOptions: [],
|
||||
programmers: [],
|
||||
requiredTools: []
|
||||
};
|
||||
}
|
||||
|
||||
const requiredTools = detailsResp.getToolsdependenciesList().map(t => <Tool>{
|
||||
name: t.getName(),
|
||||
packager: t.getPackager(),
|
||||
@ -391,18 +407,17 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
resp.on('data', (r: PlatformInstallResp) => {
|
||||
const prog = r.getProgress();
|
||||
if (prog && prog.getFile()) {
|
||||
this.toolOutputService.append({ tool: 'board download', chunk: `downloading ${prog.getFile()}\n` });
|
||||
this.outputService.append({ name: 'board download', chunk: `downloading ${prog.getFile()}\n` });
|
||||
}
|
||||
});
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
resp.on('end', resolve);
|
||||
resp.on('error', reject);
|
||||
});
|
||||
if (this.client) {
|
||||
const items = await this.search({});
|
||||
const updated = items.find(other => BoardsPackage.equals(other, item)) || item;
|
||||
this.client.notifyInstalled({ item: updated });
|
||||
}
|
||||
|
||||
const items = await this.search({});
|
||||
const updated = items.find(other => BoardsPackage.equals(other, item)) || item;
|
||||
this.notificationService.notifyPlatformInstalled({ item: updated });
|
||||
console.info('<<< Boards package installation done.', item);
|
||||
}
|
||||
|
||||
@ -426,7 +441,7 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
const resp = client.platformUninstall(req);
|
||||
resp.on('data', (_: PlatformUninstallResp) => {
|
||||
if (!logged) {
|
||||
this.toolOutputService.append({ tool: 'board uninstall', chunk: `uninstalling ${item.id}\n` });
|
||||
this.outputService.append({ name: 'board uninstall', chunk: `uninstalling ${item.id}\n` });
|
||||
logged = true;
|
||||
}
|
||||
})
|
||||
@ -434,10 +449,9 @@ export class BoardsServiceImpl implements BoardsService {
|
||||
resp.on('end', resolve);
|
||||
resp.on('error', reject);
|
||||
});
|
||||
if (this.client) {
|
||||
// Here, unlike at `install` we send out the argument `item`. Otherwise, we would not know about the board FQBN.
|
||||
this.client.notifyUninstalled({ item });
|
||||
}
|
||||
|
||||
// Here, unlike at `install` we send out the argument `item`. Otherwise, we would not know about the board FQBN.
|
||||
this.notificationService.notifyPlatformUninstalled({ item });
|
||||
console.info('<<< Boards package uninstallation done.', item);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { BackendApplicationContribution } from '@theia/core/lib/node/backend-application';
|
||||
import { ConfigService, Config, ConfigServiceClient } from '../common/protocol';
|
||||
import { ConfigService, Config, NotificationServiceServer } from '../common/protocol';
|
||||
import * as fs from './fs-extra';
|
||||
import { spawnCommand } from './exec-util';
|
||||
import { RawData } from './cli-protocol/settings/settings_pb';
|
||||
@ -38,10 +38,12 @@ export class ConfigServiceImpl implements BackendApplicationContribution, Config
|
||||
@inject(ArduinoDaemonImpl)
|
||||
protected readonly daemon: ArduinoDaemonImpl;
|
||||
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly notificationService: NotificationServiceServer;
|
||||
|
||||
protected updating = false;
|
||||
protected config: Config;
|
||||
protected cliConfig: DefaultCliConfig | undefined;
|
||||
protected clients: Array<ConfigServiceClient> = [];
|
||||
protected ready = new Deferred<void>();
|
||||
protected readonly configChangeEmitter = new Emitter<Config>();
|
||||
|
||||
@ -94,25 +96,6 @@ export class ConfigServiceImpl implements BackendApplicationContribution, Config
|
||||
return this.getConfiguration().then(({ sketchDirUri }) => new URI(sketchDirUri).isEqualOrParent(new URI(uri)));
|
||||
}
|
||||
|
||||
setClient(client: ConfigServiceClient | undefined): void {
|
||||
if (client) {
|
||||
this.clients.push(client);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.clients.length = 0;
|
||||
}
|
||||
|
||||
disposeClient(client: ConfigServiceClient): void {
|
||||
const index = this.clients.indexOf(client);
|
||||
if (index === -1) {
|
||||
this.logger.warn('Could not dispose client. It was not registered or was already disposed.');
|
||||
} else {
|
||||
this.clients.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
protected async loadCliConfig(): Promise<DefaultCliConfig | undefined> {
|
||||
const cliConfigFileUri = await this.getCliConfigFileUri();
|
||||
const cliConfigPath = FileUri.fsPath(cliConfigFileUri);
|
||||
@ -214,9 +197,7 @@ export class ConfigServiceImpl implements BackendApplicationContribution, Config
|
||||
this.cliConfig = cliConfig;
|
||||
this.config = config;
|
||||
this.configChangeEmitter.fire(this.config);
|
||||
for (const client of this.clients) {
|
||||
client.notifyConfigChanged(this.config);
|
||||
}
|
||||
this.notificationService.notifyConfigChanged({ config: this.config });
|
||||
}).finally(() => this.updating = false);
|
||||
} catch (err) {
|
||||
this.logger.error('Failed to update the daemon with the current CLI configuration.', err);
|
||||
@ -227,15 +208,11 @@ export class ConfigServiceImpl implements BackendApplicationContribution, Config
|
||||
}
|
||||
|
||||
protected fireConfigChanged(config: Config): void {
|
||||
for (const client of this.clients) {
|
||||
client.notifyConfigChanged(config);
|
||||
}
|
||||
this.notificationService.notifyConfigChanged({ config });
|
||||
}
|
||||
|
||||
protected fireInvalidConfig(): void {
|
||||
for (const client of this.clients) {
|
||||
client.notifyInvalidConfig();
|
||||
}
|
||||
this.notificationService.notifyConfigChanged({ config: undefined });
|
||||
}
|
||||
|
||||
protected async unwatchCliConfig(): Promise<void> {
|
||||
|
@ -1,26 +1,21 @@
|
||||
import * as grpc from '@grpc/grpc-js';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { Event, Emitter } from '@theia/core/lib/common/event';
|
||||
import { ToolOutputServiceServer } from '../common/protocol';
|
||||
import { GrpcClientProvider } from './grpc-client-provider';
|
||||
import { ArduinoCoreClient } from './cli-protocol/commands/commands_grpc_pb';
|
||||
import * as commandsGrpcPb from './cli-protocol/commands/commands_grpc_pb';
|
||||
import { Instance } from './cli-protocol/commands/common_pb';
|
||||
import { InitReq, InitResp, UpdateIndexReq, UpdateIndexResp, UpdateLibrariesIndexResp, UpdateLibrariesIndexReq } from './cli-protocol/commands/commands_pb';
|
||||
import { NotificationServiceServer } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Client> {
|
||||
|
||||
@inject(ToolOutputServiceServer)
|
||||
protected readonly toolOutputService: ToolOutputServiceServer;
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly notificationService: NotificationServiceServer;
|
||||
|
||||
protected readonly onIndexUpdatedEmitter = new Emitter<void>();
|
||||
protected readonly onClientReadyEmitter = new Emitter<void>();
|
||||
|
||||
get onIndexUpdated(): Event<void> {
|
||||
return this.onIndexUpdatedEmitter.event;
|
||||
}
|
||||
|
||||
get onClientReady(): Event<void> {
|
||||
return this.onClientReadyEmitter.event;
|
||||
}
|
||||
@ -76,11 +71,11 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
|
||||
indexUpdateSucceeded = true;
|
||||
break;
|
||||
} catch (e) {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `Error while updating index in attempt ${i}: ${e}`, severity: 'error' });
|
||||
console.error(`Error while updating index in attempt ${i}.`, e);
|
||||
}
|
||||
}
|
||||
if (!indexUpdateSucceeded) {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: 'Was unable to update the index. Please restart to try again.', severity: 'error' });
|
||||
console.error('Could not update the index. Please restart to try again.');
|
||||
}
|
||||
|
||||
let libIndexUpdateSucceeded = true;
|
||||
@ -90,15 +85,15 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
|
||||
libIndexUpdateSucceeded = true;
|
||||
break;
|
||||
} catch (e) {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `Error while updating library index in attempt ${i}: ${e}`, severity: 'error' });
|
||||
console.error(`Error while updating library index in attempt ${i}.`, e);
|
||||
}
|
||||
}
|
||||
if (!libIndexUpdateSucceeded) {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `Was unable to update the library index. Please restart to try again.`, severity: 'error' });
|
||||
console.error('Could not update the library index. Please restart to try again.');
|
||||
}
|
||||
|
||||
if (indexUpdateSucceeded && libIndexUpdateSucceeded) {
|
||||
this.onIndexUpdatedEmitter.fire();
|
||||
this.notificationService.notifyIndexUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,12 +111,12 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
|
||||
if (progress.getCompleted()) {
|
||||
if (file) {
|
||||
if (/\s/.test(file)) {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `${file} completed.\n` });
|
||||
console.log(`${file} completed.`);
|
||||
} else {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `Download of '${file}' completed.\n'` });
|
||||
console.log(`Download of '${file}' completed.`);
|
||||
}
|
||||
} else {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `The library index has been successfully updated.\n'` });
|
||||
console.log('The library index has been successfully updated.');
|
||||
}
|
||||
file = undefined;
|
||||
}
|
||||
@ -147,12 +142,12 @@ export class CoreClientProvider extends GrpcClientProvider<CoreClientProvider.Cl
|
||||
if (progress.getCompleted()) {
|
||||
if (file) {
|
||||
if (/\s/.test(file)) {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `${file} completed.\n` });
|
||||
console.log(`${file} completed.`);
|
||||
} else {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `Download of '${file}' completed.\n'` });
|
||||
console.log(`Download of '${file}' completed.`);
|
||||
}
|
||||
} else {
|
||||
this.toolOutputService.append({ tool: 'daemon', chunk: `The index has been successfully updated.\n'` });
|
||||
console.log('The index has been successfully updated.');
|
||||
}
|
||||
file = undefined;
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { inject, injectable, postConstruct } from 'inversify';
|
||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
import { CoreService, CoreServiceClient } from '../common/protocol/core-service';
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { dirname } from 'path';
|
||||
import { CoreService } from '../common/protocol/core-service';
|
||||
import { CompileReq, CompileResp } from './cli-protocol/commands/compile_pb';
|
||||
import { BoardsService } from '../common/protocol/boards-service';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import * as path from 'path';
|
||||
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
|
||||
import { UploadReq, UploadResp, BurnBootloaderReq, BurnBootloaderResp } from './cli-protocol/commands/upload_pb';
|
||||
import { OutputService } from '../common/protocol/output-service';
|
||||
import { NotificationServiceServer } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class CoreServiceImpl implements CoreService {
|
||||
@ -14,29 +14,17 @@ export class CoreServiceImpl implements CoreService {
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
@inject(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
|
||||
@inject(BoardsService)
|
||||
protected readonly boardsService: BoardsService;
|
||||
|
||||
@inject(ToolOutputServiceServer)
|
||||
protected readonly toolOutputService: ToolOutputServiceServer;
|
||||
|
||||
protected client: CoreServiceClient | undefined;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
this.coreClientProvider.onIndexUpdated(() => {
|
||||
if (this.client) {
|
||||
this.client.notifyIndexUpdated();
|
||||
}
|
||||
})
|
||||
}
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly notificationService: NotificationServiceServer;
|
||||
|
||||
async compile(options: CoreService.Compile.Options): Promise<void> {
|
||||
this.toolOutputService.append({ tool: 'compile', chunk: 'Compiling...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' });
|
||||
this.outputService.append({ name: 'compile', chunk: 'Compiling...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' });
|
||||
const { sketchUri, fqbn } = options;
|
||||
const sketchFilePath = FileUri.fsPath(sketchUri);
|
||||
const sketchpath = path.dirname(sketchFilePath);
|
||||
const sketchpath = dirname(sketchFilePath);
|
||||
|
||||
const coreClient = await this.coreClientProvider.client();
|
||||
if (!coreClient) {
|
||||
@ -61,25 +49,25 @@ export class CoreServiceImpl implements CoreService {
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
result.on('data', (cr: CompileResp) => {
|
||||
this.toolOutputService.append({ tool: 'compile', chunk: Buffer.from(cr.getOutStream_asU8()).toString() });
|
||||
this.toolOutputService.append({ tool: 'compile', chunk: Buffer.from(cr.getErrStream_asU8()).toString() });
|
||||
this.outputService.append({ name: 'compile', chunk: Buffer.from(cr.getOutStream_asU8()).toString() });
|
||||
this.outputService.append({ name: 'compile', chunk: Buffer.from(cr.getErrStream_asU8()).toString() });
|
||||
});
|
||||
result.on('error', error => reject(error));
|
||||
result.on('end', () => resolve());
|
||||
});
|
||||
this.toolOutputService.append({ tool: 'compile', chunk: '\n--------------------------\nCompilation complete.\n' });
|
||||
this.outputService.append({ name: 'compile', chunk: '\n--------------------------\nCompilation complete.\n' });
|
||||
} catch (e) {
|
||||
this.toolOutputService.append({ tool: 'compile', chunk: `Compilation error: ${e}\n`, severity: 'error' });
|
||||
this.outputService.append({ name: 'compile', chunk: `Compilation error: ${e}\n`, severity: 'error' });
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
async upload(options: CoreService.Upload.Options): Promise<void> {
|
||||
await this.compile(options);
|
||||
this.toolOutputService.append({ tool: 'upload', chunk: 'Uploading...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' });
|
||||
this.outputService.append({ name: 'upload', chunk: 'Uploading...\n' + JSON.stringify(options, null, 2) + '\n--------------------------\n' });
|
||||
const { sketchUri, fqbn } = options;
|
||||
const sketchFilePath = FileUri.fsPath(sketchUri);
|
||||
const sketchpath = path.dirname(sketchFilePath);
|
||||
const sketchpath = dirname(sketchFilePath);
|
||||
|
||||
const coreClient = await this.coreClientProvider.client();
|
||||
if (!coreClient) {
|
||||
@ -106,15 +94,15 @@ export class CoreServiceImpl implements CoreService {
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
result.on('data', (resp: UploadResp) => {
|
||||
this.toolOutputService.append({ tool: 'upload', chunk: Buffer.from(resp.getOutStream_asU8()).toString() });
|
||||
this.toolOutputService.append({ tool: 'upload', chunk: Buffer.from(resp.getErrStream_asU8()).toString() });
|
||||
this.outputService.append({ name: 'upload', chunk: Buffer.from(resp.getOutStream_asU8()).toString() });
|
||||
this.outputService.append({ name: 'upload', chunk: Buffer.from(resp.getErrStream_asU8()).toString() });
|
||||
});
|
||||
result.on('error', error => reject(error));
|
||||
result.on('end', () => resolve());
|
||||
});
|
||||
this.toolOutputService.append({ tool: 'upload', chunk: '\n--------------------------\nUpload complete.\n' });
|
||||
this.outputService.append({ name: 'upload', chunk: '\n--------------------------\nUpload complete.\n' });
|
||||
} catch (e) {
|
||||
this.toolOutputService.append({ tool: 'upload', chunk: `Upload error: ${e}\n`, severity: 'error' });
|
||||
this.outputService.append({ name: 'upload', chunk: `Upload error: ${e}\n`, severity: 'error' });
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@ -141,24 +129,16 @@ export class CoreServiceImpl implements CoreService {
|
||||
try {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
result.on('data', (resp: BurnBootloaderResp) => {
|
||||
this.toolOutputService.append({ tool: 'bootloader', chunk: Buffer.from(resp.getOutStream_asU8()).toString() });
|
||||
this.toolOutputService.append({ tool: 'bootloader', chunk: Buffer.from(resp.getErrStream_asU8()).toString() });
|
||||
this.outputService.append({ name: 'bootloader', chunk: Buffer.from(resp.getOutStream_asU8()).toString() });
|
||||
this.outputService.append({ name: 'bootloader', chunk: Buffer.from(resp.getErrStream_asU8()).toString() });
|
||||
});
|
||||
result.on('error', error => reject(error));
|
||||
result.on('end', () => resolve());
|
||||
});
|
||||
} catch (e) {
|
||||
this.toolOutputService.append({ tool: 'bootloader', chunk: `Error while burning the bootloader: ${e}\n`, severity: 'error' });
|
||||
this.outputService.append({ name: 'bootloader', chunk: `Error while burning the bootloader: ${e}\n`, severity: 'error' });
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
setClient(client: CoreServiceClient | undefined): void {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.client = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import { notEmpty } from '@theia/core/lib/common/objects';
|
||||
import { Sketch } from '../common/protocol/sketches-service';
|
||||
import { SketchesServiceImpl } from './sketches-service-impl';
|
||||
import { ExamplesService, ExampleContainer } from '../common/protocol/examples-service';
|
||||
import { LibraryServiceServer, LibraryLocation, LibraryPackage } from '../common/protocol';
|
||||
import { LibraryLocation, LibraryPackage, LibraryService } from '../common/protocol';
|
||||
import { ConfigServiceImpl } from './config-service-impl';
|
||||
|
||||
@injectable()
|
||||
@ -15,8 +15,8 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
@inject(SketchesServiceImpl)
|
||||
protected readonly sketchesService: SketchesServiceImpl;
|
||||
|
||||
@inject(LibraryServiceServer)
|
||||
protected readonly libraryService: LibraryServiceServer;
|
||||
@inject(LibraryService)
|
||||
protected readonly libraryService: LibraryService;
|
||||
|
||||
@inject(ConfigServiceImpl)
|
||||
protected readonly configService: ConfigServiceImpl;
|
||||
@ -44,7 +44,7 @@ export class ExamplesServiceImpl implements ExamplesService {
|
||||
const current: ExampleContainer[] = [];
|
||||
const any: ExampleContainer[] = [];
|
||||
if (fqbn) {
|
||||
const packages = await this.libraryService.list({ fqbn });
|
||||
const packages: LibraryPackage[] = await this.libraryService.list({ fqbn });
|
||||
for (const pkg of packages) {
|
||||
const container = await this.tryGroupExamples(pkg);
|
||||
const { location } = pkg;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { injectable, inject, postConstruct } from 'inversify';
|
||||
import { LibraryPackage, LibraryServiceClient, LibraryServiceServer } from '../common/protocol/library-service';
|
||||
import { LibraryPackage, LibraryService } from '../common/protocol/library-service';
|
||||
import { CoreClientProvider } from './core-client-provider';
|
||||
import {
|
||||
LibrarySearchReq,
|
||||
@ -14,14 +14,14 @@ import {
|
||||
LibraryUninstallResp,
|
||||
Library
|
||||
} from './cli-protocol/commands/lib_pb';
|
||||
import { ToolOutputServiceServer } from '../common/protocol/tool-output-service';
|
||||
import { Installable } from '../common/protocol/installable';
|
||||
import { ILogger, notEmpty } from '@theia/core';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import { FileUri } from '@theia/core/lib/node';
|
||||
import { OutputService, NotificationServiceServer } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
export class LibraryServiceImpl implements LibraryService {
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
@ -29,11 +29,13 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
@inject(CoreClientProvider)
|
||||
protected readonly coreClientProvider: CoreClientProvider;
|
||||
|
||||
@inject(ToolOutputServiceServer)
|
||||
protected readonly toolOutputService: ToolOutputServiceServer;
|
||||
@inject(OutputService)
|
||||
protected readonly outputService: OutputService;
|
||||
|
||||
@inject(NotificationServiceServer)
|
||||
protected readonly notificationServer: NotificationServiceServer;
|
||||
|
||||
protected ready = new Deferred<void>();
|
||||
protected client: LibraryServiceClient | undefined;
|
||||
|
||||
@postConstruct()
|
||||
protected init(): void {
|
||||
@ -108,7 +110,31 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
req.setFqbn(fqbn);
|
||||
}
|
||||
|
||||
const resp = await new Promise<LibraryListResp>((resolve, reject) => client.libraryList(req, ((error, resp) => !!error ? reject(error) : resolve(resp))));
|
||||
const resp = await new Promise<LibraryListResp | undefined>((resolve, reject) => {
|
||||
client.libraryList(req, ((error, r) => {
|
||||
if (error) {
|
||||
const { message } = error;
|
||||
// Required core dependency is missing.
|
||||
// https://github.com/arduino/arduino-cli/issues/954
|
||||
if (message.indexOf('missing platform release') !== -1 && message.indexOf('referenced by board') !== -1) {
|
||||
resolve(undefined);
|
||||
return;
|
||||
}
|
||||
// The core for the board is not installed, `lib list` cannot be filtered based on FQBN.
|
||||
// https://github.com/arduino/arduino-cli/issues/955
|
||||
if (message.indexOf('platform') !== -1 && message.indexOf('is not installed') !== -1) {
|
||||
resolve(undefined);
|
||||
return;
|
||||
}
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve(r);
|
||||
}));
|
||||
});
|
||||
if (!resp) {
|
||||
return [];
|
||||
}
|
||||
return resp.getInstalledLibraryList().map(item => {
|
||||
const library = item.getLibrary();
|
||||
if (!library) {
|
||||
@ -151,7 +177,7 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
resp.on('data', (r: LibraryInstallResp) => {
|
||||
const prog = r.getProgress();
|
||||
if (prog) {
|
||||
this.toolOutputService.append({ tool: 'library', chunk: `downloading ${prog.getFile()}: ${prog.getCompleted()}%\n` });
|
||||
this.outputService.append({ name: 'library', chunk: `downloading ${prog.getFile()}: ${prog.getCompleted()}%\n` });
|
||||
}
|
||||
});
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
@ -159,12 +185,9 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
resp.on('error', reject);
|
||||
});
|
||||
|
||||
if (this.client) {
|
||||
const items = await this.search({});
|
||||
const updated = items.find(other => LibraryPackage.equals(other, item)) || item;
|
||||
this.client.notifyInstalled({ item: updated });
|
||||
}
|
||||
|
||||
const items = await this.search({});
|
||||
const updated = items.find(other => LibraryPackage.equals(other, item)) || item;
|
||||
this.notificationServer.notifyLibraryInstalled({ item: updated });
|
||||
console.info('<<< Library package installation done.', item);
|
||||
}
|
||||
|
||||
@ -186,7 +209,7 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
const resp = client.libraryUninstall(req);
|
||||
resp.on('data', (_: LibraryUninstallResp) => {
|
||||
if (!logged) {
|
||||
this.toolOutputService.append({ tool: 'library', chunk: `uninstalling ${item.name}:${item.installedVersion}%\n` });
|
||||
this.outputService.append({ name: 'library', chunk: `uninstalling ${item.name}:${item.installedVersion}%\n` });
|
||||
logged = true;
|
||||
}
|
||||
});
|
||||
@ -194,19 +217,13 @@ export class LibraryServiceServerImpl implements LibraryServiceServer {
|
||||
resp.on('end', resolve);
|
||||
resp.on('error', reject);
|
||||
});
|
||||
if (this.client) {
|
||||
this.client.notifyUninstalled({ item });
|
||||
}
|
||||
console.info('<<< Library package uninstallation done.', item);
|
||||
}
|
||||
|
||||
setClient(client: LibraryServiceClient | undefined): void {
|
||||
this.client = client;
|
||||
this.notificationServer.notifyLibraryUninstalled({ item });
|
||||
console.info('<<< Library package uninstallation done.', item);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.logger.info('>>> Disposing library service...');
|
||||
this.client = undefined;
|
||||
this.logger.info('<<< Disposed library service.');
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,65 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { NotificationServiceServer, NotificationServiceClient, AttachedBoardsChangeEvent, BoardsPackage, LibraryPackage, Config } from '../common/protocol';
|
||||
|
||||
@injectable()
|
||||
export class NotificationServiceServerImpl implements NotificationServiceServer {
|
||||
|
||||
protected readonly clients: NotificationServiceClient[] = [];
|
||||
|
||||
notifyIndexUpdated(): void {
|
||||
this.clients.forEach(client => client.notifyIndexUpdated());
|
||||
}
|
||||
|
||||
notifyDaemonStarted(): void {
|
||||
this.clients.forEach(client => client.notifyDaemonStarted());
|
||||
}
|
||||
|
||||
notifyDaemonStopped(): void {
|
||||
this.clients.forEach(client => client.notifyDaemonStopped());
|
||||
}
|
||||
|
||||
notifyPlatformInstalled(event: { item: BoardsPackage }): void {
|
||||
this.clients.forEach(client => client.notifyPlatformInstalled(event));
|
||||
}
|
||||
|
||||
notifyPlatformUninstalled(event: { item: BoardsPackage }): void {
|
||||
this.clients.forEach(client => client.notifyPlatformUninstalled(event));
|
||||
}
|
||||
|
||||
notifyLibraryInstalled(event: { item: LibraryPackage }): void {
|
||||
this.clients.forEach(client => client.notifyLibraryInstalled(event));
|
||||
}
|
||||
|
||||
notifyLibraryUninstalled(event: { item: LibraryPackage }): void {
|
||||
this.clients.forEach(client => client.notifyLibraryUninstalled(event));
|
||||
}
|
||||
|
||||
notifyAttachedBoardsChanged(event: AttachedBoardsChangeEvent): void {
|
||||
this.clients.forEach(client => client.notifyAttachedBoardsChanged(event));
|
||||
}
|
||||
|
||||
notifyConfigChanged(event: { config: Config | undefined }): void {
|
||||
this.clients.forEach(client => client.notifyConfigChanged(event));
|
||||
}
|
||||
|
||||
setClient(client: NotificationServiceClient): void {
|
||||
this.clients.push(client);
|
||||
}
|
||||
|
||||
disposeClient(client: NotificationServiceClient): void {
|
||||
const index = this.clients.indexOf(client);
|
||||
if (index === -1) {
|
||||
console.warn(`Could not dispose notification service client. It was not registered.`);
|
||||
return;
|
||||
}
|
||||
this.clients.splice(index, 1);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (const client of this.clients) {
|
||||
this.disposeClient(client);
|
||||
}
|
||||
this.clients.length = 0;
|
||||
}
|
||||
|
||||
}
|
@ -2,11 +2,11 @@ import { join } from 'path';
|
||||
import { homedir } from 'os';
|
||||
import { injectable } from 'inversify';
|
||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
import { EnvVariablesServerImpl } from '@theia/core/lib/node/env-variables/env-variables-server';
|
||||
import { BackendApplicationConfigProvider } from '@theia/core/lib/node/backend-application-config-provider';
|
||||
import { EnvVariablesServerImpl as TheiaEnvVariablesServerImpl } from '@theia/core/lib/node/env-variables/env-variables-server';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoEnvVariablesServer extends EnvVariablesServerImpl {
|
||||
export class EnvVariablesServer extends TheiaEnvVariablesServerImpl {
|
||||
|
||||
protected readonly configDirUri = Promise.resolve(FileUri.create(join(homedir(), BackendApplicationConfigProvider.get().configDirName)).toString());
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { HostedPluginReader } from '@theia/plugin-ext/lib/hosted/node/plugin-reader';
|
||||
import { HostedPluginReader as TheiaHostedPluginReader } from '@theia/plugin-ext/lib/hosted/node/plugin-reader';
|
||||
import { PluginPackage, PluginContribution } from '@theia/plugin-ext/lib/common/plugin-protocol';
|
||||
import { CLI_CONFIG } from './cli-config';
|
||||
import { ConfigServiceImpl } from './config-service-impl';
|
||||
import { CLI_CONFIG } from '../../cli-config';
|
||||
import { ConfigServiceImpl } from '../../config-service-impl';
|
||||
|
||||
@injectable()
|
||||
export class ArduinoHostedPluginReader extends HostedPluginReader {
|
||||
export class HostedPluginReader extends TheiaHostedPluginReader {
|
||||
|
||||
@inject(ConfigServiceImpl)
|
||||
protected readonly configService: ConfigServiceImpl;
|
@ -1,10 +1,10 @@
|
||||
import { injectable, inject } from 'inversify';
|
||||
import { ILogger } from '@theia/core';
|
||||
import { DefaultWorkspaceServer } from '@theia/workspace/lib/node/default-workspace-server';
|
||||
import { ConfigService } from '../common/protocol/config-service';
|
||||
import { ILogger } from '@theia/core/lib/common/logger';
|
||||
import { DefaultWorkspaceServer as TheiaDefaultWorkspaceServer } from '@theia/workspace/lib/node/default-workspace-server';
|
||||
import { ConfigService } from '../../../common/protocol/config-service';
|
||||
|
||||
@injectable()
|
||||
export class DefaultWorkspaceServerExt extends DefaultWorkspaceServer {
|
||||
export class DefaultWorkspaceServer extends TheiaDefaultWorkspaceServer {
|
||||
|
||||
@inject(ConfigService)
|
||||
protected readonly configService: ConfigService;
|
@ -1,40 +0,0 @@
|
||||
import { injectable } from 'inversify';
|
||||
import { ToolOutputServiceServer, ToolOutputServiceClient, ToolOutputMessage } from '../common/protocol/tool-output-service';
|
||||
|
||||
@injectable()
|
||||
export class ToolOutputServiceServerImpl implements ToolOutputServiceServer {
|
||||
protected clients: ToolOutputServiceClient[] = [];
|
||||
|
||||
append(message: ToolOutputMessage): void {
|
||||
if (!message.chunk) {
|
||||
return;
|
||||
}
|
||||
for (const client of this.clients) {
|
||||
client.onMessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
setClient(client: ToolOutputServiceClient | undefined): void {
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
this.clients.push(client);
|
||||
}
|
||||
|
||||
disposeClient(client: ToolOutputServiceClient): void {
|
||||
const index = this.clients.indexOf(client);
|
||||
if (index === -1) {
|
||||
console.warn(`Could not dispose tools output client. It was not registered.`);
|
||||
return;
|
||||
}
|
||||
this.clients.splice(index, 1);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
for (const client of this.clients) {
|
||||
this.disposeClient(client);
|
||||
}
|
||||
this.clients.length = 0;
|
||||
}
|
||||
|
||||
}
|
@ -11,9 +11,10 @@ import { MessageClient } from '@theia/core/lib/common/message-service-protocol';
|
||||
import { MessageService } from '@theia/core/lib/common/message-service';
|
||||
import { StorageService } from '@theia/core/lib/browser/storage-service';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { BoardsService, Board, Port, BoardsPackage, BoardDetails, BoardsServiceClient } from '../../common/protocol';
|
||||
import { BoardsServiceClientImpl, AvailableBoard } from '../../browser/boards/boards-service-client-impl';
|
||||
import { BoardsService, Board, Port, BoardsPackage, BoardDetails } from '../../common/protocol';
|
||||
import { BoardsServiceProvider, AvailableBoard } from '../../browser/boards/boards-service-provider';
|
||||
import { BoardsConfig } from '../../browser/boards/boards-config';
|
||||
import { NotificationCenter } from '../../browser/notification-center';
|
||||
|
||||
// tslint:disable: no-unused-expression
|
||||
|
||||
@ -33,14 +34,14 @@ describe('boards-service-client-impl', () => {
|
||||
let stub: sinon.SinonStub;
|
||||
|
||||
let server: MockBoardsService;
|
||||
let client: BoardsServiceClientImpl;
|
||||
let client: BoardsServiceProvider;
|
||||
let notificationCenter: NotificationCenter;
|
||||
|
||||
beforeEach(() => {
|
||||
stub = sinon.stub(os, 'isOSX').value(true);
|
||||
const container = init();
|
||||
server = container.get(MockBoardsService);
|
||||
client = container.get(BoardsServiceClientImpl);
|
||||
server.setClient(client);
|
||||
client = container.get(BoardsServiceProvider);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@ -165,7 +166,7 @@ function init(): Container {
|
||||
container.bind(ILogger).toService(MockLogger);
|
||||
container.bind(MockStorageService).toSelf();
|
||||
container.bind(StorageService).toService(MockStorageService);
|
||||
container.bind(BoardsServiceClientImpl).toSelf();
|
||||
container.bind(BoardsServiceProvider).toSelf();
|
||||
container.bind(MessageClient).toSelf().inSingletonScope();
|
||||
container.bind(MessageService).toSelf().inSingletonScope();
|
||||
return container;
|
||||
@ -293,10 +294,6 @@ export class MockBoardsService implements BoardsService {
|
||||
this.client = undefined;
|
||||
}
|
||||
|
||||
setClient(client: BoardsServiceClient | undefined): void {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@injectable()
|
Loading…
x
Reference in New Issue
Block a user