diff --git a/src/backend/src/filesystem/FSNodeContext.js b/src/backend/src/filesystem/FSNodeContext.js index d57520660..cc1a9b7a6 100644 --- a/src/backend/src/filesystem/FSNodeContext.js +++ b/src/backend/src/filesystem/FSNodeContext.js @@ -87,7 +87,7 @@ module.exports = class FSNodeContext { this.fs = fs; // Decorate all fetch methods with otel span - // TODO: language tool for traits; this is a trait + // TODO: Apply method decorators using a putility class feature const fetch_methods = [ 'fetchEntry', 'fetchPath', @@ -271,8 +271,6 @@ module.exports = class FSNodeContext { resourceService, } = Context.get('services').values; - // await this.fs.resourceService - // .waitForResource(this.selector); if ( fetch_entry_options.tracer == null ) { fetch_entry_options.tracer = traceService.tracer; } @@ -288,11 +286,7 @@ module.exports = class FSNodeContext { await new Promise (rslv => { const detachables = new MultiDetachable(); - let resolved = false; - const callback = (resolver) => { - // NOTE: commented out for now because it's too verbose - resolved = true; detachables.detach(); rslv(); } @@ -499,8 +493,7 @@ module.exports = class FSNodeContext { [this.entry.id] ); const versions_tidy = []; - for (let index = 0; index < versions.length; index++) { - const version = versions[index]; + for ( const version of versions ) { let username = version.user_id ? (await get_user({id: version.user_id})).username : null; versions_tidy.push({ id: version.version_id, @@ -551,14 +544,6 @@ module.exports = class FSNodeContext { this.entry.is_empty = await is_empty(this.uid); } - // TODO: this is currently not called anywhere; for now it - // will never be fetched since sharing is not a priority. - async fetchIsShared () { - if ( ! this.mysql_id ) return; - - this.entry.is_shared = await is_shared_with_anyone(this.mysql_id); - } - async fetchAll(fsEntryFetcher, user, force) { await this.fetchEntry({ thumbnail: true }); await this.fetchSubdomains(user); @@ -610,7 +595,6 @@ module.exports = class FSNodeContext { ); } if ( ! this.path ) { - // console.log('PATH WAS NOT ON ENTRY', this); await this.fetchPath(); } if ( ! this.path ) { diff --git a/src/backend/src/filesystem/FSOperationContext.js b/src/backend/src/filesystem/FSOperationContext.js deleted file mode 100644 index 53fa0b302..000000000 --- a/src/backend/src/filesystem/FSOperationContext.js +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -const PerformanceMonitor = require('../monitor/PerformanceMonitor'); - -const FSNodeContext = require('./FSNodeContext'); -const FSAccessContext = require('./FSAccessContext'); -const { Context } = require('../util/context'); - -/** - * FSOperationContext represents a single operation on the filesystem. - * - * FSOperationContext is used to record events such as side-effects - * which occur during a high-level filesystem operation. It is also - * responsible for generating a client-safe result which describes - * the operation. - */ -module.exports = class FSOperationContext { - // TODO: rename this.fs to this.access - constructor (op_name, context, options) { - // migration: fs:create-service - // TODO: rename this.fs to this.access - // NOTE: the 2nd parameter of this constructor - // was called `fs` and was expected to be FSAccessContext. - // Now it should be a context object holding the services - // container. context.access is the FSAccessContext. - if ( context instanceof FSAccessContext ) { - this.fs = context; - } else if ( context ) { - this.context = context; - this.fs = context.access; - } else { - const x = Context.get(); - this.fs = {}; - this.fs.traceService = x.get('services').get('traceService'); - } - - this.name = op_name; - this.events = []; - this.parent_dirs_created = []; - this.created = []; - this.fields = {}; - this.safeFields = {}; - - this.valueListeners_ = {}; - this.valueFactories_ = {}; - this.values_ = {}; - this.rejections_ = {}; - - this.tasks_ = []; - - this.currentCheckpoint_ = 'checkpoint not set'; - - if ( options.parent_operation ) { - this.parent = options.parent_operation; - } - - this.donePromise = new Promise((resolve, reject) => { - this.doneResolve = resolve; - this.doneReject = reject; - }); - - // migration: arch:trace-service:move-outta-fs - if ( this.fs.traceService ) { - // Set 'span_' to current active span - const { context, trace } = require('@opentelemetry/api'); - this.span_ = trace.getSpan(context.active()); - } - - this.monitor = PerformanceMonitor.createContext(`fs.${op_name}`); - } - - checkpoint (label) { - this.currentCheckpoint_ = label; - } - - async addTask (name, fn) { - const task = { - name, - operations: [], - promise: Promise.resolve(), - }; - - const taskContext = { - registerOperation: op => { - task.operations.push(op); - task.promise = task.promise.then(() => op.awaitDone()); - } - }; - - const monitor = PerformanceMonitor.createContext('fs.rm'); - monitor.label(`task:${name}`); - task.promise = task.promise.then(() => fn(taskContext)); - this.tasks_.push(task); - - let last_promise = null; - while ( task.promise !== last_promise ) { - last_promise = task.promise; - await task.promise; - } - // await task.promise; - - monitor.stamp(); - monitor.end(); - } - - get span () { return this.span_; } - - recordParentDirCreated (fsNode) { - if ( ! fsNode ) { - throw new Error( - 'falsy value to recordParentDirCreated', - fsNode, - ); - } - this.parent_dirs_created.push(fsNode); - } - - recordCreated (fsNode) { - this.created.push(fsNode); - } - - set (field, value) { - this.fields[field] = value; - } - - async set_now (field, value) { - this.fields[field] = value; - if ( value instanceof FSNodeContext ) { - this.safeFields[field] = await value.getSafeEntry(); - } - } - - get (field) { - return this.fields[field]; - } - - complete (options) { - options = options ?? {}; - - if ( this.parent ) { - for ( const fsNode of this.parent_dirs_created ) { - this.parent.recordParentDirCreated(fsNode); - } - - for ( const fsNode of this.created ) { - this.parent.recordCreated(fsNode); - } - } - - if ( this.tasks_.length > 0 ) { - // TODO: it's mutating input options, which is not ideal - if ( ! options.after ) options.after = []; - - options.after.push( - this.tasks_.map(task => task.promise) - ); - } - - if ( options.after ) { - const thingsToWaitFor = options.after.map(item => { - if ( item.awaitDone ) return item.awaitDone; - return item; - }); - (async () => { - await Promise.all(thingsToWaitFor); - this.doneResolve(); - })(); - return; - } - - this.doneResolve(); - } - - onComplete(fn) { - this.donePromise.then(fn); - } - - awaitDone () { - return this.donePromise; - } - - provideValue (key, value) { - this.values_[key] = value; - - let listeners = this.valueListeners_[key]; - if ( ! listeners ) return; - - delete this.valueListeners_[key]; - - for ( let listener of listeners ) { - if ( Array.isArray(listener) ) listener = listener[0]; - listener(value); - } - } - - rejectValue (key, err) { - this.rejections_[key] = err; - - let listeners = this.valueListeners_[key]; - if ( ! listeners ) return; - - delete this.valueListeners_[key]; - - for ( let listener of listeners ) { - if ( ! Array.isArray(listener) ) continue; - if ( ! listener[1] ) continue; - listener = listener[1]; - - listener(err); - } - } - - awaitValue (key) { - return new Promise ((rslv, rjct) => { - this.onValue(key, rslv, rjct); - }); - } - - onValue (key, fn, rjct) { - if ( this.values_[key] ) { - fn(this.values_[key]); - return; - } - - if ( this.rejections_[key] ) { - if ( rjct ) { - rjct(this.rejections_[key]); - } else throw this.rejections_[key]; - return; - } - - if ( ! this.valueListeners_[key] ) { - this.valueListeners_[key] = []; - } - this.valueListeners_[key].push([fn, rjct]); - - if ( this.valueFactories_[key] ) { - const fn = this.valueFactories_[key]; - delete this.valueFactories_[key]; - (async () => { - try { - const value = await fn(); - this.provideValue(key, value); - } catch (e) { - this.rejectValue(key, e); - } - })(); - } - } - - async setFactory (key, factoryFn) { - if ( this.valueListeners_[key] ) { - let v; - try { - v = await factoryFn(); - } catch (e) { - this.rejectValue(key, e); - } - this.provideValue(key, v); - return; - } - - this.valueFactories_[key] = factoryFn; - } - - /** - * Listen for another operation to complete, and then - * complete this operation. This is useful for operations - * which delegate to other operations. - * - * @param {FSOperationContext} other - * @returns {FSOperationContext} this - */ - completedBy (other) { - other.onComplete(() => { - this.complete(); - }); - - return this; - } - - /** - * Produces an object which describes the operation in a - * way that is intended to be sent to the client. - * - * @returns {Promise} - */ - async getClientSafeResult () { - const result = {}; - for ( const field in this.fields ) { - if ( this.fields[field] instanceof FSNodeContext ) { - result[field] = this.safeFields[field] ?? - await this.fields[field].getSafeEntry(); - continue; - } - - result[field] = this.fields[field]; - } - - result.parent_dirs_created = []; - for ( const fsNode of this.parent_dirs_created ) { - const fsNodeResult = await fsNode.getSafeEntry(); - result.parent_dirs_created.push(fsNodeResult); - } - - return result; - } -} diff --git a/src/backend/src/filesystem/FilesystemService.js b/src/backend/src/filesystem/FilesystemService.js index a09df6192..adc2a71e0 100644 --- a/src/backend/src/filesystem/FilesystemService.js +++ b/src/backend/src/filesystem/FilesystemService.js @@ -47,12 +47,8 @@ class FilesystemService extends BaseService { } old_constructor (args) { - // super(args); const { services } = args; - // this.services = services; - - // services.registerService('resourceService', ResourceService); services.registerService('sizeService', SizeService); services.registerService('traceService', TraceService); @@ -81,7 +77,7 @@ class FilesystemService extends BaseService { // Decorate methods with otel span - // TODO: language tool for traits; this is a trait + // TODO: use putility class feature for method decorators const span_methods = [ 'write', 'mkdir', 'rm', 'mv', 'cp', 'read', 'stat', 'mkdir_2', diff --git a/src/backend/src/filesystem/ll_operations/ll_read.js b/src/backend/src/filesystem/ll_operations/ll_read.js index b903a9dd1..1785062f0 100644 --- a/src/backend/src/filesystem/ll_operations/ll_read.js +++ b/src/backend/src/filesystem/ll_operations/ll_read.js @@ -17,7 +17,6 @@ * along with this program. If not, see . */ const APIError = require("../../api/APIError"); -const { CodeModel } = require("../../codex/CodeModel"); const { Sequence } = require("../../codex/Sequence"); const { DB_WRITE } = require("../../services/database/consts");