【Python】AdminLTEとWebSocketでチャット機能を作ってみる その1(とりあえず版)
おはようございます。
昨日に引き続き、チャット機能の実装をしていきます。
予定通り、今回は Python の Tornado を使って
実際にメッセージのやり取りができるような仕組みを実装します。
スポンサーリンク
フォルダ構成
新規で Pythonプロジェクトを作成し、先日のサンプルを移植、処理を実装していきます。
SampleChat
│
│ Main.py
├─static
│ ├─css
│ │ │ AdminLTE.css
│ │ │ AdminLTE.min.css
│ │ │ bootstrap.min.css
│ │ │ font-awesome.min.css
│ │ │ style.css
│ │ │
│ │ └─skins
│ │ skin-blue.css
│ │ skin-blue.min.css
│ │
│ ├─img
│ │ konatsu.jpg
│ │ koume.jpg
│ │ riku.jpg
│ │ sora.jpg
│ │ umi.jpg
│ │
│ └─js
│ adminlte.min.js
│ bootstrap.min.js
│ jquery-ui.min.js
│ jquery.min.js
│ moment.min.js
│ script.js
│
└─templates
main.html
画面
メイン画面
main.html
CSSやJavascript、イメージなどのパスの指定と、微妙に修正した箇所があります。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>チャットサンプル</title>
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
<link rel="stylesheet" href="{{ static_url('css/bootstrap.min.css') }}">
<link rel="stylesheet" href="{{ static_url('css/font-awesome.min.css') }}">
<link rel="stylesheet" href="https:////maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="{{ static_url('css/AdminLTE.min.css') }}">
<link rel="stylesheet" href="{{ static_url('css/style.css') }}">
<link rel="stylesheet" href="{{ static_url('css/skins/skin-blue.min.css') }}">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
</head>
<body class="hold-transition fixed">
<section class="content container-fluid">
<div class="row">
<!-- Left col -->
<div class="col-xs-8">
<!-- /.box -->
<div class="row">
<div class="col-xs-8">
<!-- DIRECT CHAT -->
<div id="chat-panel" class="box box-warning direct-chat direct-chat-warning box-solid" style="display:none;">
<div class="box-header with-border">
<h3 class="box-title">チャットメッセージ</h3>
<div class="box-tools pull-right">
<span id="status" class="status"></span>
<span data-toggle="tooltip" title="3 New Messages" class="badge bg-yellow">3</span>
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i class="fa fa-minus"></i></button>
<button type="button" class="btn btn-box-tool" data-toggle="tooltip" title="Contacts" data-widget="chat-pane-toggle">
<i class="fa fa-comments"></i></button>
<button type="button" class="btn btn-box-tool" data-widget="remove"><i class="fa fa-times"></i></button>
</div>
</div>
<!-- /.box-header -->
<div class="box-body">
<!-- Conversations are loaded here -->
<div class="direct-chat-messages">
<!-- Message. Default to the left -->
<div class="direct-chat-msg">
<div class="direct-chat-info clearfix">
<span class="direct-chat-name pull-left">こなつ</span>
<span class="direct-chat-timestamp pull-right">2018/09/25(月) 02:00</span>
</div>
<!-- /.direct-chat-info -->
<img class="direct-chat-img" src="static/img/konatsu.jpg" alt="message user image">
<!-- /.direct-chat-img -->
<div class="direct-chat-text">
そら最近どうしてる?
</div>
<!-- /.direct-chat-text -->
</div>
<!-- /.direct-chat-msg -->
<!-- Message to the right -->
<div class="direct-chat-msg right">
<div class="direct-chat-info clearfix">
<span class="direct-chat-name pull-right">そら</span>
<span class="direct-chat-timestamp pull-left">2018/09/25(月) 02:05</span>
</div>
<!-- /.direct-chat-info -->
<img class="direct-chat-img" src="static/img/sora.jpg" alt="message user image">
<!-- /.direct-chat-img -->
<div class="direct-chat-text">
相変わらずだよ。<BR>
あいつらの面倒で手一杯でさ。
</div>
<!-- /.direct-chat-text -->
</div>
<!-- /.direct-chat-msg -->
<!-- Message. Default to the left -->
<div class="direct-chat-msg">
<div class="direct-chat-info clearfix">
<span class="direct-chat-name pull-left">こなつ</span>
<span class="direct-chat-timestamp pull-right">2018/09/25(月) 05:37</span>
</div>
<!-- /.direct-chat-info -->
<img class="direct-chat-img" src="static/img/konatsu.jpg" alt="message user image">
<!-- /.direct-chat-img -->
<div class="direct-chat-text">
一番のお兄さんだから大変ね。<BR>
私は一人で快適な暮らしを送っているわ(^^♪
</div>
<!-- /.direct-chat-text -->
</div>
<!-- /.direct-chat-msg -->
<!-- Message to the right -->
<div class="direct-chat-msg right">
<div class="direct-chat-info clearfix">
<span class="direct-chat-name pull-right">そら</span>
<span class="direct-chat-timestamp pull-left">2018/09/25(月) 06:10</span>
</div>
<!-- /.direct-chat-info -->
<img class="direct-chat-img" src="static/img/sora.jpg" alt="message user image">
<!-- /.direct-chat-img -->
<div class="direct-chat-text">
え、なにそれ自慢ですか?
</div>
<!-- /.direct-chat-text -->
</div>
<!-- /.direct-chat-msg -->
</div>
<!--/.direct-chat-messages-->
<!-- Contacts are loaded here -->
<div class="direct-chat-contacts">
<ul class="contacts-list">
<li>
<a href="#">
<img class="contacts-list-img" src="static/img/konatsu.jpg" alt="User Image">
<div class="contacts-list-info">
<span class="contacts-list-name">
こなつ
<small class="contacts-list-date pull-right">2018/09/25(月)</small>
</span>
<span class="contacts-list-msg">早く新しい家に引っ越ししたい。</span>
</div>
<!-- /.contacts-list-info -->
</a>
</li>
<li>
<a href="#">
<img class="contacts-list-img" src="static/img/umi.jpg" alt="User Image">
<div class="contacts-list-info">
<span class="contacts-list-name">
うみ
<small class="contacts-list-date pull-right">2018/09/25(月)</small>
</span>
<span class="contacts-list-msg">誰かブラッシングしてくれないかしら。</span>
</div>
<!-- /.contacts-list-info -->
</a>
</li>
<li>
<a href="#">
<img class="contacts-list-img" src="static/img/koume.jpg" alt="User Image">
<div class="contacts-list-info">
<span class="contacts-list-name">
こうめ
<small class="contacts-list-date pull-right">2018/09/24(日)</small>
</span>
<span class="contacts-list-msg">ちゅーるちゅーるちゃおちゅーるー</span>
</div>
<!-- /.contacts-list-info -->
</a>
</li>
<li>
<a href="#">
<img class="contacts-list-img" src="static/img/riku.jpg" alt="User Image">
<div class="contacts-list-info">
<span class="contacts-list-name">
りく
<small class="contacts-list-date pull-right">2018/09/12(水)</small>
</span>
<span class="contacts-list-msg">ごはんまだ?</span>
</div>
<!-- /.contacts-list-info -->
</a>
</li>
<!-- End Contact Item -->
</ul>
<!-- /.contatcts-list -->
</div>
<!-- /.direct-chat-pane -->
</div>
<!-- /.box-body -->
<div class="box-footer">
<form action="#" method="post">
<div class="input-group">
<input id="message" type="text" name="message" placeholder="Type Message ..." class="form-control">
<span class="input-group-btn">
<button id="sendButton" type="button" class="btn btn-warning btn-flat">Send</button>
</span>
</div>
</form>
</div>
<!-- /.box-footer-->
</div>
<!--/.direct-chat -->
</div>
<!-- /.col -->
</div>
<!-- /.col -->
</div>
</div>
</section>
<script src="{{ static_url('js/jquery.min.js') }}"></script>
<script src="{{ static_url('js/jquery-ui.min.js') }}"></script>
<script src="{{ static_url('js/bootstrap.min.js') }}"></script>
<script src="{{ static_url('js/adminlte.min.js') }}"></script>
<script src="{{ static_url('js/moment.min.js') }}"></script>
<script src="{{ static_url('js/script.js') }}"></script>
<script>
$(document).ready( function () {
initialize();
} );
</script>
</body>
</html>
スタイル
style.css
.form-control {
ime-mode: active;
}
#status {
font-size: 10px;
}
プログラム
Tornadoを利用しています。
利用方法は次の記事なんかを参考にしていただければ。
【Python】スマホで読み込むと Wi-Fi に繋げられるQRコードを生成してみる
サーバー側
Main.py
# --- coding: utf-8 ---
"""
チャットサンプル
"""
import os
import signal
import logging
import json
import tornado.web
import tornado.ioloop
import tornado.websocket
from tornado.options import options
from tornado.websocket import WebSocketHandler
client = []
class MainHandler(tornado.web.RequestHandler):
"""
初期表示処理
"""
def initialize(self):
logging.info("[MainHandler] initialize")
def get(self):
logging.info("[MainHandler] get")
self.render("main.html")
class ChatHandler(WebSocketHandler):
"""
チャット処理
"""
def open(self):
logging.info("[ChatHandler] open")
if self not in client:
client.append(self)
def on_message(self, message):
logging.info("[ChatHandler] on_message : " + message)
for cl in client:
cl.write_message(message)
def on_close(self):
logging.info("[ChatHandler] on_close")
if self in client:
client.remove(self)
application = tornado.web.Application([
(r"/", MainHandler),
(r"/chat", ChatHandler),
],
template_path=os.path.join(os.getcwd(), "templates"),
static_path=os.path.join(os.getcwd(), "static")
)
if __name__ == "__main__":
tornado.options.parse_command_line()
application.listen(8888)
logging.info("server started")
tornado.ioloop.IOLoop.instance().start()
クライアント側(Javascript)
script.js
// ソケット
var socket = new WebSocket('ws://' + location.host + '/chat');
moment.lang('ja', {
weekdays: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"],
weekdaysShort: ["日","月","火","水","木","金","土"],
});
/**
* 初期処理.
*/
function initialize() {
// 通信ソケットオープン
socket.onopen = function(data) {
$("#status").css("color", "#FFFFFF");
$("#status").text(" [オンライン]");
}
// 通信ソケットクローズ
socket.onclose = function() {
$("#status").css("color", "#999999");
$("#status").text(" [オフライン]")
}
// メッセージ受信
socket.onmessage = function(e) {
console.log(e.data);
var msg = e.data;
var tag = createMessage("そら", msg.replace(/[\"]/g,""));
$(".direct-chat-messages").append(tag);
$(".direct-chat-messages").animate({
scrollTop: $(".direct-chat-messages")[0].scrollHeight
}, 500);
}
// ボタンにイベントを追加
$("#sendButton").click(function () {
sendMessage();
});
// チャットの表示を一番下に
$("#chat-panel").show();
$(".direct-chat-messages")[0].scrollTop = $(".direct-chat-messages")[0].scrollHeight;
}
/**
* メッセージを送信.
*/
function sendMessage() {
var msg = $("#message").val();
if (msg != ""){
socket.send(JSON.stringify(msg));
}
}
/**
* メッセージタグを作成して返します.
*/
function createMessage(userName, message) {
var msgDiv = $("<div>", {
"class" : "direct-chat-text"
, "text" : message
});
var img = $("<img>", {
"class" : "direct-chat-img"
, "src" : "static/img/sora.jpg"
});
// とりあえず現在時刻を表示(本来は送信時刻)
var now = new moment();
var date = now.format("YYYY/MM/DD(ddd) hh:mm")
var dt = $("<span>", {
"class" : "direct-chat-timestamp pull-left"
, "text" : date
});
var name = $("<span>", {
"class" : "direct-chat-name pull-right"
, "text" : userName
});
var info = $("<div>", {
"class" : "direct-chat-info clearfix"
});
var chatMsg = $("<div>", {
"class" : "direct-chat-msg right"
});
// タグを作成していく
info.append(name);
info.append(dt);
chatMsg.append(info);
chatMsg.append(img);
chatMsg.append(msgDiv);
return chatMsg;
}
起動してみる
送信したメッセージが無事に戻ってきました。
まとめ
ひとまず簡単に、
Websocketを使った処理が実装できました。
次回はユーザー毎の制御でも実装していきましょうか。
それにはログイン機能が必要ですね。
ではでは。
ディスカッション
コメント一覧
まだ、コメントがありません