dataController.js 6.36 KB
Newer Older
1
import fs from "fs";
2
import fetch from "node-fetch";
3
4
import { serverMSG, statusCode } from "../serverinfo";
import { pool as db, dbMSG, pool } from "../db";
5
6
7
import dotenv from "dotenv";

dotenv.config();
8

9
10
11
const OUT = "Out";
const IN = "In";

12
13
14
const OUTSIDE = "Outside";
const USERS = "Users";

15
16
17
const OUT_DATA_HEADER = "date,temp,humi,press,wind_speed\n";
const IN_DATA_HEADER = "date,temp,humi,lights\n";

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 데이터 수집 기로 부터 받아온 지역 코드 세분화
const locCodeSep = (code = "") => {
  const DO = code.slice(0, 2);
  const SGG = code.slice(0, 5);
  const EMD = code;

  const loc = {
    DO: DO,
    SGG: SGG,
    EMD: EMD,
  };

  return loc;
};

// 데이터가 들어온 시간 데이터 생성
const getTimeInfo = () => {
  const cur = new Date();

  const year = cur.getFullYear();
  const month = cur.getMonth() + 1;
  const date = cur.getDate();
  const hour = cur.getHours();
  const minute = cur.getMinutes();

  const time = {
    year: year,
45
46
47
48
    month: month < 10 ? `0${month}` : month,
    date: date < 10 ? `0${date}` : date,
    hour: hour < 10 ? `0${hour}` : hour,
    minute: minute < 10 ? `0${minute}` : minute,
49
50
51
52
53
  };

  return time;
};

54
55
// Data 접근 경로 반환, DB에 존재 하지 않을 시 Update 동작
const getDataDIR = async (loc, time, type, id) => {
56
  const year = time.year;
57
58
  const month = time.month;
  const date = time.date;
59

60
61
62
63
64
65
  const select_query =
    "SELECT DATALINK" +
    " " +
    `FROM ${type === OUT ? "LOCINFO" : "USER"}` +
    " " +
    `WHERE ${type === OUT ? `CODE=${loc.EMD}` : `ID='${id}'`}`;
66

67
68
  const [row, fields] = await db.execute(select_query);

69
70
71
  let baseDIR;
  if (row.length != 0) baseDIR = row[0]["DATALINK"];
  else baseDIR = null;
72
73
74
75

  // DB에 Data 저장 경로가 존재하지 않을 시 UPDATE
  if (baseDIR === null) {
    baseDIR =
76
      "/data" +
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
      `/${loc.DO}` +
      `/${loc.SGG}` +
      `/${loc.EMD}` +
      `/${type === OUT ? OUTSIDE : USERS + "/" + id}`;

    const update_query =
      `UPDATE ${type === OUT ? "LOCINFO" : "USER"}` +
      " " +
      `SET DATALINK='${baseDIR}'` +
      " " +
      `WHERE ${type === OUT ? `CODE=${loc.EMD}` : `ID='${id}'`}`;

    db.execute(update_query);
  }

  const timeDIR = `/${year}` + `/${year}${month}` + `/${year}${month}${date}`;

94
95
96
97
98
  // 지역별 통합 데이터와 지역+날짜별 Data 저장소 경로
  const dirs = {
    base: process.env.LOCAL_SERVER_DIR + baseDIR,
    time: timeDIR,
  };
99

100
  return dirs;
101
102
};

103
// 데이터를 파일 형식으로 저장
104
const storeData = (type, time, loc, dir, data) => {
105
  const fileName = "weather.csv";
106

107
  fs.open(dir + `/${fileName}`, "a", (err, fd) => {
108
109
110
111
112
    if (err) {
      // Directory가 존재하지 않는 경우, 생성
      if (err.code === "ENOENT") {
        console.log("There is no directory.");

113
114
115
116
117
118
119
        fs.mkdirSync(dir, { recursive: true }, (err) => {
          if (err) console.log(err);
        });

        // 디렉토리를 새로 생성하는 경우 header 추가.
        const header = type == OUT ? OUT_DATA_HEADER : IN_DATA_HEADER;
        fs.appendFile(dir + `/${fileName}`, header, (err) => {
120
          if (err) console.log(err);
121
          else console.log("Create directory and record header.");
122
123
        });

124
125
126
127
128
129
130
131
132
133
        // 헤더 추가 후 데이터 추가
        fs.appendFile(dir + `/${fileName}`, data, (err) => {
          if (err) console.log(err);
          else
            console.log(
              `${time.year}/${time.month}/${time.date} ${time.hour}:${
                time.minute
              } - ${loc.EMD} ${type === OUT ? OUTSIDE : USERS} data append.`
            );
        });
134
135
136
      }
      // 그 외의 에러는 출력
      else console.log(err);
137
    }
138
139
140
141
142
143
144
145
146
147
148
149
    // 디렉토리가 존재하는 경우 실행
    else {
      fs.appendFile(dir + `/${fileName}`, data, (err) => {
        if (err) console.log(err);
        else
          console.log(
            `${time.year}/${time.month}/${time.date} ${time.hour}:${
              time.minute
            } - ${loc.EMD} ${type === OUT ? OUTSIDE : USERS} data append.`
          );
      });
    }
150
151
152
153
  });
};

// 외부 수집기로 부터 들어온 정보 처리
154
const handleOutData = async (locCode, lat, lng) => {
155
  // OpenWeatherAPI로 부터 지역의 날씨 정보획득을 위해 지역의 경도와 위도, API Key, 단위 기준 metric 전달
156
  const response = await fetch(
157
    `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lng}&appid=${process.env.OPENWEATHERMAP_API_KEY}&units=metric`
158
159
160
161
162
163
164
165
166
167
168
  );
  const json = await response.json();

  const temp = json["main"]["temp"];
  const humi = json["main"]["humidity"];
  const press = json["main"]["pressure"];
  const wind_speed = json["wind"]["speed"];

  const loc = locCodeSep(locCode);
  const time = getTimeInfo();

169
  const dirs = await getDataDIR(loc, time, OUT, OUTSIDE);
170

171
172
  // 데이터 형식 - [ 연 월 일 시 분 | 온도 | 습도 | 기압 | 풍속 ]
  const data = `${time.year}${time.month}${time.date}${time.hour}${time.minute},${temp},${humi},${press},${wind_speed}\n`;
173

174
175
  storeData(OUT, time, loc, dirs.base, data);
  storeData(OUT, time, loc, dirs.base + dirs.time, data);
176
177
178
};

// 내부 수집기로 부터 들어온 정보 처리
179
const handleInData = async (id, locCode, temp, humi, lights) => {
180
181
182
  const loc = locCodeSep(locCode);
  const time = getTimeInfo();

183
184
185
186
  const dirs = await getDataDIR(loc, time, IN, id);

  // 데이터 형식 - [ 연 월 일 시 분 | 온도 | 습도 | 광도 ]
  const data = `${time.year}${time.month}${time.date}${time.hour}${time.minute},${temp},${humi},${lights}\n`;
187

188
189
  storeData(IN, time, loc, dirs.base, data);
  storeData(IN, time, loc, dirs.base + dirs.time, data);
190
191
192
};

// 데이터 수신 처리
193
export const getDataInput = (req, res) => {
194
195
196
197
198
199
  try {
    if (req.query.type === OUT) {
      // 외부 데이터 수집기
      const {
        query: { locCode, lat, lng },
      } = req;
200

201
202
203
204
205
206
207
208
209
210
      handleOutData(locCode, lat, lng);
    } else {
      // 내부 데이터 수집기 동작
      const {
        query: { id, locCode, temp, humi, lights },
      } = req;

      handleInData(id, locCode, temp, humi, lights);
    }

211
    res.status(statusCode.ok).send(serverMSG.server_ok);
212
213
  } catch (error) {
    console.log(error);
214
    res.status(statusCode.err).send(serverMSG.server_err);
215
  }
KangMin An's avatar
KangMin An committed
216
};
217
218
219
220
221
222
223
224
225

// 사용자의 데이터 가져오기 및 예측 값 전송
export const getUserData = (req, res) => {
  const {
    params: { id },
  } = req;

  res.status(statusCode.ok).send(serverMSG.server_ok);
};