Skip to content
Open
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/fuse-daemon/internal/filesystem/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func Mount(mountPoint string, logger *slog.Logger, client *client.Client) (*fuse
MaxReadAhead: 128 * 1024,
DisableXAttrs: false,
Debug: false,
DirectMount: true,
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a new parameter that, according to the documentation, cleans up existing mounts before remounting. This prevents orphaned mounts from causing remount failures.

https://github.com/hanwen/go-fuse/blob/v2.9.0/fuse/api.go#L312

}

server, _, err := nodefs.Mount(mountPoint, nodeFileSystem.Root(), mountOptions, nil)
Expand Down
24 changes: 20 additions & 4 deletions packages/fuse-daemon/internal/filesystem/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package filesystem

import (
"log/slog"
"syscall"

"github.com/hanwen/go-fuse/v2/fuse"
"github.com/hanwen/go-fuse/v2/fuse/nodefs"
Expand Down Expand Up @@ -30,14 +31,29 @@ func NewInternxtFilesystem(logger *slog.Logger, client *client.Client) *Internxt
client: client,
}
}

func isRootPath(name string) bool {
return name == "" || name == "/"
}

func (fs *InternxtFilesystem) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) {
fs.logger.Warn("not implemented", "op", "GetAttr", "path", name)
return nil, fuse.ENOSYS
if isRootPath(name) {
return &fuse.Attr{
Mode: uint32(syscall.S_IFDIR | 0o755),
Nlink: 2,
Owner: fuse.Owner{Uid: context.Owner.Uid, Gid: context.Owner.Gid},
}, fuse.OK
}

return nil, fuse.ENOENT
}

func (fs *InternxtFilesystem) OpenDir(name string, context *fuse.Context) ([]fuse.DirEntry, fuse.Status) {
fs.logger.Warn("not implemented", "op", "OpenDir", "path", name)
return nil, fuse.ENOSYS
if isRootPath(name) {
return []fuse.DirEntry{}, fuse.OK
}

return nil, fuse.ENOENT
}
Comment on lines 39 to 57
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These callbacks currently include only the bare minimum required to access the folder. Once the drive content loading logic is implemented, these elements will likely be relocated.

// Open returns a file handle for the given path.
// When implementing: return a nodefs.File handle that implements Read, Write, Release, and Flush.
Expand Down
1 change: 1 addition & 0 deletions src/apps/main/interface.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export interface IElectronAPI {
onRemoteChanges(func: (value: import('../main/realtime').EventPayload) => void): () => void;

openVirtualDriveFolder(): Promise<void>;
onVirtualDriveFolderOpenError(callback: () => void): () => void;

openProcessIssuesWindow(): void;

Expand Down
1 change: 1 addition & 0 deletions src/apps/main/preload.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ declare interface Window {
onVirtualDriveStatusChange(
callback: (event: { status: import('../drive/fuse/FuseDriveStatus').FuseDriveStatus }) => void,
): () => void;
onVirtualDriveFolderOpenError(callback: () => void): () => void;
startRemoteSync: () => Promise<void>;
openUrl: (url: string) => Promise<void>;
getPreferredAppLanguage: () => Promise<Array<string>>;
Expand Down
9 changes: 9 additions & 0 deletions src/apps/main/preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,15 @@ contextBridge.exposeInMainWorld('electron', {

return () => ipcRenderer.removeListener(eventName, callbackWrapper);
},
onVirtualDriveFolderOpenError(callback) {
const eventName = 'virtual-drive-folder-open-error';
const callbackWrapper = () => {
callback();
};
ipcRenderer.on(eventName, callbackWrapper);

return () => ipcRenderer.removeListener(eventName, callbackWrapper);
},
openUrl: (url) => {
ipcRenderer.invoke('open-url', url);
},
Expand Down
32 changes: 21 additions & 11 deletions src/apps/main/virtual-root-folder/service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { dialog, shell } from 'electron';
import { dialog } from 'electron';
import fs from 'fs/promises';
import path from 'node:path';
import { sep } from 'node:path';
import configStore from '../config';
import eventBus from '../event-bus';
import { exec } from 'child_process';
import { execFile } from 'node:child_process';
import { ensureFolderExists } from '../../shared/fs/ensure-folder-exists';
import { PATHS } from '../../../core/electron/paths';
import { logger } from '@internxt/drive-desktop-core/build/backend';
import { broadcastToWindows } from '../windows';

const VIRTUAL_DRIVE_FOLDER = PATHS.ROOT_DRIVE_FOLDER;

Expand Down Expand Up @@ -37,7 +39,7 @@
}

function setSyncRoot(pathname: string): void {
const pathNameWithSepInTheEnd = pathname[pathname.length - 1] === path.sep ? pathname : pathname + path.sep;
const pathNameWithSepInTheEnd = pathname[pathname.length - 1] === sep ? pathname : pathname + sep;

Check warning on line 42 in src/apps/main/virtual-root-folder/service.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `.at(…)` over `[….length - index]`.

See more on https://sonarcloud.io/project/issues?id=internxt_drive-desktop-linux&issues=AZ2TBrOlBOENhfW4lNMq&open=AZ2TBrOlBOENhfW4lNMq&pullRequest=312

Check warning on line 42 in src/apps/main/virtual-root-folder/service.ts

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use the 'String#endsWith' method instead.

See more on https://sonarcloud.io/project/issues?id=internxt_drive-desktop-linux&issues=AZ2TBrOlBOENhfW4lNMp&open=AZ2TBrOlBOENhfW4lNMp&pullRequest=312
configStore.set('syncRoot', pathNameWithSepInTheEnd);
configStore.set('lastSavedListing', '');
}
Expand Down Expand Up @@ -72,24 +74,32 @@
return null;
}

export async function openVirtualDriveRootFolder() {
export async function openVirtualDriveRootFolder(): Promise<void> {
const syncFolderPath = getRootVirtualDrive();

if (process.platform === 'linux') {
// shell.openPath is not working as intended with the mounted directory
// this is only a workaround to fix it
function openWithXdg(targetPath: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
exec(`xdg-open "${syncFolderPath}"`, (error) => {
execFile('xdg-open', [targetPath], (error) => {
if (error) {
reject(error);
return;
}

resolve();
});
});
}

const errorMessage = await shell.openPath(syncFolderPath);
try {
await openWithXdg(syncFolderPath);
return;
} catch (error) {
logger.warn({
msg: '[VIRTUAL DRIVE] opening mountpoint failed',
syncFolderPath,
error,
});

if (errorMessage) throw new Error(errorMessage);
broadcastToWindows('virtual-drive-folder-open-error', undefined);
}
}
10 changes: 10 additions & 0 deletions src/apps/renderer/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@
return cleanup;
}, []);

useEffect(() => {
const cleanup = window.electron.onVirtualDriveFolderOpenError(() => {

Check warning on line 76 in src/apps/renderer/App.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Prefer `globalThis` over `window`.

See more on https://sonarcloud.io/project/issues?id=internxt_drive-desktop-linux&issues=AZ2TBrLqBOENhfW4lNMo&open=AZ2TBrLqBOENhfW4lNMo&pullRequest=312
new Notification(i18next.t('widget.virtual-drive-folder-open-error.title'), {
body: i18next.t('widget.virtual-drive-folder-open-error.message'),
});
});

return cleanup;
}, []);

return (
<Router>
<Suspense fallback={<Loader />}>
Expand Down
4 changes: 4 additions & 0 deletions src/apps/renderer/localize/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@
"mounting": "Mounting...",
"button": "Mount"
},
"virtual-drive-folder-open-error": {
"title": "Internxt Drive",
"message": "Internxt Drive folder is not available right now."
},
"banners": {
"update-available": {
"body": "A new version is available.",
Expand Down
4 changes: 4 additions & 0 deletions src/apps/renderer/localize/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@
"mounting": "Montando..",
"button": "Montar"
},
"virtual-drive-folder-open-error": {
"title": "Internxt Drive",
"message": "La carpeta de Internxt Drive no esta disponible en este momento."
},
"banners": {
"update-available": {
"body": "Hay una nueva versión disponible.",
Expand Down
4 changes: 4 additions & 0 deletions src/apps/renderer/localize/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@
"mounting": "Montage...",
"button": "Monter"
},
"virtual-drive-folder-open-error": {
"title": "Internxt Drive",
"message": "Le dossier Internxt Drive n'est pas disponible pour le moment."
},
"banners": {
"update-available": {
"body": "Une nouvelle version est disponible.",
Expand Down
Loading