chat.js - 서버측 js파일. nodejs로 실행시킨다.
enter.ejs - 유저가 접속할 때 닉네임을 설정하도록 하는 페이지
index.ejs - 유저가 닉네임을 설정한 후 제공받게 되는 채팅 페이지
chat.js 설명
- '/'경로에서 enter.ejs페이지를 제공하고닉네임을 입력받음.
입력받으면 '/chat'경로로 POST요청이 들어오고 index.ejs를 제공함.
로컬 변수
whoIsTyping - 현재 타이핑하는 유저들의 배열
whoIsOn - 현재 접속중인 유저들의 배열
이벤트 리스닝
서버기준
.emit은 서버가 이벤트를 발생시키는 것이고
.on은 서버가 클라이언트의 이벤트를 핸들하는 것임.
- 목록
io.on('connection', function(socket){ ... })
socket.emit('selfData', {nickName:nickName}); - 유저에게 자신의 닉네임이 담긴 정보를 제공
io.emit('login', whoIsOn); - 모든 유저에게 현재접속자들의 배열을 인자로하는 이벤트 발생
socket.on('setNickName', function(nickName){ ... }) - 누군가 닉네임을 바꿨을 때
io.emit('setNickName', {past:pastNickName, current:nickName, whoIsOn:whoIsOn}); - 누군가 닉네임을 바꿨을 때 그 정보를 전송
socket.on('say', function(msg){ ... })누군가 채팅을 했을 때
socket.broadcast.emit('chat message', nickName+' : '+msg); - 누군가 채팅을 했을 때 그것을 화자 외에게 전달
socket.emit('mySaying', 'ME : '+msg); - 화자에게 내용 다시 보냄
socket.on('typing', function(){ .. }) - 누군가 타이핑을 시작했음을 의미
io.emit('typing', whoIsTyping); - 누군가 타이핑 중임을 알림
socket.on('quitTyping', function(){ ... }) - 누군가 타이핑을 그만 두었음을 의미
io.emit('endTyping'); - 아무도 타이핑하는 사람이 없을 때
socket.on('disconnect', function(){ ... }) - 누군가 접속이 끊어졌을 때
chat.js
var app = require('express')();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
var ejs=require('ejs');
var bodyParser=require('body-parser');
var nowNickName="";
app.use(bodyParser.urlencoded({
extended: true
}));
app.engine('html', ejs.renderFile);
app.get('/', function(req, res){
res.render(__dirname+'/enter.ejs');
console.log('in / GET');
});
app.get('/chat', function(req, res){
res.send('plz connect through "/"');
});
app.post('/chat', function(req,res){
console.log('in /chat POST');
nowNickName=req.body.nickName;
console.log('new user : '+nowNickName);
res.render(__dirname+'/index.ejs');
});
var whoIsTyping=[];
var whoIsOn=[];
io.on('connection', function(socket){
var nickName=nowNickName||socket.id;
whoIsOn.push(nickName);
socket.emit('selfData', {nickName:nickName});
//someone who has this nickName has logged in
//original :
//io.emit('login', nickName);
io.emit('login', whoIsOn);
//basically after login, execute refreshUsers
//io.emit('refreshUsers', whoIsOn);
if(whoIsTyping.length!=0){
io.emit('typing', whoIsTyping);
}
socket.on('setNickName', function(_nickName){
var pastNickName=nickName; //past nickname
nickName=_nickName;
if(whoIsTyping.indexOf(pastNickName)!=-1){
//if he was typing
console.log('setNickName debug1');
whoIsTyping.splice(whoIsTyping.indexOf(pastNickName),1,nickName);
io.emit('typing', whoIsTyping);
}
if(whoIsOn.indexOf(pastNickName)!=-1){
console.log('setNickName debug2');
whoIsOn.splice(whoIsOn.indexOf(pastNickName), 1, nickName);
}
io.emit('setNickName', {past:pastNickName, current:nickName, whoIsOn:whoIsOn});
console.log(socket.id+' to '+nickName);
});
socket.on('say', function(msg){
console.log('message: ' + msg);
//chat message to the others
//mySaying to the speaker
socket.broadcast.emit('chat message', nickName+' : '+msg);
socket.emit('mySaying', 'ME : '+msg);
});
socket.on('typing', function(){
if(!whoIsTyping.includes(nickName)){
whoIsTyping.push(nickName);
console.log('who is typing now');
console.log(whoIsTyping);
io.emit('typing', whoIsTyping);
}
});
socket.on('quitTyping', function(){
if(whoIsTyping.length==0){
//if it's empty
console.log('emit endTyping');
io.emit('endTyping');
}
else{
//if someone else is typing
var index=whoIsTyping.indexOf(nickName);
console.log(index);
if(index!=-1){
whoIsTyping.splice(index, 1);
if(whoIsTyping.length==0){
console.log('emit endTyping');
io.emit('endTyping');
}
else{
io.emit('typing', whoIsTyping);
console.log('emit quitTyping');
console.log('whoIsTyping after quit');
console.log(whoIsTyping);
}
}
}
});
//disconnect is in socket
socket.on('disconnect', function(){
console.log(nickName+' : DISCONNECTED');
whoIsOn.splice(whoIsOn.indexOf(nickName), 1);
io.emit('logout', {nickNameArr:whoIsOn, disconnected:nickName});
if(whoIsTyping.length==0){
//if it's empty
io.emit('endTyping');
}
else{
//if someone was typing
var index=whoIsTyping.indexOf(nickName);
if(index!=-1){
whoIsTyping.splice(index, 1);
//if no one is typing now
if(whoIsTyping.length==0){
io.emit('endTyping');
}
//if someone else is still typing
else{
io.emit('typing', whoIsTyping);
console.log('emit popTyping');
console.log(whoIsTyping);
}
}
}
});
});
http.listen(80, function(){
console.log('listening on *:80');
});
enter.ejs (enter.html 이나 마찬가지)
<html>
<head>
<title>
Entering SuChat
</title>
<style>
html, body{width:99%; height:99%}
form input { border: 0; padding: 10px; width: 40%; margin:auto; margin-right: .5%;
font-size:3rem;
background-color:gray; opacity:false}
form button { width: 12%; background: rgb(130, 224, 255); border: none; padding: 10px;
font-size:3rem;}
</style>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.min.js"></script>
</head>
<body>
<form action="chat" method="POST">
<input id='nickName' name='nickName'>
<button>
ENTER
</button>
</form>
</body>
</html>
index.ejs (index.html이나 마찬가지)
<!doctype html>
<html>
<head>
<title>chat_practice</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height:99%; font: 1rem Helvetica, Arial; font-weight:50}
form { background: #000; padding: 3px; width: 100%; position: relative;}
#nickNameForm{
}
#typeForm{
bottom:0;
}
#whoIsInBox{
overflow-y:scroll;
}
form input { border: 0; padding: 10px; width: 90%; margin-bottom:1%;
margin-right: .5%; font-size:2rem}
form button { background: rgb(130, 224, 255);
border: none; padding: 10px; font-size:2rem}
#messages { list-style-type: none; margin: 0; padding: 0; height:100%; overflow-y:scroll; position:relative;}
#messages li { padding: 5px 10px; }
#messages li:nth-child(even) { background: #eee; }
ul{
font-size:1.5rem
}
</style>
<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
//when the document is ready.
$(function () {
//about DOM
$('#m').focus();
//socket io
var socket = io();
var typingNotice=' is typing..';
var fontColor='black';
var nickName='';
var whoIsTyping=[];
$('#typeForm').submit(function(){
//submit only if it's not empty
if($('#m').val()!=""){
socket.emit('say', $('#m').val());
//say event means someone transmitted chat
$('#m').val('');
socket.emit('quitTyping')
}
return false;
});
$('#nickNameForm').submit(function(){
nickName=$('#nickName').val();
$('#nickName').attr('placeholder', 'NickName : '+nickName);
socket.emit('setNickName', nickName)
$('#nickName').val("");
$('#m').focus();
return false;
})
socket.on('selfData', function(obj){
console.log('getting initial data from server');
nickName=obj.nickName;
$('#nickName').attr('placeholder', 'NickName : '+nickName);
//set #nickNameForm placeholder
});
socket.on('setNickName', function(obj){
var past=obj.past;
var current=obj.current;
var whoIsOn=obj.whoIsOn;
var msg=`====== ${past} changed nickname to ${current} ======`;
$('#messages').append($('<li>').text(msg));
editUsers(whoIsOn);
})
socket.on('chat message', function(msg){
$('#messages').append($('<li>').text(msg));
});
socket.on('login', function(nickNameArr){
var newbie=nickNameArr[nickNameArr.length-1];
editUsers(nickNameArr);
$('#messages').append($('<li>').text('======'+newbie+" LOG IN======"));
})
socket.on('typing', function(nickNameArr){
var tempMsg="";
whoIsTyping=nickNameArr;
for(person in nickNameArr){
tempMsg+=nickNameArr[person]+', '
}
tempMsg=tempMsg.substring(0, tempMsg.length-2);
$('#m').attr('placeholder', tempMsg+typingNotice)
});
socket.on('mySaying', function(msg){
$('#messages').append($('<li>').text(msg));
});
socket.on('endTyping', function(){
console.log('endTyping');
whoIsTyping=[];
$('#m').attr('placeholder', "");
})
socket.on('logout', function(received){
var nickNameArr=received.whoIsOn;
var disconnected=received.disconnected;
$('#messages').append($('<li>').text(`====== ${disconnected} has disconnected ======`));
editUsers(nickNameArr);
})
function editUsers(nickNameArr){
$('#whoIsInBox ul').children().each((index, item)=>{
$(item).remove();
});
for(person in nickNameArr){
$('#whoIsInBox ul').append($('<li>').text(nickNameArr[person]));
}
}
$('#m').keyup(function(event){
if($('#m').val()!="" && !whoIsTyping.includes(nickName)){
socket.emit('typing');
console.log('emit typing');
}
else if($('#m').val()=="" && whoIsTyping.includes(nickName)){
socket.emit('quitTyping');
console.log('emit quitTyping');
}
});
});
</script>
</head>
<body>
<div style="height:70%">
<ul id="messages">
<li id='chatTitle' style='font-size:4rem; font-weight:bold; color:powderblue'>Socket io CHAT</li>
</ul>
</div>
<div id='whoIsInBox'>
<h1>
Who Is In Now?
</h1>
<ul id='whoIsIn'>
<li>Test In</li>
</ul>
</div>
<form action="" id='nickNameForm'>
<input id="nickName" placeholder="Plz input a nickname first!" autocomplete="off" /><button>Send</button>
</form>
<form action="" id='typeForm'>
<input id="m" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
'Node.js' 카테고리의 다른 글
nodejs request 모듈 기본 및 pipe 메소드에 대해 (0) | 2018.09.22 |
---|---|
유튜브 API 사용법 - 동영상 검색하기 (8) | 2018.08.20 |
Socket io, nodejs를 이용한 채팅 사이트 만들기 (0) | 2018.06.10 |
node js 웹 크롤링 예제 - request로 사진(웹툰 프리뷰) 수집하기 (0) | 2018.05.22 |
[카톡봇] openAPI와 카카오톡API를 이용한 버스 도착 정보 조회 (2) | 2018.04.26 |