-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
1,432 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
import { ModuleMetadata } from '@nestjs/common' | ||
import { PdfServiceToken } from 'src/domain' | ||
import { ClassConstructor } from 'class-transformer' | ||
|
||
import { IPdfService, PdfServiceToken } from 'src/domain' | ||
import { PdfService } from './service' | ||
|
||
export const pdfMetadata: ModuleMetadata = { | ||
providers: [ | ||
{ | ||
provide: PdfServiceToken, | ||
useClass: PdfService, | ||
useClass: PdfService satisfies ClassConstructor<IPdfService>, | ||
}, | ||
], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,14 @@ | ||
import { ModuleMetadata } from '@nestjs/common' | ||
import { PuppeteerServiceToken } from 'src/domain' | ||
import { ClassConstructor } from 'class-transformer' | ||
|
||
import { IPuppeteerService, PuppeteerServiceToken } from 'src/domain' | ||
import { PuppeteerService } from './service' | ||
|
||
export const puppeteerMetadata: ModuleMetadata = { | ||
providers: [ | ||
{ | ||
provide: PuppeteerServiceToken, | ||
useClass: PuppeteerService, | ||
useClass: PuppeteerService satisfies ClassConstructor<IPuppeteerService>, | ||
}, | ||
], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 3 additions & 1 deletion
4
apps/hcdc-access-service/src/domain/interface/storage/interface.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
export const StorageServiceToken = Symbol('StorageService') | ||
|
||
export interface IStorageService {} | ||
export interface IStorageService { | ||
upload(input: { bucket: string; key: string; buffer: Buffer }): Promise<void> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,35 @@ | ||
import { ConfigModule, MinioModule, MinioService } from '@diut/nestjs-infra' | ||
import { | ||
AwsS3ClientModule, | ||
AwsS3ClientService, | ||
ConfigModule, | ||
} from '@diut/nestjs-infra' | ||
import { ModuleMetadata } from '@nestjs/common' | ||
import { ClassConstructor } from 'class-transformer' | ||
|
||
import { IStorageService, StorageServiceToken } from 'src/domain' | ||
import { MinioConfig, loadMinioConfig } from 'src/config' | ||
|
||
export const minioMetadata: ModuleMetadata = { | ||
imports: [ | ||
MinioModule.forRootAsync({ | ||
AwsS3ClientModule.registerAsync({ | ||
imports: [ConfigModule.forFeature(loadMinioConfig)], | ||
inject: [loadMinioConfig.KEY], | ||
useFactory: async (minioConfig: MinioConfig) => ({ | ||
endPoint: minioConfig.MINIO_ENDPOINT, | ||
port: minioConfig.MINIO_PORT, | ||
useSSL: false, | ||
accessKey: minioConfig.MINIO_ACCESS_KEY, | ||
secretKey: minioConfig.MINIO_SECRET_KEY, | ||
connectionId: 'minio', | ||
endpoint: `http://${minioConfig.MINIO_ENDPOINT}:${minioConfig.MINIO_PORT}`, | ||
credentials: { | ||
accessKeyId: minioConfig.MINIO_ACCESS_KEY, | ||
secretAccessKey: minioConfig.MINIO_SECRET_KEY, | ||
}, | ||
forcePathStyle: true, | ||
}), | ||
}), | ||
], | ||
providers: [ | ||
{ | ||
provide: StorageServiceToken, | ||
useClass: MinioService satisfies IStorageService, | ||
useExisting: | ||
AwsS3ClientService satisfies ClassConstructor<IStorageService>, | ||
}, | ||
], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './module' | ||
export * from './service' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { ConfigurableModuleBuilder } from '@nestjs/common' | ||
|
||
import { AwsS3ClientOptions } from './service' | ||
|
||
export const { ConfigurableModuleClass, MODULE_OPTIONS_TOKEN } = | ||
new ConfigurableModuleBuilder<AwsS3ClientOptions>().build() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { Module } from '@nestjs/common' | ||
|
||
import { ConfigurableModuleClass } from './module-builder' | ||
import { AwsS3ClientService } from './service' | ||
|
||
@Module({ | ||
providers: [AwsS3ClientService], | ||
exports: [AwsS3ClientService], | ||
}) | ||
export class AwsS3ClientModule extends ConfigurableModuleClass {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { | ||
DeleteObjectCommand, | ||
GetObjectCommand, | ||
PutObjectCommand, | ||
S3Client, | ||
S3ClientConfigType, | ||
} from '@aws-sdk/client-s3' | ||
import { Inject, Injectable } from '@nestjs/common' | ||
import { Readable, Stream } from 'stream' | ||
import { parseUrl } from '@smithy/url-parser' | ||
import { S3RequestPresigner } from '@aws-sdk/s3-request-presigner' | ||
import { Hash } from '@smithy/hash-node' | ||
import { HttpRequest } from '@smithy/protocol-http' | ||
import { formatUrl } from '@aws-sdk/util-format-url' | ||
|
||
import { AbstractClientService } from '../service' | ||
import { MODULE_OPTIONS_TOKEN } from './module-builder' | ||
|
||
export type AwsS3ClientOptions = S3ClientConfigType & { | ||
connectionId?: string | ||
} | ||
|
||
@Injectable() | ||
export class AwsS3ClientService< | ||
TBuckets extends string = string, | ||
> extends AbstractClientService { | ||
private client: S3Client | ||
|
||
constructor( | ||
@Inject(MODULE_OPTIONS_TOKEN) | ||
private readonly clientOptions: AwsS3ClientOptions, | ||
) { | ||
super({ | ||
name: AwsS3ClientService.name, | ||
connectionId: clientOptions.connectionId, | ||
}) | ||
} | ||
|
||
initialize() { | ||
this.client = new S3Client(this.clientOptions) | ||
} | ||
|
||
terminate() { | ||
this.client.destroy() | ||
} | ||
|
||
async upload(input: { bucket: string; key: string; buffer: Buffer }) { | ||
await this.client.send( | ||
new PutObjectCommand({ | ||
Bucket: input.bucket, | ||
Key: input.key, | ||
Body: input.buffer, | ||
}), | ||
) | ||
} | ||
|
||
async getPresignedUrl(key: string) { | ||
const credentials = this.clientOptions.credentials | ||
const region = this.clientOptions.region | ||
if (!credentials || !region) { | ||
throw new Error('Missing credentials or region required for signing URL') | ||
} | ||
|
||
const s3ObjectUrl = parseUrl( | ||
`https://${process.env.S3_BUCKET}.s3.${region}.amazonaws.com/${key}`, | ||
) | ||
|
||
const presigner = new S3RequestPresigner({ | ||
credentials, | ||
region, | ||
sha256: Hash.bind(null, 'sha256'), | ||
}) | ||
|
||
const url = await presigner.presign(new HttpRequest(s3ObjectUrl)) | ||
|
||
return formatUrl(url) | ||
} | ||
|
||
async readToStream(input: { key: string; bucket: string }) { | ||
const response = await this.client.send( | ||
new GetObjectCommand({ | ||
Bucket: input.bucket, | ||
Key: input.key, | ||
}), | ||
) | ||
|
||
return response.Body as Readable | ||
} | ||
|
||
async readToBuffer(key: string, bucket: string) { | ||
const buffer = await new Promise<Buffer>((resolve, reject) => { | ||
const getObjectCommand = new GetObjectCommand({ | ||
Bucket: bucket, | ||
Key: key, | ||
}) | ||
|
||
this.client | ||
.send(getObjectCommand) | ||
.then((response) => { | ||
// Store all of data chunks returned from the response data stream | ||
// into an array then use Array#join() to use the returned contents as a String | ||
const responseDataChunks: any[] = [] | ||
const responseStream = response.Body as Stream | ||
|
||
// Handle an error while streaming the response body | ||
responseStream.once('error', (err) => reject(err)) | ||
|
||
// Attach a 'data' listener to add the chunks of data to our array | ||
// Each chunk is a Buffer instance | ||
responseStream.on('data', (chunk) => responseDataChunks.push(chunk)) | ||
|
||
// Once the stream has no more data, join the chunks into a Buffer | ||
responseStream.once('end', () => | ||
resolve(Buffer.concat(responseDataChunks)), | ||
) | ||
}) | ||
.catch((err) => { | ||
reject(err) | ||
}) | ||
}) | ||
|
||
return buffer | ||
} | ||
|
||
async deleteByKey(input: { key: string; bucket: string }) { | ||
await this.client.send( | ||
new DeleteObjectCommand({ | ||
Bucket: input.bucket, | ||
Key: input.key, | ||
}), | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './minio' | ||
export * from './aws-s3' | ||
export * from './service' |
File renamed without changes.
File renamed without changes.
File renamed without changes.
Oops, something went wrong.