|
@@ -1,6 +1,5 @@
|
|
|
import type { Readable } from 'stream';
|
|
import type { Readable } from 'stream';
|
|
|
|
|
|
|
|
-
|
|
|
|
|
import type { GetObjectCommandInput, HeadObjectCommandInput } from '@aws-sdk/client-s3';
|
|
import type { GetObjectCommandInput, HeadObjectCommandInput } from '@aws-sdk/client-s3';
|
|
|
import {
|
|
import {
|
|
|
S3Client,
|
|
S3Client,
|
|
@@ -30,7 +29,7 @@ import { configManager } from '../../config-manager';
|
|
|
import {
|
|
import {
|
|
|
AbstractFileUploader, type TemporaryUrl, type SaveFileParam,
|
|
AbstractFileUploader, type TemporaryUrl, type SaveFileParam,
|
|
|
} from '../file-uploader';
|
|
} from '../file-uploader';
|
|
|
-import { ContentHeaders, applyHeaders } from '../utils';
|
|
|
|
|
|
|
+import { ContentHeaders } from '../utils';
|
|
|
|
|
|
|
|
import { AwsMultipartUploader } from './multipart-uploader';
|
|
import { AwsMultipartUploader } from './multipart-uploader';
|
|
|
|
|
|
|
@@ -51,7 +50,7 @@ const isFileExists = async(s3: S3Client, params: HeadObjectCommandInput) => {
|
|
|
await s3.send(new HeadObjectCommand(params));
|
|
await s3.send(new HeadObjectCommand(params));
|
|
|
}
|
|
}
|
|
|
catch (err) {
|
|
catch (err) {
|
|
|
- if (err != null && (err as any).code === 'NotFound') {
|
|
|
|
|
|
|
+ if (err != null && err.code === 'NotFound') {
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
throw err;
|
|
throw err;
|
|
@@ -133,13 +132,7 @@ class AwsFileUploader extends AbstractFileUploader {
|
|
|
* @inheritdoc
|
|
* @inheritdoc
|
|
|
*/
|
|
*/
|
|
|
override isValidUploadSettings(): boolean {
|
|
override isValidUploadSettings(): boolean {
|
|
|
- return this.configManager.getConfig('aws:s3AccessKeyId') != null
|
|
|
|
|
- && this.configManager.getConfig('aws:s3SecretAccessKey') != null
|
|
|
|
|
- && (
|
|
|
|
|
- this.configManager.getConfig('aws:s3Region') != null
|
|
|
|
|
- || this.configManager.getConfig('aws:s3CustomEndpoint') != null
|
|
|
|
|
- )
|
|
|
|
|
- && this.configManager.getConfig('aws:s3Bucket') != null;
|
|
|
|
|
|
|
+ throw new Error('Method not implemented.');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -167,7 +160,7 @@ class AwsFileUploader extends AbstractFileUploader {
|
|
|
* @inheritdoc
|
|
* @inheritdoc
|
|
|
*/
|
|
*/
|
|
|
override determineResponseMode() {
|
|
override determineResponseMode() {
|
|
|
- return this.configManager.getConfig('aws:referenceFileWithRelayMode')
|
|
|
|
|
|
|
+ return configManager.getConfig('aws:referenceFileWithRelayMode')
|
|
|
? ResponseMode.RELAY
|
|
? ResponseMode.RELAY
|
|
|
: ResponseMode.REDIRECT;
|
|
: ResponseMode.REDIRECT;
|
|
|
}
|
|
}
|
|
@@ -201,25 +194,7 @@ class AwsFileUploader extends AbstractFileUploader {
|
|
|
|
|
|
|
|
|
|
|
|
|
override async respond(res: Response, attachment: IAttachmentDocument, opts?: RespondOptions): Promise<void> {
|
|
override async respond(res: Response, attachment: IAttachmentDocument, opts?: RespondOptions): Promise<void> {
|
|
|
- const responseMode = this.determineResponseMode();
|
|
|
|
|
-
|
|
|
|
|
- if (responseMode === ResponseMode.REDIRECT) {
|
|
|
|
|
- // In REDIRECT mode, generate a temporary URL and redirect
|
|
|
|
|
- const temporaryUrl = await this.generateTemporaryUrl(attachment, opts);
|
|
|
|
|
- res.redirect(temporaryUrl.url);
|
|
|
|
|
- }
|
|
|
|
|
- else if (responseMode === ResponseMode.RELAY) {
|
|
|
|
|
- // In RELAY mode, stream the file content
|
|
|
|
|
- const readableStream = await this.findDeliveryFile(attachment);
|
|
|
|
|
- const isDownload = opts?.download ?? false;
|
|
|
|
|
- const contentHeaders = new ContentHeaders(attachment, { inline: !isDownload });
|
|
|
|
|
- applyHeaders(res, contentHeaders.toExpressHttpHeaders());
|
|
|
|
|
- readableStream.pipe(res);
|
|
|
|
|
- }
|
|
|
|
|
- else {
|
|
|
|
|
- // Fallback for any unexpected ResponseMode
|
|
|
|
|
- throw new Error(`AwsFileUploader encountered an unsupported or unexpected ResponseMode: ${responseMode}.`);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ throw new Error('AwsFileUploader does not support ResponseMode.DELEGATE.');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -253,8 +228,8 @@ class AwsFileUploader extends AbstractFileUploader {
|
|
|
|
|
|
|
|
// eslint-disable-next-line no-nested-ternary
|
|
// eslint-disable-next-line no-nested-ternary
|
|
|
return 'stream' in body
|
|
return 'stream' in body
|
|
|
- ? (body as any).transformToWebStream() as unknown as NodeJS.ReadableStream // get stream from Blob and cast force
|
|
|
|
|
- : body as unknown as NodeJS.ReadableStream; // cast force -- Updated for aws-sdk v3 'Body' type
|
|
|
|
|
|
|
+ ? body.stream() as unknown as NodeJS.ReadableStream // get stream from Blob and cast force
|
|
|
|
|
+ : body as unknown as NodeJS.ReadableStream; // cast force
|
|
|
}
|
|
}
|
|
|
catch (err) {
|
|
catch (err) {
|
|
|
logger.error(err);
|
|
logger.error(err);
|
|
@@ -272,12 +247,12 @@ class AwsFileUploader extends AbstractFileUploader {
|
|
|
|
|
|
|
|
const s3 = S3Factory();
|
|
const s3 = S3Factory();
|
|
|
const filePath = getFilePathOnStorage(attachment);
|
|
const filePath = getFilePathOnStorage(attachment);
|
|
|
- const lifetimeSecForTemporaryUrl = this.configManager.getConfig('aws:lifetimeSecForTemporaryUrl'); // <-- Changed
|
|
|
|
|
|
|
+ const lifetimeSecForTemporaryUrl = configManager.getConfig('aws:lifetimeSecForTemporaryUrl');
|
|
|
|
|
|
|
|
// issue signed url (default: expires 120 seconds)
|
|
// issue signed url (default: expires 120 seconds)
|
|
|
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
|
|
// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property
|
|
|
const isDownload = opts?.download ?? false;
|
|
const isDownload = opts?.download ?? false;
|
|
|
- const contentHeaders = new ContentHeaders(attachment, { inline: !isDownload }); // <-- Changed
|
|
|
|
|
|
|
+ const contentHeaders = new ContentHeaders(attachment, { inline: !isDownload });
|
|
|
const params: GetObjectCommandInput = {
|
|
const params: GetObjectCommandInput = {
|
|
|
Bucket: getS3Bucket(),
|
|
Bucket: getS3Bucket(),
|
|
|
Key: filePath,
|
|
Key: filePath,
|
|
@@ -309,11 +284,7 @@ class AwsFileUploader extends AbstractFileUploader {
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
catch (e) {
|
|
catch (e) {
|
|
|
- // allow duplicate abort requests to ensure abortion
|
|
|
|
|
- // Note: In AWS SDK v3, 'e.response' might not exist directly.
|
|
|
|
|
- // You may need to inspect the 'name' or 'Code' property for specific error types,
|
|
|
|
|
- // e.g., if (e instanceof NotFound) or (e as any).name === 'NotFound'
|
|
|
|
|
- if ((e as any)?.name !== 'NotFound') {
|
|
|
|
|
|
|
+ if (e.response?.status !== 404) {
|
|
|
throw e;
|
|
throw e;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -321,19 +292,15 @@ class AwsFileUploader extends AbstractFileUploader {
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// This is the factory function that creates an instance of AwsFileUploader
|
|
|
|
|
-// It receives 'crowi' and needs to pass the 'configManager' to the constructor
|
|
|
|
|
module.exports = (crowi: Crowi) => {
|
|
module.exports = (crowi: Crowi) => {
|
|
|
- const lib = new AwsFileUploader(crowi, configManager);
|
|
|
|
|
|
|
+ const lib = new AwsFileUploader(crowi);
|
|
|
|
|
|
|
|
- // For ideal consistency, should be moved into the class as 'override' methods
|
|
|
|
|
- // and use 'this.configManager'.
|
|
|
|
|
lib.isValidUploadSettings = function() {
|
|
lib.isValidUploadSettings = function() {
|
|
|
return configManager.getConfig('aws:s3AccessKeyId') != null
|
|
return configManager.getConfig('aws:s3AccessKeyId') != null
|
|
|
&& configManager.getConfig('aws:s3SecretAccessKey') != null
|
|
&& configManager.getConfig('aws:s3SecretAccessKey') != null
|
|
|
&& (
|
|
&& (
|
|
|
configManager.getConfig('aws:s3Region') != null
|
|
configManager.getConfig('aws:s3Region') != null
|
|
|
- || configManager.getConfig('aws:s3CustomEndpoint') != null
|
|
|
|
|
|
|
+ || configManager.getConfig('aws:s3CustomEndpoint') != null
|
|
|
)
|
|
)
|
|
|
&& configManager.getConfig('aws:s3Bucket') != null;
|
|
&& configManager.getConfig('aws:s3Bucket') != null;
|
|
|
};
|
|
};
|