diff --git a/BE/src/common/redis/redis.domain-service.ts b/BE/src/common/redis/redis.domain-service.ts index 39fa2d5..bf29b3e 100644 --- a/BE/src/common/redis/redis.domain-service.ts +++ b/BE/src/common/redis/redis.domain-service.ts @@ -1,14 +1,19 @@ -import { Injectable, Inject } from '@nestjs/common'; +import { Injectable, Inject, OnModuleInit } from '@nestjs/common'; import Redis from 'ioredis'; @Injectable() -export class RedisDomainService { +export class RedisDomainService implements OnModuleInit { constructor( @Inject('REDIS_CLIENT') private readonly redis: Redis, @Inject('REDIS_PUBLISHER') private readonly publisher: Redis, @Inject('REDIS_SUBSCRIBER') private readonly subscriber: Redis, ) {} + async onModuleInit() { + const keys = await this.redis.keys('connections:*'); + if (keys.length > 0) await this.redis.del(keys); + } + async exists(key: string): Promise<number> { return this.redis.exists(key); } @@ -72,9 +77,9 @@ export class RedisDomainService { await this.subscriber.subscribe(channel); } - on(callback: (message: string) => void) { - this.subscriber.on('message', (message) => { - callback(message); + on(callback: (channel: string, message: string) => void) { + this.subscriber.on('message', (channel, message) => { + callback(channel, message); }); } @@ -82,11 +87,27 @@ export class RedisDomainService { return this.subscriber.unsubscribe(channel); } + async setConnection(key: string, value: number) { + return this.redis.set(`connections:${key}`, value); + } + + async getConnection(key: string): Promise<number> { + return Number(await this.redis.get(`connections:${key}`)); + } + + async delConnection(key: string) { + return this.redis.del(`connections:${key}`); + } + + async existsConnection(key: string) { + return this.redis.exists(`connections:${key}`); + } + async increment(key: string) { - return this.redis.incr(key); + return this.redis.incr(`connections:${key}`); } async decrement(key: string) { - return this.redis.decr(key); + return this.redis.decr(`connections:${key}`); } } diff --git a/BE/src/common/websocket/base-socket.domain-service.ts b/BE/src/common/websocket/base-socket.domain-service.ts index f215824..95ac62e 100644 --- a/BE/src/common/websocket/base-socket.domain-service.ts +++ b/BE/src/common/websocket/base-socket.domain-service.ts @@ -83,7 +83,7 @@ export class BaseSocketDomainService implements OnModuleInit { }, 60000); }; - this.redisDomainService.on((message) => { + this.redisDomainService.on((channel, message) => { const dataList = message.split('^'); this.socketDataHandlers.H0STCNT0(dataList); }); diff --git a/BE/src/stockSocket/stock-price-socket.service.ts b/BE/src/stockSocket/stock-price-socket.service.ts index 8897ea1..7da6b40 100644 --- a/BE/src/stockSocket/stock-price-socket.service.ts +++ b/BE/src/stockSocket/stock-price-socket.service.ts @@ -69,11 +69,11 @@ export class StockPriceSocketService extends BaseStockSocketDomainService { async subscribeByCode(trKey: string) { // 아무 서버도 한투와 구독 중이지 않을때 - if (!(await this.redisDomainService.exists(trKey))) { + if (!(await this.redisDomainService.existsConnection(trKey))) { this.baseSocketDomainService.registerCode(this.TR_ID, trKey); await this.redisDomainService.subscribe(`stock/${trKey}`); this.register.push(trKey); - await this.redisDomainService.set(trKey, 1); + await this.redisDomainService.setConnection(trKey, 1); this.connection[trKey] = 1; return; @@ -113,8 +113,8 @@ export class StockPriceSocketService extends BaseStockSocketDomainService { } // 레디스 내에서 모든 연결이 종료됐을 경우 - if ((await this.redisDomainService.get(trKey)) === 0) { - await this.redisDomainService.del(trKey); + if ((await this.redisDomainService.getConnection(trKey)) === 0) { + await this.redisDomainService.delConnection(trKey); } } } @@ -122,7 +122,7 @@ export class StockPriceSocketService extends BaseStockSocketDomainService { @Cron('*/5 * * * *') async checkConnection() { for (const trKey of this.register) { - if (!(await this.redisDomainService.exists(trKey))) { + if (!(await this.redisDomainService.existsConnection(trKey))) { this.baseSocketDomainService.unregisterCode(this.TR_ID, trKey); const idx = this.register.indexOf(trKey); if (idx) this.register.splice(idx, 1); diff --git a/FE/index.html b/FE/index.html index 8142194..f1bcca7 100644 --- a/FE/index.html +++ b/FE/index.html @@ -2,6 +2,31 @@ <html lang="en"> <head> <meta charset="UTF-8" /> + <meta + name='description' + content='실시간 주식 데이터를 활용한 모의투자 경험을 통해 주식 투자에 대해 배울 수 있는 서비스.' + /> + <meta + property='og:description' + content='실시간 주식 데이터를 활용한 모의투자 경험을 통해 주식 투자에 대해 배울 수 있는 서비스.' + /> + <meta property='og:title' content='JuGa' /> + <meta property='og:url' content='https://juga.kro.kr' /> + <meta property='og:type' content='website' /> + <meta property='og:image:type' content='image/webp' /> + <meta property='og:site_name' content='JuGa' /> + <meta property='og:image:width' content='600' /> + <meta property='og:image:height' content='640' /> + <meta + property='og:image' + content='https://juga.kro.kr/assets/logo-BUoSezEL.webp' + /> + <meta property='og:image:alt' content='JuGa Logo' /> + <meta + name='keywords' + content='JuGa, 주식, PC, 모의투자, Web Trading Simulation System' + /> + <title>JuGa</title> <link rel="icon" href="src/assets/favicon.ico" type="image/x-icon" /> <link rel="stylesheet" diff --git a/FE/src/App.tsx b/FE/src/App.tsx index d92648a..812fa45 100644 --- a/FE/src/App.tsx +++ b/FE/src/App.tsx @@ -14,7 +14,6 @@ import MyPage from 'page/MyPage'; import Rank from 'page/Rank.tsx'; import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; -import { Helmet } from 'react-helmet-async'; import { Suspense } from 'react'; import { RankingSkeleton } from './components/Rank/RankingSkeleton.tsx'; @@ -45,33 +44,6 @@ export default App; function Layout() { return ( <> - <Helmet> - <meta - name='description' - content='실시간 주식 데이터를 활용한 모의투자 경험을 통해 주식 투자에 대해 배울 수 있는 서비스.' - /> - <meta - property='og:description' - content='실시간 주식 데이터를 활용한 모의투자 경험을 통해 주식 투자에 대해 배울 수 있는 서비스.' - /> - <meta property='og:title' content='JuGa' /> - <meta property='og:url' content='https://juga.kro.kr' /> - <meta property='og:type' content='website' /> - <meta property='og:image:type' content='image/webp' /> - <meta property='og:site_name' content='JuGa' /> - <meta property='og:image:width' content='600' /> - <meta property='og:image:height' content='640' /> - <meta - property='og:image' - content='https://juga.kro.kr/assets/logo-BUoSezEL.webp' - /> - <meta property='og:image:alt' content='JuGa Logo' /> - <meta - name='keywords' - content='JuGa, 주식, PC, 모의투자, Web Trading Simulation System' - /> - <title>JuGa</title> - </Helmet> <Header /> <main className='mt-[60px] flex flex-col gap-4'> <Outlet />