Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/common/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './mutex';
export * from './request';
export * from './types';
22 changes: 22 additions & 0 deletions packages/common/src/mutex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export class Mutex {
private mutex = Promise.resolve();

lock(): PromiseLike<() => void> {
let begin: (unlock: () => void) => void = () => {};

this.mutex = this.mutex.then(() => new Promise(begin));

return new Promise((res) => {
begin = res;
});
}

async dispatch<T>(fn: () => PromiseLike<T>): Promise<T> {
const unlock = await this.lock();
try {
return await Promise.resolve(fn());
} finally {
unlock();
}
}
}
83 changes: 46 additions & 37 deletions packages/sumi-core/src/server/core/filesystem.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Deferred, getDebugLogger } from '@opensumi/ide-core-common';
import { Mutex } from '@codeblitzjs/ide-common';
import { Deferred, Disposable, getDebugLogger } from '@opensumi/ide-core-common';
import { HOME_IDB_NAME, HOME_ROOT } from '../../common';
import { RootFS } from '../../common/types';
import { BrowserFS, FileSystem } from '../node';
import { BrowserFS, FileSystem, isPathMounted } from '../node';

const { createFileSystem, FileSystem, initialize } = BrowserFS;

Expand All @@ -11,18 +12,18 @@ export const filesystemDeferred = new Deferred<void>();
export const isFilesystemReady = () => filesystemDeferred.promise;

let mountfs: RootFS | null = null;
let mountfsDeferred: Deferred<RootFS> | null = null;
let mountRootFsMutex = new Mutex();

export const initializeRootFileSystem = async () => {
if (mountfsDeferred) return mountfsDeferred.promise;
return mountRootFsMutex.dispatch(async () => {
if (mountfs) return mountfs;

mountfsDeferred = new Deferred<RootFS>();
mountfs = (await createFileSystem(FileSystem.MountableFileSystem, {})) as RootFS;
mountfsDeferred.resolve(mountfs);
mountfs = (await createFileSystem(FileSystem.MountableFileSystem, {})) as RootFS;

initialize(mountfs);
filesystemDeferred.resolve();
return mountfs;
initialize(mountfs);
filesystemDeferred.resolve();
return mountfs;
});
};

export const unmountRootFS = () => {
Expand All @@ -32,34 +33,42 @@ export const unmountRootFS = () => {
}
};

const initHomeFsMutex = new Mutex();

export const initializeHomeFileSystem = async (rootFS: RootFS, scenario?: string | null) => {
try {
let homefs: FileSystem | null = null;
// scenario 为 null 时 或者 browser 隐身模式时无法使用 indexedDB 时,回退到 memory
// TODO: 寻找更好的解决方案
if (scenario !== null && FileSystem.IndexedDB.isAvailable()) {
try {
// 通过 scenario 隔离 indexedDB
homefs = await createFileSystem(FileSystem.IndexedDB, {
storeName: `${HOME_IDB_NAME}${scenario ? `/${scenario}` : ''}`,
});
} catch (err) {
// @ts-ignore
getDebugLogger().error(`初始化 indexedDB 文件系统失败 ${err?.message || ''}`);
homefs = null;
}
return await initHomeFsMutex.dispatch(async () => {
// 如果用户使用了多个 codeblitz 实例,第一个挂载的先生效
if (isPathMounted(rootFS, HOME_ROOT)) {
return Disposable.NULL;
}
if (!homefs) {
homefs = await createFileSystem(FileSystem.InMemory, {});

try {
let homefs: FileSystem | null = null;
// scenario 为 null 时 或者 browser 隐身模式时无法使用 indexedDB 时,回退到 memory
// TODO: 寻找更好的解决方案
if (scenario !== null && FileSystem.IndexedDB.isAvailable()) {
try {
// 通过 scenario 隔离 indexedDB
homefs = await createFileSystem(FileSystem.IndexedDB, {
storeName: `${HOME_IDB_NAME}${scenario ? `/${scenario}` : ''}`,
});
} catch (err) {
getDebugLogger().error(`初始化 indexedDB 文件系统失败 ${(err as Error)?.message || ''}`);
homefs = null;
}
}
if (!homefs) {
homefs = await createFileSystem(FileSystem.InMemory, {});
}
rootFS.mount(HOME_ROOT, homefs);
} catch (err) {
getDebugLogger().error(`初始化 home 目录失败 ${(err as Error)?.message || ''}`);
}
rootFS.mount(HOME_ROOT, homefs);
} catch (err) {
// @ts-ignore
getDebugLogger().error(`初始化 home 目录失败 ${err?.message || ''}`);
}
return {
dispose() {
rootFS.umount(HOME_ROOT);
},
};

return {
dispose() {
rootFS.umount(HOME_ROOT);
},
};
});
};