【Python】AdminLTEとWebSocketでチャット機能を作ってみる その1(とりあえず版)

公開日:2019-01-18
最終更新:2019-01-18
※この記事は外部サイト(https://www.doraxdora.com/blog/2018/09/29/...)からのクロス投稿です

前回に引き続き、チャット機能の実装をしていきます。

予定通り、今回は 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

<pre class="lang:python decode:true"># --- 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

<pre class="lang:js decode:true ">// ソケット  
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 = $("&lt;div&gt;", {  
        "class" : "direct-chat-text"  
        , "text" : message  
    });  

    var img = $("&lt;img&gt;", {  
        "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 = $("&lt;span&gt;", {  
        "class" : "direct-chat-timestamp pull-left"  
        , "text" : date  
    });  

    var name = $("&lt;span&gt;", {  
        "class" : "direct-chat-name pull-right"  
        , "text" : userName  
    });  

    var info = $("&lt;div&gt;", {  
        "class" : "direct-chat-info clearfix"  
    });  

    var chatMsg = $("&lt;div&gt;", {  
        "class" : "direct-chat-msg right"  
    });  

    // タグを作成していく  
    info.append(name);  
    info.append(dt);  

    chatMsg.append(info);  
    chatMsg.append(img);  
    chatMsg.append(msgDiv);  

    return chatMsg;  
}

起動してみる


送信したメッセージが無事に戻ってきました。

まとめ


ひとまず簡単に、Websocketを使った処理が実装できました。

次回はユーザー毎の制御でも実装していきましょうか。
それにはログイン機能が必要ですね。

ではでは。

記事が少しでもいいなと思ったらクラップを送ってみよう!
18
+1
@doraxdoraの技術ブログ 主に Java, C#, Python, Javascript の記事を載せていく予定。

よく一緒に読まれている記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる

技術ブログをはじめよう

Qrunch(クランチ)は、ITエンジニアリングに携わる全ての人のための技術ブログプラットフォームです。

技術ブログを開設する

Qrunchでアウトプットをはじめよう

Qrunch(クランチ)は、ITエンジニアリングに携わる全ての人のための技術ブログプラットフォームです。

Markdownで書ける

ログ機能でアウトプットを加速

デザインのカスタマイズが可能

技術ブログ開設

ここから先はアカウント(ブログ)開設が必要です

英数字4文字以上
.qrunch.io
英数字6文字以上
ログインする