거래소 만들기
- FRONT : nunjucks를 활용한 html
- BACK : node.js활용
- SERVER : AWS server 2대 (FRONT&BACK/DEMON)
npm i express nunjucks request body-parser sequelize sequelize-cli mysql2
를 이용해 패키지들을 실행해준다.
npx sequelize init
models>index.js파일에서 fs부분을 지워준다.
config>config.json를 아래와 같이 개인 로컬 컴퓨터의 mysql의 정보로 바꿔준다. database는 mariaDB를 이용해 새로운 데이터 베이스를 만들어준다. 코인에 관련된 것이어서 평소 사용하는 coinone으로 해주었다.
views폴더를 만들어주고, 그 안에 index.html 파일을 만들어준다.
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
hello coinOne!
</body>
</html>
//server.js
const express = require('express');
const app = express();
const PORT=process.env.PORT || 3500;
const nunjucks= require('nunjucks');
const db = require('./models')
//db sequelize
db.sequelize.sync({force:true})
.then(_=>{
console.log('DB connection success')
})
.catch( err=>{
console.log(`DB disconnection ${err}`)
})
//nunjucks setting
app.set('view engine','html');
nunjucks.configure('views',{express:app});
app.get('/',(req,res)=>{
res.render('index')
})
app.listen(PORT,()=>{
console.log(`server port ${PORT}`)
})
잘 나오는 것을 확인할 수 있다.
npm i morgan
npm i -g nodemon
morgan과 nodemon을 설치해준다.
morgan
은 req.body, req.query을 찍어주어서 불필요한 console.log를 막아준다. middleware 역할을 하기에 app.use(morgan('dev'))
은 대부분의 작업 위에 써주는 편이 좋다.
nodemon
은 핫로드 기능을 가지고 있어 서버 내용을 바꾸면 서버를 껏다 키는 수고 없이 바로 서버에 변경 내용이 로드되도록 한다. 전역으로 설치해주는 편이 좋다.
nodemon
을 실행시킬 때는 nodemon server
을 터미널에 입력해주면 된다.
const express = require('express');
const app = express();
const PORT=process.env.PORT || 3500;
const nunjucks= require('nunjucks');
const db = require('./models');
const morgan = require('morgan');
//db sequelize
db.sequelize.sync({force:true})
.then(_=>{
console.log('DB connection success')
})
.catch( err=>{
console.log(`DB disconnection ${err}`)
})
app.use(morgan('dev'))
app.set('view engine','html');
nunjucks.configure('views',{express:app});
app.get('/',(req,res)=>{
res.render('index')
})
app.listen(PORT,()=>{
console.log(`server port ${PORT}`)
})
VScode의 터미널 창에node server
가 아닌 nodemon server
를 입력하면 노드몬이 실행된다.
이미 열어져있던 페이지 localhost:3500을 새로고침하면 터미널엔 다음과 같이 뜬다.
어떤 메소드로 요청으로 보냈는지 그리고 어떠한 http통신의 코드는 어떠한지 그리고 얼마만에 통신이 완료되었는지 나온다. 위의 경우는 '/'을 get method로 보냈고, 14.172ms후에 통신이 완료되었다고 나오는 것이다. 결과 코드는 304이다.
이번에는 위와 같이 주소창 뒤에 /?name=yuyu
를 써보자. 다음과 같은 결과가 나오는 것을 확인할 수 있다.
만약 노드몬이 실행이 안되다면
파워쉘에 관리자 권한으로 들어가서
views>index.html을 다음과 같이 바꾸고 수정을 해보자.
여전히 바뀌지 않는 것을 확인할 수 있다. 그리고 터미널엔 다음과 같이 나온다.
이제 server.js에서 아무것도 바꾸지 말고 그냥 저장만 해보자. 그러면 터미널에 다음과 같은 메세지가 뜬다.
그리고 이제 브라우저를 새로고침하면 반영이 된다.
하면
라고 뜬다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
페이지가 없습니다..
</body>
</html>
const express = require('express');
const app = express();
const PORT=process.env.PORT || 3500;
const nunjucks= require('nunjucks');
const db = require('./models')
const morgan = require('morgan')//middleware역할 요청이 오면 먼저 morgan이 실행됨 그래서 위에 좋재하는게 좋음
//db sequelize
db.sequelize.sync({force:true})
.then(_=>{
console.log('DB connection success')
})
.catch( err=>{
console.log(`DB disconnection ${err}`)
})
app.use(morgan('dev'))
app.set('view engine','html');
nunjucks.configure('views',{express:app});
app.get('/',(req,res)=>{
res.render('index')
})
app.use((req,res,next)=>{
console.log(`error`);
res.render('404')
})
app.listen(PORT,()=>{
console.log(`server port ${PORT}`)
})
하면 브라우저를 다시 실행해보자.
404.html이 잘 나온다.
npm i winston
위의 명령어를 터미널에 입력하여 winston을 깐다.
아래의 사이트에 들어가면 winston 패키지에 대한 정보를 얻을 수 있다.
https://www.npmjs.com/package/winston
logger.js를 만든다.
//logger.js
// const { format } = require('sequelize/types/lib/utils');
const winston = require('winston');
const logger = winston.createLogger({
level:'info',
format: winston.format.json()
})
if(!process.env.NODE_ENV !=='production'){
//개발모드일 경우
logger.add(new winston.transports.Console({format : winston.format.simple() }));
}
module.exports = logger
// NODE_ENV 환경변수를 production development를 나눠서 똑같은 코드로
위의 내용은 외우려하지 말고 그냥 저장해놨다가 쓰자.
위의 내용은 심지어 npm 사이트에도 나와있다.
server.js에 다음과 같은 문구를 추가해준다.
const logger = require('./logger')
그리고 404 에러 처리 부분 코드를 다음과 같이 바꿔준다.
app.use((req,res,next)=>{
logger.info(`hello`);
logger.error('error입니다.')
res.render('404')
})
그러면 다시 새로고침하면 페이지는 그대로 뜬다.
터미널엔 다음과 같이 뜬다.
만약 에러처리 부분 코드를 다음과 같이 바꿔주면
app.use((req,res,next)=>{
logger.info(`hello`);
logger.debug('되냐?')
logger.error('error입니다.')
res.render('404')
})
app.use((req,res,next)=>{
const error = new Error(`${req.method} ${req.url} 정보가 없습니다.`)
error.status = 404;
logger.error(error.message)
res.render('404')
})
으로 바꾸면
다음과 같이 뜬다. error.message
는 new Error
의 내용임을 알 수 있다.
log setting에 대해 더 알아보자.
이러한 형식으로 만든다.
거래소에서 DB에도 접근을 해야하고, 데몬에도 접근을 해야 한다.
데몬에 접근을 할 때는 request 메소드로, DB에 접근을 할 때는 sequlize method로 요청을 보낼 것이다.
const express = require('express');
const app = express();
const PORT=process.env.PORT || 3500;
const nunjucks= require('nunjucks');
const db = require('./models')
const morgan = require('morgan')//middleware역할 요청이 오면 먼저 morgan이 실행됨 그래서 위에 좋재하는게 좋음
const logger = require('./logger')
const router = require('./routes')
require('dotenv').config()
//db sequelize
db.sequelize.sync({force:true})
.then(_=>{
console.log('DB connection success')
})
.catch( err=>{
console.log(`DB disconnection ${err}`)
})
app.use(morgan('dev'))
app.set('view engine','html');
nunjucks.configure('views',{express:app});
app.use('/',router)
app.use((req,res,next)=>{
const error = new Error(`${req.method} ${req.url} 정보가 없습니다.`)
error.status = 404;
logger.error(error.message)
res.render('404')
})
app.listen(PORT,()=>{
console.log(`server port ${PORT}`)
})
const express=require('express');
const router= express.Router();
//거래소 관련
//api 관련
router.use('/api',require('./rpc'))
module.exports = router
이 파일은 rpc통신을 담당하는 코드를 넣은 파일이다.
const express = require('express');
const router = express.Router();
const request =require('request');
const logger= require('../logger');
require('dotenv').config()
//실제 개발할때는 리눅스에 환경변수를 넣고 하는거임. dotenv를 쓰는 것이 아니라 ㅎㅎㅎㅎ
function createbody(method,params=[]){
let obj={
jsonrpc:"1.0",
id:ID_STRING,
method,
params,
}
return JSON.stringify(obj);
}
const headers = {"Content-type":"application/json"}
const USER = process.env.RPC_USER ;
const PASS = process.env.RPC_PASSWORD;
const RPCPORT = process.env.RPC_PORT;
const url = `http://${USER}:${PASS}@127.0.0.1:${RPCPORT}`
const ID_STRING = 'penguine_coinOne'
//거래소만의 계정이 있어야함. 거래소는 코인을 많이 가지고 있어야함.
const ACCOUNT = 'Penguinecoin'
router.get('/test',(req,res)=>{
res.json({msg:'test api'})
})
router.get('/getblockcount',(req,res,next)=>{
let body=createbody('getblockcount',[])
logger.info(body)
logger.info(USER)
logger.info(PASS)
logger.info(RPCPORT)
let options = {url,method:"POST",headers,body}
const callback=(err,response,data)=>{
if(err==null && response.statusCode ==200){
const body = JSON.parse(data)
logger.info('afadsfa')
res.json(body)
}else{
logger.error('getblockcount error')
next()
}
}
request(options,callback)
})
module.exports = router;
require('dotenv').config()
를 server.js뿐만 아니라 사용되는 각 파일마다 선언해주어야지 process.env를 읽을 수 있다.
request(options,callback)
을 선언하고, options에는 rpc통신에 필요한 정보들을 객체의 형태로 전달한다. options에 들어갈 내용으로는 url, method, headers,body가 있다. 여기서 url은 rpc통신을 위한 http주소이다.
http://${USER}:${PASS}@127.0.0.1:${RPCPORT}
body 내용은 rpc통신에 들어갈 정보를 넣는다. 여기서는 jsonrpc, id, method, params등이 있다. body.method는 라이트코인의 API를 뜻한다. get,use,post같은 것이 아니라 getbalance같은 것이다.
select a.in-a.ou as price (select userid,SUM(input) as in,SUM(output) as ou FROM asset GROUP BY userid) as a
where userid='web7722'
module.exports = (sequelize,DataTypes)=>{
const Uer = sequelize.define('user',{
userid:{
type:DataTypes.STRING(50),
allowNull:false
},
userpw:{
type:DataTypes.STRING(255),
allowNull:false
},
username:{
type:DataTypes.STRING(10),
allowNull:false
}
},{
timestamps:false,
userscored:false,
paranoid:false,
modelName:'user',
tableName:'user',
charset:'utf8mb4',
collate:'utf8mb4_general_ci',
})
}
sequelize-cli로 만드는 방법도 있다.
npx sequelize-cli model:generate --name User2 --attributes userid:string userpw:string, username:string
이러한 모양으로 생성이 된다.
모양이 좀 다르긴한데 적용되는건 똑같다.
그리고
db.User = require('./user')(sequelize,Sequelize)
을 추가해준다.'use strict';
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
db.User = require('./user')(sequelize,Sequelize)
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
오늘은 기본적인 틀을 만들었다.