-
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
1 parent
6eee73b
commit 4307432
Showing
15 changed files
with
658 additions
and
80 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 |
---|---|---|
|
@@ -4,5 +4,8 @@ | |
"sourceRoot": "src", | ||
"compilerOptions": { | ||
"deleteOutDir": true | ||
}, | ||
"generateOptions": { | ||
"spec": false | ||
} | ||
} |
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 |
---|---|---|
@@ -1,12 +1,17 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; | ||
|
||
import { AppController } from './app.controller'; | ||
import { AppService } from './app.service'; | ||
import { ConfigurationModule } from './libs/config/config.module'; | ||
import { HttpLoggerMiddleware } from './libs/logging/http-logger.middleware'; | ||
|
||
@Module({ | ||
imports: [ConfigurationModule], | ||
controllers: [AppController], | ||
providers: [AppService], | ||
}) | ||
export class AppModule {} | ||
export class AppModule implements NestModule { | ||
configure(consumer: MiddlewareConsumer) { | ||
consumer.apply(HttpLoggerMiddleware).forRoutes('*'); | ||
} | ||
} |
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,12 @@ | ||
import { CreateDateColumn, DeleteDateColumn, PrimaryGeneratedColumn } from 'typeorm'; | ||
|
||
export class CoreEntity { | ||
@PrimaryGeneratedColumn() | ||
id: number; | ||
|
||
@CreateDateColumn() | ||
createdAt: Date; | ||
|
||
@DeleteDateColumn() | ||
deletedAt: Date | null; | ||
} |
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,24 @@ | ||
import { Logger, Module } from '@nestjs/common'; | ||
import { TypeOrmModule } from '@nestjs/typeorm'; | ||
|
||
import { DataSource } from 'typeorm'; | ||
|
||
import { ConfigurationModule } from '../config/config.module'; | ||
import { options } from './typeorm.datasource'; | ||
|
||
@Module({ | ||
imports: [ | ||
TypeOrmModule.forRootAsync({ | ||
imports: [ConfigurationModule], | ||
useFactory: () => options, | ||
dataSourceFactory: async (opt) => { | ||
const logger = new Logger('DataBaseModule'); | ||
logger.log('♺ Connecting to DataBase'); | ||
const dataSource = await new DataSource(opt).initialize(); | ||
logger.log('✔ DataBase connect Success'); | ||
return dataSource; | ||
}, | ||
}), | ||
], | ||
}) | ||
export class DatabaseModule {} |
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,25 @@ | ||
import { config } from 'dotenv'; | ||
import { DataSource, DataSourceOptions } from 'typeorm'; | ||
|
||
config({ | ||
path: `.env.${process.env.NODE_ENV}`, | ||
}); | ||
|
||
export const options: DataSourceOptions = { | ||
type: 'mysql', | ||
host: process.env.DB_HOST, | ||
port: Number(process.env.DB_PORT), | ||
username: process.env.DB_USER, | ||
password: process.env.DB_PASSWORD, | ||
database: process.env.DB_NAME, | ||
synchronize: true, | ||
logging: process.env.NODE_ENV !== 'production', | ||
entities: ['dist/**/*.entity.{js,ts}'], | ||
migrations: ['dist/migrations/*{.ts,.js}'], | ||
migrationsRun: false, | ||
// authSource: 'admin', | ||
}; | ||
|
||
const AppDataSource = new DataSource(options); | ||
|
||
export default AppDataSource; |
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,49 @@ | ||
import { CallHandler, ExecutionContext, Injectable, Logger, NestInterceptor } from '@nestjs/common'; | ||
|
||
import { Request, Response } from 'express'; | ||
import { Observable, catchError, finalize, throwError } from 'rxjs'; | ||
|
||
@Injectable() | ||
export class HttpLoggerInterceptor implements NestInterceptor { | ||
logger = new Logger('HttpLogger'); | ||
|
||
intercept( | ||
context: ExecutionContext, | ||
next: CallHandler<any>, | ||
): Observable<any> | Promise<Observable<any>> { | ||
const ctx = context.switchToHttp(); | ||
const request = ctx.getRequest<Request>(); | ||
|
||
const path = request.path; | ||
const method = request.method; | ||
|
||
// Nest의 Request Lifecyle 에 따라 Middleware 레벨에서 Exception이 발생하는 경우 Interceptor 까지 요청이 도달하지 않음 | ||
// Middleware에서 Exception이 발생하더라도 요청 로그를 남기기 위해 logger.middleware.ts 에서 요청 로그는 따로 남김 | ||
// this.logger.log(`${method} ${path} <==`); | ||
|
||
let isError = false; | ||
const nextObserver = next.handle().pipe( | ||
finalize(() => { | ||
const response = ctx.getResponse<Response>(); | ||
!isError && this.logger.log(`${method} ${path} ==> ${response?.statusCode}`); | ||
}), | ||
catchError((err) => { | ||
isError = true; | ||
let message: string = err.message; | ||
if (err?.response?.message) { | ||
const errorResponseMessage = err?.response?.message; | ||
message = Array.isArray(errorResponseMessage as string[]) | ||
? errorResponseMessage.join(',') | ||
: message; | ||
// err = new BadRequestException(message); | ||
} | ||
this.logger.error( | ||
`${method} ${path} ==> ${err?.statusCode || err?.status || err?.code} ${message}`, | ||
); | ||
return throwError(() => err); | ||
}), | ||
); | ||
|
||
return nextObserver; | ||
} | ||
} |
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,20 @@ | ||
import { Injectable, Logger, NestMiddleware } from '@nestjs/common'; | ||
|
||
import { NextFunction, Request, Response } from 'express'; | ||
|
||
@Injectable() | ||
export class HttpLoggerMiddleware implements NestMiddleware { | ||
logger = new Logger('HttpLogger'); | ||
|
||
use(req: Request, res: Response, next: NextFunction) { | ||
const path = req.path; | ||
const method = req.method; | ||
|
||
// const _headers = JSON.stringify(req.headers ? req.headers : {}); | ||
const _query = JSON.stringify(req.query ? req.query : {}); | ||
const _body = JSON.stringify(req.body ? req.body : {}); | ||
|
||
this.logger.log(`${method} ${path} <== ${_body} ${_query}`); | ||
next(); | ||
} | ||
} |
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,11 +1,25 @@ | ||
import { ConfigService } from '@nestjs/config'; | ||
import { NestFactory } from '@nestjs/core'; | ||
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; | ||
|
||
import { AppModule } from './app.module'; | ||
import { HttpLoggerInterceptor } from './libs/logging/http-logger.interceptor'; | ||
|
||
async function bootstrap() { | ||
const app = await NestFactory.create(AppModule); | ||
const config = app.get(ConfigService); | ||
await app.listen(config.getOrThrow('PORT')); | ||
|
||
const config = new DocumentBuilder() | ||
.setTitle('Sound Git API') | ||
.setDescription('The sound git server API docs') | ||
.build(); | ||
const document = SwaggerModule.createDocument(app, config); | ||
SwaggerModule.setup('docs', app, document); | ||
|
||
app.useGlobalInterceptors(new HttpLoggerInterceptor()); | ||
|
||
const configService = app.get(ConfigService); | ||
|
||
await app.listen(configService.getOrThrow('PORT')); | ||
} | ||
|
||
bootstrap(); |
16 changes: 16 additions & 0 deletions
16
apps/server/src/modules/object-storage/entity/objectMeta.entity.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 |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Model } from '@sound-git/types'; | ||
import { CoreEntity } from 'src/libs/database/core.entity'; | ||
import { Column, Entity, Index } from 'typeorm'; | ||
|
||
@Entity() | ||
export class ObjectMeta extends CoreEntity implements Model.ObjectMetaInfo { | ||
@Index({ unique: true }) | ||
@Column({ nullable: false }) | ||
name: string; | ||
|
||
@Column({ nullable: false }) | ||
type: string; | ||
|
||
@Column({ nullable: false }) | ||
isPublic: boolean; | ||
} |
12 changes: 12 additions & 0 deletions
12
apps/server/src/modules/object-storage/object-storage.module.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 |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { TypeOrmModule } from '@nestjs/typeorm'; | ||
|
||
import { ObjectMeta } from './entity/objectMeta.entity'; | ||
import { ObjectStorageService } from './object-storage.service'; | ||
|
||
@Module({ | ||
imports: [TypeOrmModule.forFeature([ObjectMeta])], | ||
exports: [ObjectStorageService], | ||
providers: [ObjectStorageService], | ||
}) | ||
export class ObjectStorageModule {} |
115 changes: 115 additions & 0 deletions
115
apps/server/src/modules/object-storage/object-storage.service.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 |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { Injectable, Logger, NotFoundException } from '@nestjs/common'; | ||
import { ConfigService } from '@nestjs/config'; | ||
import { InjectRepository } from '@nestjs/typeorm'; | ||
|
||
import { Region, SimpleAuthenticationDetailsProvider } from 'oci-common'; | ||
import { ObjectStorageClient } from 'oci-objectstorage'; | ||
import { CreatePreauthenticatedRequestDetails } from 'oci-objectstorage/lib/model'; | ||
import { PutObjectRequest } from 'oci-objectstorage/lib/request'; | ||
import { Readable } from 'stream'; | ||
import { Repository } from 'typeorm'; | ||
|
||
import { ObjectMeta } from './entity/objectMeta.entity'; | ||
|
||
@Injectable() | ||
export class ObjectStorageService { | ||
private logger = new Logger(ObjectStorageService.name); | ||
private oracleAuthProvider: SimpleAuthenticationDetailsProvider; | ||
private oracleObjectStorageClient: ObjectStorageClient; | ||
|
||
constructor( | ||
@InjectRepository(ObjectMeta) | ||
private readonly objectMetaRepository: Repository<ObjectMeta>, | ||
private readonly configService: ConfigService, | ||
) { | ||
this.oracleAuthProvider = new SimpleAuthenticationDetailsProvider( | ||
configService.getOrThrow('OCI_TENANCY'), | ||
configService.getOrThrow('OCI_USER'), | ||
configService.getOrThrow('OCI_FINGERPRINT'), | ||
configService.getOrThrow('OCI_PRIVATEKEY'), | ||
null, | ||
Region.fromRegionId(configService.getOrThrow('OCI_REGION')), | ||
); | ||
|
||
this.oracleObjectStorageClient = new ObjectStorageClient({ | ||
authenticationDetailsProvider: this.oracleAuthProvider, | ||
}); | ||
} | ||
|
||
async findObjectMetaById(id: number) { | ||
return this.objectMetaRepository.findOneBy({ id }); | ||
} | ||
|
||
async findObjectMetaByName(name: string) { | ||
return this.objectMetaRepository.findOneBy({ name }); | ||
} | ||
|
||
async save(dataStream: Readable, name: string, type: string, isPublic = false) { | ||
const bucketName = this.configService.getOrThrow( | ||
isPublic ? 'OCI_STORAGE_PUBLIC_BUCKET' : 'OCI_STORAGE_PRIVATE_BUCKET', | ||
); | ||
|
||
const putObjectRequest: PutObjectRequest = { | ||
namespaceName: this.configService.getOrThrow('OCI_STORAGE_NAMESPACE'), | ||
bucketName, | ||
objectName: name, | ||
contentType: type, | ||
putObjectBody: dataStream, | ||
}; | ||
const putObjectResponse = await this.oracleObjectStorageClient.putObject(putObjectRequest); | ||
this.logger.debug('put finish', putObjectResponse); | ||
|
||
const existObject = await this.findObjectMetaByName(name); | ||
if (existObject) { | ||
const mergedObjcet = this.objectMetaRepository.merge(existObject, { | ||
name, | ||
type, | ||
isPublic, | ||
}); | ||
return this.objectMetaRepository.save(mergedObjcet); | ||
} | ||
|
||
const object = this.objectMetaRepository.create({ name, type, isPublic }); | ||
return this.objectMetaRepository.save(object); | ||
} | ||
|
||
async getObjectUrl(name: string, expiresInSec = 60) { | ||
const objectMeta = await this.findObjectMetaByName(name); | ||
if (!objectMeta) throw new NotFoundException('object를 찾을 수 없습니다.'); | ||
|
||
const bucketName = this.configService.getOrThrow( | ||
objectMeta.isPublic ? 'OCI_STORAGE_PUBLIC_BUCKET' : 'OCI_STORAGE_PRIVATE_BUCKET', | ||
); | ||
const preAuthedUrl = await this.createPreAuthedUrl(name, bucketName, expiresInSec); | ||
|
||
return preAuthedUrl; | ||
} | ||
|
||
private async createPreAuthedUrl(name: string, bucketName: string, expiresInSec: number) { | ||
// const objectMeta = await this.objectMetaRepository.findOneBy({ name }); | ||
|
||
const expires = new Date(Date.now() + expiresInSec * 1000); | ||
const uniqueRequestId = Date.now(); | ||
const createPreauthedRequest = | ||
await this.oracleObjectStorageClient.createPreauthenticatedRequest({ | ||
createPreauthenticatedRequestDetails: { | ||
name: uniqueRequestId.toString(), | ||
objectName: name, | ||
accessType: CreatePreauthenticatedRequestDetails.AccessType.ObjectRead, | ||
timeExpires: expires, | ||
}, | ||
bucketName, | ||
namespaceName: this.configService.getOrThrow('OCI_STORAGE_NAMESPACE'), | ||
}); | ||
|
||
const baseUrl = | ||
'https://' + | ||
[ | ||
this.configService.getOrThrow('OCI_STORAGE_NAMESPACE'), | ||
'objectstorage', | ||
this.configService.getOrThrow('OCI_REGION'), | ||
'oci.customer-oci.com', | ||
].join('.'); | ||
return baseUrl + createPreauthedRequest.preauthenticatedRequest.accessUri; | ||
} | ||
} |
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 +1,2 @@ | ||
export * from "./user"; | ||
export * from "./object"; |
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 @@ | ||
export interface ObjectMetaInfo { | ||
id: number; | ||
name: string; | ||
type: string; | ||
isPublic: boolean; | ||
} |
Oops, something went wrong.