Skip to content

Commit 4c5c145

Browse files
committed
dev: LocalDiskStorageController with upload method
Begin work on LocalDiskStorageController in the `puterfs` extension. This replaces LocalDiskStorageStrategy and LocalDiskStorageService from the core. The `upload()` method is implemented to verify that it's working. This commit by itself will break other storage strategies. The next step is to allow extensions to register storage controllers for puterfs. Part of that work is done in this commit by emitting an event to register storage controllers, but this commit does not include a way to configure/select storage controllers.
1 parent e1799ae commit 4c5c145

File tree

4 files changed

+120
-3
lines changed

4 files changed

+120
-3
lines changed

extensions/puterfs/PuterFSProvider.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@ const {
9797
} = extension.import('fs').util;
9898

9999
export default class PuterFSProvider {
100-
constructor ({ fsEntryController }) {
100+
constructor ({ fsEntryController, storageController }) {
101101
this.fsEntryController = fsEntryController;
102+
this.storageController = storageController;
102103
this.name = 'puterfs';
103104
}
104105

@@ -943,7 +944,7 @@ export default class PuterFSProvider {
943944
const state_upload = storage.create_upload();
944945

945946
try {
946-
await state_upload.run({
947+
await this.storageController.upload({
947948
uid: uuid,
948949
file,
949950
storage_meta: { bucket, bucket_region },

extensions/puterfs/main.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,45 @@
1919

2020
import FSEntryController from './fsentries/FSEntryController.js';
2121
import PuterFSProvider from './PuterFSProvider.js';
22+
import LocalDiskStorageController from './storage/LocalDiskStorageController.js';
23+
import ProxyStorageController from './storage/ProxyStorageController.js';
2224

2325
const fsEntryController = new FSEntryController();
26+
const storageController = new ProxyStorageController();
2427

25-
extension.on('init', () => {
28+
extension.on('init', async () => {
2629
fsEntryController.init();
30+
31+
// Keep track of possible storage strategies for puterfs here
32+
const storageStrategies = {
33+
'flat-files': new LocalDiskStorageController(),
34+
};
35+
36+
// Emit the "create storage strategies" event
37+
const event = {
38+
createStorageStrategy (name, implementation) {
39+
storageStrategies[name] = implementation;
40+
},
41+
};
42+
// Awaiting the event ensures all the storage strategies are registered
43+
await extension.emit('puterfs.storage.create', event);
44+
45+
// Not we can select the configured strategy
46+
const storageToUse = storageStrategies['flat-files'];
47+
storageController.setDelegate(storageToUse);
48+
49+
// The StorageController may need to await some asynchronous operations
50+
// before it's ready to be used.
51+
await storageController.init();
52+
2753
});
2854

2955
extension.on('create.filesystem-types', event => {
3056
event.createFilesystemType('puterfs', {
3157
mount ({ path }) {
3258
return new PuterFSProvider({
3359
fsEntryController,
60+
storageController,
3461
});
3562
},
3663
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import putility from '@heyputer/putility';
2+
import fs from 'node:fs';
3+
import path_ from 'node:path';
4+
5+
const {
6+
progress_stream,
7+
size_limit_stream,
8+
} = extension.import('core').util.streamutil;
9+
10+
export default class LocalDiskStorageController {
11+
constructor () {
12+
this.path = path_.join(process.cwd(), '/storage');
13+
}
14+
15+
async init () {
16+
await fs.promises.mkdir(this.path, { recursive: true });
17+
}
18+
19+
async upload ({ uid, file, storage_api }) {
20+
const { progress_tracker } = storage_api;
21+
22+
if ( file.buffer ) {
23+
const path = this.#getPath(uid);
24+
await fs.promises.writeFile(path, file.buffer);
25+
26+
progress_tracker.set_total(file.buffer.length);
27+
progress_tracker.set(file.buffer.length);
28+
return;
29+
}
30+
31+
let stream = file.stream;
32+
stream = progress_stream(stream, {
33+
total: file.size,
34+
progress_callback: evt => {
35+
progress_tracker.set_total(file.size);
36+
progress_tracker.set(evt.uploaded);
37+
},
38+
});
39+
stream = size_limit_stream(stream, {
40+
limit: file.size,
41+
});
42+
43+
const writePromise = new putility.libs.promise.TeePromise();
44+
const path = this.#getPath(uid);
45+
const write_stream = fs.createWriteStream(path);
46+
47+
write_stream.on('error', () => writePromise.reject());
48+
write_stream.on('finish', () => writePromise.resolve());
49+
50+
stream.pipe(write_stream);
51+
52+
// @ts-ignore (it's wrong about this)
53+
await writePromise;
54+
}
55+
copy () {
56+
}
57+
delete () {
58+
}
59+
read () {
60+
}
61+
62+
#getPath (key) {
63+
return path_.join(this.path, key);
64+
}
65+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
export default class {
2+
constructor (delegate) {
3+
this.delegate = delegate ?? null;
4+
}
5+
setDelegate (delegate) {
6+
this.delegate = delegate;
7+
}
8+
9+
init (...a) {
10+
return this.delegate.init(...a);
11+
}
12+
upload (...a) {
13+
return this.delegate.upload(...a);
14+
}
15+
copy (...a) {
16+
return this.delegate.copy(...a);
17+
}
18+
delete (...a) {
19+
return this.delegate.delete(...a);
20+
}
21+
read (...a) {
22+
return this.delegate.read(...a);
23+
}
24+
}

0 commit comments

Comments
 (0)