socketio.js
9.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
const db = require('./db.js');
const secret_key = require('../keys/api_option').weather_key;
const traffic_key = require('../keys/api_option').traffic_key;
const requesting = require('request');
const lat = "37.239795";
const lon = "127.083240";
const city = "1300";
const town = "1302";
const year_range = 6;
const year_start = 2012;
module.exports = (server, app) => {
const io = require('socket.io')(server, {
transports: ['websocket'] // websocket 사용시 polling 사용을 배제하고 안정적인 websocket만 사용함
});
//명시적 형 선언
let Current_Weather = {};
let Sensible_T = {};
let Heat_index = {};
let Discomport_index = {};
let Ultra_Violet_index = {};
let Traffic_Accident = {};
let Death_Factors = [];
let sending_to_client_info = {};
let client_send = {};
let client_name = "";
let client_birth ;
let Destiny;
let sql;
let info = {}
const req_API = (when, what) => {
//async await 사용하기 위하여 promise 사용
return new Promise((resolve, reject) => {
requesting.get({
// api를 요청할 주소 -- 시크릿키,위도,경도 입력
url: `https://api2.sktelecom.com/weather/${when}/${what}?appKey=${secret_key}&lat=${lat}&lon=${lon}`,
json: true
},
//api에게 응답 받았을때 실행되는 callback function
function (err, api_res, api_body) {
//err 존재시 promise reject 호출
if (err) reject(err);
// api의 response이 있을경우 promise resolve 호출
if (api_res) {
console.log("calling api");
resolve(api_body);
}
});
})
}
// 교통사고정보를 받아오는 함수
const req_traffic_API = (year) => {
//async await 사용하기 위하여 promise 사용
return new Promise((resolve, reject) => {
requesting.get({
// api를 요청할 주소 -- 시크릿키,위도,경도 입력
url: `http://taas.koroad.or.kr/data/rest/accident/death?authKey=${traffic_key}&searchYear=${year}&siDo=${city}&guGun=${town}&type=json`,
json: true
},
//api에게 응답 받았을때 실행되는 callback function
function (err, api_res, api_body) {
//err 존재시 promise reject 호출
if (err) reject(err);
// api의 response이 있을경우 promise resolve 호출
if (api_res) {
console.log("calling traffic api");
resolve(api_body);
}
});
})
}
const API_bundle = async () => {
try {
Current_Weather = await req_API("current", "minutely"); //현재날씨 (분별)
Sensible_T = await req_API("index", "wct"); //체감온도
Heat_index = await req_API("index", "heat"); //열지수
Discomport_index = await req_API("index", "th"); //불쾌지수
Ultra_Violet_index = await req_API("index", "uv"); //자외선지수
// 사용자의 생일에 따라서 다른 년도의 교통사고정보를 가져옴.
const year = year_start + (client_birth % (year_range+1));
Traffic_Accident = await req_traffic_API(year); //교통사고정보
info = {
heat: Heat_index.weather.wIndex.heatIndex[0].current.index, //열지수
sensible_temperature: Sensible_T.weather.wIndex.wctIndex[0].current.index, //체감온도
discomport: Discomport_index.weather.wIndex.thIndex[0].current.index, //불쾌지수
UV: Ultra_Violet_index.weather.wIndex.uvindex[0].day01.index, //자외선지수
windspd: Current_Weather.weather.minutely[0].wind.wspd, //바람 속도
sky: Current_Weather.weather.minutely[0].sky.code, //하늘 상태
rain: Current_Weather.weather.minutely[0].rain.last24hour, //강수량
current_temperature: Current_Weather.weather.minutely[0].temperature.tc, //현재 온도
lightning: Current_Weather.weather.minutely[0].lightning, //현재 낙뢰
warning: Current_Weather.common.alertYn, //현재 특보 유무
typhoon: Current_Weather.common.stormYn, //현재 태풍
time: Current_Weather.weather.minutely[0].timeObservation, // 불러온 시각
traffic: Traffic_Accident.totalCount, // 교통사고 발생횟수
death_factor: "", //사망요인
death_countdown: 0, //죽기까지 남은 시간(단위: 초)
death_prob: 0 //확률
}
console.log("API INFO \n", info);
console.log("Traffic count:", info.traffic);
// ------------------------------ death_prob 정의 ------------------------------
info.death_prob += info.sky.substr(5) * 1 //하늘 상태에 따라 확률 증가
if (info.lightning === 1) //낙뢰시에 확률 증가
info.death_prob += 1.5;
if (info.typhoon === "Y") //태풍시에 확률 증가
info.death_prob += 1.5;
if (info.warning === "Y") // 특보 발령시 확률 증가
info.death_prob += 1
//죽을 확률 계산(내맘대로 커스텀)
info.death_prob = (
(info.heat / 50) + (Math.abs(info.sensible_temperature - 15) / 10) + (info.discomport / 10) + (info.UV / 10)
+ info.windspd*1 + (info.rain / 10) + (Math.abs(info.current_temperature - 15) / 10) + (info.traffic / 5)
);
// ------------------------------ death_factor 정의 ------------------------------
if (info.typhoon == "Y")
Death_Factors.push("태풍에 휩쓸려 사망");
if (info.lightning == 1)
Death_Factors.push("번개에 맞아 사망");
if (info.warning == "Y")
Death_Factors.push("우박에 머리를 맞아 사망");
if (info.windspd*1 >= 2)
Death_Factors.push("애인에게 바람맞아 그 충격으로 인해 사망");
if (info.heat*1 >= 100)
Death_Factors.push("학점이 너무 낮아 화병으로 사망");
if (info.discomport*1 >= 40)
Death_Factors.push("날씨가 너무 찝찝해서 사망");
Death_Factors.push("심장마비로 사망"); //반드시 하나의 요인은 추가되어야 함
info.death_factor = Death_Factors[Math.round(Math.random()*Death_Factors.length)]; //사망요인 하나를 렌덤으로 고른다.
//이벤트 기반으로 일정 시간 간격으로 클라이언트에게 보낼 정보
client_send = {
time: info.time,
wind: info.windspd,
temperature: info.current_temperature,
rain: info.rain,
death: info.death_prob,
factor: info.death_factor,
};
function getRandom_add_prob(min, max) {
return Math.random() * (max - min) + min;
}
//심장이 크게 뛰며 확률이 증가하거나 감소 할 수 있음
Math.random() * 2 >= 1 ? client_send.death += getRandom_add_prob(0,5) : client_send.death -= getRandom_add_prob(0,5) ;
//운명의 장난으로 죽을 확률이 증가하거나 감소함
const rand = Math.floor(Math.random() * 6) * 10//생년월일 중 한자리 뽑음
Destiny=client_birth.charAt(rand)/3; //명시적 형 변환
if(Destiny==0)Destiny=1; //사용자 잘못 입력했을때 예외처리
Math.random() * 2 >= 1 ? client_send.death += Destiny : client_send.death -= Destiny ;
//만약 날이 너무 안좋아서 확률이 100을 넘긴다면 100으로 예외처리
if (client_send.death >= 100) {
client_send.death = 100;
}
console.log("client send data \n",client_send)
app.get("socket").emit("weatherInfo_minutely_send_to_client", client_send); // 클라이언트에게 정보 담아서 이벤트 발산
console.log("emit");
//db에 저장
sql = "INSERT INTO weather_info (time,wind,temperature,rain,prob,factor) VALUES (?,?,?,?,?,?)";
db.query(sql, [client_send.time, client_send.wind, client_send.temperature, client_send.rain, client_send.death, client_send.factor], (err, result) => {
if (err) console.log(err);
})
} catch (err) { //promise err or try err catch
console.log("================Error Occured !!================\n", err);
}
}
let call_interval;
const Start_Interval = (second, CALL) => {
CALL(); //처음 불러올때 한번 호출하고
call_interval = setInterval(CALL, second * 1000); //그 후에 1분마다 호출
}
io.on('connection', (socket) => { //프론트와 소켓 연결시 이벤트 루프 동작
app.set("socket", socket);
socket.on("connection", (client_data) => {
console.log("SOCKET CONNECTED");
client_name = client_data.name;
client_birth = client_data.birth;
Start_Interval(60, API_bundle); //소켓 연결후 interval 활성화하여 1분마다 API 호출
});
socket.on('disconnect', (reason) => {
console.log("disconnected");
clearInterval(call_interval); //연결 종료시 interval 해제
})
})
}