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