Spaces:
Running
Running
import uuid | |
from flask import Flask, render_template, request | |
from flask_socketio import SocketIO, join_room, leave_room, emit | |
app = Flask(__name__) | |
socketio = SocketIO(app, cors_allowed_origins="*") | |
# In-memory matchmaking state | |
PROFILES = {} # sid -> profile dict | |
WAITING = [] # list of sids waiting | |
ROOMS = {} # room_id -> (sid1, sid2) | |
def index(): | |
return render_template("index.html") | |
def chat(): | |
return render_template("chat.html") | |
def handle_find(profile): | |
sid = request.sid | |
PROFILES[sid] = profile | |
WAITING.append(sid) | |
emit("status", {"msg": "Finding partner..."}, room=sid) | |
try_match() | |
def handle_disconnect(sid): | |
# `sid` is passed in by Socket.IO on disconnect | |
if sid in WAITING: | |
WAITING.remove(sid) | |
PROFILES.pop(sid, None) | |
# Remove from any room | |
for room, pair in list(ROOMS.items()): | |
if sid in pair: | |
other = pair[1] if pair[0] == sid else pair[0] | |
emit("status", {"msg": "Partner left."}, room=other) | |
leave_room(room, sid=other) | |
ROOMS.pop(room) | |
def handle_subscribe(data): | |
room = data.get("room") | |
sid = request.sid | |
if room in ROOMS and sid in ROOMS[room]: | |
join_room(room) | |
emit("status", {"msg": f"Joined room {room}!"}, room=sid) | |
else: | |
emit("status", {"msg": "Invalid room or not in this room."}, room=sid) | |
def handle_chat(data): | |
room = data.get("room") | |
msg = data.get("msg") | |
sid = data.get("sid") or request.sid | |
if room in ROOMS: | |
emit("chat", {"msg": msg, "sid": sid}, room=room) | |
def handle_leave(data): | |
room = data.get("room") | |
sid = request.sid | |
emit("left", {}, room=sid) | |
if room in ROOMS: | |
other = next(s for s in ROOMS[room] if s != sid) | |
emit("status", {"msg": "Partner left."}, room=other) | |
leave_room(room, sid=other) | |
ROOMS.pop(room) | |
def try_match(): | |
import random | |
random.shuffle(WAITING) # To ensure fairness | |
used = set() | |
pairs = [] | |
# === FIRST: Try matching by interest === | |
for i, sid1 in enumerate(WAITING): | |
if sid1 in used: continue | |
p1 = PROFILES.get(sid1) | |
if not p1: continue | |
for j in range(i + 1, len(WAITING)): | |
sid2 = WAITING[j] | |
if sid2 in used: continue | |
p2 = PROFILES.get(sid2) | |
if not p2: continue | |
# Gender filtering | |
if p1['looking'] != 'any' and p2['gender'].lower() != p1['looking'].lower(): | |
continue | |
if p2['looking'] != 'any' and p1['gender'].lower() != p2['looking'].lower(): | |
continue | |
# Interests matching | |
if set(p1['interests']) & set(p2['interests']): | |
pairs.append((sid1, sid2)) | |
used.update([sid1, sid2]) | |
break | |
# === SECOND: Fallback to random match (respect gender) === | |
for i, sid1 in enumerate(WAITING): | |
if sid1 in used: continue | |
p1 = PROFILES.get(sid1) | |
if not p1: continue | |
for j in range(i + 1, len(WAITING)): | |
sid2 = WAITING[j] | |
if sid2 in used: continue | |
p2 = PROFILES.get(sid2) | |
if not p2: continue | |
# Gender filtering only | |
if p1['looking'] != 'any' and p2['gender'].lower() != p1['looking'].lower(): | |
continue | |
if p2['looking'] != 'any' and p1['gender'].lower() != p2['looking'].lower(): | |
continue | |
pairs.append((sid1, sid2)) | |
used.update([sid1, sid2]) | |
break | |
# === Finalize pairs and assign rooms === | |
for sid1, sid2 in pairs: | |
for sid in (sid1, sid2): | |
if sid in WAITING: | |
WAITING.remove(sid) | |
room = str(uuid.uuid4()) | |
ROOMS[room] = (sid1, sid2) | |
join_room(room, sid=sid1) | |
join_room(room, sid=sid2) | |
emit("matched", { | |
"room": room, | |
"my_id": PROFILES[sid1]["id"], | |
"my_sid": sid1, | |
"partner_id": PROFILES[sid2]["id"], | |
"partner_sid": sid2 | |
}, room=sid1) | |
emit("matched", { | |
"room": room, | |
"my_id": PROFILES[sid2]["id"], | |
"my_sid": sid2, | |
"partner_id": PROFILES[sid1]["id"], | |
"partner_sid": sid1 | |
}, room=sid2) | |
if __name__ == "__main__": | |
socketio.run(app, host="0.0.0.0", port=7860) |