mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-12-02 13:27:15 +00:00
Pluggable monitor (#982)
* backend structure WIP * Scaffold interfaces and classes for pluggable monitors * Implement MonitorService to handle pluggable monitor lifetime * Rename WebSocketService to WebSocketProvider and uninjected it * Moved some interfaces * Changed upload settings * Enhance MonitorManager APIs * Fixed WebSocketChange event signature * Add monitor proxy functions for the frontend * Moved settings to MonitorService * Remove several unnecessary serial monitor classes * Changed how connection is handled on upload * Proxied more monitor methods to frontend * WebSocketProvider is not injectable anymore * Add generic monitor settings storaging * More serial classes removal * Remove unused file * Changed plotter contribution to use new manager proxy * Changed MonitorWidget and children to use new monitor proxy * Updated MonitorWidget to use new monitor proxy * Fix backend logger bindings * Delete unnecessary Symbol * coreClientProvider is now set when constructing MonitorService * Add missing binding * Fix `MonitorManagerProxy` DI issue * fix monitor connection * delete duplex when connection is closed * update arduino-cli to 0.22.0 * fix upload when monitor is open * add MonitorSettingsProvider interface * monitor settings provider stub * updated pseudo code * refactor monitor settings interfaces * monitor service provider singleton * add unit tests * change MonitorService providers to injectable deps * fix monitor settings client communication * refactor monitor commands protocol * use monitor settings provider properly * add settings to monitor model * add settings to monitor model * reset serial monitor when port changes * fix serial plotter opening * refine monitor connection settings * fix hanging web socket connections * add serial plotter reset command * send port to web socket clients * monitor service wait for success serial port open * fix reset loop * update serial plotter version * update arduino-cli version to 0.23.0-rc1 and regenerate grpc protocol * remove useless plotter protocol file * localize web socket errors * clean-up code * update translation file * Fix duplicated editor tabs (#1012) * Save dialog for closing temporary sketch and unsaved files (#893) * Use normal `OnWillStop` event * Align `CLOSE` command to rest of app * Fixed FS path vs encoded URL comparision when handling stop request. Ref: https://github.com/eclipse-theia/theia/issues/11226 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> * Fixed the translations. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> * Fixed the translations again. Removed `electron` from the `nls-extract`. It does not contain app code. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> * Aligned the stop handler code to Theia. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> Co-authored-by: Akos Kitta <a.kitta@arduino.cc> * fix serial monitor send line ending * refactor monitor-service poll for test/readability * localize web socket errors * update translation file * Fix duplicated editor tabs (#1012) * i18n:check rerun * Speed up IDE startup time. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> * override coreClientProvider in monitor-service * cleanup merged code Co-authored-by: Francesco Stasi <f.stasi@me.com> Co-authored-by: Silvano Cerza <silvanocerza@gmail.com> Co-authored-by: Mark Sujew <mark.sujew@typefox.io> Co-authored-by: David Simpson <45690499+davegarthsimpson@users.noreply.github.com> Co-authored-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
committed by
GitHub
parent
4c55807392
commit
df8658eff9
@@ -0,0 +1,130 @@
|
||||
import * as fs from 'fs';
|
||||
import { join } from 'path';
|
||||
import { injectable, inject, postConstruct } from 'inversify';
|
||||
import { EnvVariablesServer } from '@theia/core/lib/common/env-variables';
|
||||
import { FileUri } from '@theia/core/lib/node/file-uri';
|
||||
import { promisify } from 'util';
|
||||
import {
|
||||
PluggableMonitorSettings,
|
||||
MonitorSettingsProvider,
|
||||
} from './monitor-settings-provider';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import {
|
||||
longestPrefixMatch,
|
||||
reconcileSettings,
|
||||
} from './monitor-settings-utils';
|
||||
import { ILogger } from '@theia/core';
|
||||
|
||||
const MONITOR_SETTINGS_FILE = 'pluggable-monitor-settings.json';
|
||||
|
||||
@injectable()
|
||||
export class MonitorSettingsProviderImpl implements MonitorSettingsProvider {
|
||||
@inject(EnvVariablesServer)
|
||||
protected readonly envVariablesServer: EnvVariablesServer;
|
||||
|
||||
@inject(ILogger)
|
||||
protected logger: ILogger;
|
||||
|
||||
// deferred used to guarantee file operations are performed after the service is initialized
|
||||
protected ready = new Deferred<void>();
|
||||
|
||||
// this contains actual values coming from the stored file and edited by the user
|
||||
// this is a map with MonitorId as key and PluggableMonitorSetting as value
|
||||
private monitorSettings: Record<string, PluggableMonitorSettings>;
|
||||
|
||||
// this is the path to the pluggable monitor settings file, set during init
|
||||
private pluggableMonitorSettingsPath: string;
|
||||
|
||||
@postConstruct()
|
||||
protected async init(): Promise<void> {
|
||||
// get the monitor settings file path
|
||||
const configDirUri = await this.envVariablesServer.getConfigDirUri();
|
||||
this.pluggableMonitorSettingsPath = join(
|
||||
FileUri.fsPath(configDirUri),
|
||||
MONITOR_SETTINGS_FILE
|
||||
);
|
||||
|
||||
// read existing settings
|
||||
await this.readSettingsFromFS();
|
||||
|
||||
// init is done, resolve the deferred and unblock any call that was waiting for it
|
||||
this.ready.resolve();
|
||||
}
|
||||
|
||||
async getSettings(
|
||||
monitorId: string,
|
||||
defaultSettings: PluggableMonitorSettings
|
||||
): Promise<PluggableMonitorSettings> {
|
||||
// wait for the service to complete the init
|
||||
await this.ready.promise;
|
||||
|
||||
const { matchingSettings } = this.longestPrefixMatch(monitorId);
|
||||
|
||||
this.monitorSettings[monitorId] = this.reconcileSettings(
|
||||
matchingSettings,
|
||||
defaultSettings
|
||||
);
|
||||
return this.monitorSettings[monitorId];
|
||||
}
|
||||
|
||||
async setSettings(
|
||||
monitorId: string,
|
||||
settings: PluggableMonitorSettings
|
||||
): Promise<PluggableMonitorSettings> {
|
||||
// wait for the service to complete the init
|
||||
await this.ready.promise;
|
||||
|
||||
const newSettings = this.reconcileSettings(
|
||||
settings,
|
||||
this.monitorSettings[monitorId] || {}
|
||||
);
|
||||
this.monitorSettings[monitorId] = newSettings;
|
||||
|
||||
await this.writeSettingsToFS();
|
||||
return newSettings;
|
||||
}
|
||||
|
||||
private reconcileSettings(
|
||||
newSettings: PluggableMonitorSettings,
|
||||
defaultSettings: PluggableMonitorSettings
|
||||
): PluggableMonitorSettings {
|
||||
return reconcileSettings(newSettings, defaultSettings);
|
||||
}
|
||||
|
||||
private async readSettingsFromFS(): Promise<void> {
|
||||
const rawJson = await promisify(fs.readFile)(
|
||||
this.pluggableMonitorSettingsPath,
|
||||
{
|
||||
encoding: 'utf-8',
|
||||
flag: 'a+', // a+ = append and read, creating the file if it doesn't exist
|
||||
}
|
||||
);
|
||||
|
||||
if (!rawJson) {
|
||||
this.monitorSettings = {};
|
||||
}
|
||||
|
||||
try {
|
||||
this.monitorSettings = JSON.parse(rawJson);
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
'Could not parse the pluggable monitor settings file. Using empty file.'
|
||||
);
|
||||
this.monitorSettings = {};
|
||||
}
|
||||
}
|
||||
|
||||
private async writeSettingsToFS(): Promise<void> {
|
||||
await promisify(fs.writeFile)(
|
||||
this.pluggableMonitorSettingsPath,
|
||||
JSON.stringify(this.monitorSettings)
|
||||
);
|
||||
}
|
||||
|
||||
private longestPrefixMatch(id: string): {
|
||||
matchingPrefix: string;
|
||||
matchingSettings: PluggableMonitorSettings;
|
||||
} {
|
||||
return longestPrefixMatch(id, this.monitorSettings);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user