Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve user experience reliability #29

Merged
merged 12 commits into from
Oct 23, 2024
95 changes: 62 additions & 33 deletions src/s3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,12 @@ export const listS3Contents = async (
path?: string
): Promise<Contents.IModel> => {
const fileList: IContentsList = {};
const prefix = path ? PathExt.join(root, path) : root;

// listing contents of folder
const command = new ListObjectsV2Command({
Bucket: bucketName,
Prefix: path ? PathExt.join(root, path) : root
Prefix: prefix + (prefix ? '/' : '')
});

let isTruncated: boolean | undefined = true;
Expand Down Expand Up @@ -256,21 +257,35 @@ export const createS3Object = async (
if (options) {
body = Private.formatBody(options, fileFormat, fileType, fileMimeType);
}
let lastModified;

await s3Client.send(
new PutObjectCommand({
Bucket: bucketName,
Key: path + (PathExt.extname(name) === '' ? '/' : ''),
Body: body,
CacheControl: options ? 'no-cache' : undefined
await s3Client
.send(
new PutObjectCommand({
Bucket: bucketName,
Key: path + (PathExt.extname(name) === '' ? '/' : ''),
Body: body,
CacheControl: options ? 'no-cache' : undefined
})
)
.then(async () => {
const newFileInfo = await s3Client.send(
new HeadObjectCommand({
Bucket: bucketName,
Key: path + (PathExt.extname(name) === '' ? '/' : '')
})
);
lastModified = newFileInfo.LastModified?.toISOString();
})
);
.catch(error => {
console.error('Failed saving or creating the S3 object: ', error);
});

data = {
name: name,
path: PathExt.join(path, name),
last_modified: new Date().toISOString(),
created: new Date().toISOString(),
last_modified: lastModified ?? new Date().toISOString(),
created: lastModified ?? new Date().toISOString(),
content: path.split('.').length === 1 ? [] : body,
format: fileFormat as Contents.FileFormat,
mimetype: fileMimeType,
Expand Down Expand Up @@ -312,9 +327,9 @@ export const deleteS3Objects = async (

if (Contents) {
await Promise.all(
Contents.map(c => {
Contents.map(async c => {
// delete each file with given path
Private.deleteFile(s3Client, bucketName, c.Key!);
return Private.deleteFile(s3Client, bucketName, c.Key!);
})
);
}
Expand Down Expand Up @@ -402,28 +417,14 @@ export const renameS3Objects = async (
await s3Client.send(command);

if (Contents) {
// retrieve information of file or directory
const fileContents = await s3Client.send(
// retrieve content of file or directory
const oldFileContents = await s3Client.send(
new GetObjectCommand({
Bucket: bucketName,
Key: Contents[0].Key!
})
);

const body = await fileContents.Body?.transformToString();

data = {
name: newFileName,
path: newLocalPath,
last_modified: fileContents.LastModified!.toISOString(),
created: '',
content: body ? body : [],
format: fileFormat as Contents.FileFormat,
mimetype: fileMimeType,
size: fileContents.ContentLength!,
writable: true,
type: fileType
};
const body = await oldFileContents.Body?.transformToString();

const promises = Contents.map(async c => {
const remainingFilePath = c.Key!.substring(oldLocalPath.length);
Expand All @@ -442,13 +443,37 @@ export const renameS3Objects = async (
);
});
await Promise.all(promises);

let lastModifiedDate = new Date().toISOString();
if (!isDir) {
// retrieve last modified time for new file, does not apply to remaming directory
const newFileMetadata = await s3Client.send(
new HeadObjectCommand({
Bucket: bucketName,
Key: newLocalPath
})
);
lastModifiedDate = newFileMetadata.LastModified!.toISOString();
}

data = {
name: newFileName,
path: newLocalPath.replace(root, ''),
last_modified: lastModifiedDate,
created: '',
content: body ? body : [],
format: fileFormat as Contents.FileFormat,
mimetype: fileMimeType,
size: oldFileContents.ContentLength!,
writable: true,
type: fileType
};
}
if (isTruncated) {
isTruncated = IsTruncated;
}
command.input.ContinuationToken = NextContinuationToken;
}

return data;
};

Expand Down Expand Up @@ -479,12 +504,12 @@ export const copyS3Objects = async (
newBucketName?: string
): Promise<Contents.IModel> => {
const isDir: boolean = PathExt.extname(path) === '';
let suffix: string = '';

path = PathExt.join(root, path);
toDir = PathExt.join(root, toDir);

name = PathExt.join(toDir, name);
path = isDir ? path + '/' : path;
path = path + (isDir ? '/' : '');

// list contents of path - contents of directory or one file
const command = new ListObjectsV2Command({
Expand All @@ -500,6 +525,9 @@ export const copyS3Objects = async (

if (Contents) {
const promises = Contents.map(c => {
if (!suffix && c.Key!.search('/.emptyFolderPlaceholder') !== -1) {
suffix = '.emptyFolderPlaceholder';
}
const remainingFilePath = c.Key!.substring(path.length);
// copy each file from old directory to new location
return Private.copyFile(
Expand Down Expand Up @@ -528,7 +556,7 @@ export const copyS3Objects = async (
const newFileContents = await s3Client.send(
new GetObjectCommand({
Bucket: newBucketName ?? bucketName,
Key: name
Key: name + (suffix ? suffix : '')
})
);

Expand Down Expand Up @@ -672,6 +700,7 @@ namespace Private {
Key: PathExt.join(newPath, remainingFilePath)
})
);
console.log('copy: ', PathExt.join(newPath, remainingFilePath));
}

/**
Expand Down
47 changes: 20 additions & 27 deletions src/s3contents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,6 @@ export class Drive implements Contents.IDrive {
oldValue: null,
newValue: data
});

return data;
}

Expand Down Expand Up @@ -428,35 +427,29 @@ export class Drive implements Contents.IDrive {
): Promise<Contents.IModel> {
let newFileName = PathExt.basename(newLocalPath);

await checkS3Object(this._s3Client, this._name, this._root, newLocalPath)
.then(async () => {
console.log('File name already exists!');
// construct new incremented name
newFileName = await this.incrementName(newLocalPath, this._name);
})
.catch(() => {
// function throws error as the file name doesn't exist
console.log("Name doesn't exist!");
})
.finally(async () => {
// once the name has been incremented if needed, proceed with the renaming
data = await renameS3Objects(
this._s3Client,
this._name,
this._root,
oldLocalPath,
newLocalPath,
newFileName,
this._registeredFileTypes
);
});
try {
await checkS3Object(this._s3Client, this._name, this._root, newLocalPath);
newFileName = await this.incrementName(newLocalPath, this._name);
} catch (error) {
// HEAD request failed for this file name, continue, as name doesn't already exist.
} finally {
data = await renameS3Objects(
this._s3Client,
this._name,
this._root,
oldLocalPath,
newLocalPath,
newFileName,
this._registeredFileTypes
);
}

Contents.validateContentsModel(data);
this._fileChanged.emit({
type: 'rename',
oldValue: { path: oldLocalPath },
newValue: data
});
Contents.validateContentsModel(data);
return data;
}

Expand Down Expand Up @@ -534,12 +527,12 @@ export class Drive implements Contents.IDrive {
options
);

Contents.validateContentsModel(data);
this._fileChanged.emit({
type: 'save',
oldValue: null,
newValue: data
});
Contents.validateContentsModel(data);
return data;
}

Expand Down Expand Up @@ -605,12 +598,12 @@ export class Drive implements Contents.IDrive {
this._registeredFileTypes
);

Contents.validateContentsModel(data);
this._fileChanged.emit({
type: 'new',
oldValue: null,
newValue: data
});
Contents.validateContentsModel(data);
return data;
}

Expand Down Expand Up @@ -773,7 +766,7 @@ export class Drive implements Contents.IDrive {
root = PathExt.removeSlash(PathExt.normalize(root));
// check if directory exists within bucket
try {
checkS3Object(this._s3Client, this._name, root);
await checkS3Object(this._s3Client, this._name, root);
// the directory exists, root is formatted correctly
return root;
} catch (error) {
Expand Down
Loading