mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-02 04:59:23 -05:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user