Avoid deleting the workspace when it's still in use.

- From now on, NSFW service disposes after last reference
is removed. No more 10sec delay.
 - Moved the temp workspace deletion to a startup task.
 - Can set initial task for the window from electron-main.
 - Removed the `browser-app`.

Closes #39

Signed-off-by: Akos Kitta <a.kitta@arduino.cc>
This commit is contained in:
Akos Kitta
2022-09-05 11:22:16 +02:00
committed by Akos Kitta
parent 0151e4c224
commit fdf6f0f9c8
38 changed files with 560 additions and 582 deletions

View File

@@ -1,4 +1,4 @@
import { ContainerModule } from '@theia/core/shared/inversify';
import { ContainerModule, interfaces } from '@theia/core/shared/inversify';
import { ArduinoDaemonImpl } from './arduino-daemon-impl';
import {
ArduinoFirmwareUploader,
@@ -110,6 +110,7 @@ import {
SurveyNotificationServicePath,
} from '../common/protocol/survey-service';
import { IsTempSketch } from './is-temp-sketch';
import { rebindNsfwFileSystemWatcher } from './theia/filesystem/nsfw-watcher/nsfw-bindings';
export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(BackendApplication).toSelf().inSingletonScope();
@@ -288,6 +289,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
)
)
.inSingletonScope();
rebindNsfwFileSystemWatcher(rebind);
// Output service per connection.
bind(ConnectionContainerModule).toConstantValue(
@@ -325,58 +327,14 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
})
);
// Logger for the Arduino daemon
bind(ILogger)
.toDynamicValue((ctx) => {
const parentLogger = ctx.container.get<ILogger>(ILogger);
return parentLogger.child('daemon');
})
.inSingletonScope()
.whenTargetNamed('daemon');
// Logger for the Arduino daemon
bind(ILogger)
.toDynamicValue((ctx) => {
const parentLogger = ctx.container.get<ILogger>(ILogger);
return parentLogger.child('fwuploader');
})
.inSingletonScope()
.whenTargetNamed('fwuploader');
// Logger for the "serial discovery".
bind(ILogger)
.toDynamicValue((ctx) => {
const parentLogger = ctx.container.get<ILogger>(ILogger);
return parentLogger.child('discovery-log'); // TODO: revert
})
.inSingletonScope()
.whenTargetNamed('discovery-log'); // TODO: revert
// Logger for the CLI config service. From the CLI config (FS path aware), we make a URI-aware app config.
bind(ILogger)
.toDynamicValue((ctx) => {
const parentLogger = ctx.container.get<ILogger>(ILogger);
return parentLogger.child('config');
})
.inSingletonScope()
.whenTargetNamed('config');
// Logger for the monitor manager and its services
bind(ILogger)
.toDynamicValue((ctx) => {
const parentLogger = ctx.container.get<ILogger>(ILogger);
return parentLogger.child(MonitorManagerName);
})
.inSingletonScope()
.whenTargetNamed(MonitorManagerName);
bind(ILogger)
.toDynamicValue((ctx) => {
const parentLogger = ctx.container.get<ILogger>(ILogger);
return parentLogger.child(MonitorServiceName);
})
.inSingletonScope()
.whenTargetNamed(MonitorServiceName);
[
'daemon', // Logger for the Arduino daemon
'fwuploader', // Arduino Firmware uploader
'discovery-log', // Boards discovery
'config', // Logger for the CLI config reading and manipulation
MonitorManagerName, // Logger for the monitor manager and its services
MonitorServiceName,
].forEach((name) => bindChildLogger(bind, name));
// Remote sketchbook bindings
bind(AuthenticationServiceImpl).toSelf().inSingletonScope();
@@ -423,3 +381,12 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => {
bind(IsTempSketch).toSelf().inSingletonScope();
});
function bindChildLogger(bind: interfaces.Bind, name: string): void {
bind(ILogger)
.toDynamicValue(({ container }) =>
container.get<ILogger>(ILogger).child(name)
)
.inSingletonScope()
.whenTargetNamed(name);
}

View File

@@ -561,14 +561,18 @@ void loop() {
return path.join(os.tmpdir(), `arduino-ide2-${suffix}`);
}
notifyDeleteSketch(sketch: Sketch): void {
const sketchPath = FileUri.fsPath(sketch.uri);
fs.rm(sketchPath, { recursive: true, maxRetries: 5 }, (error) => {
if (error) {
console.error(`Failed to delete sketch at ${sketchPath}.`, error);
} else {
console.error(`Successfully delete sketch at ${sketchPath}.`);
}
async deleteSketch(sketch: Sketch): Promise<void> {
return new Promise<void>((resolve, reject) => {
const sketchPath = FileUri.fsPath(sketch.uri);
fs.rm(sketchPath, { recursive: true, maxRetries: 5 }, (error) => {
if (error) {
console.error(`Failed to delete sketch at ${sketchPath}.`, error);
reject(error);
} else {
console.log(`Successfully deleted sketch at ${sketchPath}.`);
resolve();
}
});
});
}
}

View File

@@ -0,0 +1,31 @@
import * as yargs from '@theia/core/shared/yargs';
import { JsonRpcProxyFactory } from '@theia/core';
import { NoDelayDisposalTimeoutNsfwFileSystemWatcherService } from './nsfw-filesystem-service';
import type { IPCEntryPoint } from '@theia/core/lib/node/messaging/ipc-protocol';
import type { FileSystemWatcherServiceClient } from '@theia/filesystem/lib/common/filesystem-watcher-protocol';
const options: {
verbose: boolean;
} = yargs
.option('verbose', {
default: false,
alias: 'v',
type: 'boolean',
})
.option('nsfwOptions', {
alias: 'o',
type: 'string',
coerce: JSON.parse,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}).argv as any;
export default <IPCEntryPoint>((connection) => {
const server = new NoDelayDisposalTimeoutNsfwFileSystemWatcherService(
options
);
const factory = new JsonRpcProxyFactory<FileSystemWatcherServiceClient>(
server
);
server.setClient(factory.createProxy());
factory.listen(connection);
});

View File

@@ -0,0 +1,42 @@
import { join } from 'path';
import { interfaces } from '@theia/core/shared/inversify';
import {
NsfwFileSystemWatcherServiceProcessOptions,
NSFW_SINGLE_THREADED,
spawnNsfwFileSystemWatcherServiceProcess,
} from '@theia/filesystem/lib/node/filesystem-backend-module';
import { FileSystemWatcherService } from '@theia/filesystem/lib/common/filesystem-watcher-protocol';
import { NsfwFileSystemWatcherServerOptions } from '@theia/filesystem/lib/node/nsfw-watcher/nsfw-filesystem-service';
import { FileSystemWatcherServiceDispatcher } from '@theia/filesystem/lib/node/filesystem-watcher-dispatcher';
import { NoDelayDisposalTimeoutNsfwFileSystemWatcherService } from './nsfw-filesystem-service';
export function rebindNsfwFileSystemWatcher(rebind: interfaces.Rebind): void {
rebind<NsfwFileSystemWatcherServiceProcessOptions>(
NsfwFileSystemWatcherServiceProcessOptions
).toConstantValue({
entryPoint: join(__dirname, 'index.js'),
});
rebind<FileSystemWatcherService>(FileSystemWatcherService)
.toDynamicValue((context) =>
NSFW_SINGLE_THREADED
? createNsfwFileSystemWatcherService(context)
: spawnNsfwFileSystemWatcherServiceProcess(context)
)
.inSingletonScope();
}
function createNsfwFileSystemWatcherService({
container,
}: interfaces.Context): FileSystemWatcherService {
const options = container.get<NsfwFileSystemWatcherServerOptions>(
NsfwFileSystemWatcherServerOptions
);
const dispatcher = container.get<FileSystemWatcherServiceDispatcher>(
FileSystemWatcherServiceDispatcher
);
const server = new NoDelayDisposalTimeoutNsfwFileSystemWatcherService(
options
);
server.setClient(dispatcher);
return server;
}

View File

@@ -0,0 +1,32 @@
import { Minimatch } from 'minimatch';
import type { WatchOptions } from '@theia/filesystem/lib/common/filesystem-watcher-protocol';
import {
NsfwFileSystemWatcherService,
NsfwWatcher,
} from '@theia/filesystem/lib/node/nsfw-watcher/nsfw-filesystem-service';
// Dispose the watcher immediately when the last reference is removed. By default, Theia waits 10 sec.
// https://github.com/eclipse-theia/theia/issues/11639#issuecomment-1238980708
const NoDelay = 0;
export class NoDelayDisposalTimeoutNsfwFileSystemWatcherService extends NsfwFileSystemWatcherService {
protected override createWatcher(
clientId: number,
fsPath: string,
options: WatchOptions
): NsfwWatcher {
const watcherOptions = {
ignored: options.ignored.map(
(pattern) => new Minimatch(pattern, { dot: true })
),
};
return new NsfwWatcher(
clientId,
fsPath,
watcherOptions,
this.options,
this.maybeClient,
NoDelay
);
}
}