Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const uuid = require('uuid/v4')
- const config = require('config')
- const Minio = require('minio')
- const { isString, isUndefined } = require('ramda-adjunct')
- const pkg = require('./../package.json')
- const {
- BucketNotExistsError,
- BucketAlreadyExistsError,
- MinioPingError,
- MinioInitializationError,
- } = require('./../error')
- const {
- DEFAULT_REGION,
- URL_EXPIRE,
- } = require('./../constants')
- const FsService = {
- name: 'fs',
- settings: {
- endPoint: config.get('minio.endPoint'),
- port: config.get('minio.port'),
- accessKey: config.get('minio.accessKey'),
- secretKey: config.get('minio.secretKey'),
- useSSL: false,
- minioHealthCheckInterval: 5000,
- },
- actions: {
- version: () => pkg.version,
- /**
- * Create a new Bucket
- *
- * @actions
- *
- * @param {string} bucket - The name of a bucket
- * @param {string} region - The region to create the bucket in. Defaults to 'us-east-1'
- */
- 'bucket.create': {
- params: {
- bucket: 'string',
- region: {
- type: 'string',
- optional: true,
- },
- },
- async handler (ctx) {
- const { bucket, region } = ctx.params
- if (await this.bucketExists(bucket)) {
- throw new BucketAlreadyExistsError()
- }
- await this.makeBucket(bucket, region)
- return `Bucket with name ${bucket} was created`
- },
- },
- /**
- * Checks if a bucket exists.
- *
- * @param {string} bucket = Name of the bucket
- */
- 'bucket.exists': {
- params: {
- bucket: 'string',
- },
- handler (ctx) {
- return this.minio.bucketExists(ctx.params.bucket)
- },
- },
- /**
- * List all buckets
- */
- 'bucket.list': {
- description: 'Lists all buckets.',
- handler () {
- return this.minio.listBuckets().then(buckets => (isUndefined(buckets) ? [] : buckets))
- },
- },
- /**
- * Removes a bucket
- *
- * @actions
- * @param {string} bucket = Name of the bucket
- */
- 'bucket.destroy': {
- params: {
- bucket: 'string',
- },
- handler (ctx) {
- return this.minio.removeBucket(ctx.params.bucket)
- },
- },
- /**
- * Lists all objects in a bucket.
- *
- * @actions
- * @param {string} bucket - Name of the bucket
- * @param {string} prefix - The prefix of the objects that should be listed
- * (optional, default '').
- * @param {boolean} recursive - `true` indicates recursive style listing and false indicates
- * directory style listing delimited by '/'. (optional, default `false`).
- *
- * @returns {PromiseLike<Object[]|Error>}
- */
- 'object.list': {
- params: {
- bucket: { type: 'string' },
- prefix: { type: 'string', optional: true },
- recursive: { type: 'boolean', optional: true },
- },
- handler (ctx) {
- return this.Promise.resolve(ctx.params)
- .then(({ bucket, prefix = '', recursive = false }) => new this.Promise((resolve, reject) => {
- try {
- const stream = this.minio.listObjects(bucket, prefix, recursive)
- const objects = []
- stream.on('data', el => objects.push(el))
- stream.on('end', () => resolve(objects))
- stream.on('error', reject)
- } catch (e) {
- reject(e)
- }
- }))
- },
- },
- /**
- * Lists partially uploaded objects in a bucket.
- *
- * @actions
- * @param {string} bucketName - Name of the bucket
- * @param {string} prefix - The prefix of the objects that should
- * be listed (optional, default '').
- * @param {boolean} recursive - `true` indicates recursive style listing and false
- * indicates directory style listing delimited by '/'. (optional, default `false`).
- *
- * @returns {PromiseLike<Object[]|Error>}
- */
- 'object.listIncompleteUploads': {
- params: {
- bucket: { type: 'string' },
- prefix: { type: 'string', optional: true },
- recursive: { type: 'boolean', optional: true },
- },
- handler (ctx) {
- return this.Promise.resolve(ctx.params)
- .then(({ bucket, prefix = '', recursive = false }) => new this.Promise((resolve, reject) => {
- try {
- const stream = this.minio.listIncompleteUploads(bucket, prefix, recursive)
- const objects = []
- stream.on('data', el => objects.push(el))
- stream.on('end', () => resolve(objects))
- stream.on('error', reject)
- } catch (e) {
- reject(e)
- }
- }))
- },
- },
- 'object.put': {
- params: {
- bucket: 'string',
- file: 'object',
- name: {
- type: 'string',
- optional: true,
- },
- meta: {
- type: 'object',
- optional: true,
- },
- },
- async handler (ctx) {
- const filename = ctx.params.name || uuid
- const { bucket, file, meta } = ctx.params
- await this.createBucketIfNotExists(bucket)
- await this.minio.putObject(
- bucket,
- filename,
- file,
- meta,
- )
- return filename
- },
- },
- /**
- * Downloads an object as a stream.
- *
- * @actions
- * @param {string} bucket - Name of the bucket
- * @param {string} name - Name of the object.
- *
- * @returns {PromiseLike<ReadableStream|Error>}
- */
- 'object.get': {
- params: {
- bucket: 'string',
- name: 'string',
- },
- handler (ctx) {
- return this.minio.getObject(
- ctx.params.bucket,
- ctx.params.name,
- )
- },
- },
- /**
- * Downloads the specified range bytes of an object as a stream.
- *
- * @actions
- * @param {string} bucket - Name of the bucket.
- * @param {string} name - Name of the object.
- * @param {number} offset - `offset` of the object from where the stream will start.
- * @param {number} length - `length` of the object that will be read in the stream (optional,
- * if not specified we read the rest of the file from the offset).
- *
- * @returns {PromiseLike<ReadableStream|Error>}
- */
- 'object.getPartial': {
- params: {
- bucket: { type: 'string' },
- name: { type: 'string' },
- offset: { type: 'number' },
- length: { type: 'number', optional: true },
- },
- handler (ctx) {
- return this.minio.getPartialObject(
- ctx.params.bucket, ctx.params.name, ctx.params.offset, ctx.params.length,
- )
- },
- },
- /**
- * Generates a presigned URL for the provided HTTP method, 'httpMethod'.
- * Browsers/Mobile clients may point to this URL to directly download objects even
- * if the bucket is private.
- * This presigned URL can have an associated expiration time in seconds after which
- * the URL is no longer valid. The default value is 7 days.
- *
- * @actions
- * @param {string} httpMethod - The HTTP-Method (eg. `GET`). Default value is 'GET'
- * @param {string} bucket - Name of the bucket.
- * @param {string} name - Name of the object.
- * @param {number} expires - Expiry time in seconds. Default value is 7 days. (optional)
- * @param {object} reqParams - request parameters. (optional)
- * @param {string} requestDate - An ISO date string, the url will be issued at.
- * Default value is now. (optional)
- * @returns {PromiseLike<String|Error>}
- */
- 'object.url': {
- params: {
- httpMethod: {
- type: 'string',
- optional: true,
- },
- bucket: 'string',
- name: 'string',
- expiry: {
- type: 'number',
- integer: true,
- optional: true,
- },
- reqParams: { type: 'object', optional: true },
- requestDate: { type: 'string', optional: true },
- },
- async handler (ctx) {
- return this.Promise.resolve(ctx.params)
- .then(({
- httpMethod = 'GET',
- bucket,
- name,
- expires = URL_EXPIRE,
- reqParams = {},
- requestDate = new Date(),
- }) => {
- let reqDate = requestDate
- if (isString(reqDate)) {
- reqDate = new Date(reqDate)
- }
- return new this.Promise((resolve, reject) => {
- this.minio.presignedUrl(
- httpMethod,
- bucket,
- name,
- expires,
- reqParams,
- reqDate,
- (error, url) => {
- if (error) {
- reject(error)
- } else {
- resolve(url)
- }
- },
- )
- })
- })
- },
- },
- /**
- * Gets metadata of an object.
- *
- * @actions
- * @param {string} bucketName - Name of the bucket.
- * @param {string} name - Name of the object.
- *
- * @returns {PromiseLike<{size: {number}, metaData: {object},
- * lastModified: {string}, etag: {string}}|Error>}
- */
- 'object.stat': {
- params: {
- bucket: 'string',
- name: 'string',
- },
- handler (ctx) {
- return this.minio.statObject(ctx.params.bucket, ctx.params.name)
- },
- },
- /**
- * Removes an Object
- *
- * @actions
- * @param {string} bucket - Name of the bucket.
- * @param {string} name - Name of the object.
- *
- * @returns {PromiseLike<undefined|Error>}
- */
- 'object.remove': {
- params: {
- bucket: { type: 'string' },
- name: { type: 'string' },
- },
- handler (ctx) {
- return this.minio.removeObject(ctx.params.bucketName, ctx.params.objectName)
- },
- },
- /**
- * Removes a list of Objects
- *
- * @actions
- * @param {string} bucket - Name of the bucket.
- * @param {string[]} names - Names of the objects.
- *
- * @returns {PromiseLike<undefined|Error>}
- */
- 'object.removeMany': {
- params: {
- bucket: { type: 'string' },
- names: { type: 'array', items: 'string' },
- },
- handler (ctx) {
- return this.minio.removeObjects(ctx.params.bucketName, ctx.params.objectNames)
- },
- },
- /**
- * Removes a partially uploaded object.
- *
- * @actions
- * @param {string} bucket - Name of the bucket.
- * @param {string} name - Name of the object.
- *
- * @returns {PromiseLike<undefined|Error>}
- */
- 'object.removeIncompleteUpload': {
- params: {
- bucket: { type: 'string' },
- name: { type: 'string' },
- },
- handler (ctx) {
- return this.Promise.resolve(ctx.params)
- .then(({ bucket, name }) => this.minio.removeIncompleteUpload(bucket, name))
- },
- },
- },
- methods: {
- createMinioClient () {
- return new Minio.Client({
- endPoint: this.settings.endPoint,
- port: this.settings.port,
- accessKey: this.settings.accessKey,
- secretKey: this.settings.secretKey,
- useSSL: this.settings.useSSL,
- })
- },
- makeBucket (bucketName, region = DEFAULT_REGION) {
- this.logger.info('bucketName: ', bucketName)
- return this.minio.makeBucket(bucketName, region)
- },
- async assertBucketExist (ctx) {
- const result = await this.bucketExists(ctx.params.bucket)
- if (!result) throw new BucketNotExistsError()
- return true
- },
- async createBucketIfNotExists (bucket) {
- const result = await this.bucketExists(bucket)
- if (!result) await this.makeBucket(bucket)
- },
- ping ({ timeout = 5000 } = {}) {
- return this.Promise.race([
- this.minio.listBuckets().then(() => true),
- this.Promise.delay(timeout).then(() => { throw new MinioPingError() }),
- ])
- },
- },
- created () {
- this.minio = this.createMinioClient()
- },
- started () {
- return this.Promise.resolve()
- .then(() => this.ping())
- .then(() => {
- if (this.settings.minioHealthCheckInterval) {
- this.healthCheckInterval = setInterval(
- () => this.ping().catch(e => this.logger.error('Minio backend can not be reached', e)),
- this.settings.minioHealthCheckInterval,
- )
- return this.healthCheckInterval
- }
- return undefined
- }).catch(e => {
- throw new MinioInitializationError(e.message)
- })
- },
- stopped () {
- if (this.healthCheckInterval) clearInterval(this.healthCheckInterval)
- },
- }
- module.exports = FsService
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement