Files
dap/ts/classes.mountmanager.ts
T

77 lines
2.7 KiB
TypeScript
Raw Permalink Normal View History

import * as plugins from './plugins.js';
import { SshClient } from './classes.sshclient.js';
import type { IMountRequest, TDapMountBackend } from './types.js';
export class MountManager {
constructor(private sshClient = new SshClient()) {}
public parseRemoteSpec(remoteSpec: string): { host: string; remotePath: string } {
const separatorIndex = remoteSpec.indexOf(':');
if (separatorIndex <= 0) {
throw new Error('Remote mount spec must look like <host>:<remotePath>');
}
const host = remoteSpec.slice(0, separatorIndex);
const remotePath = remoteSpec.slice(separatorIndex + 1) || '.';
return { host, remotePath };
}
public buildSshfsArgs(request: IMountRequest): string[] {
return [`${request.host}:${request.remotePath}`, request.localPath];
}
public buildRcloneArgs(request: IMountRequest): string[] {
return [
'mount',
`:sftp:${request.remotePath}`,
request.localPath,
'--sftp-ssh',
`ssh ${request.host}`,
'--sftp-shell-type',
'none',
'--vfs-cache-mode',
'writes',
];
}
public async mount(request: IMountRequest): Promise<number> {
await plugins.fs.mkdir(request.localPath, { recursive: true });
const backend = request.backend ?? (await this.detectBackend());
if (backend === 'sshfs') {
return this.sshClient.spawnInteractive('sshfs', this.buildSshfsArgs(request));
}
return this.sshClient.spawnInteractive('rclone', this.buildRcloneArgs(request));
}
public async mountDetached(request: IMountRequest): Promise<number> {
await plugins.fs.mkdir(request.localPath, { recursive: true });
const backend = request.backend ?? (await this.detectBackend());
if (backend === 'sshfs') {
return this.sshClient.spawnInteractive('sshfs', this.buildSshfsArgs(request));
}
return this.sshClient.spawnDetached('rclone', this.buildRcloneArgs(request));
}
public async unmount(localPath: string): Promise<number> {
if (process.platform === 'darwin') {
return this.sshClient.spawnInteractive('umount', [localPath]);
}
if (await this.sshClient.commandExists('fusermount3')) {
return this.sshClient.spawnInteractive('fusermount3', ['-u', localPath]);
}
if (await this.sshClient.commandExists('fusermount')) {
return this.sshClient.spawnInteractive('fusermount', ['-u', localPath]);
}
return this.sshClient.spawnInteractive('umount', [localPath]);
}
public async detectBackend(): Promise<TDapMountBackend> {
if (await this.sshClient.commandExists('sshfs')) {
return 'sshfs';
}
if (await this.sshClient.commandExists('rclone')) {
return 'rclone';
}
throw new Error('No mount backend found. Install sshfs, or install rclone with FUSE/macFUSE support.');
}
}