mirror of
https://github.com/arduino/arduino-ide.git
synced 2025-11-11 19:29:28 +00:00
[atl-1217] sketchbook explorer local & remote
This commit is contained in:
committed by
Francesco Stasi
parent
e6cbefb880
commit
4c536ec8fc
@@ -0,0 +1,167 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { URI as Uri } from 'vscode-uri';
|
||||
import URI from '@theia/core/lib/common/uri';
|
||||
import { Deferred } from '@theia/core/lib/common/promise-util';
|
||||
import {
|
||||
FileSystemProvider,
|
||||
FileSystemProviderError,
|
||||
FileSystemProviderErrorCode,
|
||||
} from '@theia/filesystem/lib/common/files';
|
||||
import { DisposableCollection } from '@theia/core/lib/common/disposable';
|
||||
import { DelegatingFileSystemProvider } from '@theia/filesystem/lib/common/delegating-file-system-provider';
|
||||
import {
|
||||
FileService,
|
||||
FileServiceContribution,
|
||||
} from '@theia/filesystem/lib/browser/file-service';
|
||||
import { AuthenticationClientService } from '../auth/authentication-client-service';
|
||||
import { AuthenticationSession } from '../../common/protocol/authentication-service';
|
||||
import { ConfigService } from '../../common/protocol';
|
||||
|
||||
export namespace LocalCacheUri {
|
||||
export const scheme = 'arduino-local-cache';
|
||||
export const root = new URI(
|
||||
Uri.parse('/').with({ scheme, authority: 'create' })
|
||||
);
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class LocalCacheFsProvider
|
||||
implements
|
||||
FileServiceContribution,
|
||||
DelegatingFileSystemProvider.URIConverter
|
||||
{
|
||||
@inject(ConfigService)
|
||||
protected readonly configService: ConfigService;
|
||||
|
||||
@inject(AuthenticationClientService)
|
||||
protected readonly authenticationService: AuthenticationClientService;
|
||||
|
||||
// TODO: do we need this? Cannot we `await` on the `init` call from `registerFileSystemProviders`?
|
||||
readonly ready = new Deferred<void>();
|
||||
|
||||
private _localCacheRoot: URI;
|
||||
|
||||
registerFileSystemProviders(fileService: FileService): void {
|
||||
fileService.onWillActivateFileSystemProvider(async (event) => {
|
||||
if (event.scheme === LocalCacheUri.scheme) {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
this.init(fileService);
|
||||
const provider = await this.createProvider(fileService);
|
||||
fileService.registerProvider(
|
||||
LocalCacheUri.scheme,
|
||||
provider
|
||||
);
|
||||
})()
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
to(resource: URI): URI | undefined {
|
||||
const relativePath = LocalCacheUri.root.relative(resource);
|
||||
if (relativePath) {
|
||||
return this.currentUserUri.resolve(relativePath).normalizePath();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
from(resource: URI): URI | undefined {
|
||||
const relativePath = this.currentUserUri.relative(resource);
|
||||
if (relativePath) {
|
||||
return LocalCacheUri.root.resolve(relativePath);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected async createProvider(
|
||||
fileService: FileService
|
||||
): Promise<FileSystemProvider> {
|
||||
const delegate = await fileService.activateProvider('file');
|
||||
await this.ready.promise;
|
||||
return new DelegatingFileSystemProvider(
|
||||
delegate,
|
||||
{
|
||||
uriConverter: this,
|
||||
},
|
||||
new DisposableCollection(
|
||||
delegate.watch(this.localCacheRoot, {
|
||||
excludes: [],
|
||||
recursive: true,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected async init(fileService: FileService): Promise<void> {
|
||||
const config = await this.configService.getConfiguration();
|
||||
this._localCacheRoot = new URI(config.dataDirUri);
|
||||
for (const segment of ['RemoteSketchbook', 'ArduinoCloud']) {
|
||||
this._localCacheRoot = this._localCacheRoot.resolve(segment);
|
||||
await fileService.createFolder(this._localCacheRoot);
|
||||
}
|
||||
this.session(fileService).then(() => this.ready.resolve());
|
||||
this.authenticationService.onSessionDidChange(async (session) => {
|
||||
if (session) {
|
||||
await this.ensureExists(session, fileService);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private get currentUserUri(): URI {
|
||||
const { session } = this.authenticationService;
|
||||
if (!session) {
|
||||
throw new FileSystemProviderError(
|
||||
'Not logged in.',
|
||||
FileSystemProviderErrorCode.NoPermissions
|
||||
);
|
||||
}
|
||||
return this.toUri(session);
|
||||
}
|
||||
|
||||
private get localCacheRoot(): URI {
|
||||
return this._localCacheRoot;
|
||||
}
|
||||
|
||||
private async session(
|
||||
fileService: FileService
|
||||
): Promise<AuthenticationSession> {
|
||||
return new Promise<AuthenticationSession>(async (resolve) => {
|
||||
const { session } = this.authenticationService;
|
||||
if (session) {
|
||||
await this.ensureExists(session, fileService);
|
||||
resolve(session);
|
||||
return;
|
||||
}
|
||||
const toDispose = new DisposableCollection();
|
||||
toDispose.push(
|
||||
this.authenticationService.onSessionDidChange(
|
||||
async (session) => {
|
||||
if (session) {
|
||||
await this.ensureExists(session, fileService);
|
||||
toDispose.dispose();
|
||||
resolve(session);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private async ensureExists(
|
||||
session: AuthenticationSession,
|
||||
fileService: FileService
|
||||
): Promise<URI> {
|
||||
const uri = this.toUri(session);
|
||||
const exists = await fileService.exists(uri);
|
||||
if (!exists) {
|
||||
await fileService.createFolder(uri);
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
private toUri(session: AuthenticationSession): URI {
|
||||
// Hack: instead of getting the UUID only, we get `auth0|UUID` after the authentication. `|` cannot be part of filesystem path or filename.
|
||||
return this._localCacheRoot.resolve(session.id.split('|')[1]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user