概要
二人専用チャットルームを簡単に作成してみます
環境
- macOS 15.7.2
- Python 3.12.11
- Flask==3.1.2
- Flask-SocketIO==5.6.0
- eventlet==0.40.4
インストール
- pyenv local 3.12.11
- pipenv install flask flask-socketio eventlet
アプリ
-
vim app.py
from typing import cast
from flask import Flask, render_template, request
from flask_socketio import SocketIO, emit, join_room, leave_room
app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins="*")
CHAT_ROOM_ID = "hoge"
# 接続管理(sid を保持)
chat_clients: set[str] = set()
@app.route("/<room_id>")
def chat(room_id: str):
if room_id != CHAT_ROOM_ID:
return "Not Found", 404
return render_template("index.html", room_id=CHAT_ROOM_ID)
@socketio.on("connect")
def on_connect():
sid = cast(str, request.sid) # type: ignore
if len(chat_clients) >= 2:
emit("full", to=sid)
return False
chat_clients.add(sid)
join_room(CHAT_ROOM_ID)
if len(chat_clients) == 1:
# 1人目
emit("status", "待っています…", to=sid)
else:
# 2人目が入った瞬間に「全員」に通知
emit("status", "準備OK!", to=CHAT_ROOM_ID)
@socketio.on("message")
def on_message(data):
msg = data.get("message")
if msg:
emit("message", msg, to=CHAT_ROOM_ID, include_self=False)
@socketio.on("disconnect")
def on_disconnect():
sid = cast(str, request.sid) # type: ignore
chat_clients.discard(sid)
leave_room(CHAT_ROOM_ID)
if len(chat_clients) == 1:
# 残った1人に通知
emit("status", "終わり", to=CHAT_ROOM_ID)
if __name__ == "__main__":
socketio.run(app, host="0.0.0.0", port=5000, debug=False)
テンプレート
-
vim templates/index.html
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Private Chat</title>
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
</head>
<body>
<h3>Private Chat</h3>
<div id="status"></div>
<ul id="log"></ul>
<input id="msg" placeholder="message" />
<button onclick="send()">Send</button>
<script>
const socket = io();
socket.on("status", (msg) => {
document.getElementById("status").innerText = msg;
});
socket.on("message", (msg) => {
const li = document.createElement("li");
li.textContent = msg;
log.appendChild(li);
});
socket.on("full", () => {
alert("このチャットは満員です");
});
function send() {
const input = document.getElementById("msg");
socket.emit("message", { message: input.value });
input.value = "";
}
</script>
</body>
</html>
動作確認
localhost:5000/hoge に複数のブラウザでアクセスしてメッセージのやり取りができることを確認しましょう
できない場合はファイアウォールや NetFilter、リバースプロキシなどの設定を確認しましょう
WebSocket は Upgrade: example/1, foo/2 のような Upgrade ヘッダの許可が必須なので前段でヘッダが弾かれている可能性があります
最後に
5000 番ポートがすでに使われている場合はポートを変更するか AirPlay レシーバをオフにしましょう
lsof -i :5000
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ControlCe 1129 user01 10u IPv4 0xfb24a12bbd08b2c2 0t0 TCP *:commplex-main (LISTEN)
ControlCe 1129 user01 11u IPv6 0x9dc35b82883e083d 0t0 TCP *:commplex-main (LISTEN)
0 件のコメント:
コメントを投稿