Search Posts

Visits: 701

概要

@ITにある「Socket.IO開発時に役立つツール4選とroom、namespaceライブラリの使い方」記事を参考にAWS EC2 CloudFrontにNginxをプロキシーにしたNode.jsの実行環境でroomとnamespaceを確認する。ディレクトリ構成は次のとおり。
[変更点]
サーバープログラム名をindex.jsとし、publicディレクトリにindex.htmlとjavascriptプログラムmain.jsを置いた。

.
├── index.js
├── node_modules
│   ├── express
│   ├── socket.io
│   ├── socket.io-adapter
│   ├── socket.io-client
│   ├── socket.io-parser
...
├── package.json
└── public
    ├── index.html
    └── main.js

[変更点]
Nginx経由でアクセスするためにchatroomをlocation定義に追加した。

location ~ ^/(chat|chatroom)/(.*)$ {
    alias /your/host/public_html/$1/$2;
}

[変更点]
サーバープログラム名をindex.jsとしpackage.jsonにexpressとsocket.ioをdependenciesに追加した。

{
  "name": "socket.io-room",
  "version": "0.0.0",
  "description": "A simple chat client using socket.io",
  "main": "index.js",
  "author": "",
  "private": true,
  "license": "MIT",
  "dependencies": {
    "express": "^4.13.4",
    "socket.io": "^1.7.4"
  },
  "scripts": {
    "start": "node index.js"
  }
}

サーバープログラム

[変更点]
S04でio.of(‘/chat’)やio.of(‘/fortune’)のようにnamespaceを指定する。

var chat = io.of('/chat').on('connection', function(socket) {
...
});

S02 /public/index.htmlを表示する。
イベント名をto_serverやto_clientのように短くした。

// S01. 必要なモジュールを読み込む
var http = require('http');
var socketio = require('socket.io');
var fs = require('fs');
var port = process.env.PORT || 3000;
// S02. HTTPサーバを生成する
var server = http.createServer(function(req, res) {
  res.writeHead(200, {'Content-Type' : 'text/html'});
  res.end(fs.readFileSync(__dirname + '/public/index.html', 'utf-8'));
})
.listen(port, () => {
  console.log('Server listening at port %d', port);
});

// S03. HTTPサーバにソケットをひも付ける(WebSocket有効化)
var io = socketio.listen(server);
 
// チャット機能
// S04. connectionイベントを受信する
var chat = io.of('/chat').on('connection', function(socket) {
  var room = '';
  var name = '';

  // roomへの入室は、「socket.join(room名)」
  socket.on('join', function(data) {
    room = data.value;
    socket.join(room);
  });
  // S05. to_serverイベント・データを受信する
  socket.on('to_server', function(data) {
    // S06. to_clientイベント・データを送信する
    chat.to(room).emit('to_client', {value : data.value});
  });
  // S07. broadcastイベント・データを受信し、送信元以外に送信する
  socket.on('broadcast', function(data) {
    socket.broadcast.to(room).emit('to_client', {value : data.value});
  });
  // S08. personalイベント・データを受信し、送信元のみに送信する
  socket.on('personal', function(data) {
    var id = socket.id;
    name = data.value;
    var personalMessage = "あなたは、" + name + "さんとして入室しました。"
    chat.to(id).emit('to_client', {value : personalMessage});
  });
  // S09. dicconnectイベントを受信し、退出メッセージを送信する
  socket.on('disconnect', function() {
    if (name == '') {
      console.log("未入室のまま、どこかへ去っていきました。");
    } else {
      var endMessage = name + "さんが退出しました。"
      chat.to(room).emit('to_client', {value : endMessage});
    }
  });
});
 
// 今日の運勢機能
var fortune = io.of('/fortune').on('connection', function(socket) {
  var id = socket.id;
  // 運勢の配列からランダムで取得してアクセスしたクライアントに送信する
  var fortunes = ["大吉", "吉", "中吉", "小吉", "末吉", "凶", "大凶"];
  var selectedFortune = fortunes[Math.floor(Math.random() * fortunes.length)];
  var todaysFortune = "今日のあなたの運勢は… " + selectedFortune + " です。"
  fortune.to(id).emit('to_client', {value : todaysFortune});
});

クライアントプログラム

index.html

[変更点]
C01でsocket.ioライブラリを <script src=”https://cdn.jsdelivr.net/npm/socket.io-client@2/dist/socket.io.js”></script> に変更した。
jqueryを除外してjavascriptのみとした。
javascriptを別ファイルにして、src=”/chatroom/public/main.js”から読み込む。
roomの値をuuid(v4)の値から’-‘を除いた値に変更した。
C02. ソケットへの接続 で接続先の指定を var chat = io(‘/chat’); および var fortune = io(‘/fortune’); に変更した。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>websocket-chat</title>
<link rel="stylesheet"
    href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<!-- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> -->
<!-- C01. Socket.IOクライアントライブラリの読込み -->
<script src="https://cdn.jsdelivr.net/npm/socket.io-client@2/dist/socket.io.js"></script>
<!-- <script type="text/javascript" src="/socket.io/socket.io.js"></script> -->
</head>
<body>
<div class="container">
  <h1>WebSocket-Chat</h1>
  <form class="form-inline" onsubmit="submitForm()">
    <div class="form-group">
      <label class="roomLabel" for="rooms">部屋:</label>
      <select class="form-control" id="rooms">
        <option value="c90f7cc407c64aee91b52a99f897ff5a">部屋01</option>
        <option value="8ac69ef6a26c46c68003a028e7633cf7">部屋02</option>
      </select>
      <label class="nameLabel" for="msgForm">名前:</label>
      <input type="text" class="form-control" id="msgForm">
    </div>
    <button type="submit" class="btn btn-primary" id="sendButton">入室</button>
  </form>
  <br>

  <div id="chatLogs">
    <p>=====チャットログ=====</p>
  </div>
  <br>
  <div id="fortune">
    <p>======今日の運勢======</p>
  </div>
</div>
<script type="text/javascript" src="/chatroom/public/main.js"></script>
</script>
</body>
</html>
main.js
var chat = io('/chat');
var fortune = io('/fortune');  // C02. ソケットへの接続
var isEnter = false;
var name = '';

// C04. to_clientイベント・データを受信する
chat.on('to_client', function(data){
  appendMsg(data.value);
});
fortune.on('to_client', function(data) {
  appendFortune(data.value);
});

function appendMsg(text) {
  document.getElementById('chatLogs')
  .insertAdjacentHTML('beforeend', `<div>${text}</div>`);
}

function appendFortune(text) {
  // $("#fortune").append("<div>" + text + "</div>");
  document.getElementById('fortune')
  .insertAdjacentHTML('beforeend', `<div>${text}</div>`);
}

function submitForm() {
  var message = document.getElementById('msgForm').value;
  var selectRoom = document.getElementById('rooms').value;
  document.getElementById('msgForm').value = '';
  if (isEnter) {
    message = `[${name}]: ${message}`;
    // C03. to_serverイベント・データを送信する
    chat.emit('to_server', {value : message});
  } else {
    name = message;
    var entryMessage = name + "さんが入室しました。";
    chat.emit('join', {value : selectRoom});
    // C05. broadcastイベント・データを送信する
    chat.emit('broadcast', {value : entryMessage});
    // C06. personalイベント・データを送信する
    chat.emit('personal', {value : name});
    changeLabel();
  }
  event.preventDefault();
}

function changeLabel() {
  document.querySelector('.nameLabel').innerText = 'メッセージ:';
  document.getElementById('rooms').setAttribute('disabled',true);
  document.getElementsByTagName('button')[0].innerText = '送信';
  isEnter = true;
}