socketio.js
7.7 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
const db = require('./db.js');
const secret_key = require('./keys/api_option').key;
const requesting = require('request');
const key = require('./keys/api_map').key;
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 sending_to_client_info = {};
let client_send = {};
let client_name = "";
let client_birth ;
let Destiny;
let sql;
let city;
let county;
let village;
let info = {};
let query;
let lat;
let lon;
const req_API = (when, what) => {
//async await 사용하기 위하여 promise 사용
return new Promise((resolve, reject) => {
requesting.get({
// api를 요청할 주소 -- 시크릿키,위도,경도 입력
url: encodeURI(`https://api2.sktelecom.com/weather/${when}/${what}?version=1&lat=${lat}&lon=${lon}&appKey=${secret_key}`),
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 API_bundle = async () => {
try {
Current_Weather = await req_API("current", "minutely"); //현재날씨 (분별)
console.log(Current_Weather);
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"); //자외선지수
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, // 불러온 시각
death_prob: 0 //확률
}
console.log("API INFO \n", info);
// ------------------------------ 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)
);
//이벤트 기반으로 일정 시간 간격으로 클라이언트에게 보낼 정보
client_send = {
time: info.time,
wind: info.windspd,
temperature: info.current_temperature,
rain: info.rain,
death: info.death_prob
};
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) //생년월일 중 한자리 뽑음
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 weatherInfo (time,wind,temperature,rain,prob) VALUES (?,?,?,?,?)";
db.query(sql, [client_send.time, client_send.wind, client_send.temperature, client_send.rain, client_send.death], (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;
city = client_data.city;
county = client_data.county;
village = client_data.village;
query = city+' '+county+' '+village;
var headers = {
'Authorization': 'KakaoAK '+ key
};
var options = {
url: encodeURI('https://dapi.kakao.com/v2/local/search/address.json?query=' + query),
headers: headers,
json : true
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
lat = body.documents[0].y;
lat = lat.substring(0, 8);
lon = body.documents[0].x;
lon = lon.substring(0, 8);
}
}
requesting.get(options, callback);
Start_Interval(60, API_bundle); //소켓 연결후 interval 활성화하여 1분마다 API 호출
});
socket.on('disconnect', (reason) => {
console.log("disconnected");
clearInterval(call_interval); //연결 종료시 interval 해제
})
})
}