From 08736ed61069a5f1634eb1bf721369263199ccc9 Mon Sep 17 00:00:00 2001 From: Hayden Young Date: Thu, 14 Oct 2021 23:04:03 +0100 Subject: [PATCH] feat: implement an S3-based storage API --- cdn/package-lock.json | Bin 385043 -> 316498 bytes cdn/package.json | 2 ++ cdn/src/util/S3Storage.ts | 53 ++++++++++++++++++++++++++++++++++++++ cdn/src/util/Storage.ts | 32 +++++++++++++++++++++-- 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 cdn/src/util/S3Storage.ts diff --git a/cdn/package-lock.json b/cdn/package-lock.json index f0cce0aff220faab0397a75912f72e8bc2e2bfd1..006746517b412b2a8808ba022a6eea193d83fed8 100644 GIT binary patch delta 73347 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 delta 52291 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­I=33 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 => + new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + readable.on('data', chunk => chunks.push(chunk)); + readable.on('error', reject); + readable.on('end', () => resolve(Buffer.concat(chunks))); + }); + +export class S3Storage implements Storage { + public constructor( + private client: S3, + private basePath: string, + private bucket: string + ) {} + + async set(path: string, data: Buffer): Promise { + await this.client.putObject({ + Bucket: this.bucket, + Key: `${this.basePath}${path}`, + Body: data + }); + } + + async get(path: string): Promise { + try { + const s3Object = await this.client.getObject({ + Bucket: this.bucket, + Key: `${this.basePath}${path}` + }); + + if (!s3Object.Body) return null; + + const body = s3Object.Body; + + return await readableToBuffer( body); + } catch(err) { + console.error(`[CDN] Unable to get S3 object at path ${path}.`); + console.error(err); + return null; + } + } + + async delete(path: string): Promise { + await this.client.deleteObject({ + Bucket: this.bucket, + Key: `${this.basePath}${path}` + }); + } +} diff --git a/cdn/src/util/Storage.ts b/cdn/src/util/Storage.ts index 91f841a6..acef9df3 100644 --- a/cdn/src/util/Storage.ts +++ b/cdn/src/util/Storage.ts @@ -2,6 +2,8 @@ import { FileStorage } from "./FileStorage"; import path from "path"; import fse from "fs-extra"; import { bgCyan, black } from "nanocolors"; +import { S3 } from '@aws-sdk/client-s3'; +import { S3Storage } from "./S3Storage"; process.cwd(); export interface Storage { @@ -10,10 +12,10 @@ export interface Storage { delete(path: string): Promise; } -var storage: Storage; +let storage: Storage; if (process.env.STORAGE_PROVIDER === "file" || !process.env.STORAGE_PROVIDER) { - var location = process.env.STORAGE_LOCATION; + let location = process.env.STORAGE_LOCATION; if (location) { location = path.resolve(location); } else { @@ -24,6 +26,32 @@ if (process.env.STORAGE_PROVIDER === "file" || !process.env.STORAGE_PROVIDER) { process.env.STORAGE_LOCATION = location; storage = new FileStorage(); +} else if (process.env.STORAGE_PROVIDER === "s3") { + const + region = process.env.STORAGE_REGION, + bucket = process.env.STORAGE_BUCKET; + + if (!region) { + console.error(`[CDN] You must provide a region when using the S3 storage provider.`); + process.exit(1); + } + + if (!bucket) { + console.error(`[CDN] You must provide a bucket when using the S3 storage provider.`); + process.exit(1); + } + + // in the S3 provider, this should be the root path in the bucket + let location = process.env.STORAGE_LOCATION; + + if (!location) { + console.warn(`[CDN] STORAGE_LOCATION unconfigured for S3 provider, defaulting to '/'...`); + location = "/"; + } + + const client = new S3({ region }); + + storage = new S3Storage(client, location, bucket); } export { storage };