feat: object storage
This commit is contained in:
parent
8d5bf93360
commit
f66a79fe08
5 changed files with 2721 additions and 3 deletions
2615
server/package-lock.json
generated
2615
server/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -39,6 +39,8 @@
|
||||||
"api:generate": "node ./bin/sync-spec-version.js && bash ./bin/generate-open-api.sh"
|
"api:generate": "node ./bin/sync-spec-version.js && bash ./bin/generate-open-api.sh"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@aws-sdk/client-s3": "^3.427.0",
|
||||||
|
"@aws-sdk/lib-storage": "^3.427.0",
|
||||||
"@babel/runtime": "^7.22.11",
|
"@babel/runtime": "^7.22.11",
|
||||||
"@nestjs/bullmq": "^10.0.1",
|
"@nestjs/bullmq": "^10.0.1",
|
||||||
"@nestjs/common": "^10.2.2",
|
"@nestjs/common": "^10.2.2",
|
||||||
|
|
27
server/src/domain/fs/fs.ts
Normal file
27
server/src/domain/fs/fs.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { Readable, Writable } from "stream";
|
||||||
|
|
||||||
|
export interface FS {
|
||||||
|
// create creates an object with the given name.
|
||||||
|
create(name: string): Promise<Writable>;
|
||||||
|
|
||||||
|
// open opens the named object.
|
||||||
|
open(name: string): Promise<Readable>;
|
||||||
|
|
||||||
|
// remove removes the named object.
|
||||||
|
remove(name: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// export interface FS {
|
||||||
|
// // create creates an object with the given name.
|
||||||
|
// create(name: string): Promise<Writable>;
|
||||||
|
|
||||||
|
// // open opens the object with the given name.
|
||||||
|
// open(name: string): Promise<Object>;
|
||||||
|
|
||||||
|
// // remove removes the named object.
|
||||||
|
// remove(name: string): Promise<void>;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// export interface Object {
|
||||||
|
// createReadableStream(): Promise<Readable>;
|
||||||
|
// }
|
21
server/src/domain/fs/local.ts
Normal file
21
server/src/domain/fs/local.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { constants, open, unlink } from "fs/promises";
|
||||||
|
import { join } from "path";
|
||||||
|
import { Readable, Writable } from "stream";
|
||||||
|
|
||||||
|
export class LocalFS {
|
||||||
|
constructor(private dir: string) { }
|
||||||
|
|
||||||
|
async create(name: string): Promise<Writable> {
|
||||||
|
const file = await open(join(this.dir, name), constants.O_WRONLY);
|
||||||
|
return file.createWriteStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
async open(name: string): Promise<Readable> {
|
||||||
|
const file = await open(join(this.dir, name), constants.O_RDONLY);
|
||||||
|
return file.createReadStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(name: string): Promise<void> {
|
||||||
|
await unlink(join(this.dir, name));
|
||||||
|
}
|
||||||
|
}
|
59
server/src/domain/fs/s3.ts
Normal file
59
server/src/domain/fs/s3.ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import { PassThrough, Readable, Writable } from "stream";
|
||||||
|
import { S3 } from "@aws-sdk/client-s3";
|
||||||
|
import { FS } from "./fs";
|
||||||
|
import { Upload } from "@aws-sdk/lib-storage";
|
||||||
|
|
||||||
|
export class S3FS implements FS {
|
||||||
|
s3: S3;
|
||||||
|
|
||||||
|
constructor(private bucket: string) {
|
||||||
|
this.s3 = new S3();
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(name: string): Promise<Writable> {
|
||||||
|
const stream = new PassThrough();
|
||||||
|
const upload = new Upload({
|
||||||
|
client: this.s3,
|
||||||
|
params: {
|
||||||
|
Body: stream,
|
||||||
|
Bucket: this.bucket,
|
||||||
|
Key: name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Abort the upload if the stream has finished. Should be a
|
||||||
|
// no-op if the upload has already finished.
|
||||||
|
stream.on('close', () => void upload.abort());
|
||||||
|
|
||||||
|
// Close the stream when the upload is finished.
|
||||||
|
upload.done().then(() => void stream.end());
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
async open(name: string): Promise<Readable> {
|
||||||
|
const stream = new PassThrough();
|
||||||
|
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
|
||||||
|
const obj = await this.s3.getObject({
|
||||||
|
Bucket: this.bucket,
|
||||||
|
Key: name,
|
||||||
|
});
|
||||||
|
return obj.Body as Readable;
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(name: string): Promise<void> {
|
||||||
|
await this.s3.deleteObject({
|
||||||
|
Bucket: this.bucket,
|
||||||
|
Key: name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// class ObjectReadable extends Readable {
|
||||||
|
// constructor(private s3: S3, private bucket: string) { }
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
Loading…
Reference in a new issue