doc: add comments under filesystem, modules, entitystorage

* Added reference documentation for: src/backend/src/modules/puterfs/DatabaseFSEntryFetcher.js

* Added reference documentation for: src/backend/src/modules/dns/DNSService.js

* Added reference documentation for: src/backend/src/filesystem/ll_operations/ll_write.js

* Added reference documentation for: src/backend/src/filesystem/strategies/storage_a/LocalDiskStorageStrategy.js

* Added reference documentation for: src/backend/src/om/entitystorage/WriteByOwnerOnlyES.js

---------

Co-authored-by: askmanu[bot] <192355599+askmanu[bot]@users.noreply.github.com>
This commit is contained in:
Andrei Onel
2025-09-29 21:16:50 +03:00
committed by GitHub
parent 5caf148ae9
commit d216887fa0
5 changed files with 199 additions and 0 deletions
@@ -32,12 +32,27 @@ const crypto = require('crypto');
const STUCK_STATUS_TIMEOUT = 10 * 1000;
const STUCK_ALARM_TIMEOUT = 20 * 1000;
/**
* Base class for low-level write operations providing common storage upload functionality.
* @extends LLFilesystemOperation
*/
class LLWriteBase extends LLFilesystemOperation {
static MODULES = {
config: require('../../config.js'),
simple_retry: require('../../util/retryutil.js').simple_retry,
}
/**
* Uploads a file to storage with progress tracking and error handling.
* @param {Object} params - Upload parameters
* @param {string} params.uuid - Unique identifier for the file
* @param {string} [params.bucket] - Storage bucket name
* @param {string} [params.bucket_region] - Storage bucket region
* @param {Object} params.file - File object containing stream or buffer
* @param {Object} params.tmp - Temporary file information
* @returns {Promise<Object>} The upload state object
* @throws {APIError} When upload fails
*/
async _storage_upload ({
uuid,
bucket, bucket_region, file,
@@ -154,6 +169,11 @@ class LLWriteBase extends LLFilesystemOperation {
* @extends LLWriteBase
*/
class LLOWrite extends LLWriteBase {
/**
* Executes the overwrite operation by writing to an existing file node.
* @returns {Promise<Object>} Result of the write operation
* @throws {APIError} When the target node does not exist
*/
async _run () {
const node = this.values.node;
@@ -193,6 +213,11 @@ class LLCWrite extends LLWriteBase {
config: require('../../config.js'),
}
/**
* Executes the create operation by writing a new file to the parent directory.
* @returns {Promise<Object>} Result of the write operation
* @throws {APIError} When the parent directory does not exist
*/
async _run () {
const parent = this.values.parent;
@@ -18,13 +18,26 @@
*/
const { BaseOperation } = require("../../../services/OperationTraceService");
/**
* Handles file upload operations to local disk storage.
* Extends BaseOperation to provide upload functionality with progress tracking.
*/
class LocalDiskUploadStrategy extends BaseOperation {
/**
* Creates a new LocalDiskUploadStrategy instance.
* @param {Object} parent - The parent storage strategy instance
*/
constructor (parent) {
super();
this.parent = parent;
this.uid = null;
}
/**
* Executes the upload operation by storing file data to local disk.
* Handles both buffer and stream-based uploads with progress tracking.
* @returns {Promise<void>} Resolves when the upload is complete
*/
async _run () {
const { uid, file, storage_api } = this.values;
@@ -50,15 +63,31 @@ class LocalDiskUploadStrategy extends BaseOperation {
}
}
/**
* Hook called after the operation is inserted into the trace.
*/
post_insert () {}
}
/**
* Handles file copy operations within local disk storage.
* Extends BaseOperation to provide copy functionality with progress tracking.
*/
class LocalDiskCopyStrategy extends BaseOperation {
/**
* Creates a new LocalDiskCopyStrategy instance.
* @param {Object} parent - The parent storage strategy instance
*/
constructor (parent) {
super();
this.parent = parent;
}
/**
* Executes the copy operation by duplicating a file from source to destination.
* Updates progress tracker to indicate completion.
* @returns {Promise<void>} Resolves when the copy is complete
*/
async _run () {
const { src_node, dst_storage, storage_api } = this.values;
const { progress_tracker } = storage_api;
@@ -73,15 +102,30 @@ class LocalDiskCopyStrategy extends BaseOperation {
progress_tracker.set(1);
}
/**
* Hook called after the operation is inserted into the trace.
*/
post_insert () {}
}
/**
* Handles file deletion operations from local disk storage.
* Extends BaseOperation to provide delete functionality.
*/
class LocalDiskDeleteStrategy extends BaseOperation {
/**
* Creates a new LocalDiskDeleteStrategy instance.
* @param {Object} parent - The parent storage strategy instance
*/
constructor (parent) {
super();
this.parent = parent;
}
/**
* Executes the delete operation by removing a file from local disk storage.
* @returns {Promise<void>} Resolves when the deletion is complete
*/
async _run () {
const { node } = this.values;
@@ -91,20 +135,50 @@ class LocalDiskDeleteStrategy extends BaseOperation {
}
}
/**
* Main strategy class for managing local disk storage operations.
* Provides factory methods for creating upload, copy, and delete operations.
*/
class LocalDiskStorageStrategy {
/**
* Creates a new LocalDiskStorageStrategy instance.
* @param {Object} config - Configuration object
* @param {Object} config.services - Services container for dependency injection
*/
constructor ({ services }) {
this.svc_localDiskStorage = services.get('local-disk-storage');
}
/**
* Creates a new upload operation instance.
* @returns {LocalDiskUploadStrategy} A new upload strategy instance
*/
create_upload () {
return new LocalDiskUploadStrategy(this);
}
/**
* Creates a new copy operation instance.
* @returns {LocalDiskCopyStrategy} A new copy strategy instance
*/
create_copy () {
return new LocalDiskCopyStrategy(this);
}
/**
* Creates a new delete operation instance.
* @returns {LocalDiskDeleteStrategy} A new delete strategy instance
*/
create_delete () {
return new LocalDiskDeleteStrategy(this);
}
/**
* Creates a readable stream for accessing file data from local disk storage.
* @param {string} uid - The unique identifier of the file to read
* @param {Object} [options={}] - Optional parameters for stream creation
* @returns {Promise<ReadableStream>} A readable stream for the file data
*/
async create_read_stream (uid, options = {}) {
return await this.svc_localDiskStorage.create_read_stream(uid, options);
}
+16
View File
@@ -1,7 +1,15 @@
const BaseService = require("../../services/BaseService");
const { sleep } = require("../../util/asyncutil");
/**
* DNS service that provides DNS client functionality and optional test server
* @extends BaseService
*/
class DNSService extends BaseService {
/**
* Initializes the DNS service by creating a DNS client and optionally starting a test server
* @returns {Promise<void>}
*/
async _init () {
const dns2 = require('dns2');
// this.dns = new dns2(this.config.client);
@@ -15,10 +23,18 @@ class DNSService extends BaseService {
}
}
/**
* Returns the DNS client instance
* @returns {Object} The DNS client
*/
get_client () {
return this.dns;
}
/**
* Creates and starts a test DNS server that responds to A and TXT record queries
* The server listens on port 5300 and returns mock responses for testing purposes
*/
test_server_ () {
const dns2 = require('dns2');
const { Packet } = dns2
@@ -20,8 +20,16 @@ const { DB_READ } = require("../../services/database/consts");
const { NodePathSelector, NodeUIDSelector, NodeInternalIDSelector, NodeChildSelector, RootNodeSelector } = require("../../filesystem/node/selectors");
const BaseService = require("../../services/BaseService");
/**
* Service for fetching filesystem entries from the database using various selector types.
* Handles different methods of locating files and directories in the filesystem.
*/
module.exports = class DatabaseFSEntryFetcher extends BaseService {
static CONCERN = 'filesystem';
/**
* Initializes the default properties that will be selected from the database.
*/
_construct () {
this.defaultProperties = [
'id',
@@ -53,10 +61,19 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
]
}
/**
* Initializes the database connection for filesystem operations.
*/
_init () {
this.db = this.services.get('database').get(DB_READ, 'filesystem');
}
/**
* Finds a filesystem entry using the provided selector.
* @param {Object} selector - The selector object specifying how to find the entry
* @param {Object} fetch_entry_options - Options for fetching the entry
* @returns {Promise<Object|null>} The filesystem entry or null if not found
*/
async find (selector, fetch_entry_options) {
if ( selector instanceof RootNodeSelector ) {
return selector.entry;
@@ -98,6 +115,12 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
}
}
/**
* Finds a filesystem entry by its UUID.
* @param {string} uuid - The UUID of the entry to find
* @param {Object} fetch_entry_options - Options including thumbnail flag
* @returns {Promise<Object|undefined>} The filesystem entry or undefined if not found
*/
async findByUID(uuid, fetch_entry_options = {}) {
const { thumbnail } = fetch_entry_options;
@@ -112,6 +135,12 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
return fsentry[0];
}
/**
* Finds a filesystem entry by its internal database ID.
* @param {number} id - The internal ID of the entry to find
* @param {Object} fetch_entry_options - Options including thumbnail flag
* @returns {Promise<Object|undefined>} The filesystem entry or undefined if not found
*/
async findByID(id, fetch_entry_options = {}) {
const { thumbnail } = fetch_entry_options;
@@ -126,6 +155,12 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
return fsentry[0];
}
/**
* Finds a filesystem entry by its full path.
* @param {string} path - The full path of the entry to find
* @param {Object} fetch_entry_options - Options including thumbnail flag and tracer
* @returns {Promise<Object|false>} The filesystem entry or false if not found
*/
async findByPath(path, fetch_entry_options = {}) {
const { thumbnail } = fetch_entry_options;
@@ -199,6 +234,11 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
return result[0];
}
/**
* Finds the ID of a child entry with the given name in the root directory.
* @param {string} name - The name of the child entry to find
* @returns {Promise<number|undefined>} The ID of the child entry or undefined if not found
*/
async findNameInRoot (name) {
let child_id = await this.db.read(
"SELECT `id` FROM `fsentries` WHERE `parent_uid` IS NULL AND name = ? LIMIT 1",
@@ -207,6 +247,12 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
return child_id[0]?.id;
}
/**
* Finds the ID of a child entry with the given name under a specific parent.
* @param {string} parent_uid - The UUID of the parent directory
* @param {string} name - The name of the child entry to find
* @returns {Promise<number|undefined>} The ID of the child entry or undefined if not found
*/
async findNameInParent (parent_uid, name) {
let child_id = await this.db.read(
"SELECT `id` FROM `fsentries` WHERE `parent_uid` = ? AND name = ? LIMIT 1",
@@ -215,6 +261,12 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
return child_id[0]?.id;
}
/**
* Checks if an entry with the given name exists under a specific parent.
* @param {string} parent_uid - The UUID of the parent directory
* @param {string} name - The name to check for
* @returns {Promise<boolean>} True if the name exists under the parent, false otherwise
*/
async nameExistsUnderParent (parent_uid, name) {
let check_dupe = await this.db.read(
"SELECT `id` FROM `fsentries` WHERE `parent_uid` = ? AND name = ? LIMIT 1",
@@ -223,6 +275,12 @@ module.exports = class DatabaseFSEntryFetcher extends BaseService {
return !! check_dupe[0];
}
/**
* Checks if an entry with the given name exists under a parent specified by ID.
* @param {number} parent_id - The internal ID of the parent directory
* @param {string} name - The name to check for
* @returns {Promise<boolean>} True if the name exists under the parent, false otherwise
*/
async nameExistsUnderParentID (parent_id, name) {
const parent = await this.findByID(parent_id);
if ( ! parent ) {
@@ -22,8 +22,21 @@ const { BaseES } = require("./BaseES");
const WRITE_ALL_OWNER_ES = 'system:es:write-all-owners';
/**
* Entity storage layer that restricts write operations to entity owners only.
* Extends BaseES to add ownership-based access control for upsert and delete operations.
*/
class WriteByOwnerOnlyES extends BaseES {
/**
* Static methods object containing the access-controlled entity storage operations.
*/
static METHODS = {
/**
* Updates or inserts an entity after verifying ownership permissions.
* @param {Object} entity - The entity to upsert
* @param {Object} extra - Additional parameters including old_entity
* @returns {Promise} Result of the upstream upsert operation
*/
async upsert (entity, extra) {
const { old_entity } = extra;
@@ -34,6 +47,12 @@ class WriteByOwnerOnlyES extends BaseES {
return await this.upstream.upsert(entity, extra);
},
/**
* Deletes an entity after verifying the current user owns it.
* @param {string} uid - The unique identifier of the entity to delete
* @param {Object} extra - Additional parameters including old_entity
* @returns {Promise} Result of the upstream delete operation
*/
async delete (uid, extra) {
const { old_entity } = extra;
@@ -42,6 +61,13 @@ class WriteByOwnerOnlyES extends BaseES {
return await this.upstream.delete(uid, extra);
},
/**
* Verifies that the current user has permission to modify the entity.
* Allows access if user has system-wide write permission or owns the entity.
* @param {Object} params - Parameters object
* @param {Object} params.old_entity - The existing entity to check ownership for
* @throws {APIError} Throws forbidden error if user lacks permission
*/
async _check_allowed ({ old_entity }) {
const svc_permission = this.context.get('services').get('permission');
const has_permission_to_write_all = await svc_permission.check(Context.get("actor"), WRITE_ALL_OWNER_ES);