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