From 773348ae799333da8393636bd077da1065c51a62 Mon Sep 17 00:00:00 2001 From: Grigorii Sharapov Date: Wed, 26 May 2021 21:59:55 +0600 Subject: [PATCH] feat: add aws s3 provider --- src/providers/aws.js | 88 ++++++++++++++++++++++++++++++++++++ src/providers/factory.js | 8 ++++ src/providers/index.js | 6 +++ test/suites/providers/aws.js | 18 ++++++++ 4 files changed, 120 insertions(+) create mode 100644 src/providers/aws.js create mode 100644 test/suites/providers/aws.js diff --git a/src/providers/aws.js b/src/providers/aws.js new file mode 100644 index 00000000..e879b1a0 --- /dev/null +++ b/src/providers/aws.js @@ -0,0 +1,88 @@ +const AbstractFileTransfer = require('ms-files-transport'); +const S3 = require('aws-sdk/clients/s3'); +const { merge } = require('lodash'); +const assert = require('assert'); + +const UPLOAD_URL_EXPIRES_IN_SEC = 60000; +const DOWNLOAD_URL_EXPIRES_IN_SEC = 60000; + +class AWSTransport extends AbstractFileTransfer { + constructor(opts = {}) { + super(); + + const config = merge({}, AWSTransport.defaultOpts, opts); + this._config = config; + this._logger = this._config.logger; + + assert(config !== undefined); + assert(config.options !== undefined); + assert(config.options.accessKeyId !== undefined); + assert(config.options.secretAccessKey !== undefined); + assert(config.options.region !== undefined); + assert(config.options.bucketName !== undefined); + + this.setupS3(); + } + + setupS3() { + try { + this._s3 = new S3({ + signatureVersion: 'v4', + region: this._config.region, + credentials: { + accessKeyId: this._config.accessKeyId, + secretAccessKey: this._config.secretAccessKey, + }, + }); + } catch (e) { + this._logger.warn('failed to load aws-sdk/clients/s3', e); + } + } + + connect() { + return Promise + .bind(this) + .then(this.findOrCreateBucket); + } + + async findOrCreateBucket() { + const { bucketName } = this._config; + + const s3 = this._s3; + + const buckets = s3.listBuckets(); + const exists = buckets.find(bucketName); + + if (!exists) { + this.log.debug('initiating createBucket: %s', bucketName); + await this._s3.createBucket({ + Bucket: bucketName, + }); + } + } + + async getSignedUrl(action, input) { + const params = { + Bucket: this._config.bucketName, + Expires: action === 'putObject' ? UPLOAD_URL_EXPIRES_IN_SEC : DOWNLOAD_URL_EXPIRES_IN_SEC, + Key: input.key, + }; + + if (action === 'putObject') { + params.ContentType = input.contentType; + } + + return new Promise((resolve, reject) => { + this._s3.getSignedUrl('putObject', params, (err, url) => { + if (err) { + return reject(err); + } + return resolve(url); + }); + }); + } +} + +AWSTransport.defaultOpts = {}; + +module.exports = AWSTransport; diff --git a/src/providers/factory.js b/src/providers/factory.js index fdce3471..96993d35 100644 --- a/src/providers/factory.js +++ b/src/providers/factory.js @@ -57,6 +57,14 @@ class ProviderFactory { return provider; } + + // eslint-disable-next-line class-methods-use-this + getProviderAWS(transport) { + const ProviderAWS = require('./aws'); + const provider = new ProviderAWS(transport); + + return provider; + } } module.exports = ProviderFactory; diff --git a/src/providers/index.js b/src/providers/index.js index 4e9111e2..a1a68282 100644 --- a/src/providers/index.js +++ b/src/providers/index.js @@ -54,6 +54,12 @@ function initProviders(service) { factory.getProviderOSS(transport) ); } + + if (transport.name === 'aws') { + service.providers.push( + factory.getProviderAWS(transport) + ); + } } // create providerByBucket map for fast access diff --git a/test/suites/providers/aws.js b/test/suites/providers/aws.js new file mode 100644 index 00000000..56126c7c --- /dev/null +++ b/test/suites/providers/aws.js @@ -0,0 +1,18 @@ +// const { strictEqual } = require('assert'); +const AWSTransport = require('../../../src/providers/aws'); + +describe('util fetch-data suite', () => { + it('should be able to create instance', () => { + const provider = new AWSTransport({ + options: { + accessKeyId: 'AKIASS5V3WV23VA4KYOF', + accessKeySecret: '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', + bucket: 'test', + region: 'us-west-2', + secure: true, + }, + }); + + console.log(provider); + }); +});