"use strict";
var __asyncValues = (this && this.__asyncValues) || function (o) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var m = o[Symbol.asyncIterator], i;
    return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpacesProvider = void 0;
const client_s3_1 = require("@aws-sdk/client-s3");
const s3_request_presigner_1 = require("@aws-sdk/s3-request-presigner");
const common_1 = require("@nestjs/common");
const fs_1 = require("fs");
const path_1 = require("path");
const abstract_provider_1 = require("./abstract.provider");
class SpacesProvider extends abstract_provider_1.AbstractProvider {
    constructor(setting) {
        super();
        this.setting = setting;
    }
    get endpoint() {
        return `https://${this.setting['storage-spaces-region']}.digitaloceanspaces.com`;
    }
    get bucketUrl() {
        const cdn = this.setting['storage-spaces-cdn'];
        if (cdn) {
            return cdn.replace(/\/$/, '');
        }
        return `https://${this.setting['storage-spaces-bucket']}.${this.setting['storage-spaces-region']}.digitaloceanspaces.com`;
    }
    resolveKey(filepath) {
        if (!filepath) {
            throw new Error('Invalid filepath for DigitalOcean Spaces');
        }
        return filepath;
    }
    async initValidation() {
        if (!this.setting['storage-spaces-key']) {
            throw new common_1.BadRequestException(`You must set the storage-spaces-key in the setting.`);
        }
        if (!this.setting['storage-spaces-secret']) {
            throw new common_1.BadRequestException(`You must set the storage-spaces-secret in the setting.`);
        }
        if (!this.setting['storage-spaces-region']) {
            throw new common_1.BadRequestException(`You must set the storage-spaces-region in the setting.`);
        }
        if (!this.setting['storage-spaces-bucket']) {
            throw new common_1.BadRequestException(`You must set the storage-spaces-bucket in the setting.`);
        }
        const s3 = await this.getClient();
        try {
            await s3.send(new client_s3_1.HeadBucketCommand({
                Bucket: this.setting['storage-spaces-bucket'],
            }));
        }
        catch (error) {
            throw new common_1.BadRequestException(`The bucket "${this.setting['storage-spaces-bucket']}" does not exist or you do not have access to it.`);
        }
    }
    async getClient() {
        if (this.S3) {
            return this.S3;
        }
        const credentials = {
            accessKeyId: this.setting['storage-spaces-key'],
            secretAccessKey: this.setting['storage-spaces-secret'],
        };
        this.S3Client = new client_s3_1.S3Client({
            credentials,
            endpoint: this.endpoint,
            region: this.setting['storage-spaces-region'],
            forcePathStyle: false,
        });
        return (this.S3 = new client_s3_1.S3({
            credentials,
            endpoint: this.endpoint,
            region: this.setting['storage-spaces-region'],
            forcePathStyle: false,
        }));
    }
    async getS3Client() {
        if (this.S3Client) {
            return this.S3Client;
        }
        this.S3Client = new client_s3_1.S3Client({
            credentials: {
                accessKeyId: this.setting['storage-spaces-key'],
                secretAccessKey: this.setting['storage-spaces-secret'],
            },
            endpoint: this.endpoint,
            region: this.setting['storage-spaces-region'],
            forcePathStyle: false,
        });
        return this.S3Client;
    }
    async buffer(filepath) {
        var _a, e_1, _b, _c;
        const s3 = await this.getClient();
        const key = this.resolveKey(filepath);
        const result = await s3.send(new client_s3_1.GetObjectCommand({
            Bucket: this.setting['storage-spaces-bucket'],
            Key: key,
        }));
        // @ts-ignore
        const stream = result.Body;
        const chunks = [];
        try {
            for (var _d = true, stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = await stream_1.next(), _a = stream_1_1.done, !_a; _d = true) {
                _c = stream_1_1.value;
                _d = false;
                const chunk = _c;
                chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (!_d && !_a && (_b = stream_1.return)) await _b.call(stream_1);
            }
            finally { if (e_1) throw e_1.error; }
        }
        return Buffer.concat(chunks);
    }
    async upload(destination, file) {
        const s3 = await this.getClient();
        const storedFilename = this.getFilename(file.originalname);
        const key = [destination, storedFilename].join('/');
        await s3.send(new client_s3_1.PutObjectCommand({
            Bucket: this.setting['storage-spaces-bucket'],
            Key: key,
            Body: file.buffer,
            ACL: 'public-read',
        }));
        return storedFilename;
    }
    async uploadFromString(destination, filename, fileContent) {
        const s3 = await this.getClient();
        const storedFilename = this.getFilename(filename);
        const key = [destination, storedFilename].join('/');
        await s3.send(new client_s3_1.PutObjectCommand({
            Bucket: this.setting['storage-spaces-bucket'],
            Key: key,
            Body: fileContent,
            ACL: 'public-read',
        }));
        return storedFilename;
    }
    async uploadFromPath(destination, filePath, options) {
        var _a;
        const s3 = await this.getClient();
        const originalName = (_a = options === null || options === void 0 ? void 0 : options.filename) !== null && _a !== void 0 ? _a : (0, path_1.basename)(filePath);
        const storedFilename = this.getFilename(originalName);
        const key = [destination, storedFilename].join('/');
        await s3.send(new client_s3_1.PutObjectCommand({
            Bucket: this.setting['storage-spaces-bucket'],
            Key: key,
            Body: (0, fs_1.createReadStream)(filePath),
            ContentType: options === null || options === void 0 ? void 0 : options.mimetype,
            ACL: 'public-read',
        }));
        return storedFilename;
    }
    async delete(filepath) {
        const s3 = await this.getClient();
        const key = this.resolveKey(filepath);
        await s3.send(new client_s3_1.DeleteObjectCommand({
            Bucket: this.setting['storage-spaces-bucket'],
            Key: key,
        }));
        return true;
    }
    async readStream(filepath) {
        const s3 = await this.getClient();
        const key = this.resolveKey(filepath);
        const result = await s3.send(new client_s3_1.GetObjectCommand({
            Bucket: this.setting['storage-spaces-bucket'],
            Key: key,
        }));
        // @ts-ignore
        return result.Body;
    }
    async metaData(filepath) {
        const s3 = await this.getClient();
        const key = this.resolveKey(filepath);
        const result = await s3.send(new client_s3_1.HeadObjectCommand({
            Bucket: this.setting['storage-spaces-bucket'],
            Key: key,
        }));
        return result;
    }
    async tempURL(filepath, expires = 3600) {
        const s3Client = await this.getS3Client();
        const key = this.resolveKey(filepath);
        const command = new client_s3_1.GetObjectCommand({
            Bucket: this.setting['storage-spaces-bucket'],
            Key: key,
        });
        return await (0, s3_request_presigner_1.getSignedUrl)(s3Client, command, { expiresIn: expires });
    }
}
exports.SpacesProvider = SpacesProvider;
//# sourceMappingURL=spaces.provider.js.map