File size: 4,737 Bytes
16a9a79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a10cb30
 
 
 
 
 
 
16a9a79
 
 
 
 
 
 
 
 
 
 
2d37f90
22d703d
 
 
 
 
 
2d37f90
22d703d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2d37f90
22d703d
 
2d37f90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22d703d
 
 
 
 
 
 
 
 
2d37f90
ef64087
 
bd548c2
 
 
 
 
ef64087
 
 
bd548c2
 
 
 
2d37f90
16a9a79
cda539a
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
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)  
  
@app.route("/", methods=["GET"])  
def index():  
    return render_template("index.html")  
  
@app.route("/chat", methods=["GET"])  
def chat():  
    return render_template("chat.html")  
  
@socketio.on("find")  
def handle_find(profile):  
    sid = request.sid  
    PROFILES[sid] = profile  
    WAITING.append(sid)  
    emit("status", {"msg": "Finding partner..."}, room=sid)  
    try_match()  
  
@socketio.on("disconnect")  
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)  
  
@socketio.on("subscribe")  
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)  
  
@socketio.on("chat")
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)
  
@socketio.on("leave")  
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)