const SEND_MESSAGE_ACTION = "send-message" // 채팅 메시지 const USER_JOINED_ACTION = "user-join" // 회원 접속 const USER_LEFT_ACTION = "user-left" // 회원 접속 종료 const JOIN_ROOM_ACTION = "join-room" // 방 입장 const LEAVE_ROOM_ACTION = "leave-room" // 방 퇴장 const JOIN_ROOM_PRIVATE_ACTION = "join-room-private" // 방 비밀 입장 const ROOM_JOINED_ACTION = "room-joined" // 방 입장함 const DUPLICATION_ACTION = "duplication" // 회원 중복 const CHAT_HISTORY_ACTION = "set-history" const SERVER_URL = "ws://localhost:7070"; const ChatClient = class { constructor(url) { this.url = url; } isConnected = null; socket = null; user = null; rooms = []; users = []; // 작업영역 notice = null; log = null; message = null; btnPush = null; // 글자크기 fontSize = 14; init() { if (!window.WebSocket) { this.setWarning("해당 브라우저는 채팅을 지원하지 않습니다. 최신 버전의 브라우저를 설치 후 실행 해주세요.") } else { this.isConnected = false; this.notice = document.getElementById("chatNotice"); this.log = document.getElementById("chatLog"); this.message = document.getElementById("message"); this.btnPush = document.getElementById("btnPushMessage"); this.connect(); let $this = this; this.socket.onopen = function() { console.log("[Connected]"); $this.isConnected = true; $this.btnPush.removeAttribute("disabled"); $this.message.focus(); $this.setNotice("서버와 연결 되었습니다."); $this.setEvent(); $this.emit(CHAT_HISTORY_ACTION); }; this.socket.onmessage = function (e) { let data = e.data; data = data.split(/\r?\n/); for (let i = 0; i < data.length; i++) { let msg = JSON.parse(data[i]); switch (msg.action) { case DUPLICATION_ACTION: $this.setAlert("중복접속으로 이전접속을 종료합니다."); break; case SEND_MESSAGE_ACTION: $this.setMessage(msg) break; case USER_JOINED_ACTION: $this.handleUserJoined(msg); break; case USER_LEFT_ACTION: $this.handleUserLeft(msg); break; case ROOM_JOINED_ACTION: break; case CHAT_HISTORY_ACTION: $this.handleSetHistory(msg); break; default: break; } } }; this.socket.onerror = function() { $this.setWarning("연결 요청에 실패하였습니다."); }; this.socket.onclose = function() { $this.setFailed("서버 연결이 종료되었습니다."); }; } } // 서버 소켓 연결 connect() { try { let query = "?"; // 로그인 회원 정보 if (IS_USER) { let userInfo = document.getElementById("userInfo").value.trim(); if (typeof userInfo !== "undefined") { this.user = JSON.parse(atob(userInfo, true)); query += "bearer=" + this.user.token; } }else{ query += "name=" + generateRandomString(6); } // 웹소켓 연결 this.socket = new WebSocket(this.url + query); } catch (err) { this.setFailed(err); } } // 클라이언트 기능 처리 담당 setEvent() { // 메시지 전송 document.getElementById("btnPushMessage").addEventListener("click", function (e) { this.emit(SEND_MESSAGE_ACTION, { message: this.message.value }); }.bind(this)); this.message.addEventListener("keyup", function (e) { if (e.key === "Enter" || e.keyCode === 13) { this.emit(SEND_MESSAGE_ACTION, { message: e.target.value }); e.preventDefault(); } }.bind(this)); // 새창으로 document.getElementById("btnPopupChat").addEventListener("click", function() { window.open(window.location.href, "master", "popup=1,toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=no,copyhistory=no"); }); // 청소하기 document.getElementById("btnTxtClear").addEventListener("click", function() { this.clear(); }.bind(this)); // 글자크게 document.getElementById("btnTxtPlus").addEventListener("click", function(e) { e.stopPropagation(); this.textResize(1); }.bind(this)); // 글자작게 document.getElementById("btnTxtMinus").addEventListener("click", function(e) { e.stopPropagation(); this.textResize(-1); }.bind(this)); // 새로고침 document.getElementById("btnTxtRefresh").addEventListener("click", function() { this.refresh(); }.bind(this)); } // 서버에 송신 담당 emit(name, data) { if (this.socket.readyState === 1) { this.socket.send(JSON.stringify(Object.assign({action: name}, data))); }else{ this.setFailed("통신이 불가합니다. 새로고침 후 다시 시도하세요."); } } // 송/수신 메시지 표시 setDisplay(s) { $(this.log).append(s.trim()); this.log.scrollTop = this.log.scrollHeight; this.message.value = ""; } // 일반 메시지 setMessage(s) { this.setDisplay(`${s.sender.User.Name}: ${s.message}`); } // 공지사항 setNotice(s) { this.setDisplay('

' + s + '

'); } // 경고 setAlert(s) { this.setDisplay('

' + s + '

'); } // 알림 setWarning(s) { this.setDisplay('

' + s + '

'); } // 실패 setFailed(s) { this.setDisplay('

' + s + '

'); } // 글자 크게/작게 textResize(num) { let n = Number(num); let fontSize = (Number(this.fontSize) + n); if (!(fontSize > 10 && fontSize < 23)) { return; } document.getElementById("chatLog").querySelectorAll("em").forEach(function (row) { row.style.fontSize = (fontSize + "px"); }); this.fontSize = fontSize; } // 청소하기 clear() { this.message.focus(); this.log.innerText = ""; this.setAlert("채팅방이 청소되었습니다."); } // 새로고침 refresh() { window.location.reload(); } // 이미 존재하는 회원인지 확인 userExists(user) { for (let i = 0; i < this.users.length; i++) { if (this.users[i].id == user.id) { return true; } } return false; } // 회원 입장 handleUserJoined(msg) { document.getElementById("chatUserRows").innerText = msg.message; if (!this.userExists(msg.sender)) { this.users.push(msg.sender); } } // 회원 퇴장 handleUserLeft(msg) { document.getElementById("chatUserRows").innerText = msg.message; for (let i = 0; i < this.users.length; i++) { if (this.users[i].id == msg.sender.id) { this.users.splice(i, 1); return; } } } handleSetHistory(msg) { let histories = JSON.parse(msg.message.replace("\x00", "")); if (histories.length > 0) { for (let row of histories) { this.setMessage(row); } } } } let client; window.addEventListener("DOMContentLoaded", function() { client = new ChatClient(SERVER_URL); client.init(); });