【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、イメージなどのパスの指定と、微妙に修正した箇所があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | <!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
1 2 3 4 5 6 7 | .form-control { ime-mode:active; } #status { font-size:10px; } |
プログラム
Tornadoを利用しています。
利用方法は次の記事なんかを参考にしていただければ。
【Python】スマホで読み込むと Wi-Fi に繋げられるQRコードを生成してみる
サーバー側
Main.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | # --- coding: utf-8 --- """ チャットサンプル """ importos importsignal importlogging importjson importtornado.web importtornado.ioloop importtornado.websocket fromtornado.options importoptions fromtornado.websocket importWebSocketHandler client=[] classMainHandler(tornado.web.RequestHandler): """ 初期表示処理 """ definitialize(self): logging.info("[MainHandler] initialize") defget(self): logging.info("[MainHandler] get") self.render("main.html") classChatHandler(WebSocketHandler): """ チャット処理 """ defopen(self): logging.info("[ChatHandler] open") ifselfnotinclient: client.append(self) defon_message(self,message): logging.info("[ChatHandler] on_message : "+message) forcl inclient: cl.write_message(message) defon_close(self): logging.info("[ChatHandler] on_close") ifselfinclient: 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | // ソケット varsocket=newWebSocket('ws://'+location.host+'/chat'); moment.lang('ja',{ weekdays:["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"], weekdaysShort:["日","月","火","水","木","金","土"], }); /** * 初期処理. */ functioninitialize(){ // 通信ソケットオープン 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); varmsg=e.data; vartag=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; } /** * メッセージを送信. */ functionsendMessage(){ varmsg=$("#message").val(); if(msg!=""){ socket.send(JSON.stringify(msg)); } } /** * メッセージタグを作成して返します. */ functioncreateMessage(userName,message){ varmsgDiv=$("<div>",{ "class":"direct-chat-text" ,"text":message }); varimg=$("<img>",{ "class":"direct-chat-img" ,"src":"static/img/sora.jpg" }); // とりあえず現在時刻を表示(本来は送信時刻) varnow=newmoment(); vardate=now.format("YYYY/MM/DD(ddd) hh:mm") vardt=$("<span>",{ "class":"direct-chat-timestamp pull-left" ,"text":date }); varname=$("<span>",{ "class":"direct-chat-name pull-right" ,"text":userName }); varinfo=$("<div>",{ "class":"direct-chat-info clearfix" }); varchatMsg=$("<div>",{ "class":"direct-chat-msg right" }); // タグを作成していく info.append(name); info.append(dt); chatMsg.append(info); chatMsg.append(img); chatMsg.append(msgDiv); returnchatMsg; } |
起動してみる
送信したメッセージが無事に戻ってきました。
まとめ
ひとまず簡単に、
Websocketを使った処理が実装できました。
次回はユーザー毎の制御でも実装していきましょうか。
それにはログイン機能が必要ですね。
ではでは。
ディスカッション
コメント一覧
まだ、コメントがありません