BlockChain> 거래소 만들기 준비1

YU YU·2021년 9월 28일
0

경일_BlockChain

목록 보기
14/24
post-thumbnail

거래소 만들기

  • FRONT : nunjucks를 활용한 html
  • BACK : node.js활용
  • SERVER : AWS server 2대 (FRONT&BACK/DEMON)

1. 기본 패키지 설정


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 파일을 만들어준다.

  • 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
    server.js파일을 만들어 기본적인 세팅을 해주고, nunjucks와 sequelize 세팅을 해준다.
//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}`)
})


잘 나오는 것을 확인할 수 있다.

1-1. nodemon, morgan

npm i morgan
npm i -g nodemon
morgan과 nodemon을 설치해준다.
morgan은 req.body, req.query을 찍어주어서 불필요한 console.log를 막아준다. middleware 역할을 하기에 app.use(morgan('dev'))은 대부분의 작업 위에 써주는 편이 좋다.

nodemon

nodemon은 핫로드 기능을 가지고 있어 서버 내용을 바꾸면 서버를 껏다 키는 수고 없이 바로 서버에 변경 내용이 로드되도록 한다. 전역으로 설치해주는 편이 좋다.
nodemon을 실행시킬 때는 nodemon server을 터미널에 입력해주면 된다.

morgan

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에서 아무것도 바꾸지 말고 그냥 저장만 해보자. 그러면 터미널에 다음과 같은 메세지가 뜬다.

그리고 이제 브라우저를 새로고침하면 반영이 된다.

페이지 에러 처리


하면
라고 뜬다.

  • views>404.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>
    페이지가 없습니다.. 
</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')
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이 잘 나온다.

1-2. winston

npm i winston
위의 명령어를 터미널에 입력하여 winston을 깐다.
아래의 사이트에 들어가면 winston 패키지에 대한 정보를 얻을 수 있다.
https://www.npmjs.com/package/winston

logger.js를 만든다.

  • 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.messagenew Error의 내용임을 알 수 있다.

log setting에 대해 더 알아보자.



2. API만들기(getblockcount)


이러한 형식으로 만든다.
거래소에서 DB에도 접근을 해야하고, 데몬에도 접근을 해야 한다.
데몬에 접근을 할 때는 request 메소드로, DB에 접근을 할 때는 sequlize method로 요청을 보낼 것이다.

2-1.server.js

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}`)
})

2-2.routes>index.js

const express=require('express');
const router= express.Router();

//거래소 관련
//api 관련
router.use('/api',require('./rpc'))


module.exports = router

2-3. .env

2-4. routes>rpc.js

이 파일은 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같은 것이다.





3. DB 스키마


3-1.스키마

3-2.쿼리문

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'


4. DB 테이블 생성하기


  • models>user.js
    models 폴더에 user.js라는 파일을 만든다.
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

이러한 모양으로 생성이 된다.
모양이 좀 다르긴한데 적용되는건 똑같다.

그리고

  • models>index.js
    user.js의 내용을 추가해주기 위해서는 models>index.js에 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;

오늘은 기본적인 틀을 만들었다.

profile
코딩 재밌어요!

0개의 댓글