configure meta-fuse to connect to meta-core
This commit is contained in:
@@ -242,8 +242,8 @@ WEBDAV_USERNAME=metamesh # WebDAV username
|
|||||||
WEBDAV_PASSWORD=metamesh # WebDAV password
|
WEBDAV_PASSWORD=metamesh # WebDAV password
|
||||||
WEBDAV_READONLY=true # Read-only mode
|
WEBDAV_READONLY=true # Read-only mode
|
||||||
|
|
||||||
# meta-sort WebDAV Access (reading files from meta-sort)
|
# meta-core WebDAV Access (reading files from meta-core)
|
||||||
META_SORT_WEBDAV_URL=http://meta-sort-dev/webdav # URL to access files via meta-sort's WebDAV
|
META_CORE_WEBDAV_URL=http://meta-core/webdav # URL to access files via meta-core's WebDAV
|
||||||
# Enables access to SMB/rclone mounts
|
# Enables access to SMB/rclone mounts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -276,8 +276,8 @@ services:
|
|||||||
- FILES_VOLUME=/files
|
- FILES_VOLUME=/files
|
||||||
- FUSE_MOUNT_POINT=/mnt/virtual
|
- FUSE_MOUNT_POINT=/mnt/virtual
|
||||||
- REDIS_PREFIX=meta-sort:
|
- REDIS_PREFIX=meta-sort:
|
||||||
# Optional: Read files via meta-sort WebDAV (enables SMB/rclone mount access)
|
# Optional: Read files via meta-core WebDAV (enables SMB/rclone mount access)
|
||||||
- META_SORT_WEBDAV_URL=http://meta-sort/webdav
|
- META_CORE_WEBDAV_URL=http://meta-core/webdav
|
||||||
```
|
```
|
||||||
|
|
||||||
## API Endpoints
|
## API Endpoints
|
||||||
|
|||||||
@@ -57,13 +57,13 @@ async function main(): Promise<void> {
|
|||||||
vfsRefreshInterval: parseInt(process.env.VFS_REFRESH_INTERVAL ?? '30000', 10),
|
vfsRefreshInterval: parseInt(process.env.VFS_REFRESH_INTERVAL ?? '30000', 10),
|
||||||
baseUrl: process.env.BASE_URL,
|
baseUrl: process.env.BASE_URL,
|
||||||
serviceVersion: process.env.SERVICE_VERSION ?? '1.0.0',
|
serviceVersion: process.env.SERVICE_VERSION ?? '1.0.0',
|
||||||
// WebDAV URL for meta-sort file access (e.g., http://meta-sort-dev/webdav)
|
// WebDAV URL for meta-core file access (e.g., http://meta-core/webdav)
|
||||||
metaSortWebdavUrl: process.env.META_SORT_WEBDAV_URL,
|
metaCoreWebdavUrl: process.env.META_CORE_WEBDAV_URL,
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.info(`Config: META_CORE_PATH=${config.metaCorePath}, FILES_VOLUME=${config.filesPath}`);
|
logger.info(`Config: META_CORE_PATH=${config.metaCorePath}, FILES_VOLUME=${config.filesPath}`);
|
||||||
if (config.metaSortWebdavUrl) {
|
if (config.metaCoreWebdavUrl) {
|
||||||
logger.info(`WebDAV: Using meta-sort WebDAV at ${config.metaSortWebdavUrl}`);
|
logger.info(`WebDAV: Using meta-core WebDAV at ${config.metaCoreWebdavUrl}`);
|
||||||
} else {
|
} else {
|
||||||
logger.info(`WebDAV: Not configured, FUSE driver will use local filesystem`);
|
logger.info(`WebDAV: Not configured, FUSE driver will use local filesystem`);
|
||||||
}
|
}
|
||||||
@@ -125,7 +125,7 @@ async function main(): Promise<void> {
|
|||||||
gid: parseInt(process.env.PGID ?? '1000', 10),
|
gid: parseInt(process.env.PGID ?? '1000', 10),
|
||||||
refreshInterval: config.vfsRefreshInterval,
|
refreshInterval: config.vfsRefreshInterval,
|
||||||
configDir: process.env.CONFIG_DIR ?? '/meta-fuse/config',
|
configDir: process.env.CONFIG_DIR ?? '/meta-fuse/config',
|
||||||
webdavBaseUrl: config.metaSortWebdavUrl,
|
webdavBaseUrl: config.metaCoreWebdavUrl,
|
||||||
filesPath: config.filesPath,
|
filesPath: config.filesPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ export class VirtualFileSystem {
|
|||||||
// Compute virtual path using rules or fallback
|
// Compute virtual path using rules or fallback
|
||||||
const virtualPath = this.computeVirtualPath(metadata, sourcePath);
|
const virtualPath = this.computeVirtualPath(metadata, sourcePath);
|
||||||
if (virtualPath) {
|
if (virtualPath) {
|
||||||
this.addFile(virtualPath, metadata);
|
await this.addFile(virtualPath, metadata);
|
||||||
this.sourcePathToVirtualPath.set(sourcePath, virtualPath);
|
this.sourcePathToVirtualPath.set(sourcePath, virtualPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,7 +325,7 @@ export class VirtualFileSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add/update file
|
// Add/update file
|
||||||
this.addFile(virtualPath, metadata);
|
await this.addFile(virtualPath, metadata);
|
||||||
this.sourcePathToVirtualPath.set(metadata.sourcePath, virtualPath);
|
this.sourcePathToVirtualPath.set(metadata.sourcePath, virtualPath);
|
||||||
|
|
||||||
logger.debug(`File ${action}ed: ${virtualPath}`);
|
logger.debug(`File ${action}ed: ${virtualPath}`);
|
||||||
@@ -334,7 +334,7 @@ export class VirtualFileSystem {
|
|||||||
/**
|
/**
|
||||||
* Add a file to the VFS
|
* Add a file to the VFS
|
||||||
*/
|
*/
|
||||||
private addFile(virtualPath: string, metadata: FileMetadata): void {
|
private async addFile(virtualPath: string, metadata: FileMetadata): Promise<void> {
|
||||||
virtualPath = this.normalizePath(virtualPath);
|
virtualPath = this.normalizePath(virtualPath);
|
||||||
|
|
||||||
// Skip if file already exists at this path
|
// Skip if file already exists at this path
|
||||||
@@ -363,10 +363,22 @@ export class VirtualFileSystem {
|
|||||||
mtime = stats.mtime;
|
mtime = stats.mtime;
|
||||||
ctime = stats.ctime;
|
ctime = stats.ctime;
|
||||||
} catch {
|
} catch {
|
||||||
|
// Local stat failed, try WebDAV if configured
|
||||||
|
if (this.config.webdavBaseUrl) {
|
||||||
|
const webdavStats = await this.statViaWebDAV(metadata.sourcePath);
|
||||||
|
if (webdavStats) {
|
||||||
|
size = webdavStats.size;
|
||||||
|
mtime = webdavStats.mtime || mtime;
|
||||||
|
} else {
|
||||||
|
logger.warn(`Cannot stat source file via WebDAV: ${metadata.sourcePath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
logger.warn(`Cannot stat source file: ${metadata.sourcePath}`);
|
logger.warn(`Cannot stat source file: ${metadata.sourcePath}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add file node
|
// Add file node
|
||||||
const filename = path.basename(virtualPath);
|
const filename = path.basename(virtualPath);
|
||||||
@@ -392,6 +404,49 @@ export class VirtualFileSystem {
|
|||||||
this.cachedStats.totalSize += size;
|
this.cachedStats.totalSize += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get file stats via WebDAV HEAD request
|
||||||
|
*/
|
||||||
|
private async statViaWebDAV(sourcePath: string): Promise<{ size: number; mtime?: Date } | null> {
|
||||||
|
if (!this.config.webdavBaseUrl) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Convert source path to WebDAV URL
|
||||||
|
let relativePath = sourcePath;
|
||||||
|
if (this.config.filesPath && sourcePath.startsWith(this.config.filesPath)) {
|
||||||
|
relativePath = sourcePath.slice(this.config.filesPath.length);
|
||||||
|
}
|
||||||
|
if (!relativePath.startsWith('/')) {
|
||||||
|
relativePath = '/' + relativePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
// URL-encode path segments (but not slashes)
|
||||||
|
const encodedPath = relativePath.split('/').map(segment => encodeURIComponent(segment)).join('/');
|
||||||
|
const webdavUrl = this.config.webdavBaseUrl + encodedPath;
|
||||||
|
|
||||||
|
// Make HEAD request
|
||||||
|
const response = await fetch(webdavUrl, { method: 'HEAD' });
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
const contentLength = response.headers.get('Content-Length');
|
||||||
|
const lastModified = response.headers.get('Last-Modified');
|
||||||
|
|
||||||
|
return {
|
||||||
|
size: contentLength ? parseInt(contentLength, 10) : 0,
|
||||||
|
mtime: lastModified ? new Date(lastModified) : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug(`WebDAV HEAD failed for ${webdavUrl}: ${response.status}`);
|
||||||
|
return null;
|
||||||
|
} catch (error: any) {
|
||||||
|
logger.debug(`WebDAV stat error for ${sourcePath}: ${error.message}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a file from the VFS
|
* Remove a file from the VFS
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user