【チュートリアル】NodeJS＋SocketIOを使おう

今回はNodejs＋SocketIOの簡単なAppChatを開発しましょう！！
それぞれの技術のホームページ：
- [Nodejs](https://nodejs.org/ja/)
- [Socket.io](https://socket.io/)

#使用した技術のバージョン
Ejs：2.6.1
Express：4.16.3
Socket.io：2.1.1
Jquery：3.3.1
Nodejs：10.14.1

#Socket.io
クライアントはサーバーをアクセスする時、単一のIdが出来ます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/332720/fed80a66-c1aa-9925-e37e-d26da5d85acb.png)
**socket.io**だと、以下のfunctionは非常に大切です
*socket.on*: Clientはイベントを聞いて、データを貰います
*io.sockets.emit*: サーバーは全てのClientIdにデータを送ります
<img width="716" alt="Screen Shot 2019-01-28 at 11.32.31 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/332720/43a45057-83d2-3645-abb8-e7d2cc8483bd.png">
*socket.emit*: イベントをemitしたClientIdだけにデータを送ります
<img width="694" alt="Screen Shot 2019-01-28 at 11.30.11 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/332720/ac91f61c-9f56-ffcb-fc47-758f3953c1b2.png">
*socket.broadcast.emit*: イベントをemitしたClientId以外、全てのClientIdにデータを送ります
<img width="718" alt="Screen Shot 2019-01-28 at 11.31.00 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/332720/060e5113-1ef5-0f4b-51b2-04de3cdd7f93.png">


#プロジェクトのディレクトリ
最初は```npm init```→```npm install express ejs socket.io```をターミナルで書いてください。
その後、以下のようなディレクトリを作成しましょう！

```
.
├── public
│   ├── jquery-3.3.1.min.js
│   └── layout.css
│   └── main.js
├──  views
│   └── home.ejs
├── server.js
├── package.json
```
※ [Jqueryのホームページ](https://jquery.com/download/)でファイルをダウンロードして、publicにコピーしましょう

#コーディング
```layout.css
body {
	background-color: #e75400;
}

#wrapper {
	width: 600px;
}

#username {
	background-color: transparent;
	border: solid 1px black;
}

#left, #right {
	min-height: 30%;
}

#left {
	width: 30%;
	float: left;
	background-color: #99d88c;
}

#right {
	width: 70%;
	float: right;
	background-color: #f5f788;
	text-align: right;
}

#box-title {
	border: solid 1px black;
	padding: 5px;
	text-align: center;
	font-weight: bold;
}

#box-content {
	border: solid 1px black;
	padding: 5px;
	border-top: none;
	text-align: center;
}

#list-message {
	height: 200px;
	background-color: #fcb3f0;
	margin-bottom: 15px;
	overflow-y: scroll;
	resize: none;
}

#message {
	width: 85%;
}

#send-message {
	width: 13%;
}
```
```server.js
var express = require('express');


var app = express();

app.use(express.static('./public'));
app.set('view engine', 'ejs');
app.set('views', './views');

var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(process.env.PORT || 3000);

var arrayUser = [];

io.on('connection', function(socket) {
	console.log('Client ' + socket.id + ' connected');

	socket.on('client-send-username', function(data) {
		if(arrayUser.indexOf(data) >= 0) {
			socket.emit('server-send-fail');
		} else {
			arrayUser.push(data);
			socket.username = data;
			socket.emit('server-send-success', data);
			io.sockets.emit('server-send-array-user', arrayUser);
		}
	});

	socket.on('logout', function() {
		arrayUser.splice(arrayUser.indexOf(socket.username), 1);
		socket.broadcast.emit('server-send-array-user', arrayUser);
	});

	socket.on('user-send-message', function(data) {
		io.sockets.emit('server-send-message', {
			username: socket.username,
			message: data
		});
	});

	socket.on('user-typing-message', function() {
		socket.broadcast.emit('server-send-typing', socket.username);
	});

	socket.on('user-stop-typing-message', function() {
		socket.broadcast.emit('server-send-stop-typing', socket.username);
	})
})

app.get('/', function(req, res) {
	res.render('home');
})
```
※ 全てのsocket.ioの処理コードを**io.on**の中に入らないと、コードが動きません。

```home.ejs
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title> Demo chat app </title>
    <script type="text/javascript" src="jquery-3.3.1.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.1.1/socket.io.js"></script>
	<script type="text/javascript" src="main.js"></script>
    <link rel="stylesheet" type="text/css" href="layout.css">
</head>
<body>
	<div id="wrapper">
        <div id="login-form">
            <h3> What is your name ? </h3>
            <input type="text" id="username" name="username" >
            <input type="button" value="Register" id="register" >
        </div>
        <div id="chat-form">
            <div id="left">
                <div id="box-title">
                    Online Users
                </div>
                <div id="box-content">
                    
                </div>
            </div>
            <div id="right">
                <div id="welcome">
                    Hello <span id="current-user">  </span>
                    <input type="button" id="logout" name="" value="Logout">
                </div>
                <div id="list-message" scrollable>
                    
                </div>
                <div id="input-message">
                    <input type="text" id="message" name="" placeholder="Input message here">
                    <input type="button" id="send-message" name="" value="Send">
                </div>
            </div>
        </div>   
    </div>
</body>
</html>
```
※ main.jsでsocket.ioを使えるように、home.ejsの中ではsocket.ioのCDNリンクが必要です。

```main.js
var socket = io('http://localhost:3000');

$(document).ready(function() {
	$('#login-form').show();
	$('#chat-form').hide();

	socket.on('server-send-fail', function() {
		alert('The username is already exists !');
	});

	socket.on('server-send-success', function(data) {
		console.log(data);
		$('#current-user').html(data);
		$('#login-form').hide(2000);
		$('#chat-form').show(1000);
	});

	socket.on('server-send-array-user', function(data) {
		$('#box-content').html('');
		data.forEach(function(username) {
			$('#box-content').append('<div class="user-online"> ' + username + '</div>');
		});
	});

	socket.on('server-send-message', function(data) {
		$('#list-message').append('<div>' + data.username + ': ' + data.message + '</div>');
	});

	socket.on('server-send-typing', function(data) {
		$('#list-message').append('<div id="' + data + '">' + data + ' is typing message ... </div>');
	});

	socket.on('server-send-stop-typing', function(data) {
		$('#'+data).remove();
	});

	$('#register').click(function() {
		socket.emit('client-send-username', $('#username').val());
	});

	$('#logout').click(function() {
		socket.emit('logout');
		$('#login-form').show(1000);
		$('#chat-form').hide(2000);
	});

	$('#send-message').click(function() {
		socket.emit('user-send-message', $('#message').val());
	});

	$('#message').focus(function() {
		socket.emit('user-typing-message');
	});

	$('#message').focusout(function() {
		socket.emit('user-stop-typing-message');
	});
})
```
重大なイベント
1. client-send-username: Registerのボタンをクリックすると、イベントをemitします。
    - server-send-success: 登録した名前がない場合です
    - server-send-fail: 登録した名前がありました
2. logout: ログアウト、イベントを送ります
3. user-send-message
4. user-typing-message
5. user-stop-typing-message

#結果
以下のコマンドラインをターミナルで書きます
```node server.js
```
その後、http://localhost:3000 にアクセスすると、以下の画面が出てきます。
<img width="1440" alt="Screen Shot 2019-01-28 at 8.25.28 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/332720/6c239c0f-d764-66f3-7ed9-807be990fad9.png">
名前を入力して、Registerのボタンをクリックすると、以下のようなチャット画面を移動します。
<img width="1440" alt="Screen Shot 2019-01-28 at 8.38.46 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/332720/bbe48830-4559-01e6-13b4-ac7c6ccd6483.png">