From 16440dcc755c53f5d9a716217fd64b27ccd3ebf6 Mon Sep 17 00:00:00 2001 From: anjdydhody Date: Tue, 12 Nov 2024 19:42:46 +0900 Subject: [PATCH 1/5] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20socket=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/stock/index/stock-index.module.ts | 1 - BE/src/stock/order/stock-order.controller.ts | 8 ++-- BE/src/websocket/base-socket.service.ts | 44 +++++++++++++------ BE/src/websocket/socket.module.ts | 13 +++++- .../websocket/stock-index-socket.service.ts | 37 +++++++++------- 5 files changed, 66 insertions(+), 37 deletions(-) diff --git a/BE/src/stock/index/stock-index.module.ts b/BE/src/stock/index/stock-index.module.ts index 64e0c575..498ddd8b 100644 --- a/BE/src/stock/index/stock-index.module.ts +++ b/BE/src/stock/index/stock-index.module.ts @@ -8,6 +8,5 @@ import { SocketModule } from '../../websocket/socket.module'; imports: [KoreaInvestmentModule, SocketModule], controllers: [StockIndexController], providers: [StockIndexService], - exports: [StockIndexService], }) export class StockIndexModule {} diff --git a/BE/src/stock/order/stock-order.controller.ts b/BE/src/stock/order/stock-order.controller.ts index 82d72083..31960590 100644 --- a/BE/src/stock/order/stock-order.controller.ts +++ b/BE/src/stock/order/stock-order.controller.ts @@ -22,7 +22,7 @@ import { RequestInterface } from './interface/request.interface'; @Controller('/api/stocks/trade') @ApiTags('주식 매수/매도 API') export class StockOrderController { - constructor(private readonly stockTradeService: StockOrderService) {} + constructor(private readonly stockOrderService: StockOrderService) {} @Post('/buy') @ApiBearerAuth() @@ -39,7 +39,7 @@ export class StockOrderController { @Req() request: RequestInterface, @Body(ValidationPipe) stockOrderRequest: StockOrderRequestDto, ) { - await this.stockTradeService.buy(request.user.id, stockOrderRequest); + await this.stockOrderService.buy(request.user.id, stockOrderRequest); } @Post('/sell') @@ -57,7 +57,7 @@ export class StockOrderController { @Req() request: RequestInterface, @Body(ValidationPipe) stockOrderRequest: StockOrderRequestDto, ) { - await this.stockTradeService.sell(request.user.id, stockOrderRequest); + await this.stockOrderService.sell(request.user.id, stockOrderRequest); } @Delete('/:order_id') @@ -75,6 +75,6 @@ export class StockOrderController { @Req() request: RequestInterface, @Param('order_id') orderId: number, ) { - await this.stockTradeService.cancel(request.user.id, orderId); + await this.stockOrderService.cancel(request.user.id, orderId); } } diff --git a/BE/src/websocket/base-socket.service.ts b/BE/src/websocket/base-socket.service.ts index 9322196f..7796e669 100644 --- a/BE/src/websocket/base-socket.service.ts +++ b/BE/src/websocket/base-socket.service.ts @@ -1,17 +1,22 @@ import { WebSocket } from 'ws'; -import { Injectable, OnModuleInit } from '@nestjs/common'; +import { + Injectable, + InternalServerErrorException, + OnModuleInit, +} from '@nestjs/common'; import { SocketGateway } from './socket.gateway'; import { SocketTokenService } from './socket-token.service'; @Injectable() -export abstract class BaseSocketService implements OnModuleInit { - protected socket: WebSocket; - protected socketConnectionKey: string; +export class BaseSocketService implements OnModuleInit { + private socket: WebSocket; + private socketConnectionKey: string; + private socketOpenHandlers: (() => void | Promise)[] = []; + private socketDataHandlers: { + [key: string]: (data) => void; + } = {}; - constructor( - protected readonly socketTokenService: SocketTokenService, - protected readonly socketGateway: SocketGateway, - ) {} + constructor(private readonly socketTokenService: SocketTokenService) {} async onModuleInit() { this.socketConnectionKey = @@ -19,7 +24,13 @@ export abstract class BaseSocketService implements OnModuleInit { this.socket = new WebSocket(process.env.KOREA_INVESTMENT_SOCKET_URL); this.socket.onopen = () => { - this.handleSocketOpen(); + Promise.all( + this.socketOpenHandlers.map(async (socketOpenHandler) => { + await socketOpenHandler(); + }), + ).catch(() => { + throw new InternalServerErrorException(); + }); }; this.socket.onmessage = (event) => { @@ -30,14 +41,11 @@ export abstract class BaseSocketService implements OnModuleInit { if (data.length < 2) return; const dataList = data[3].split('^'); - this.handleSocketData(dataList); + this.socketDataHandlers[data[1]](dataList); }; } - protected abstract handleSocketOpen(): void; - protected abstract handleSocketData(dataList): void; - - protected registerCode(trId: string, trKey: string) { + registerCode(trId: string, trKey: string) { this.socket.send( JSON.stringify({ header: { @@ -55,4 +63,12 @@ export abstract class BaseSocketService implements OnModuleInit { }), ); } + + registerSocketOpenHandler(handler: () => void | Promise) { + this.socketOpenHandlers.push(handler); + } + + registerSocketDataHandler(tradeCode: string, handler: (data) => void) { + this.socketDataHandlers[tradeCode] = handler; + } } diff --git a/BE/src/websocket/socket.module.ts b/BE/src/websocket/socket.module.ts index 026ed02b..ee2ed0bc 100644 --- a/BE/src/websocket/socket.module.ts +++ b/BE/src/websocket/socket.module.ts @@ -2,11 +2,20 @@ import { Module } from '@nestjs/common'; import { StockIndexSocketService } from './stock-index-socket.service'; import { SocketGateway } from './socket.gateway'; import { SocketTokenService } from './socket-token.service'; +import { StockPriceSocketService } from './stock/price/stock-price-socket.service'; +import { StockItemModule } from '../stock/item/stock-item.module'; +import { BaseSocketService } from './base-socket.service'; @Module({ - imports: [], + imports: [StockItemModule], controllers: [], - providers: [SocketTokenService, StockIndexSocketService, SocketGateway], + providers: [ + SocketTokenService, + StockIndexSocketService, + SocketGateway, + StockPriceSocketService, + BaseSocketService, + ], exports: [SocketGateway], }) export class SocketModule {} diff --git a/BE/src/websocket/stock-index-socket.service.ts b/BE/src/websocket/stock-index-socket.service.ts index 4febad48..f6a37940 100644 --- a/BE/src/websocket/stock-index-socket.service.ts +++ b/BE/src/websocket/stock-index-socket.service.ts @@ -1,9 +1,11 @@ import { Injectable } from '@nestjs/common'; import { StockIndexValueElementDto } from '../stock/index/dto/stock-index-value-element.dto'; import { BaseSocketService } from './base-socket.service'; +import { SocketGateway } from './socket.gateway'; @Injectable() -export class StockIndexSocketService extends BaseSocketService { +export class StockIndexSocketService { + private TRADE_CODE = 'H0UPCNT0'; private STOCK_CODE = { '0001': 'KOSPI', '1001': 'KOSDAQ', @@ -11,22 +13,25 @@ export class StockIndexSocketService extends BaseSocketService { '3003': 'KSQ150', }; - protected handleSocketOpen() { - this.registerCode('H0UPCNT0', '0001'); // 코스피 - this.registerCode('H0UPCNT0', '1001'); // 코스닥 - this.registerCode('H0UPCNT0', '2001'); // 코스피200 - this.registerCode('H0UPCNT0', '3003'); // KSQ150 - } + constructor( + private readonly socketGateway: SocketGateway, + private readonly baseSocketService: BaseSocketService, + ) { + baseSocketService.registerSocketOpenHandler(() => { + this.baseSocketService.registerCode(this.TRADE_CODE, '0001'); // 코스피 + this.baseSocketService.registerCode(this.TRADE_CODE, '1001'); // 코스닥 + this.baseSocketService.registerCode(this.TRADE_CODE, '2001'); // 코스피200 + this.baseSocketService.registerCode(this.TRADE_CODE, '3003'); // KSQ150 + }); - protected handleSocketData(dataList: string[]) { - this.socketGateway.sendStockIndexValueToClient( - this.STOCK_CODE[dataList[0]], - new StockIndexValueElementDto( - dataList[2], - dataList[4], - dataList[9], - dataList[3], - ), + baseSocketService.registerSocketDataHandler( + this.TRADE_CODE, + (data: string[]) => { + this.socketGateway.sendStockIndexValueToClient( + this.STOCK_CODE[data[0]], + new StockIndexValueElementDto(data[2], data[4], data[9], data[3]), + ); + }, ); } } From 79a49020c7be31b711525d07b12fb6dd0765f0ae Mon Sep 17 00:00:00 2001 From: anjdydhody Date: Tue, 12 Nov 2024 19:50:30 +0900 Subject: [PATCH 2/5] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20chore:=20lint=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/websocket/base-socket.service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/BE/src/websocket/base-socket.service.ts b/BE/src/websocket/base-socket.service.ts index 7796e669..9c39d431 100644 --- a/BE/src/websocket/base-socket.service.ts +++ b/BE/src/websocket/base-socket.service.ts @@ -4,7 +4,6 @@ import { InternalServerErrorException, OnModuleInit, } from '@nestjs/common'; -import { SocketGateway } from './socket.gateway'; import { SocketTokenService } from './socket-token.service'; @Injectable() From df7eb3ba5103117c8b10e8c460a69bf87b25d6bc Mon Sep 17 00:00:00 2001 From: anjdydhody Date: Tue, 12 Nov 2024 19:53:19 +0900 Subject: [PATCH 3/5] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20chore:=20lint=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EB=8B=A4=EC=8B=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/websocket/socket.module.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/BE/src/websocket/socket.module.ts b/BE/src/websocket/socket.module.ts index ee2ed0bc..21bbbf2e 100644 --- a/BE/src/websocket/socket.module.ts +++ b/BE/src/websocket/socket.module.ts @@ -2,18 +2,15 @@ import { Module } from '@nestjs/common'; import { StockIndexSocketService } from './stock-index-socket.service'; import { SocketGateway } from './socket.gateway'; import { SocketTokenService } from './socket-token.service'; -import { StockPriceSocketService } from './stock/price/stock-price-socket.service'; -import { StockItemModule } from '../stock/item/stock-item.module'; import { BaseSocketService } from './base-socket.service'; @Module({ - imports: [StockItemModule], + imports: [], controllers: [], providers: [ SocketTokenService, StockIndexSocketService, SocketGateway, - StockPriceSocketService, BaseSocketService, ], exports: [SocketGateway], From 437f622460e73665e6907f5e5be029f413e68641 Mon Sep 17 00:00:00 2001 From: anjdydhody Date: Tue, 12 Nov 2024 20:11:37 +0900 Subject: [PATCH 4/5] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20chore:=20TR=5FID?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EC=88=98=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/websocket/stock-index-socket.service.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/BE/src/websocket/stock-index-socket.service.ts b/BE/src/websocket/stock-index-socket.service.ts index f6a37940..604096c6 100644 --- a/BE/src/websocket/stock-index-socket.service.ts +++ b/BE/src/websocket/stock-index-socket.service.ts @@ -5,7 +5,7 @@ import { SocketGateway } from './socket.gateway'; @Injectable() export class StockIndexSocketService { - private TRADE_CODE = 'H0UPCNT0'; + private TR_ID = 'H0UPCNT0'; private STOCK_CODE = { '0001': 'KOSPI', '1001': 'KOSDAQ', @@ -18,14 +18,14 @@ export class StockIndexSocketService { private readonly baseSocketService: BaseSocketService, ) { baseSocketService.registerSocketOpenHandler(() => { - this.baseSocketService.registerCode(this.TRADE_CODE, '0001'); // 코스피 - this.baseSocketService.registerCode(this.TRADE_CODE, '1001'); // 코스닥 - this.baseSocketService.registerCode(this.TRADE_CODE, '2001'); // 코스피200 - this.baseSocketService.registerCode(this.TRADE_CODE, '3003'); // KSQ150 + this.baseSocketService.registerCode(this.TR_ID, '0001'); // 코스피 + this.baseSocketService.registerCode(this.TR_ID, '1001'); // 코스닥 + this.baseSocketService.registerCode(this.TR_ID, '2001'); // 코스피200 + this.baseSocketService.registerCode(this.TR_ID, '3003'); // KSQ150 }); baseSocketService.registerSocketDataHandler( - this.TRADE_CODE, + this.TR_ID, (data: string[]) => { this.socketGateway.sendStockIndexValueToClient( this.STOCK_CODE[data[0]], From 890e447d38bb052cc2db2146c6813788432df6c4 Mon Sep 17 00:00:00 2001 From: anjdydhody Date: Tue, 12 Nov 2024 20:13:56 +0900 Subject: [PATCH 5/5] =?UTF-8?q?=E2=9A=99=EF=B8=8F=20chore:=20=EC=86=8C?= =?UTF-8?q?=EC=BC=93=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=84=A4=EB=AA=85=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BE/src/websocket/stock-index-socket.service.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/BE/src/websocket/stock-index-socket.service.ts b/BE/src/websocket/stock-index-socket.service.ts index 604096c6..751807f6 100644 --- a/BE/src/websocket/stock-index-socket.service.ts +++ b/BE/src/websocket/stock-index-socket.service.ts @@ -29,7 +29,12 @@ export class StockIndexSocketService { (data: string[]) => { this.socketGateway.sendStockIndexValueToClient( this.STOCK_CODE[data[0]], - new StockIndexValueElementDto(data[2], data[4], data[9], data[3]), + new StockIndexValueElementDto( + data[2], // 주가 지수 + data[4], // 전일 대비 등락 + data[9], // 전일 대비 등락률 + data[3], // 부호 + ), ); }, );