메시지 브릿지
매뉴얼 [웹] 1.4.0 기능 패치로 변경된 엔진 소스
페이지 정보
본문
<script>
/* -------------------------------------------
기본 변수
- domain : 현재 접속한 사이트 주소
- MB_ID : 로그인 아이디
- USER_IP: 사용자 IP
- myKey : 아이디가 있으면 아이디, 없으면 IP 사용
------------------------------------------- */
const domain = window.location.hostname;
const MB_ID = "아이디";
const USER_IP = "ip주소(해당 언어 참고)";
const myKey = MB_ID || USER_IP;
let ws; // 웹소켓 연결을 담는 변수 (빈 상자)
let activeUsers = new Map();
let userListString = "";
/* -------------------------------------------
WebSocket 서버 연결 경로 설정
★ 아주 중요 ★
아래 주소는 "실제로 서버로 들어가는 통로(문)" 입니다.
- wss:// → https처럼 보안 통신
- designonex.com:14147 → 서버가 대기하는 장소(문 번호)
- ?group=사이트주소 → 서버가 어느 그룹(방)에 넣을지 구분하는 정보
------------------------------------------- */
const WS_URL = 'wss://designonex.com:14147/?group=' + encodeURIComponent(domain);
let reconnectTimer = null; // 자동 재접속 타이머
let retryDelay = 1000; // 재접속 대기 시간 (1초 시작)
const maxDelay = 10000; // 재접속 최대 대기 시간 (10초)
/* -------------------------------------------
WebSocket 연결 시작
- 서버와 연결을 만들어주는 함수
- 연결 성공/메시지수신/오류/닫힘을 모두 처리함
------------------------------------------- */
function connectWebSocket() {
console.log("%c[WS] Connecting...", "color: cyan");
ws = new WebSocket(WS_URL); // ★ 여기에서 서버 "문"을 실제로 연다!
/* 연결 성공 */
ws.onopen = () => {
console.log("%c[WS] Connected", "color: lime");
retryDelay = 1000; // 재접속 딜레이 초기화
// 서버에 "나 접속했어요" 메시지 보내기
sendEvent({type: "join", mb_id: MB_ID, ip: USER_IP});
};
/* 서버에서 메시지를 보냈을 때 */
ws.onmessage = (event) => {
let data;
try {
data = JSON.parse(event.data);
} catch {
return;
}
console.log("[WS] Recv:", data);
/* 사이트 처음 열었을 때 전체 접속자 목록 받기 */
if (data.type === "init") {
activeUsers.clear();
for (const u of data.users) {
const key = u.mb_id || u.ip || Math.random();
activeUsers.set(key, u);
}
}
/* 새로운 접속 또는 사용자 정보 변경 */
else if (data.type === "join" || data.type === "update") {
const key = data.mb_id || data.ip || Math.random();
activeUsers.set(key, data);
}
/* 접속 종료 */
else if (data.type === "leave") {
const key = data.mb_id || data.ip;
activeUsers.delete(key);
}
rebuildUserString();
if (typeof updateDisplay === "function") {
updateDisplay(activeUsers, data);
}
};
/* 오류 */
ws.onerror = () => {
console.warn("%c[WS] ERROR", "color: red");
};
/* 연결이 끊어졌을 때 → 자동 재접속 예약 */
ws.onclose = () => {
console.warn("%c[WS] CLOSED", "color: orange");
scheduleReconnect();
};
}
/* -------------------------------------------
자동 재접속 스케줄러
------------------------------------------- */
function scheduleReconnect() {
if (reconnectTimer) return;
console.log(
`%c[WS] Reconnecting in ${retryDelay / 1000}s`,
"color: yellow"
);
reconnectTimer = setTimeout(() => {
reconnectTimer = null;
retryDelay = Math.min(maxDelay, retryDelay + 1000);
connectWebSocket();
}, retryDelay);
}
/* -------------------------------------------
인터넷이 다시 연결되면 즉시 재접속
------------------------------------------- */
window.addEventListener("online", () => {
console.log("%c[WS] ONLINE → immediate reconnect", "color: #4FC3F7");
if (!ws || ws.readyState !== WebSocket.OPEN) {
retryDelay = 1000;
connectWebSocket();
}
});
/* -------------------------------------------
탭/창이 다시 활성화되면 즉시 재접속
------------------------------------------- */
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
console.log("%c[WS] TAB ACTIVE", "color: #FFD740");
if (!ws || ws.readyState !== WebSocket.OPEN) {
connectWebSocket();
}
}
});
/* -------------------------------------------
서버에 메시지 보내기
------------------------------------------- */
function sendEvent(jsonData) {
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(jsonData));
}
}
/* -------------------------------------------
페이지 종료 시 안전하게 퇴장 알림
------------------------------------------- */
function gracefulDisconnect() {
const leaveData = {type: "leave", mb_id: MB_ID, ip: USER_IP};
// 1) WebSocket으로 퇴장 알림
if (ws && ws.readyState === WebSocket.OPEN) {
try {
ws.send(JSON.stringify(leaveData));
ws.close();
} catch(e) {}
}
// 2) 페이지가 닫혀도 전송 가능한 sendBeacon
try {
const blob = new Blob([JSON.stringify(leaveData)], {type: "application/json"});
navigator.sendBeacon("/ws-leave", blob);
} catch(e) {}
}
/* -------------------------------------------
페이지 종료 관련 이벤트 처리
------------------------------------------- */
window.addEventListener("beforeunload", gracefulDisconnect);
window.addEventListener("pagehide", gracefulDisconnect);
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "hidden") {
gracefulDisconnect();
}
});
/* -------------------------------------------
접속자 문자열 생성
------------------------------------------- */
function rebuildUserString() {
userListString = Array.from(activeUsers.values())
.map(u => u.mb_id || u.ip)
.join(" | ");
}
/* -------------------------------------------
페이지가 로드되면 바로 서버에 연결
------------------------------------------- */
connectWebSocket();
</script>
댓글목록
등록된 댓글이 없습니다.
