packages/services-s3/src/mode/base.ts
import { S3 as S3C } from '@seagull/commands-s3'
import { IMode } from '@seagull/mode'
import * as AWS from 'aws-sdk'
import { PromiseResult } from 'aws-sdk/lib/request'
import { injectable } from 'inversify'
import 'reflect-metadata'
import { S3Error } from '../error'
import { IS3 } from '../interface'
/**
* Http (default) cloud mode implementation.
*/
@injectable()
export abstract class S3Base implements IS3 {
protected abstract mode: Readonly<IMode>
/**
* Lists all files of a S3 bucket
* @param bucketName bucket name
* @param filePath file path
* @throws {S3Error} if an S3 error (e.g. NoSuchKey) occurs
*/
async listFiles(bucketName: string, filePath?: string): Promise<string[]> {
const cmd = new S3C.ListFiles(bucketName, filePath)
cmd.mode = this.mode
return await cmd.execute() // TODO: figure out why this s3cmd has no error interface
}
/**
* Reads a file from a S3 bucket
* @param bucketName bucket name
* @param filePath file path
* @throws {S3Error} if an S3 error (e.g. NoSuchKey) occurs
*/
async readFile(bucketName: string, filePath: string): Promise<string> {
const cmd = new S3C.ReadFile(bucketName, filePath)
cmd.mode = this.mode
return await cmd.execute() // TODO: figure out why this s3cmd has no error interface
}
/**
* Writes a file to a S3 bucket
* @param bucketName bucket name
* @param filePath file path
* @param content file content
* @throws {S3Error} if an S3 error (e.g. NoSuchKey) occurs
*/
async writeFile(
bucketName: string,
filePath: string,
content: string
): Promise<PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>> {
const cmd = new S3C.WriteFile(bucketName, filePath, content)
cmd.mode = this.mode
return await this.handle(cmd.execute())
}
/**
* Writes a couple of files to a S3 bucket \
* @param bucketName bucket name
* @param files list of (S3) file paths and contents
* @throws {S3Error} if an S3 error (e.g. NoSuchKey) occurs
*/
async writeFiles(
bucketName: string,
files: Array<{ path: string; content: string }>
): Promise<Array<PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>>> {
// TODO: error handling & transaction
const writePromises = []
for (const file of files) {
writePromises.push(this.writeFile(bucketName, file.path, file.content))
}
return await Promise.all(writePromises)
}
/**
* Deletes a file from a S3 bucket
* @param bucketName bucket name
* @param filePath file path
* @throws {S3Error} if an S3 error (e.g. NoSuchKey) occurs
*/
async deleteFile(
bucketName: string,
filePath: string
): Promise<PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>> {
const cmd = new S3C.DeleteFile(bucketName, filePath)
cmd.mode = this.mode
return await this.handle(cmd.execute())
}
protected async handle(
response: Promise<PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>>
): Promise<PromiseResult<AWS.S3.PutObjectOutput, AWS.AWSError>> {
const res = await response
if (res && res.$response && res.$response.error) {
throw new S3Error(
`S3 error code ${res.$response.error.code}: ${
res.$response.error.message
}`,
res
)
}
return res
}
}