rlagkdud898 / AJIN star
mycoms 02-28
240228김하영 커밋
@ac81ffc7749174980fa6b71acb6bce440e31a6c1
 
package-lock.json (added)
+++ package-lock.json
This file is too big to display.
 
package.json (added)
+++ package.json
@@ -0,0 +1,32 @@
+{
+  "dependencies": {
+    "@babel/cli": "^7.22.10",
+    "@babel/core": "^7.22.10",
+    "animate.css": "^4.1.1",
+    "axios": "^1.4.0",
+    "babel-loader": "^9.1.3",
+    "bootstrap": "^5.3.3",
+    "css-loader": "^6.8.1",
+    "express": "^4.18.2",
+    "express-http-proxy": "^1.6.3",
+    "file-loader": "^6.2.0",
+    "fs": "^0.0.1-security",
+    "new-line": "^1.1.1",
+    "vue": "^3.3.4",
+    "vue-loader": "^17.2.2",
+    "vue-router": "^4.2.4",
+    "vue-style-loader": "^4.1.3",
+    "webpack": "^5.88.2",
+    "webpack-cli": "^5.1.4"
+  },
+  "scripts": {
+    "prod": "set NODE_ENV=production&&node ./server/modules/web/Server.js",
+    "dev": "set NODE_ENV=development&&node ./server/modules/web/Server.js",
+    "windows-prod": "set NODE_ENV=production&&node ./server/modules/web/Server.js",
+    "windows-dev": "set NODE_ENV=development&&node ./server/modules/web/Server.js",
+    "linux-prod": "export NODE_ENV=production&&node ./server/modules/web/Server.js",
+    "linux-dev": "export NODE_ENV=development&&node ./server/modules/web/Server.js",
+    "webpack-build": "webpack",
+    "webpack-build-watch": "webpack --watch"
+  }
+}
 
server/modules/log/Logger.js (added)
+++ server/modules/log/Logger.js
@@ -0,0 +1,131 @@
+const { LOG_BASE_DIR, SERVICE_STATUS } = require('../../../Global');
+const fs = require('fs');
+const Queue = require('../util/Queue');
+
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : Log 생성기 모듈 입니다.
+ */
+const Logger = (function () {
+
+    /* let testInterval = setInterval(() => {
+        const date = new Date();
+        var now = `${date.getFullYear()}.${(date.getMonth()+1)}.${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}.${date.getMilliseconds()}`;
+        console.log('now :', now);
+    }, 1000) */
+
+    //로그 쓰기 전, 대기 저장소
+    const eventQueue = new Queue();
+    //로그 쓰는 중인지 아닌지 상태값
+    let isLogging = false;
+
+    /**
+     * @author : 하석형
+     * @since : 2023.08.24
+     * @dscription : Log 처리
+     */
+    const logging = (message) => {
+        const date = new Date();
+        let year = date.getFullYear();
+        let month = prefixZero((date.getMonth() + 1), 2);
+        let day = prefixZero(date.getDate(), 2);
+        let hour = prefixZero(date.getHours(), 2);
+        let minute = prefixZero(date.getMinutes(), 2);
+        let second = prefixZero(date.getSeconds(), 2);
+        let millisecond = prefixZero(date.getMilliseconds(), 3);
+
+        //로그에 쓰일 정보
+        const logMessage = {
+            message: message,
+            datetime: `${year}.${month}.${day} ${hour}:${minute}:${second}.${millisecond}`,
+            logFolderDir: `${LOG_BASE_DIR}/${year}${month}`,//log 폴더 경로
+            logFileName: `log-${year}${month}${day}.log`//log 파일명
+        }
+
+        //로그 쓰는 중이면, 대기 저장소에 등록
+        if (isLogging == true) {
+            eventQueue.push(logMessage);
+        } else {//로그 쓰는 중이 아니면, 로그 쓰는 중인 상태로 변경 후, 로그 쓰기
+            isLogging = true;
+
+            try {
+                //log 폴더 생성
+                if (!fs.existsSync(logMessage.logFolderDir)) {
+                    fs.mkdirSync(logMessage.logFolderDir, { recursive: true/*재귀적 폴더 생성*/ });
+                }
+
+                //log 파일 Full Path
+                let logFileFullPath = `${logMessage.logFolderDir}/${logMessage.logFileName}`;
+                //log 내용
+                let logContent = `[${logMessage.datetime}] ${logMessage.message}`;
+
+                //log 내용 쓰기
+                writeLogFile(logFileFullPath, logContent);
+            } catch (error) {
+                console.log('logging error : ', error);
+            } finally {
+                isLogging = false;
+            }
+        }
+    }
+
+    /**
+     * @author : 하석형
+     * @since : 2023.08.24
+     * @dscription : Log 내용 쓰기
+     */
+    const writeLogFile = (path, content) => {
+        if (SERVICE_STATUS == 'development') {
+            console.log(content);
+        }
+        
+        //파일 쓰기
+        fs.appendFileSync(path, `${content}\n`, 'utf8');
+
+        //로그 쓰기 저장소에서 로그 메세지 꺼내기
+        let logMessage = eventQueue.pop();
+        //메세지가 존재하면 => Log 내용 쓰기 (재귀 호출)
+        if (logMessage != undefined) {
+            //log 파일 Full Path
+            let logFileFullPath = `${logMessage.logFolderDir}/${logMessage.logFileName}`;
+            //log 내용
+            let logContent = `[${logMessage.datetime}] ${logMessage.message}`;
+            //Log 내용 쓰기 (재귀 호출)
+            writeLogFile(logFileFullPath, logContent);
+        } else {
+            return;
+        }
+    }
+
+    /**
+     * @author : 하석형
+     * @since : 2023.08.24
+     * @dscription : 특정 길이만큼 앞에 '0' 붙이기
+     */
+    const prefixZero = (target, length) => {
+        let zero = '';
+        let suffix = target;
+        let result = '';
+
+        if ((typeof target) === "number") {
+            suffix = target.toString();
+        }
+        if (suffix.length < length) {
+            for (i = 0; i < length - suffix.length; i++) {
+                zero += '0';
+            }
+        }
+        result = zero + suffix;
+        return result;
+    }
+
+
+    return {
+        logging: logging
+    }
+
+})();
+
+//Module Export
+module.exports = Logger;(파일 끝에 줄바꿈 문자 없음)
 
server/modules/util/Queue.js (added)
+++ server/modules/util/Queue.js
@@ -0,0 +1,32 @@
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : Queue(선입선출) 자료형 객체 입니다.
+ */
+class Queue {
+    constructor() {
+        this._arr = [];
+    }
+
+    //입력
+    push (item) {
+        this._arr.push(item);
+    }
+
+    //출력 후, 제거
+    pop () {
+        return this._arr.shift();
+    }
+
+    //출력 대기 중인 item return
+    peek () {
+        return this._arr[0];
+    }
+
+    //확인
+    showQueue () {
+        console.log('Queue : ', this._arr);
+    }
+}
+
+module.exports = Queue;(파일 끝에 줄바꿈 문자 없음)
 
server/modules/web/Server.js (added)
+++ server/modules/web/Server.js
@@ -0,0 +1,105 @@
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : Express 라이브러리 활용 HTTP Web Server 모듈입니다.
+ */
+const { BASE_DIR, PORT, API_SERVER_HOST } = require('../../../Global');
+const Logger = require('../log/Logger');//Logger(필수)
+
+const express = require('express');
+const webServer = express();
+const expressProxy = require('express-http-proxy');
+
+//파일 시스템 관련 라이브러리
+const FS = require('fs');
+//stream: 특정 자원을 Streaming 하기 위한 라이브러리 => Transform: Streaming 중인 자원의 Data에 Data 수정 및 추가를 지원해주는 객체
+const Transform = require('stream').Transform;
+//Streaming 중인 자원에 새로운 데이터를 stream 공간에 추가하기 위한 라이브러리
+const newLineStream = require('new-line');
+
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : HTTP Server start
+ */
+webServer.listen(PORT, function () {
+    Logger.logging(`★★★ Node.js를 활용한 Web Server 구동(Port:${PORT}) ★★★`);
+})
+
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : Intercepter 역할을 하는 미들웨어 기능
+ */
+webServer.use(function (request, response, next) {
+    let ip = request.headers['x-forwarded-for'] || request.socket.remoteAddress;
+    Logger.logging(`[HTTP] ${request.url} (Method: ${request.method}, IP: ${ip})`);
+    next();
+});
+
+
+
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : ROOT URL -> index.html
+ */
+webServer.get('/', function (request, response) {
+    //response.sendFile을 통한 HTTP html reponse (html내용 Streaming)
+    response.sendFile(`${BASE_DIR}/client/views/index.html`);
+})
+
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : 화면요청 URL 처리
+ */
+webServer.get('*.page', function (request, response, next) {
+    //index.html 내용을 직접 Streaming하여 Response, Streaming 중간에 내용 수정
+    //수정 내용 : URL 요청이 아닌, 브라우저에 표시된 URL만 변경하여, 해당하는 URL PATH의 Vue Component를 routing하기 위함
+    const StreamTransform = new Transform();
+    StreamTransform._transform = function (data, encoding, done) {
+        let fileContent = data.toString();
+        let replaceBeforeContent = `<script id="app-start-vue-page">const APP_USER_HTTP_REQUEST_URL = '/';</script>`;
+        let replaceAfterContent = `<script id="app-start-vue-page">const APP_USER_HTTP_REQUEST_URL = '${request.params['0']}.page';</script>`;
+        fileContent.replace(replaceBeforeContent, replaceAfterContent);
+        this.push(fileContent);
+        done();
+    }
+    //Streaming 진행
+    FS.createReadStream(`${BASE_DIR}/client/views/index.html`).pipe(newLineStream()).pipe(StreamTransform).pipe(response);
+})
+
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : REST API 서버에 데이터 요청 보내기(Proxy)
+ */
+webServer.use('*.json', expressProxy(API_SERVER_HOST, {
+    proxyReqPathResolver: function (request) {
+        //console.log('request : ', request.url, request.params[0]);
+        return `${request.params['0']}.json`;
+    }
+}));
+
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : ROOT URL, Router's, 화면요청 URL 등.. 이 외 나머지 정적 자원에 대한 처리 기능
+ */
+webServer.get('*.*', function (request, response, next) {
+    response.sendFile(`${BASE_DIR}${request.params['0']}.${request.params['1']}`);
+})
+
+/**
+ * @author : 하석형
+ * @since : 2023.08.24
+ * @dscription : Global Error Handler (*맨 마지막에 적용해야됨)
+ */
+webServer.use(function (error, request, response, next) {
+    const errorCode = !error.statusCode ? 500 : error.statusCode;
+    response.status(errorCode).send('에러가 발생하였습니다. 관리자에게 문의바랍니다.');
+    let message = `[Error:${errorCode}] ${request.url}/n ${error.stack}/n`;
+    Logger.logging(message);
+    //next();
+})(파일 끝에 줄바꿈 문자 없음)
Add a comment
List