mirror of
https://github.com/DustinBrett/daedalOS.git
synced 2025-12-06 00:20:05 +01:00
Emscripten mounting support
This commit is contained in:
parent
64f67ca2df
commit
676d2ece21
|
|
@ -7,6 +7,8 @@ import useTitle from "components/system/Window/useTitle";
|
|||
import { useFileSystem } from "contexts/fileSystem";
|
||||
import { useProcesses } from "contexts/process";
|
||||
import { getExtension, isCanvasDrawn, loadFiles } from "utils/functions";
|
||||
import type { EmscriptenFS } from "contexts/fileSystem/useAsyncFs";
|
||||
import useEmscriptenMount from "components/system/Files/FileManager/useEmscriptenMount";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
|
@ -37,6 +39,7 @@ const useBoxedWine = ({
|
|||
const { appendFileToTitle } = useTitle(id);
|
||||
const { processes: { [id]: { libs = [] } = {} } = {} } = useProcesses();
|
||||
const { readFile } = useFileSystem();
|
||||
const mountEmFs = useEmscriptenMount();
|
||||
const loadedUrl = useRef<string>();
|
||||
const blankCanvasCheckerTimer = useRef<number | undefined>();
|
||||
const loadEmulator = useCallback(async (): Promise<void> => {
|
||||
|
|
@ -101,15 +104,26 @@ const useBoxedWine = ({
|
|||
loadFiles(libs).then(() => {
|
||||
if (url) appendFileToTitle(appName || basename(url));
|
||||
try {
|
||||
window.BoxedWineShell(() => setLoading(false));
|
||||
window.BoxedWineShell(() => {
|
||||
setLoading(false);
|
||||
mountEmFs(window.FS as EmscriptenFS, "BoxedWine");
|
||||
});
|
||||
} catch {
|
||||
// Ignore BoxedWine errors
|
||||
}
|
||||
});
|
||||
}, [appendFileToTitle, containerRef, libs, readFile, setLoading, url]);
|
||||
}, [
|
||||
appendFileToTitle,
|
||||
containerRef,
|
||||
libs,
|
||||
mountEmFs,
|
||||
readFile,
|
||||
setLoading,
|
||||
url,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (loadedUrl.current !== url) {
|
||||
if (loadedUrl.current !== url && (url || !loadedUrl.current)) {
|
||||
loadedUrl.current = url;
|
||||
loadEmulator();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import { useProcesses } from "contexts/process";
|
|||
import { useSession } from "contexts/session";
|
||||
import { TRANSITIONS_IN_MILLISECONDS } from "utils/constants";
|
||||
import { loadFiles, pxToNum } from "utils/functions";
|
||||
import type { EmscriptenFS } from "contexts/fileSystem/useAsyncFs";
|
||||
import useEmscriptenMount from "components/system/Files/FileManager/useEmscriptenMount";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
|
@ -26,6 +28,7 @@ const useClassiCube = ({
|
|||
setLoading,
|
||||
}: ContainerHookProps): void => {
|
||||
const { processes: { [id]: process } = {} } = useProcesses();
|
||||
const mountEmFs = useEmscriptenMount();
|
||||
const {
|
||||
windowStates: { [id]: windowState },
|
||||
} = useSession();
|
||||
|
|
@ -62,7 +65,10 @@ const useClassiCube = ({
|
|||
arguments: ["Singleplayer"],
|
||||
canvas,
|
||||
postRun: [
|
||||
() => setLoading(false),
|
||||
() => {
|
||||
setLoading(false);
|
||||
mountEmFs(window.FS as EmscriptenFS, "ClassiCube");
|
||||
},
|
||||
() => {
|
||||
const { width, height } = canvas.getBoundingClientRect() || {};
|
||||
|
||||
|
|
@ -76,7 +82,7 @@ const useClassiCube = ({
|
|||
|
||||
loadFiles(libs);
|
||||
}, TRANSITIONS_IN_MILLISECONDS.WINDOW);
|
||||
}, [getCanvas, libs, setLoading]);
|
||||
}, [getCanvas, libs, mountEmFs, setLoading]);
|
||||
};
|
||||
|
||||
export default useClassiCube;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import { useProcesses } from "contexts/process";
|
|||
import { ICON_CACHE, ICON_CACHE_EXTENSION, SAVE_PATH } from "utils/constants";
|
||||
import { bufferToUrl, getExtension, loadFiles } from "utils/functions";
|
||||
import { zipAsync } from "utils/zipFunctions";
|
||||
import type { EmscriptenFS } from "contexts/fileSystem/useAsyncFs";
|
||||
import useEmscriptenMount from "components/system/Files/FileManager/useEmscriptenMount";
|
||||
|
||||
const getCore = (extension: string): [string, Core] => {
|
||||
return (Object.entries(emulatorCores).find(([, { ext }]) =>
|
||||
|
|
@ -26,6 +28,7 @@ const useEmulator = ({
|
|||
}: ContainerHookProps): void => {
|
||||
const { exists, mkdirRecursive, readFile, updateFolder, writeFile } =
|
||||
useFileSystem();
|
||||
const mountEmFs = useEmscriptenMount();
|
||||
const { linkElement, processes: { [id]: { closing = false } = {} } = {} } =
|
||||
useProcesses();
|
||||
const { prependFileToTitle } = useTitle(id);
|
||||
|
|
@ -39,7 +42,13 @@ const useEmulator = ({
|
|||
if (loadedUrlRef.current) {
|
||||
if (loadedUrlRef.current !== url) {
|
||||
loadedUrlRef.current = "";
|
||||
window.EJS_terminate?.();
|
||||
|
||||
try {
|
||||
window.EJS_terminate?.();
|
||||
} catch {
|
||||
// Ignore errors during termination
|
||||
}
|
||||
|
||||
if (containerRef.current) {
|
||||
const div = document.createElement("div");
|
||||
|
||||
|
|
@ -76,6 +85,7 @@ const useEmulator = ({
|
|||
}
|
||||
|
||||
setLoading(false);
|
||||
mountEmFs(window.FS as EmscriptenFS, "EmulatorJs");
|
||||
emulatorRef.current = currentEmulator;
|
||||
};
|
||||
|
||||
|
|
@ -130,6 +140,7 @@ const useEmulator = ({
|
|||
mkdirRecursive,
|
||||
prependFileToTitle,
|
||||
readFile,
|
||||
mountEmFs,
|
||||
setLoading,
|
||||
updateFolder,
|
||||
url,
|
||||
|
|
@ -140,9 +151,10 @@ const useEmulator = ({
|
|||
if (url) loadRom();
|
||||
else {
|
||||
setLoading(false);
|
||||
mountEmFs(window.FS as EmscriptenFS, "EmulatorJs");
|
||||
containerRef.current?.classList.add("drop");
|
||||
}
|
||||
}, [containerRef, loadRom, setLoading, url]);
|
||||
}, [containerRef, loadRom, mountEmFs, setLoading, url]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
ROOT_NAME,
|
||||
} from "utils/constants";
|
||||
import { haltEvent } from "utils/functions";
|
||||
import { isMountedFolder } from "contexts/fileSystem/functions";
|
||||
|
||||
const FileExplorer: FC<ComponentProcessProps> = ({ id }) => {
|
||||
const {
|
||||
|
|
@ -47,7 +48,7 @@ const FileExplorer: FC<ComponentProcessProps> = ({ id }) => {
|
|||
if (isMounted) {
|
||||
setProcessIcon(
|
||||
id,
|
||||
rootFs?.mntMap[url].getName() === "FileSystemAccess"
|
||||
isMountedFolder(rootFs?.mntMap[url])
|
||||
? MOUNTED_FOLDER_ICON
|
||||
: COMPRESSED_FOLDER_ICON
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import type { DosFactoryType } from "emulators-ui/dist/types/js-dos";
|
||||
import type { EmscriptenFS } from "contexts/fileSystem/useAsyncFs";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
Dos: DosFactoryType;
|
||||
JSDOS_FS: EmscriptenFS;
|
||||
SimpleKeyboardInstances?: {
|
||||
emulatorKeyboard?: {
|
||||
destroy: () => void;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { useProcesses } from "contexts/process";
|
|||
import { useSession } from "contexts/session";
|
||||
import { PREVENT_SCROLL } from "utils/constants";
|
||||
import { loadFiles, pxToNum } from "utils/functions";
|
||||
import useEmscriptenMount from "components/system/Files/FileManager/useEmscriptenMount";
|
||||
|
||||
const captureKeys = (event: KeyboardEvent): void => {
|
||||
if (CAPTURED_KEYS.has(event.key)) event.preventDefault();
|
||||
|
|
@ -26,6 +27,7 @@ const useJSDOS = ({
|
|||
}: ContainerHookProps): void => {
|
||||
const { updateWindowSize } = useWindowSize(id);
|
||||
const [dosInstance, setDosInstance] = useState<DosInstance>();
|
||||
const mountEmFs = useEmscriptenMount();
|
||||
const loadingInstanceRef = useRef(false);
|
||||
const { foregroundId } = useSession();
|
||||
const dosCI = useDosCI(id, url, containerRef, dosInstance);
|
||||
|
|
@ -102,6 +104,7 @@ const useJSDOS = ({
|
|||
);
|
||||
|
||||
setLoading(false);
|
||||
mountEmFs(window.JSDOS_FS, "JS-DOS");
|
||||
}
|
||||
}, [
|
||||
closeWithTransition,
|
||||
|
|
@ -110,6 +113,7 @@ const useJSDOS = ({
|
|||
dosInstance?.layers,
|
||||
id,
|
||||
loading,
|
||||
mountEmFs,
|
||||
setLoading,
|
||||
updateWindowSize,
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import type { ContainerHookProps } from "components/system/Apps/AppContainer";
|
|||
import { useProcesses } from "contexts/process";
|
||||
import { useSession } from "contexts/session";
|
||||
import { loadFiles, pxToNum } from "utils/functions";
|
||||
import type { EmscriptenFS } from "contexts/fileSystem/useAsyncFs";
|
||||
import useEmscriptenMount from "components/system/Files/FileManager/useEmscriptenMount";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
|
@ -35,6 +37,7 @@ const useQuake3 = ({
|
|||
const {
|
||||
sizes: { titleBar },
|
||||
} = useTheme();
|
||||
const mountEmFs = useEmscriptenMount();
|
||||
const { size } = windowState || {};
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -46,8 +49,9 @@ const useQuake3 = ({
|
|||
window.ioq3.callMain([]);
|
||||
|
||||
setLoading(false);
|
||||
mountEmFs(window.FS as EmscriptenFS, "Quake3");
|
||||
});
|
||||
}, [containerRef, libs, setLoading]);
|
||||
}, [containerRef, libs, mountEmFs, setLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!window.ioq3) return;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import type { ContainerHookProps } from "components/system/Apps/AppContainer";
|
|||
import { useProcesses } from "contexts/process";
|
||||
import { TRANSITIONS_IN_MILLISECONDS } from "utils/constants";
|
||||
import { loadFiles } from "utils/functions";
|
||||
import type { EmscriptenFS } from "contexts/fileSystem/useAsyncFs";
|
||||
import useEmscriptenMount from "components/system/Files/FileManager/useEmscriptenMount";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
|
@ -23,6 +25,7 @@ const useSpaceCadet = ({
|
|||
}: ContainerHookProps): void => {
|
||||
const { processes: { [id]: { libs = [] } = {} } = {} } = useProcesses();
|
||||
const [canvas, setCanvas] = useState<HTMLCanvasElement>();
|
||||
const mountEmFs = useEmscriptenMount();
|
||||
|
||||
useEffect(() => {
|
||||
const containerCanvas = containerRef.current?.querySelector("canvas");
|
||||
|
|
@ -30,11 +33,14 @@ const useSpaceCadet = ({
|
|||
if (containerCanvas instanceof HTMLCanvasElement) {
|
||||
window.Module = {
|
||||
canvas: containerCanvas,
|
||||
postRun: () => setLoading(false),
|
||||
postRun: () => {
|
||||
setLoading(false);
|
||||
mountEmFs(window.FS as EmscriptenFS, "SpaceCadet");
|
||||
},
|
||||
};
|
||||
setCanvas(containerCanvas);
|
||||
}
|
||||
}, [containerRef, setLoading]);
|
||||
}, [containerRef, mountEmFs, setLoading]);
|
||||
|
||||
useEffect(() => {
|
||||
if (canvas) {
|
||||
|
|
@ -53,7 +59,11 @@ const useSpaceCadet = ({
|
|||
|
||||
return () => {
|
||||
if (canvas && window.Module) {
|
||||
window.Module.SDL2?.audioContext.close();
|
||||
try {
|
||||
window.Module.SDL2?.audioContext.close();
|
||||
} catch {
|
||||
// Ignore errors during closing
|
||||
}
|
||||
}
|
||||
};
|
||||
}, [canvas, containerRef, libs]);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { useFileSystem } from "contexts/fileSystem";
|
|||
import { useProcesses } from "contexts/process";
|
||||
import { DEFAULT_TEXT_FILE_SAVE_PATH } from "utils/constants";
|
||||
import { haltEvent, loadFiles } from "utils/functions";
|
||||
import useEmscriptenMount from "components/system/Files/FileManager/useEmscriptenMount";
|
||||
|
||||
const Vim: FC<ComponentProcessProps> = ({ id }) => {
|
||||
const {
|
||||
|
|
@ -16,6 +17,7 @@ const Vim: FC<ComponentProcessProps> = ({ id }) => {
|
|||
processes: { [id]: process },
|
||||
} = useProcesses();
|
||||
const { readFile, updateFolder, writeFile } = useFileSystem();
|
||||
const mountEmFs = useEmscriptenMount();
|
||||
const { prependFileToTitle } = useTitle(id);
|
||||
const { libs = [], url = "" } = process || {};
|
||||
const [updateQueue, setUpdateQueue] = useState<QueueItem[]>([]);
|
||||
|
|
@ -45,6 +47,7 @@ const Vim: FC<ComponentProcessProps> = ({ id }) => {
|
|||
postRun: [
|
||||
() => {
|
||||
loading.current = false;
|
||||
mountEmFs(window.VimWrapperModule?.VimModule?.FS, "Vim");
|
||||
},
|
||||
],
|
||||
preRun: [
|
||||
|
|
@ -90,7 +93,15 @@ const Vim: FC<ComponentProcessProps> = ({ id }) => {
|
|||
});
|
||||
|
||||
prependFileToTitle(basename(saveUrl));
|
||||
}, [closeWithTransition, id, libs, prependFileToTitle, readFile, url]);
|
||||
}, [
|
||||
closeWithTransition,
|
||||
id,
|
||||
libs,
|
||||
mountEmFs,
|
||||
prependFileToTitle,
|
||||
readFile,
|
||||
url,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (updateQueue.length > 0) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import type { EmscriptenFS } from "contexts/fileSystem/useAsyncFs";
|
||||
|
||||
export type QueueItem = {
|
||||
buffer: Buffer;
|
||||
url: string;
|
||||
};
|
||||
|
||||
type VimModule = {
|
||||
FS?: EmscriptenFS;
|
||||
FS_createDataFile?: (
|
||||
parentPath: string,
|
||||
newPath: string,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import {
|
|||
isSafari,
|
||||
isYouTubeUrl,
|
||||
} from "utils/functions";
|
||||
import { isMountedFolder } from "contexts/fileSystem/functions";
|
||||
|
||||
type InternetShortcut = {
|
||||
BaseURL: string;
|
||||
|
|
@ -277,7 +278,7 @@ export const getInfoWithoutExtension = (
|
|||
): void =>
|
||||
callback({ getIcon, icon, pid: "FileExplorer", subIcons, url: path });
|
||||
const getFolderIcon = (): string => {
|
||||
if (rootFs?.mntMap[path]?.getName() === "FileSystemAccess") {
|
||||
if (isMountedFolder(rootFs?.mntMap[path])) {
|
||||
return MOUNTED_FOLDER_ICON;
|
||||
}
|
||||
if (hasNewFolderIcon) return NEW_FOLDER_ICON;
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import {
|
|||
IMAGE_ENCODE_FORMATS,
|
||||
} from "utils/imagemagick/formats";
|
||||
import type { ImageMagickConvertFile } from "utils/imagemagick/types";
|
||||
import { isMountedFolder } from "contexts/fileSystem/functions";
|
||||
|
||||
const { alias } = PACKAGE_DATA;
|
||||
|
||||
|
|
@ -116,8 +117,7 @@ const useFileContextMenu = (
|
|||
const isShortcut = pathExtension === SHORTCUT_EXTENSION;
|
||||
const remoteMount = rootFs?.mountList.some(
|
||||
(mountPath) =>
|
||||
mountPath === path &&
|
||||
rootFs?.mntMap[mountPath]?.getName() === "FileSystemAccess"
|
||||
mountPath === path && isMountedFolder(rootFs?.mntMap[mountPath])
|
||||
);
|
||||
|
||||
if (!readOnly && !remoteMount) {
|
||||
|
|
@ -448,7 +448,11 @@ const useFileContextMenu = (
|
|||
|
||||
if (remoteMount) {
|
||||
menuItems.push(MENU_SEPERATOR, {
|
||||
action: () => unMapFs(path),
|
||||
action: () =>
|
||||
unMapFs(
|
||||
path,
|
||||
rootFs?.mntMap[path].getName() !== "FileSystemAccess"
|
||||
),
|
||||
label: "Disconnect",
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
import { useFileSystem } from "contexts/fileSystem";
|
||||
import { MOUNTABLE_EXTENSIONS } from "utils/constants";
|
||||
import { getExtension } from "utils/functions";
|
||||
import { isMountedFolder } from "contexts/fileSystem/functions";
|
||||
|
||||
export type FileInfo = {
|
||||
comment?: string;
|
||||
|
|
@ -44,7 +45,7 @@ const useFileInfo = (
|
|||
!extension ||
|
||||
(isDirectory &&
|
||||
!MOUNTABLE_EXTENSIONS.has(extension) &&
|
||||
rootFs.mntMap[path]?.getName() !== "FileSystemAccess")
|
||||
!isMountedFolder(rootFs.mntMap[path]))
|
||||
) {
|
||||
getInfoWithoutExtension(
|
||||
fs,
|
||||
|
|
|
|||
51
components/system/Files/FileManager/useEmscriptenMount.ts
Normal file
51
components/system/Files/FileManager/useEmscriptenMount.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { useFileSystem } from "contexts/fileSystem";
|
||||
import type { EmscriptenFS } from "contexts/fileSystem/useAsyncFs";
|
||||
import { useCallback, useEffect, useRef } from "react";
|
||||
|
||||
type EmscriptenMounter = (FS?: EmscriptenFS, fsName?: string) => Promise<void>;
|
||||
|
||||
const useEmscriptenMount = (): EmscriptenMounter => {
|
||||
const { mountEmscriptenFs, unMapFs, updateFolder } = useFileSystem();
|
||||
const mountName = useRef<string>();
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
if (mountName.current) {
|
||||
const unMountPath = mountName.current;
|
||||
|
||||
mountName.current = "";
|
||||
|
||||
try {
|
||||
unMapFs(unMountPath, true).then(() =>
|
||||
updateFolder("/", undefined, unMountPath)
|
||||
);
|
||||
} catch {
|
||||
// Ignore error during unmounting
|
||||
}
|
||||
}
|
||||
},
|
||||
[unMapFs, updateFolder]
|
||||
);
|
||||
|
||||
return useCallback(
|
||||
async (FS?: EmscriptenFS, fsName?: string): Promise<void> => {
|
||||
if (!FS) return;
|
||||
|
||||
let name = "";
|
||||
|
||||
try {
|
||||
name = await mountEmscriptenFs(FS, fsName);
|
||||
} catch {
|
||||
// Ignore error during mounting
|
||||
}
|
||||
|
||||
if (name) {
|
||||
updateFolder("/", name);
|
||||
mountName.current = name;
|
||||
}
|
||||
},
|
||||
[mountEmscriptenFs, updateFolder]
|
||||
);
|
||||
};
|
||||
|
||||
export default useEmscriptenMount;
|
||||
|
|
@ -1,7 +1,11 @@
|
|||
import type HTTPRequest from "browserfs/dist/node/backend/HTTPRequest";
|
||||
import type IndexedDBFileSystem from "browserfs/dist/node/backend/IndexedDB";
|
||||
import type OverlayFS from "browserfs/dist/node/backend/OverlayFS";
|
||||
import type { RootFileSystem } from "contexts/fileSystem/useAsyncFs";
|
||||
import type {
|
||||
ExtendedEmscriptenFileSystem,
|
||||
Mount,
|
||||
RootFileSystem,
|
||||
} from "contexts/fileSystem/useAsyncFs";
|
||||
import { join } from "path";
|
||||
import { FS_HANDLES } from "utils/constants";
|
||||
import {
|
||||
|
|
@ -23,6 +27,11 @@ const KNOWN_IDB_DBS = [
|
|||
"keyval-store",
|
||||
];
|
||||
|
||||
export const isMountedFolder = (mount?: Mount): boolean =>
|
||||
typeof mount === "object" &&
|
||||
(mount.getName() === "FileSystemAccess" ||
|
||||
(mount as ExtendedEmscriptenFileSystem)._FS?.DB_STORE_NAME === "FILE_DATA");
|
||||
|
||||
export const addFileSystemHandle = async (
|
||||
directory: string,
|
||||
handle: FileSystemDirectoryHandle,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import {
|
|||
ICON_CACHE_EXTENSION,
|
||||
SESSION_FILE,
|
||||
} from "utils/constants";
|
||||
import type EmscriptenFileSystem from "browserfs/dist/node/backend/Emscripten";
|
||||
|
||||
export type AsyncFS = {
|
||||
exists: (path: string) => Promise<boolean>;
|
||||
|
|
@ -35,18 +36,26 @@ export type AsyncFS = {
|
|||
|
||||
const { BFSRequire, configure } = BrowserFS as typeof IBrowserFS;
|
||||
|
||||
export type EmscriptenFS = {
|
||||
DB_NAME: () => string;
|
||||
DB_STORE_NAME: string;
|
||||
};
|
||||
|
||||
export type ExtendedEmscriptenFileSystem = Omit<EmscriptenFileSystem, "_FS"> & {
|
||||
_FS?: EmscriptenFS;
|
||||
};
|
||||
|
||||
export type Mount = {
|
||||
_data?: Buffer;
|
||||
data?: Buffer;
|
||||
getName: () => string;
|
||||
};
|
||||
|
||||
export type RootFileSystem = Omit<
|
||||
MountableFileSystem,
|
||||
"mntMap" | "mountList"
|
||||
> & {
|
||||
mntMap: Record<
|
||||
string,
|
||||
{
|
||||
_data?: Buffer;
|
||||
data?: Buffer;
|
||||
getName: () => string;
|
||||
}
|
||||
>;
|
||||
mntMap: Record<string, Mount>;
|
||||
mountList: string[];
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,12 @@ import {
|
|||
} from "components/system/Files/FileManager/functions";
|
||||
import type { NewPath } from "components/system/Files/FileManager/useFolder";
|
||||
import { getFileSystemHandles } from "contexts/fileSystem/core";
|
||||
import type { AsyncFS, RootFileSystem } from "contexts/fileSystem/useAsyncFs";
|
||||
import type {
|
||||
AsyncFS,
|
||||
EmscriptenFS,
|
||||
ExtendedEmscriptenFileSystem,
|
||||
RootFileSystem,
|
||||
} from "contexts/fileSystem/useAsyncFs";
|
||||
import useAsyncFs from "contexts/fileSystem/useAsyncFs";
|
||||
import { useProcesses } from "contexts/process";
|
||||
import type { UpdateFiles } from "contexts/session/types";
|
||||
|
|
@ -32,6 +37,7 @@ import {
|
|||
TRANSITIONS_IN_MILLISECONDS,
|
||||
} from "utils/constants";
|
||||
import { bufferToBlob, getExtension } from "utils/functions";
|
||||
import { isMountedFolder } from "contexts/fileSystem/functions";
|
||||
|
||||
type FilePasteOperations = Record<string, "copy" | "move">;
|
||||
|
||||
|
|
@ -69,12 +75,13 @@ type FileSystemContextState = AsyncFS & {
|
|||
existingHandle?: FileSystemDirectoryHandle
|
||||
) => Promise<string>;
|
||||
mkdirRecursive: (path: string) => Promise<void>;
|
||||
mountEmscriptenFs: (FS: EmscriptenFS, fsName?: string) => Promise<string>;
|
||||
mountFs: (url: string) => Promise<void>;
|
||||
moveEntries: (entries: string[]) => void;
|
||||
pasteList: FilePasteOperations;
|
||||
removeFsWatcher: (folder: string, updateFiles: UpdateFiles) => void;
|
||||
rootFs?: RootFileSystem;
|
||||
unMapFs: (directory: string) => void;
|
||||
unMapFs: (directory: string, hasNoHandle?: boolean) => Promise<void>;
|
||||
unMountFs: (url: string) => void;
|
||||
updateFolder: (folder: string, newFile?: string, oldFile?: string) => void;
|
||||
};
|
||||
|
|
@ -82,7 +89,7 @@ type FileSystemContextState = AsyncFS & {
|
|||
const SYSTEM_DIRECTORIES = new Set(["/OPFS"]);
|
||||
|
||||
const {
|
||||
FileSystem: { FileSystemAccess, IsoFS, ZipFS },
|
||||
FileSystem: { Emscripten, FileSystemAccess, IsoFS, ZipFS },
|
||||
} = BrowserFS as IFileSystemAccess & typeof IBrowserFS;
|
||||
|
||||
const useFileSystemContextState = (): FileSystemContextState => {
|
||||
|
|
@ -176,7 +183,7 @@ const useFileSystemContextState = (): FileSystemContextState => {
|
|||
!watchedPaths.some((watchedPath) =>
|
||||
watchedPath.startsWith(mountedPath)
|
||||
) &&
|
||||
rootFs.mntMap[mountedPath]?.getName() !== "FileSystemAccess"
|
||||
!isMountedFolder(rootFs.mntMap[mountedPath])
|
||||
) {
|
||||
if (secondCheck) {
|
||||
rootFs.umount?.(mountedPath);
|
||||
|
|
@ -215,6 +222,28 @@ const useFileSystemContextState = (): FileSystemContextState => {
|
|||
),
|
||||
[]
|
||||
);
|
||||
const mountEmscriptenFs = useCallback(
|
||||
async (FS: EmscriptenFS, fsName?: string) =>
|
||||
new Promise<string>((resolve, reject) => {
|
||||
Emscripten?.Create({ FS }, (error, newFs) => {
|
||||
const emscriptenFS = newFs as unknown as ExtendedEmscriptenFileSystem;
|
||||
|
||||
if (error || !newFs || !emscriptenFS._FS?.DB_NAME) {
|
||||
reject();
|
||||
return;
|
||||
}
|
||||
|
||||
const dbName =
|
||||
fsName ||
|
||||
`${emscriptenFS._FS?.DB_NAME().replace(/\/+$/, "")}${emscriptenFS
|
||||
._FS?.DB_STORE_NAME}`;
|
||||
|
||||
rootFs?.mount?.(join("/", dbName), newFs);
|
||||
resolve(dbName);
|
||||
});
|
||||
}),
|
||||
[rootFs]
|
||||
);
|
||||
const mapFs = useCallback(
|
||||
async (
|
||||
directory: string,
|
||||
|
|
@ -289,13 +318,17 @@ const useFileSystemContextState = (): FileSystemContextState => {
|
|||
[rootFs]
|
||||
);
|
||||
const unMapFs = useCallback(
|
||||
(directory: string): void => {
|
||||
async (directory: string, hasNoHandle?: boolean): Promise<void> => {
|
||||
unMountFs(directory);
|
||||
updateFolder(dirname(directory), undefined, directory);
|
||||
|
||||
import("contexts/fileSystem/functions").then(
|
||||
({ removeFileSystemHandle }) => removeFileSystemHandle(directory)
|
||||
if (hasNoHandle) return;
|
||||
|
||||
const { removeFileSystemHandle } = await import(
|
||||
"contexts/fileSystem/functions"
|
||||
);
|
||||
|
||||
removeFileSystemHandle(directory);
|
||||
},
|
||||
[unMountFs, updateFolder]
|
||||
);
|
||||
|
|
@ -498,6 +531,7 @@ const useFileSystemContextState = (): FileSystemContextState => {
|
|||
deletePath,
|
||||
mapFs,
|
||||
mkdirRecursive,
|
||||
mountEmscriptenFs,
|
||||
mountFs,
|
||||
moveEntries,
|
||||
pasteList,
|
||||
|
|
|
|||
|
|
@ -2023,8 +2023,12 @@ var FS = {
|
|||
"r+": 2,
|
||||
"w": 577,
|
||||
"w+": 578,
|
||||
"wx": 705,
|
||||
"wx+": 706,
|
||||
"a": 1089,
|
||||
"a+": 1090
|
||||
"a+": 1090,
|
||||
"ax": 1217,
|
||||
"ax+": 1218
|
||||
},
|
||||
modeStringToFlags: function(str) {
|
||||
var flags = FS.flagModes[str];
|
||||
|
|
|
|||
|
|
@ -7650,6 +7650,7 @@ __ATEXIT__.push({
|
|||
FS.quit()
|
||||
})
|
||||
});
|
||||
VimModule["FS"] = FS;
|
||||
VimModule["FS_createFolder"] = FS.createFolder;
|
||||
VimModule["FS_createPath"] = FS.createPath;
|
||||
VimModule["FS_createDataFile"] = FS.createDataFile;
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
5
public/System/BrowserFS/browserfs.min.js
vendored
5
public/System/BrowserFS/browserfs.min.js
vendored
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user