【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を使った処理が実装できました。
次回はユーザー毎の制御でも実装していきましょうか。
それにはログイン機能が必要ですね。
ではでは。
ディスカッション
コメント一覧
まだ、コメントがありません