Просмотр исходного кода

Add a list directory method to the S3 persistor

GitOrigin-RevId: 6ecff3eb457dc2168ca49ff9409bb09fa932781c
Andrew Rumble 1 год назад
Родитель
Сommit
4157f8ca00

+ 16 - 2
libraries/object-persistor/src/PerProjectEncryptedS3Persistor.js

@@ -33,6 +33,10 @@ const AES256_KEY_LENGTH = 32
  * @property {() => Promise<Array<RootKeyEncryptionKey>>} getRootKeyEncryptionKeys
  */
 
+/**
+ * @typedef {import('./types').ListDirectoryResult} ListDirectoryResult
+ */
+
 /**
  * Helper function to make TS happy when accessing error properties
  * AWSError is not an actual class, so we cannot use instanceof.
@@ -391,9 +395,9 @@ class PerProjectEncryptedS3Persistor extends S3Persistor {
  * A general "cache" for project keys is another alternative. For now, use a helper class.
  */
 class CachedPerProjectEncryptedS3Persistor {
-  /** @type SSECOptions */
+  /** @type SSECOptions  */
   #projectKeyOptions
-  /** @type PerProjectEncryptedS3Persistor */
+  /** @type PerProjectEncryptedS3Persistor  */
   #parent
 
   /**
@@ -424,6 +428,16 @@ class CachedPerProjectEncryptedS3Persistor {
     return await this.#parent.getObjectSize(bucketName, path)
   }
 
+  /**
+   *
+   * @param {string} bucketName
+   * @param {string} path
+   * @return {Promise<ListDirectoryResult>}
+   */
+  async listDirectory(bucketName, path) {
+    return await this.#parent.listDirectory(bucketName, path)
+  }
+
   /**
    * @param {string} bucketName
    * @param {string} path

+ 48 - 20
libraries/object-persistor/src/S3Persistor.js

@@ -20,6 +20,18 @@ const { URL } = require('node:url')
 const { WriteError, ReadError, NotFoundError } = require('./Errors')
 const zlib = require('node:zlib')
 
+/**
+ * @typedef {import('aws-sdk/clients/s3').ListObjectsV2Output} ListObjectsV2Output
+ */
+
+/**
+ * @typedef {import('aws-sdk/clients/s3').Object} S3Object
+ */
+
+/**
+ * @typedef {import('./types').ListDirectoryResult} ListDirectoryResult
+ */
+
 /**
  * Wrapper with private fields to avoid revealing them on console, JSON.stringify or similar.
  */
@@ -266,26 +278,12 @@ class S3Persistor extends AbstractPersistor {
    * @return {Promise<void>}
    */
   async deleteDirectory(bucketName, key, continuationToken) {
-    let response
-    const options = { Bucket: bucketName, Prefix: key }
-    if (continuationToken) {
-      options.ContinuationToken = continuationToken
-    }
-
-    try {
-      response = await this._getClientForBucket(bucketName)
-        .listObjectsV2(options)
-        .promise()
-    } catch (err) {
-      throw PersistorHelper.wrapError(
-        err,
-        'failed to list objects in S3',
-        { bucketName, key },
-        ReadError
-      )
-    }
-
-    const objects = response.Contents?.map(item => ({ Key: item.Key || '' }))
+    const { contents, response } = await this.listDirectory(
+      bucketName,
+      key,
+      continuationToken
+    )
+    const objects = contents.map(item => ({ Key: item.Key || '' }))
     if (objects?.length) {
       try {
         await this._getClientForBucket(bucketName)
@@ -316,6 +314,36 @@ class S3Persistor extends AbstractPersistor {
     }
   }
 
+  /**
+   *
+   * @param {string} bucketName
+   * @param {string} key
+   * @param {string} [continuationToken]
+   * @return {Promise<ListDirectoryResult>}
+   */
+  async listDirectory(bucketName, key, continuationToken) {
+    let response
+    const options = { Bucket: bucketName, Prefix: key }
+    if (continuationToken) {
+      options.ContinuationToken = continuationToken
+    }
+
+    try {
+      response = await this._getClientForBucket(bucketName)
+        .listObjectsV2(options)
+        .promise()
+    } catch (err) {
+      throw PersistorHelper.wrapError(
+        err,
+        'failed to list objects in S3',
+        { bucketName, key },
+        ReadError
+      )
+    }
+
+    return { contents: response.Contents ?? [], response }
+  }
+
   /**
    * @param {string} bucketName
    * @param {string} key

+ 6 - 0
libraries/object-persistor/src/types.d.ts

@@ -0,0 +1,6 @@
+import type { ListObjectsV2Output, Object } from 'aws-sdk/clients/s3'
+
+export type ListDirectoryResult = {
+  contents: Array<Object>
+  response: ListObjectsV2Output
+}