mirror of
https://github.com/HeyPuter/puter.git
synced 2025-12-30 17:50:00 -06:00
143 lines
4.5 KiB
JavaScript
143 lines
4.5 KiB
JavaScript
/*
|
|
* Copyright (C) 2024-present 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
const svc_metering = extension.import('service:meteringService');
|
|
const svc_trace = extension.import('service:traceService');
|
|
|
|
// TODO: these services ought to be part of this extension
|
|
const svc_size = extension.import('service:sizeService');
|
|
const svc_fsEntry = extension.import('service:fsEntryService');
|
|
|
|
// TODO: depending on mountpoint service will not be necessary
|
|
// once the storage provider is moved to this extension
|
|
const svc_mountpoint = extension.import('service:mountpoint');
|
|
|
|
const {
|
|
APIError,
|
|
Actor,
|
|
Context,
|
|
UserActorType,
|
|
} = extension.import('core');
|
|
|
|
const {
|
|
get_user,
|
|
} = extension.import('core').util.helpers;
|
|
|
|
const {
|
|
ParallelTasks,
|
|
} = extension.import('core').util.otelutil;
|
|
|
|
const {
|
|
TYPE_DIRECTORY,
|
|
} = extension.import('core').fs;
|
|
|
|
class PuterFSProvider {
|
|
async unlink ({ context, node, options = {} }) {
|
|
if ( await node.get('type') === TYPE_DIRECTORY ) {
|
|
throw new APIError(409, 'Cannot unlink a directory.');
|
|
}
|
|
|
|
await this.#rmnode({ context, node, options });
|
|
}
|
|
|
|
async rmdir ({ context, node, options = {} }) {
|
|
if ( await node.get('type') !== TYPE_DIRECTORY ) {
|
|
throw new APIError(409, 'Cannot rmdir a file.');
|
|
}
|
|
|
|
if ( await node.get('immutable') ) {
|
|
throw APIError.create('immutable');
|
|
}
|
|
|
|
const children = await svc_fsEntry.fast_get_direct_descendants(await node.get('uid'));
|
|
|
|
if ( children.length > 0 && !options.ignore_not_empty ) {
|
|
throw APIError.create('not_empty');
|
|
}
|
|
|
|
await this.#rmnode({ context, node, options });
|
|
}
|
|
|
|
async read ({ context, node, version_id, range }) {
|
|
const svc_mountpoint = context.get('services').get('mountpoint');
|
|
const storage = svc_mountpoint.get_storage(this.constructor.name);
|
|
const location = await node.get('s3:location') ?? {};
|
|
const stream = (await storage.create_read_stream(await node.get('uid'), {
|
|
// TODO: fs:decouple-s3
|
|
bucket: location.bucket,
|
|
bucket_region: location.bucket_region,
|
|
version_id,
|
|
key: location.key,
|
|
memory_file: node.entry,
|
|
...(range ? { range } : {}),
|
|
}));
|
|
return stream;
|
|
}
|
|
|
|
async #rmnode ({ node, options }) {
|
|
// Services
|
|
if ( !options.override_immutable && await node.get('immutable') ) {
|
|
throw new APIError(403, 'File is immutable.');
|
|
}
|
|
|
|
const userId = await node.get('user_id');
|
|
const fileSize = await node.get('size');
|
|
svc_size.change_usage(userId,
|
|
-1 * fileSize);
|
|
|
|
const ownerActor = new Actor({
|
|
type: new UserActorType({
|
|
user: await get_user({ id: userId }),
|
|
}),
|
|
});
|
|
|
|
svc_metering.incrementUsage(ownerActor, 'filesystem:delete:bytes', fileSize);
|
|
|
|
const tracer = svc_trace.tracer;
|
|
const tasks = new ParallelTasks({ tracer, max: 4 });
|
|
|
|
tasks.add('remove-fsentry', async () => {
|
|
await svc_fsEntry.delete(await node.get('uid'));
|
|
});
|
|
|
|
if ( await node.get('has-s3') ) {
|
|
tasks.add('remove-from-s3', async () => {
|
|
// const storage = new PuterS3StorageStrategy({ services: svc });
|
|
const storage = Context.get('storage');
|
|
const state_delete = storage.create_delete();
|
|
await state_delete.run({
|
|
node: node,
|
|
});
|
|
});
|
|
}
|
|
|
|
await tasks.awaitAll();
|
|
}
|
|
}
|
|
|
|
const { TmpProxyFSProvider } = extension.import('fs');
|
|
|
|
extension.on('create.filesystem-types', event => {
|
|
event.createFilesystemType('puterfs', {
|
|
mount ({ path }) {
|
|
return new TmpProxyFSProvider(path, new PuterFSProvider(path));
|
|
},
|
|
});
|
|
});
|