From 68b3d9a2820cac29c0453fca910ee1b3ff270a5a Mon Sep 17 00:00:00 2001 From: asn6878 Date: Tue, 7 Jan 2025 05:18:58 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=F0=9F=93=A6=20chore:=20tsyringe=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feed-crawler/package-lock.json | 17 +++++++++++++++++ feed-crawler/package.json | 1 + 2 files changed, 18 insertions(+) diff --git a/feed-crawler/package-lock.json b/feed-crawler/package-lock.json index 27cbb6d..392922d 100644 --- a/feed-crawler/package-lock.json +++ b/feed-crawler/package-lock.json @@ -12,6 +12,7 @@ "mysql2": "^3.11.3", "node-cron": "^3.0.3", "node-html-parser": "^6.1.13", + "tsyringe": "^4.8.0", "winston": "^3.16.0" }, "devDependencies": { @@ -797,6 +798,22 @@ "node": ">= 14.0.0" } }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/tsyringe": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.8.0.tgz", + "integrity": "sha512-YB1FG+axdxADa3ncEtRnQCFq/M0lALGLxSZeVNbTU8NqhOVc51nnv2CISTcvc1kyv6EGPtXVr0v6lWeDxiijOA==", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/typescript": { "version": "5.6.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", diff --git a/feed-crawler/package.json b/feed-crawler/package.json index f2b232d..61bdf9e 100644 --- a/feed-crawler/package.json +++ b/feed-crawler/package.json @@ -7,6 +7,7 @@ "mysql2": "^3.11.3", "node-cron": "^3.0.3", "node-html-parser": "^6.1.13", + "tsyringe": "^4.8.0", "winston": "^3.16.0" }, "devDependencies": { From dde5c7472ca447876e44a4957a61e77aedfc0c6a Mon Sep 17 00:00:00 2001 From: asn6878 Date: Tue, 7 Jan 2025 05:20:10 +0900 Subject: [PATCH 2/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20db=20?= =?UTF-8?q?=EC=BB=A4=EB=84=A5=EC=85=98=20=EC=9D=B8=ED=84=B0=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feed-crawler/src/types/database-connection.ts | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 feed-crawler/src/types/database-connection.ts diff --git a/feed-crawler/src/types/database-connection.ts b/feed-crawler/src/types/database-connection.ts new file mode 100644 index 0000000..02fafc9 --- /dev/null +++ b/feed-crawler/src/types/database-connection.ts @@ -0,0 +1,4 @@ +export interface DatabaseConnection { + executeQuery(query: string, params: any[]): Promise; + end(): Promise; +} \ No newline at end of file From 183e562ca1653b7f1203eab61a04dbf3d626462b Mon Sep 17 00:00:00 2001 From: asn6878 Date: Tue, 7 Jan 2025 05:20:32 +0900 Subject: [PATCH 3/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20di=20conta?= =?UTF-8?q?iner=20=EC=82=AC=EC=9A=A9=20=EC=8B=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=A0=20=EC=8B=AC=EB=B3=BC=20=EC=84=A0=EC=96=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feed-crawler/src/types/dependency-symbols.ts | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 feed-crawler/src/types/dependency-symbols.ts diff --git a/feed-crawler/src/types/dependency-symbols.ts b/feed-crawler/src/types/dependency-symbols.ts new file mode 100644 index 0000000..205b4ca --- /dev/null +++ b/feed-crawler/src/types/dependency-symbols.ts @@ -0,0 +1,5 @@ +export const DEPENDENCY_SYMBOLS = { + DatabaseConnection: Symbol.for("DatabaseConnection"), + RssRepository: Symbol.for("RssRepository"), + FeedRepository: Symbol.for("FeedRepository"), +} \ No newline at end of file From 15e486959dff1f5e2505b9c6eb5bbc18b7b6e5e3 Mon Sep 17 00:00:00 2001 From: asn6878 Date: Tue, 7 Jan 2025 05:21:25 +0900 Subject: [PATCH 4/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20=EC=BB=A8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=84=88=20=EC=83=9D=EC=84=B1=20=EB=B0=8F=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=A0=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=93=A4=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feed-crawler/src/common/mysql-access.ts | 3 ++- feed-crawler/src/container.ts | 15 +++++++++++++++ feed-crawler/src/repository/feed.repository.ts | 10 +++++++--- feed-crawler/src/repository/rss.repository.ts | 10 +++++++--- 4 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 feed-crawler/src/container.ts diff --git a/feed-crawler/src/common/mysql-access.ts b/feed-crawler/src/common/mysql-access.ts index 99fc540..86c1cd4 100644 --- a/feed-crawler/src/common/mysql-access.ts +++ b/feed-crawler/src/common/mysql-access.ts @@ -1,6 +1,7 @@ import * as mysql from "mysql2/promise"; import { CONNECTION_LIMIT } from "./constant"; import { PoolConnection } from "mysql2/promise"; +import { DatabaseConnection } from "../types/database-connection"; import logger from "./logger"; import * as dotenv from "dotenv"; @@ -8,7 +9,7 @@ dotenv.config({ path: process.env.NODE_ENV === "production" ? "feed-crawler/.env" : ".env", }); -class MySQLConnection { +class MySQLConnection implements DatabaseConnection { private pool: mysql.Pool; private nameTag: string; constructor() { diff --git a/feed-crawler/src/container.ts b/feed-crawler/src/container.ts new file mode 100644 index 0000000..58efd0e --- /dev/null +++ b/feed-crawler/src/container.ts @@ -0,0 +1,15 @@ +import { container } from "tsyringe"; +import { DatabaseConnection } from "./types/database-connection"; +import { DEPENDENCY_SYMBOLS } from "./types/dependency-symbols"; +import { mysqlConnection } from "./common/mysql-access"; +import {RssRepository} from "./repository/rss.repository"; +import {FeedRepository} from "./repository/feed.repository"; + +container.register(DEPENDENCY_SYMBOLS.DatabaseConnection, { + useValue: mysqlConnection +}); + +container.registerSingleton(DEPENDENCY_SYMBOLS.RssRepository, RssRepository); +container.registerSingleton(DEPENDENCY_SYMBOLS.FeedRepository, FeedRepository); + +export { container }; diff --git a/feed-crawler/src/repository/feed.repository.ts b/feed-crawler/src/repository/feed.repository.ts index 064c5fe..cda5d36 100644 --- a/feed-crawler/src/repository/feed.repository.ts +++ b/feed-crawler/src/repository/feed.repository.ts @@ -3,8 +3,14 @@ import logger from "../common/logger"; import { mysqlConnection } from "../common/mysql-access"; import { redisConstant } from "../common/constant"; import { redisConnection } from "../common/redis-access"; +import {inject, injectable} from "tsyringe"; +import {DEPENDENCY_SYMBOLS} from "../types/dependency-symbols"; +import {DatabaseConnection} from "../types/database-connection"; + +@injectable() +export class FeedRepository { + constructor(@inject(DEPENDENCY_SYMBOLS.DatabaseConnection) private readonly dbConnection: DatabaseConnection) {}; -class FeedRepository { public async insertFeeds(resultData: FeedDetail[]) { const query = ` INSERT INTO feed (blog_id, created_at, title, path, thumbnail) @@ -102,5 +108,3 @@ class FeedRepository { logger.info(`[Redis] 최근 게시글 캐시가 정상적으로 저장되었습니다.`); } } - -export const feedRepository = new FeedRepository(); diff --git a/feed-crawler/src/repository/rss.repository.ts b/feed-crawler/src/repository/rss.repository.ts index 683dfe2..e36fe69 100644 --- a/feed-crawler/src/repository/rss.repository.ts +++ b/feed-crawler/src/repository/rss.repository.ts @@ -1,12 +1,16 @@ import { mysqlConnection } from "../common/mysql-access"; import { RssObj } from "../common/types"; +import { DatabaseConnection } from "../types/database-connection"; +import { DEPENDENCY_SYMBOLS } from "../types/dependency-symbols"; +import { inject, injectable } from "tsyringe"; + +@injectable() +export class RssRepository { + constructor(@inject(DEPENDENCY_SYMBOLS.DatabaseConnection) private readonly dbConnection: DatabaseConnection) {}; -class RssRepository { public async selectAllRss(): Promise { const query = `SELECT id, rss_url as rssUrl, name as blogName, blog_platform as blogPlatform FROM rss_accept`; return mysqlConnection.executeQuery(query); } } - -export const rssRepository = new RssRepository(); From e1da3e15e52fba10bc53272cf10f17cc1d5fe345 Mon Sep 17 00:00:00 2001 From: asn6878 Date: Tue, 7 Jan 2025 05:22:03 +0900 Subject: [PATCH 5/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20feedCrawle?= =?UTF-8?q?r.ts=20=EC=97=90=20=EB=B3=80=EA=B2=BD=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=20=EB=B0=8F=20=EB=A9=94=EC=9D=B8=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feed-crawler/src/feed-crawler.ts | 25 ++++++++++--------------- feed-crawler/src/main.ts | 22 +++++++++++++++++----- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/feed-crawler/src/feed-crawler.ts b/feed-crawler/src/feed-crawler.ts index 75097c2..0fa53b5 100644 --- a/feed-crawler/src/feed-crawler.ts +++ b/feed-crawler/src/feed-crawler.ts @@ -1,5 +1,5 @@ -import { feedRepository } from "./repository/feed.repository"; -import { rssRepository } from "./repository/rss.repository"; +import { FeedRepository } from "./repository/feed.repository"; +import { RssRepository } from "./repository/rss.repository"; import logger from "./common/logger"; import { RssObj, FeedDetail, RawFeed } from "./common/types"; import { XMLParser } from "fast-xml-parser"; @@ -7,17 +7,14 @@ import { parse } from "node-html-parser"; import { unescape } from "html-escaper"; import { ONE_MINUTE } from "./common/constant"; -class FeedCrawler { - private rssParser: RssParser; - - constructor() { - this.rssParser = new RssParser(); - } +export class FeedCrawler { + private rssParser: RssParser = new RssParser(); + constructor(private readonly rssRepository: RssRepository, private readonly feedRepository: FeedRepository) {}; async start() { - await feedRepository.deleteRecentFeed(); + await this.feedRepository.deleteRecentFeed(); - const rssObjects = await rssRepository.selectAllRss(); + const rssObjects = await this.rssRepository.selectAllRss(); if (!rssObjects || !rssObjects.length) { logger.info("등록된 RSS가 없습니다."); @@ -33,9 +30,9 @@ class FeedCrawler { } logger.info(`총 ${newFeeds.length}개의 새로운 피드가 있습니다.`); - const insertedData = await feedRepository.insertFeeds(newFeeds); + const insertedData = await this.feedRepository.insertFeeds(newFeeds); - await feedRepository.setRecentFeedList(insertedData); + await this.feedRepository.setRecentFeedList(insertedData); } private async findNewFeeds( @@ -174,6 +171,4 @@ class RssParser { return unescape(feedTitle); } -} - -export const feedCrawler = new FeedCrawler(); +} \ No newline at end of file diff --git a/feed-crawler/src/main.ts b/feed-crawler/src/main.ts index d184605..f62f61b 100644 --- a/feed-crawler/src/main.ts +++ b/feed-crawler/src/main.ts @@ -1,16 +1,28 @@ import logger from "./common/logger.js"; -import { feedCrawler } from "./feed-crawler.js"; -import { mysqlConnection } from "./common/mysql-access.js"; +import { FeedCrawler } from "./feed-crawler.js"; +import { container } from "./container"; +import {RssRepository} from "./repository/rss.repository"; +import {FeedRepository} from "./repository/feed.repository"; +import {DEPENDENCY_SYMBOLS} from "./types/dependency-symbols"; +import {DatabaseConnection} from "./types/database-connection"; -async function runCrawler() { +async function main() { logger.info("==========작업 시작=========="); const startTime = Date.now(); + + const rssRepository = container.resolve("RssRepository"); + const feedRepository = container.resolve("FeedRepository"); + const dbConnection = container.resolve(DEPENDENCY_SYMBOLS.DatabaseConnection); + + const feedCrawler = new FeedCrawler(rssRepository, feedRepository); await feedCrawler.start(); + const endTime = Date.now(); const executionTime = endTime - startTime; - await mysqlConnection.end(); + + await dbConnection.end(); logger.info(`실행 시간: ${executionTime / 1000}seconds`); logger.info("==========작업 완료=========="); } -runCrawler(); +main(); From 90ce05dbbc6d8c18c0bd8a8b7fcf655e3061927d Mon Sep 17 00:00:00 2001 From: asn6878 Date: Tue, 7 Jan 2025 16:37:38 +0900 Subject: [PATCH 6/8] =?UTF-8?q?=F0=9F=93=A6=20chore:=20reflect-metadata=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feed-crawler/package-lock.json | 6 ++++++ feed-crawler/package.json | 1 + feed-crawler/src/main.ts | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/feed-crawler/package-lock.json b/feed-crawler/package-lock.json index 392922d..4e14453 100644 --- a/feed-crawler/package-lock.json +++ b/feed-crawler/package-lock.json @@ -12,6 +12,7 @@ "mysql2": "^3.11.3", "node-cron": "^3.0.3", "node-html-parser": "^6.1.13", + "reflect-metadata": "^0.2.2", "tsyringe": "^4.8.0", "winston": "^3.16.0" }, @@ -705,6 +706,11 @@ "node": ">=4" } }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", diff --git a/feed-crawler/package.json b/feed-crawler/package.json index 61bdf9e..d0fb1fd 100644 --- a/feed-crawler/package.json +++ b/feed-crawler/package.json @@ -7,6 +7,7 @@ "mysql2": "^3.11.3", "node-cron": "^3.0.3", "node-html-parser": "^6.1.13", + "reflect-metadata": "^0.2.2", "tsyringe": "^4.8.0", "winston": "^3.16.0" }, diff --git a/feed-crawler/src/main.ts b/feed-crawler/src/main.ts index f62f61b..66d0386 100644 --- a/feed-crawler/src/main.ts +++ b/feed-crawler/src/main.ts @@ -1,3 +1,4 @@ +import "reflect-metadata"; import logger from "./common/logger.js"; import { FeedCrawler } from "./feed-crawler.js"; import { container } from "./container"; @@ -10,8 +11,8 @@ async function main() { logger.info("==========작업 시작=========="); const startTime = Date.now(); - const rssRepository = container.resolve("RssRepository"); - const feedRepository = container.resolve("FeedRepository"); + const rssRepository = container.resolve(DEPENDENCY_SYMBOLS.RssRepository); + const feedRepository = container.resolve(DEPENDENCY_SYMBOLS.FeedRepository); const dbConnection = container.resolve(DEPENDENCY_SYMBOLS.DatabaseConnection); const feedCrawler = new FeedCrawler(rssRepository, feedRepository); From 51e5a5419f3306c5ec4a8dc0ec06b6902335f821 Mon Sep 17 00:00:00 2001 From: asn6878 Date: Tue, 7 Jan 2025 17:09:07 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20DI=20Container=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=B0=9B=EC=95=84=EC=93=B0=EB=8F=84=EB=A1=9D=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feed-crawler/src/repository/feed.repository.ts | 3 +-- feed-crawler/src/repository/rss.repository.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/feed-crawler/src/repository/feed.repository.ts b/feed-crawler/src/repository/feed.repository.ts index cda5d36..ac385d4 100644 --- a/feed-crawler/src/repository/feed.repository.ts +++ b/feed-crawler/src/repository/feed.repository.ts @@ -1,6 +1,5 @@ import { FeedDetail } from "../common/types"; import logger from "../common/logger"; -import { mysqlConnection } from "../common/mysql-access"; import { redisConstant } from "../common/constant"; import { redisConnection } from "../common/redis-access"; import {inject, injectable} from "tsyringe"; @@ -18,7 +17,7 @@ export class FeedRepository { `; const insertPromises = resultData.map(async (feed) => { - return mysqlConnection.executeQuery(query, [ + return this.dbConnection.executeQuery(query, [ feed.blogId, feed.pubDate, feed.title, diff --git a/feed-crawler/src/repository/rss.repository.ts b/feed-crawler/src/repository/rss.repository.ts index e36fe69..53ed428 100644 --- a/feed-crawler/src/repository/rss.repository.ts +++ b/feed-crawler/src/repository/rss.repository.ts @@ -1,4 +1,3 @@ -import { mysqlConnection } from "../common/mysql-access"; import { RssObj } from "../common/types"; import { DatabaseConnection } from "../types/database-connection"; import { DEPENDENCY_SYMBOLS } from "../types/dependency-symbols"; @@ -11,6 +10,6 @@ export class RssRepository { public async selectAllRss(): Promise { const query = `SELECT id, rss_url as rssUrl, name as blogName, blog_platform as blogPlatform FROM rss_accept`; - return mysqlConnection.executeQuery(query); + return this.dbConnection.executeQuery(query, []); } } From c49990995d2cdb3c47ba17f3613add39439d73e7 Mon Sep 17 00:00:00 2001 From: asn6878 Date: Wed, 8 Jan 2025 06:24:24 +0900 Subject: [PATCH 8/8] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20mysqlConec?= =?UTF-8?q?tion=20=EC=8B=B1=EA=B8=80=ED=86=A4=20=EA=B0=9D=EC=B2=B4?= =?UTF-8?q?=EB=A1=9C=20DI=20=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- feed-crawler/src/common/mysql-access.ts | 4 +--- feed-crawler/src/container.ts | 6 ++---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/feed-crawler/src/common/mysql-access.ts b/feed-crawler/src/common/mysql-access.ts index 86c1cd4..17a70ec 100644 --- a/feed-crawler/src/common/mysql-access.ts +++ b/feed-crawler/src/common/mysql-access.ts @@ -9,7 +9,7 @@ dotenv.config({ path: process.env.NODE_ENV === "production" ? "feed-crawler/.env" : ".env", }); -class MySQLConnection implements DatabaseConnection { +export class MySQLConnection implements DatabaseConnection { private pool: mysql.Pool; private nameTag: string; constructor() { @@ -58,5 +58,3 @@ class MySQLConnection implements DatabaseConnection { await this.pool.end(); } } - -export const mysqlConnection = new MySQLConnection(); diff --git a/feed-crawler/src/container.ts b/feed-crawler/src/container.ts index 58efd0e..8e345bd 100644 --- a/feed-crawler/src/container.ts +++ b/feed-crawler/src/container.ts @@ -1,13 +1,11 @@ import { container } from "tsyringe"; import { DatabaseConnection } from "./types/database-connection"; import { DEPENDENCY_SYMBOLS } from "./types/dependency-symbols"; -import { mysqlConnection } from "./common/mysql-access"; +import {MySQLConnection} from "./common/mysql-access"; import {RssRepository} from "./repository/rss.repository"; import {FeedRepository} from "./repository/feed.repository"; -container.register(DEPENDENCY_SYMBOLS.DatabaseConnection, { - useValue: mysqlConnection -}); +container.registerSingleton(DEPENDENCY_SYMBOLS.DatabaseConnection, MySQLConnection); container.registerSingleton(DEPENDENCY_SYMBOLS.RssRepository, RssRepository); container.registerSingleton(DEPENDENCY_SYMBOLS.FeedRepository, FeedRepository);