diff --git a/src/backend/src/filesystem/FSNodeContext.js b/src/backend/src/filesystem/FSNodeContext.js index 9885818be..2385c1e91 100644 --- a/src/backend/src/filesystem/FSNodeContext.js +++ b/src/backend/src/filesystem/FSNodeContext.js @@ -69,6 +69,8 @@ module.exports = class FSNodeContext { NodePathSelector, ]; + #writable; + /** * Creates an instance of FSNodeContext. * @param {*} opt_identifier @@ -401,30 +403,35 @@ module.exports = class FSNodeContext { this.entry.subdomains = []; this.entry.workers = []; - let subdomains = await db.read('SELECT * FROM subdomains WHERE root_dir_id = ? AND user_id = ?', - [this.entry.id, user.id]); + let subdomains = await db.read( + 'SELECT * FROM subdomains WHERE root_dir_id = ? AND user_id = ?', + [this.entry.id, user.id], + ); if ( subdomains.length > 0 ) { subdomains.forEach((sd) => { - if ( this.entry.is_dir ) { - this.entry.subdomains.push({ - subdomain: sd.subdomain, - address: `${config.protocol }://${ sd.subdomain }.` + 'puter.site', - uuid: sd.uuid, - }); - } else { - const workerName = sd.subdomain.split('.').pop(); - this.entry.workers.push({ - subdomain: workerName, - address: `https://${ workerName }.` + 'puter.work', - uuid: sd.uuid, - }); - } - + this.applySingleSubdomain(sd); }); this.entry.has_website = true; } } + applySingleSubdomain (sd) { + if ( this.entry.is_dir ) { + this.entry.subdomains.push({ + subdomain: sd.subdomain, + address: `${config.protocol }://${ sd.subdomain }.` + 'puter.site', + uuid: sd.uuid, + }); + } else { + const workerName = sd.subdomain.split('.').pop(); + this.entry.workers.push({ + subdomain: workerName, + address: `https://${ workerName }.` + 'puter.work', + uuid: sd.uuid, + }); + } + } + /** * Fetches the owner of a directory or file and stores it on the * `owner` property of the fsentry. @@ -535,8 +542,10 @@ module.exports = class FSNodeContext { const db = this.services.get('database').get(DB_READ, 'filesystem'); - let versions = await db.read('SELECT * FROM fsentry_versions WHERE fsentry_id = ?', - [this.entry.id]); + let versions = await db.read( + 'SELECT * FROM fsentry_versions WHERE fsentry_id = ?', + [this.entry.id], + ); const versions_tidy = []; for ( const version of versions ) { let username = version.user_id ? (await get_user({ id: version.user_id })).username : null; @@ -599,7 +608,7 @@ module.exports = class FSNodeContext { await this.fetchIsEmpty(); } - async get (key) { + async get (key, force) { /* This isn't supposed to stay like this! @@ -719,10 +728,11 @@ module.exports = class FSNodeContext { } if ( key === 'writable' ) { + if ( this.#writable && !force ) return this.#writable; const actor = Context.get('actor'); if ( !actor || !actor.type.user ) return undefined; const svc_acl = this.services.get('acl'); - return await svc_acl.check(actor, this, 'write'); + return this.#writable = await svc_acl.check(actor, this, 'write'); } throw new Error(`unrecognize key for FSNodeContext.get: ${key}`); diff --git a/src/backend/src/filesystem/hl_operations/hl_stat.js b/src/backend/src/filesystem/hl_operations/hl_stat.js index 71a350500..a5812230f 100644 --- a/src/backend/src/filesystem/hl_operations/hl_stat.js +++ b/src/backend/src/filesystem/hl_operations/hl_stat.js @@ -54,41 +54,86 @@ class HLStat extends HLFilesystemOperation { const user_unix_ts = Number((`${Date.parse(Context.get('actor')?.type?.user?.timestamp)}`).slice(0, -3)); const paths_are_fine = user_unix_ts >= 1722385593; - if ( maybe_uid_selector || paths_are_fine ) { - // We are able to fetch the entry and is_empty simultaneously - await Promise.all([ - subject.fetchEntry(), - subject.fetchIsEmpty(), - ]); - } else { - // We need the entry first in order for is_empty to work correctly - await subject.fetchEntry(); - await subject.fetchIsEmpty(); + const do_after_fetchEntry = []; + const do_alongside_fetchEntry = []; + + if ( return_size ) { + do_after_fetchEntry.push(async () => { + await subject.fetchSize(user); + }); } + if ( return_subdomains ) { + do_after_fetchEntry.push(async () => { + await subject.fetchSubdomains(user); + }); + } + + if ( return_shares || return_permissions ) { + do_after_fetchEntry.push(async () => { + await subject.fetchShares(); + }); + } + + if ( return_versions ) { + do_after_fetchEntry.push(async () => { + await subject.fetchVersions(); + }); + } + + do_after_fetchEntry.push(async () => { + await subject.fetchOwner(); + }, async () => { + await subject.get('writable'); + }); + + ((maybe_uid_selector || paths_are_fine) + ? do_alongside_fetchEntry + : do_after_fetchEntry).push(subject.fetchIsEmpty.bind(subject)); + + // if ( maybe_uid_selector || paths_are_fine ) { + // await Promise.all([ + // subject.fetchEntry(), + // subject.fetchIsEmpty(), + // ]); + // } else { + // // We need the entry first in order for is_empty to work correctly + // await subject.fetchEntry(); + // await subject.fetchIsEmpty(); + // } + + await Promise.all([ + (async () => { + await subject.fetchEntry(); + const context = Context.get(); + const svc_acl = context.get('services').get('acl'); + const actor = context.get('actor'); + if ( ! await svc_acl.check(actor, subject, 'read') ) { + throw await svc_acl.get_safe_acl_error(actor, subject, 'read'); + } + if ( ! subject.found ) { + throw APIError.create('subject_does_not_exist'); + } + await Promise.all(do_after_fetchEntry.map(f => f())); + })(), + ...(do_alongside_fetchEntry.map(f => f())), + ]); + // file not found - if ( ! subject.found ) throw APIError.create('subject_does_not_exist'); - await subject.fetchOwner(); - - const context = Context.get(); - const svc_acl = context.get('services').get('acl'); - const actor = context.get('actor'); - if ( ! await svc_acl.check(actor, subject, 'read') ) { - throw await svc_acl.get_safe_acl_error(actor, subject, 'read'); - } + // await subject.fetchOwner(); // TODO: why is this specific to stat? const mime = this.require('mime-types'); const contentType = mime.contentType(subject.entry.name); subject.entry.type = contentType ? contentType : null; - if ( return_size ) await subject.fetchSize(user); - if ( return_subdomains ) await subject.fetchSubdomains(user); - if ( return_shares || return_permissions ) { - await subject.fetchShares(); - } - if ( return_versions ) await subject.fetchVersions(); + // if ( return_size ) await subject.fetchSize(user); + // if ( return_subdomains ) await subject.fetchSubdomains(user); + // if ( return_shares || return_permissions ) { + // await subject.fetchShares(); + // } + // if ( return_versions ) await subject.fetchVersions(); return await subject.getSafeEntry(); }