From 0ef184901310201b4b8e3e4aafd31b7d576e14ef Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 31 Dec 2024 15:00:29 -0500 Subject: [PATCH] dev: make puterfs a mountpoint --- .../src/filesystem/FilesystemService.js | 7 +- .../src/modules/puterfs/MountpointService.js | 68 ++++++++++++++++++- .../src/modules/puterfs/PuterFSModule.js | 3 + .../src/modules/puterfs/PuterFSService.js | 22 ++++++ .../puterfs/lib}/PuterFSProvider.js | 6 +- src/backend/src/services/UserService.js | 2 +- 6 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 src/backend/src/modules/puterfs/PuterFSService.js rename src/backend/src/{filesystem/puterfs => modules/puterfs/lib}/PuterFSProvider.js (93%) diff --git a/src/backend/src/filesystem/FilesystemService.js b/src/backend/src/filesystem/FilesystemService.js index b7453f44f..549b4da63 100644 --- a/src/backend/src/filesystem/FilesystemService.js +++ b/src/backend/src/filesystem/FilesystemService.js @@ -34,7 +34,7 @@ const { DB_WRITE } = require("../services/database/consts"); const { UserActorType } = require('../services/auth/Actor'); const { get_user } = require('../helpers'); const BaseService = require('../services/BaseService'); -const { PuterFSProvider } = require('./puterfs/PuterFSProvider.js'); +const { PuterFSProvider } = require('../modules/puterfs/lib/PuterFSProvider.js'); class FilesystemService extends BaseService { static MODULES = { @@ -344,8 +344,11 @@ class FilesystemService extends BaseService { } } + const svc_mountpoint = this.services.get('mountpoint'); + const provider = await svc_mountpoint.get_provider(selector); + let fsNode = new FSNodeContext({ - provider: new PuterFSProvider(), + provider, services: this.services, selector, fs: this diff --git a/src/backend/src/modules/puterfs/MountpointService.js b/src/backend/src/modules/puterfs/MountpointService.js index 6505968b2..5fce89d20 100644 --- a/src/backend/src/modules/puterfs/MountpointService.js +++ b/src/backend/src/modules/puterfs/MountpointService.js @@ -19,6 +19,7 @@ */ // const Mountpoint = o => ({ ...o }); +const { RootNodeSelector, NodeUIDSelector } = require("../../filesystem/node/selectors"); const BaseService = require("../../services/BaseService"); /** @@ -38,6 +39,15 @@ const BaseService = require("../../services/BaseService"); * and their associated storage backends in future implementations. */ class MountpointService extends BaseService { + _construct () { + this.mounters_ = {}; + this.mountpoints_ = {}; + } + + register_mounter (name, mounter) { + this.mounters_[name] = mounter; + } + /** * Initializes the MountpointService instance * Sets up initial state with null storage backend @@ -46,11 +56,65 @@ class MountpointService extends BaseService { * @returns {Promise} */ async _init () { - // this.mountpoints_ = {}; - // Temporary solution - we'll develop this incrementally this.storage_ = null; } + + async ['__on_boot.consolidation'] () { + const mountpoints = this.config.mountpoints ?? { + '/': { + mounter: 'puterfs', + }, + }; + + for ( const path of Object.keys(mountpoints) ) { + const { mounter: mounter_name, options } = + mountpoints[path]; + const mounter = this.mounters_[mounter_name]; + const provider = await mounter.mount({ + path, + options + }); + this.mountpoints_[path] = { + provider, + }; + } + + this.services.emit('filesystem.ready', { + mountpoints: Object.keys(this.mountpoints_), + }); + } + + async get_provider (selector) { + if ( selector instanceof RootNodeSelector ) { + return this.mountpoints_['/'].provider; + } + + if ( selector instanceof NodeUIDSelector ) { + return this.mountpoints_['/'].provider; + } + + const probe = {}; + selector.setPropertiesKnownBySelector(probe); + if ( probe.path ) { + let longest_mount_path = ''; + for ( const path of Object.keys(this.mountpoints_) ) { + if ( ! probe.path.startsWith(path) ) { + continue; + } + if ( path.length > longest_mount_path.length ) { + longest_mount_path = path; + } + } + + if ( longest_mount_path ) { + return this.mountpoints_[longest_mount_path].provider; + } + } + + // Use root mountpoint as fallback + return this.mountpoints_['/'].provider; + } // Temporary solution - we'll develop this incrementally set_storage (storage) { diff --git a/src/backend/src/modules/puterfs/PuterFSModule.js b/src/backend/src/modules/puterfs/PuterFSModule.js index c78220478..09f157d4f 100644 --- a/src/backend/src/modules/puterfs/PuterFSModule.js +++ b/src/backend/src/modules/puterfs/PuterFSModule.js @@ -15,6 +15,9 @@ class PuterFSModule extends AdvancedBase { const { MountpointService } = require('./MountpointService'); services.registerService('mountpoint', MountpointService); + + const { PuterFSService } = require('./PuterFSService'); + services.registerService('puterfs', PuterFSService); const DatabaseFSEntryFetcher = require("./DatabaseFSEntryFetcher"); services.registerService('fsEntryFetcher', DatabaseFSEntryFetcher); diff --git a/src/backend/src/modules/puterfs/PuterFSService.js b/src/backend/src/modules/puterfs/PuterFSService.js new file mode 100644 index 000000000..4678c050d --- /dev/null +++ b/src/backend/src/modules/puterfs/PuterFSService.js @@ -0,0 +1,22 @@ +const BaseService = require("../../services/BaseService"); +const { PuterFSProvider } = require("./lib/PuterFSProvider"); + +class PuterFSService extends BaseService { + async _init () { + const svc_mountpoint = this.services.get('mountpoint'); + svc_mountpoint.register_mounter('puterfs', this.as('mounter')); + } + + static IMPLEMENTS = { + mounter: { + async mount ({ path, options }) { + const provider = new PuterFSProvider(); + return provider; + } + } + } +} + +module.exports = { + PuterFSService, +}; \ No newline at end of file diff --git a/src/backend/src/filesystem/puterfs/PuterFSProvider.js b/src/backend/src/modules/puterfs/lib/PuterFSProvider.js similarity index 93% rename from src/backend/src/filesystem/puterfs/PuterFSProvider.js rename to src/backend/src/modules/puterfs/lib/PuterFSProvider.js index 1c4023302..b40657f71 100644 --- a/src/backend/src/filesystem/puterfs/PuterFSProvider.js +++ b/src/backend/src/modules/puterfs/lib/PuterFSProvider.js @@ -2,9 +2,9 @@ const putility = require('@heyputer/putility'); const { MultiDetachable } = putility.libs.listener; const { TDetachable } = putility.traits; -const { NodeInternalIDSelector, NodeChildSelector, NodeUIDSelector, RootNodeSelector, NodePathSelector } = require("../node/selectors"); -const { Context } = require("../../util/context"); -const fsCapabilities = require('../definitions/capabilities'); +const { NodeInternalIDSelector, NodeChildSelector, NodeUIDSelector, RootNodeSelector, NodePathSelector } = require("../../../filesystem/node/selectors"); +const { Context } = require("../../../util/context"); +const fsCapabilities = require('../../../filesystem/definitions/capabilities'); class PuterFSProvider { get_capabilities () { diff --git a/src/backend/src/services/UserService.js b/src/backend/src/services/UserService.js index 70c87ba24..1ac735ef2 100644 --- a/src/backend/src/services/UserService.js +++ b/src/backend/src/services/UserService.js @@ -14,7 +14,7 @@ class UserService extends BaseService { this.dir_system = null; } - async ['__on_boot.consolidation'] () { + async ['__on_filesystem.ready'] () { const svc_fs = this.services.get('filesystem'); // Ensure system user has a home directory const dir_system = await svc_fs.node(