AWS Ec2で自作のチャット
いろいろな情報を元にNode.js +Socket.io+ bootstrap で構築してみました。結構前に試してはいたのですが、アウトプットとして発信できていなかったので再度行いました。
最終的な成果は、以下で確認して下さい。めっちゃ簡単で、機能不足もありますが、チャットです。
ログインボタンを押して初めて下さい。(ブラウザがsafariだとダメでした。。。)
ここをクリック(中止してます) yos-chat
複数ブラウザか複数タブでアクセスすると、通信が双方向に走るのがわかります。
片方でのメッセージを送ると、それが送られるとか、あとは現在チャットに接続している人数も出ます。ちょこちょこっといじってみて下さい。動作してなかったら、予期せぬエラーなので、コメント欄に書いて下さい・・)
今後もどこかで随時機能追加できたらなーと思ってます。 今回やったことをまとめると以下になります。
- 環境構築
- Node.jsのinstall
- 機能追加とデザイン調整しながら試行錯誤
- サーバーサイドのJSの作成
- クライアント側のIndex.htmlの作成
- クライアント側のCSSの作成
- デザイン調整
- AWSサーバーで動かす
- サーバーへのNode.jsのインストール
- サーバーへのデプロイ
- 動作検証
- ブログ記事更新
- 参考にしたリンクの整理と文章化
機能追加とデザイン調整 実際のソース
サーバーサイドのJS
var path = require('path'); var express = require('express'); var app = express(); // 1.モジュールオブジェクトの初期化 var fs = require("fs"); var http = require("http").Server(app); app.use(express.static(path.join(__dirname, 'htdocs'))); http.listen(8000); var io = require("socket.io").listen(http); console.log("start to server"); // ユーザ管理ハッシュ var userHash = new Map(); var counter = 0; // 2.イベントの定義 io.sockets.on("connection", function (socket) { // 接続開始カスタムイベント(接続元ユーザを保存し、他ユーザへ通知) socket.on("connected", function (data) { var msg = data.name + " has joined chat "; userHash.set(socket.id, data.name); counter++; //console.log(socket.id); //console.log(userHash.get(socket.id)); io.sockets.emit("countChange",{count:counter}); io.sockets.emit("publish", {isSystemReply: true,msg: msg}); }); // メッセージ送信カスタムイベント socket.on("publish", function (data) { io.sockets.emit("publish", {msg:data.msg,name:data.name}); }); // 接続終了組み込みイベント(接続元ユーザを削除し、他ユーザへ通知) socket.on("disconnect", function () { if (userHash.get(socket.id)) { var name = userHash.get(socket.id); var msg = name + " has left"; userHash.delete(socket.id); counter--; io.sockets.emit("countChange",{count:counter}); io.sockets.emit("publish", {isSystemReply:true,msg: msg}); console.log(msg); } }); });
クライアント側のIndex.html
<!DOCTYPE html> <html lang="en"> <script src="/lib/jquery.min.js"></script> <script src="/lib/jquery-ui-1.12.1/jquery-ui.js"></script> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>YOS-CHAT</title> </head> <body> <div class="container-fluid"> <h1>YOS-CHAT <small>Even small just do it</small></h1> <div id="timer"></div> <div id="current-member-num"> <h4>Members in the chat <small id ="NoM">--</small></h4> </div> <div id="status"></div> <form class="form-inline"> <div class="form-group"> <button class= "btn" type="button" value="LogIn" id="ConnectButton"/> </div> <div class="form-group"> <input type="text" class="form-control" id="msg_input" style ="width: 30em" placeholder="write your message"> </div> <div class="form-group"> <button class= "btn" type="button" value="Send"id="sendMessage" onclick="publishMessage();">Send</> </div> </form> <div id="msg" style = "padding: 1em;"></div> <div id="dialog" title="Input your name"> <h3 class="validateTips">Please input your name</h3> <label for="name">Name </label> <input type="text" name="name" id="dialog-username" value="" class="form-control ui-widget-content ui-corner-all"> </div> </div> <script src="/socket.io/socket.io.js"></script> <script src="/chat.js"></script> <script src="/lib/bootstrap-3.3.7-dist/js/bootstrap.js"></script> <link rel="stylesheet" type="text/css" href="/chat.css"> <link rel="stylesheet" type="text/css" href="/lib/jquery-ui-1.12.1/jquery-ui.css"> <link rel="stylesheet" type="text/css" href="/lib/bootstrap-3.3.7-dist/css/bootstrap.css"> </body> </html>
クライアント側のJS/CSSの作成
//定数 var socketio; var myName; var msgArea = $("#msg"); var input = $("#msg_input"); var sendButton = $("#sendMessage"); var connectButton = $("#ConnectButton"); var textInput = $("#msg_input"); var number = $("#NoM"); var dialog = $("#dialog"); var userName = $("#dialog-username"); var requiredFields = $().add(userName); var tips = $(".validateTips"); /*ボタンを押した時の動作*/ //talk function publishMessage() { socketio.emit("publish", {msg: textInput.val(),name:myName}); textInput.val(""); } //ユーサー名入力画面を開く function openDialog(){ dialog.dialog("open"); } //login通信の開始 function login(inputUserName){ myName = inputUserName; var data = {name:myName,msg:"You are entered room as " + myName} socketio = io.connect('http://yos-blog.com:8000'); socketio.on("connected", function(name) { //do nothing }); socketio.on("publish", function(data) { addMessage(data); }); socketio.on("disconnect", function() { //do nothing }); socketio.on("countChange",function(data){ changeCounter(data); }); socketio.emit("connected", data); addMessage(data); changeComponent(true); textInput.focus(); } //logout通信の終了 function logout(){ var data = {name:myName,msg:"left this chatting"} socketio.emit("disconnect",{}); socketio.disconnect(); addMessage(data); changeComponent(false); } /*メソッド群*/ //メッセージの追加 function addMessage (data) { var msg; //Login or LogOut if(data.isSystemReply){ msg = new Date().toLocaleTimeString() + ' ' + data.msg; }else{ msg = new Date().toLocaleTimeString() + ' ' + "[" + data.name + "]" + ' ' + data.msg; } msgArea.prepend(`<div>${msg}</div>`); } //コンポーネントの切り替え function changeComponent(isConnected){ connectButton.off("click"); if(isConnected){ connectButton.on("click",logout); connectButton.text("LogOut"); }else{ connectButton.on("click",openDialog); connectButton.text("LogIn"); textInput.val(""); number.text("--") } input.prop('disabled', !isConnected); sendButton.prop('disabled', !isConnected); } function changeCounter(data){ number.text(data.count); } function initComponent(){ initDialog(); changeComponent(false); } function initDialog(){ dialog.dialog({ autoOpen: false, height: 220, width: 375, modal: true, position: { of : connectButton, at: 'center bottom', my: 'left top'}, buttons: { "Join chatting": pressJoinChat, Cancel: function() { dialog.dialog("close"); } }, close: function() { dialog.dialog("close"); } }); function pressJoinChat(){ if(checkRequiredFields()){ //temp tips.text("please input your name").addClass( "ui-state-highlight" ); setTimeout(function() { tips.removeClass( "ui-state-highlight", 2000 ); }, 1000 ); return false; } dialog.dialog("close"); login(userName.val()); } function checkRequiredFields(){ // temp requiredFields.removeClass("ui-state-error"); return userName.val() === ""; } dialog.keypress(function(e) { if (e.keyCode == $.ui.keyCode.ENTER) { pressJoinChat(); return false; } });} //key bind $(window).keypress(function(e){ if (e.keyCode == $.ui.keyCode.ENTER) { publishMessage(); return false; } }); initComponent();
AWSで動かす
今回はすでにブログのサイトがあったので、そこにつけくわえる形で対応しています。
参考にしたサイト群
メインで参考にした記事
参考Socket.ioで双方向通信チャットアプリを構築 〜 JSおくのほそ道 #005
Node.js のexpress というMVCフレームワークに気付いた時に参考にしたサイト
参考Node.jsのMVCフレームワーク「Express」の基礎知識
参考Node.js、Express.js入門
参考ExpressとSocket.IOを使ったカウンターのサンプル
途中で自分をモチベートした記事
サーバーへのNode.jsのインストール
参考Amazon Linuxに Node.js と npm を入れる
サーバーへのデプロイ
FileZillaを使ってやりました。まぁ、転送するだけですが。
アクセス権とかでファイルの転送ができなかったら、ここを参考に修正
参考チュートリアル: Amazon Linux への LAMP ウェブサーバーのインストール
突然だけど、心に響いた言葉
行動を伴わない想像は何の意味もない Imagination means nothing without doing. by Charlie Chaplin(チャーリー・チャップリン)
そう、アウトプットが大事、それでは、また。
コメント、嬉しいでしょ。それがわかってるからコメントしちゃう。
やるやるとは思っていたけど、まぢ天才だわ兄貴。
引き続き購読してるからね(^ ^)
なんか、女々しいなw