|
|
|
@@ -1,6 +1,9 @@
|
|
|
|
|
import * as plugins from './plugins.js';
|
|
|
|
|
import * as helpers from './helpers.js';
|
|
|
|
|
import * as interfaces from './interfaces.js';
|
|
|
|
|
import { SmartBucket } from './classes.smartbucket.js';
|
|
|
|
|
import { Directory } from './classes.directory.js';
|
|
|
|
|
import { File } from './classes.file.js';
|
|
|
|
|
|
|
|
|
|
export class Bucket {
|
|
|
|
|
public static async getBucketByName(smartbucketRef: SmartBucket, bucketNameArg: string) {
|
|
|
|
@@ -38,10 +41,19 @@ export class Bucket {
|
|
|
|
|
/**
|
|
|
|
|
* gets the base directory of the bucket
|
|
|
|
|
*/
|
|
|
|
|
public async getBaseDirectory() {
|
|
|
|
|
public async getBaseDirectory(): Promise<Directory> {
|
|
|
|
|
return new Directory(this, null, '');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getDirectoryFromPath(pathDescriptorArg: interfaces.IPathDecriptor): Promise<Directory> {
|
|
|
|
|
if (!pathDescriptorArg.path && !pathDescriptorArg.directory) {
|
|
|
|
|
return this.getBaseDirectory();
|
|
|
|
|
}
|
|
|
|
|
let checkPath = await helpers.reducePathDescriptorToPath(pathDescriptorArg);
|
|
|
|
|
const baseDirectory = await this.getBaseDirectory();
|
|
|
|
|
return await baseDirectory.getSubDirectoryByName(checkPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===============
|
|
|
|
|
// Fast Operations
|
|
|
|
|
// ===============
|
|
|
|
@@ -53,28 +65,38 @@ export class Bucket {
|
|
|
|
|
path: string;
|
|
|
|
|
contents: string | Buffer;
|
|
|
|
|
overwrite?: boolean;
|
|
|
|
|
}): Promise<void> {
|
|
|
|
|
}): Promise<File> {
|
|
|
|
|
try {
|
|
|
|
|
const reducedPath = await helpers.reducePathDescriptorToPath({
|
|
|
|
|
path: optionsArg.path,
|
|
|
|
|
})
|
|
|
|
|
// Check if the object already exists
|
|
|
|
|
const exists = await this.fastExists({ path: optionsArg.path });
|
|
|
|
|
const exists = await this.fastExists({ path: reducedPath });
|
|
|
|
|
|
|
|
|
|
if (exists && !optionsArg.overwrite) {
|
|
|
|
|
console.error(`Object already exists at path '${optionsArg.path}' in bucket '${this.name}'.`);
|
|
|
|
|
console.error(`Object already exists at path '${reducedPath}' in bucket '${this.name}'.`);
|
|
|
|
|
return;
|
|
|
|
|
} else if (exists && optionsArg.overwrite) {
|
|
|
|
|
console.log(`Overwriting existing object at path '${optionsArg.path}' in bucket '${this.name}'.`);
|
|
|
|
|
console.log(`Overwriting existing object at path '${reducedPath}' in bucket '${this.name}'.`);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(`Creating new object at path '${optionsArg.path}' in bucket '${this.name}'.`);
|
|
|
|
|
console.log(`Creating new object at path '${reducedPath}' in bucket '${this.name}'.`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Proceed with putting the object
|
|
|
|
|
const streamIntake = new plugins.smartstream.StreamIntake();
|
|
|
|
|
const putPromise = this.smartbucketRef.minioClient.putObject(this.name, optionsArg.path, streamIntake);
|
|
|
|
|
const putPromise = this.smartbucketRef.minioClient.putObject(this.name, reducedPath, streamIntake);
|
|
|
|
|
streamIntake.pushData(optionsArg.contents);
|
|
|
|
|
streamIntake.signalEnd();
|
|
|
|
|
await putPromise;
|
|
|
|
|
|
|
|
|
|
console.log(`Object '${optionsArg.path}' has been successfully stored in bucket '${this.name}'.`);
|
|
|
|
|
console.log(`Object '${reducedPath}' has been successfully stored in bucket '${this.name}'.`);
|
|
|
|
|
const parsedPath = plugins.path.parse(reducedPath);
|
|
|
|
|
return new File({
|
|
|
|
|
directoryRefArg: await this.getDirectoryFromPath({
|
|
|
|
|
path: parsedPath.dir,
|
|
|
|
|
}),
|
|
|
|
|
fileName: parsedPath.base,
|
|
|
|
|
});
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(`Error storing object at path '${optionsArg.path}' in bucket '${this.name}':`, error);
|
|
|
|
|
throw error;
|
|
|
|
@@ -183,19 +205,10 @@ export class Bucket {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public async copyObject(optionsArg: {
|
|
|
|
|
/**
|
|
|
|
|
* the
|
|
|
|
|
*/
|
|
|
|
|
objectKey: string;
|
|
|
|
|
/**
|
|
|
|
|
* in case you want to copy to another bucket specify it here
|
|
|
|
|
*/
|
|
|
|
|
public async fastCopy(optionsArg: {
|
|
|
|
|
sourcePath: string;
|
|
|
|
|
destinationPath?: string;
|
|
|
|
|
targetBucket?: Bucket;
|
|
|
|
|
targetBucketKey?: string;
|
|
|
|
|
/**
|
|
|
|
|
* metadata will be merged with existing metadata
|
|
|
|
|
*/
|
|
|
|
|
nativeMetadata?: { [key: string]: string };
|
|
|
|
|
deleteExistingNativeMetadata?: boolean;
|
|
|
|
|
}): Promise<void> {
|
|
|
|
@@ -205,7 +218,7 @@ export class Bucket {
|
|
|
|
|
// Retrieve current object information to use in copy conditions
|
|
|
|
|
const currentObjInfo = await this.smartbucketRef.minioClient.statObject(
|
|
|
|
|
targetBucketName,
|
|
|
|
|
optionsArg.objectKey
|
|
|
|
|
optionsArg.sourcePath
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Setting up copy conditions
|
|
|
|
@@ -221,8 +234,8 @@ export class Bucket {
|
|
|
|
|
// TODO: check on issue here: https://github.com/minio/minio-js/issues/1286
|
|
|
|
|
await this.smartbucketRef.minioClient.copyObject(
|
|
|
|
|
this.name,
|
|
|
|
|
optionsArg.objectKey,
|
|
|
|
|
`/${targetBucketName}/${optionsArg.objectKey}`,
|
|
|
|
|
optionsArg.sourcePath,
|
|
|
|
|
`/${targetBucketName}/${optionsArg.destinationPath || optionsArg.sourcePath}`,
|
|
|
|
|
copyConditions
|
|
|
|
|
);
|
|
|
|
|
} catch (err) {
|
|
|
|
@@ -231,6 +244,43 @@ export class Bucket {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Move object from one path to another within the same bucket or to another bucket
|
|
|
|
|
*/
|
|
|
|
|
public async fastMove(optionsArg: {
|
|
|
|
|
sourcePath: string;
|
|
|
|
|
destinationPath: string;
|
|
|
|
|
targetBucket?: Bucket;
|
|
|
|
|
overwrite?: boolean;
|
|
|
|
|
}): Promise<void> {
|
|
|
|
|
try {
|
|
|
|
|
// Check if the destination object already exists
|
|
|
|
|
const destinationBucket = optionsArg.targetBucket || this;
|
|
|
|
|
const exists = await destinationBucket.fastExists({ path: optionsArg.destinationPath });
|
|
|
|
|
|
|
|
|
|
if (exists && !optionsArg.overwrite) {
|
|
|
|
|
console.error(`Object already exists at destination path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`);
|
|
|
|
|
return;
|
|
|
|
|
} else if (exists && optionsArg.overwrite) {
|
|
|
|
|
console.log(`Overwriting existing object at destination path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`);
|
|
|
|
|
} else {
|
|
|
|
|
console.log(`Moving object to path '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Proceed with copying the object to the new path
|
|
|
|
|
await this.fastCopy(optionsArg);
|
|
|
|
|
|
|
|
|
|
// Remove the original object after successful copy
|
|
|
|
|
await this.fastRemove({ path: optionsArg.sourcePath });
|
|
|
|
|
|
|
|
|
|
console.log(`Object '${optionsArg.sourcePath}' has been successfully moved to '${optionsArg.destinationPath}' in bucket '${destinationBucket.name}'.`);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(`Error moving object from '${optionsArg.sourcePath}' to '${optionsArg.destinationPath}':`, error);
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* removeObject
|
|
|
|
|
*/
|
|
|
|
@@ -263,9 +313,56 @@ export class Bucket {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async fastStat(optionsArg: {
|
|
|
|
|
path: string;
|
|
|
|
|
}) {
|
|
|
|
|
return this.smartbucketRef.minioClient.statObject(this.name, optionsArg.path);
|
|
|
|
|
public async fastStat(pathDescriptor: interfaces.IPathDecriptor) {
|
|
|
|
|
let checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
|
|
|
|
|
return this.smartbucketRef.minioClient.statObject(this.name, checkPath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async isDirectory(pathDescriptor: interfaces.IPathDecriptor): Promise<boolean> {
|
|
|
|
|
let checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
|
|
|
|
|
|
|
|
|
|
// lets check if the checkPath is a directory
|
|
|
|
|
const stream = this.smartbucketRef.minioClient.listObjectsV2(this.name, checkPath, true);
|
|
|
|
|
const done = plugins.smartpromise.defer<boolean>();
|
|
|
|
|
stream.on('data', (dataArg) => {
|
|
|
|
|
stream.destroy(); // Stop the stream early if we find at least one object
|
|
|
|
|
if (dataArg.prefix.startsWith(checkPath + '/')) {
|
|
|
|
|
done.resolve(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
stream.on('end', () => {
|
|
|
|
|
done.resolve(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
stream.on('error', (err) => {
|
|
|
|
|
done.reject(err);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return done.promise;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public async isFile(pathDescriptor: interfaces.IPathDecriptor): Promise<boolean> {
|
|
|
|
|
let checkPath = await helpers.reducePathDescriptorToPath(pathDescriptor);
|
|
|
|
|
|
|
|
|
|
// lets check if the checkPath is a directory
|
|
|
|
|
const stream = this.smartbucketRef.minioClient.listObjectsV2(this.name, checkPath, true);
|
|
|
|
|
const done = plugins.smartpromise.defer<boolean>();
|
|
|
|
|
stream.on('data', (dataArg) => {
|
|
|
|
|
stream.destroy(); // Stop the stream early if we find at least one object
|
|
|
|
|
if (dataArg.prefix === checkPath) {
|
|
|
|
|
done.resolve(true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
stream.on('end', () => {
|
|
|
|
|
done.resolve(false);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
stream.on('error', (err) => {
|
|
|
|
|
done.reject(err);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return done.promise;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|