import socketio import base64 import numpy as np import threading import sounddevice as sd import protocol sio = socketio.Client() _client_instance = None def init_network(client_instance): """Binds the network events to the active TUI client instance state.""" global _client_instance _client_instance = client_instance @sio.event def incoming_packet(data): if not _client_instance: return from_uin = data["from_uin"] payload_base64 = data["payload"] try: audio_bytes = base64.b64decode(payload_base64.encode('utf-8')) audio_data = np.frombuffer(audio_bytes, dtype=np.float32) srv_tone = protocol.detect_service_tone(audio_data) if srv_tone: sd.play(audio_data, protocol.SAMPLE_RATE) if from_uin not in _client_instance.contacts: return if srv_tone == protocol.FREQ_QUERY: if _client_instance.is_busy: _client_instance.send_service_tone(from_uin, protocol.FREQ_RESP_YES) else: _client_instance.pending_windows.append({"type": "query", "uin": from_uin}) _client_instance.refresh_ui() return elif srv_tone == protocol.FREQ_ALERT: _client_instance.pending_windows.append({"type": "alert", "uin": from_uin}) _client_instance.refresh_ui() return elif srv_tone == protocol.FREQ_RESP_YES: _client_instance.add_to_history(from_uin, f"[SYSTEM]: Quick status answer -> Yes, I'm busy") return elif srv_tone == protocol.FREQ_RESP_NO: _client_instance.add_to_history(from_uin, f"[SYSTEM]: Quick status answer -> No, go on") return fast_text = protocol.fast_decode(audio_data) if fast_text.startswith("SYS:"): cmd = fast_text[4:] if cmd.startswith("ROOM_MSG:"): parts = cmd.split(":", 3) if len(parts) >= 4: room_id = parts[1] sender_uin = parts[2] actual_msg = parts[3] if room_id in _client_instance.groups: _client_instance.add_to_history(room_id, f"[UIN {sender_uin}]: {actual_msg}") return elif cmd == "REQ_ADD": if from_uin in _client_instance.blocklist: _client_instance.send_sys_packet(from_uin, "RES_DEC") elif _client_instance.is_busy: _client_instance.send_sys_packet(from_uin, "RES_BSY") else: if from_uin not in _client_instance.pending_requests and from_uin not in _client_instance.contacts: _client_instance.pending_requests.append(from_uin) _client_instance.refresh_ui() return elif cmd == "RES_ACC": if _client_instance.dialing_uin == from_uin: _client_instance.dialing_uin = None if from_uin not in _client_instance.contacts: _client_instance.contacts[from_uin] = {"status": "online", "unread": 0, "attention": False} _client_instance.history[from_uin] = ["[SYSTEM]: Handshake accepted. Contact added."] _client_instance.save_config() _client_instance.active_chat = from_uin _client_instance.refresh_ui() return elif cmd == "RES_DEC" or cmd == "RES_BSY": if _client_instance.dialing_uin == from_uin: _client_instance.dialing_uin = None return if from_uin not in _client_instance.contacts: return if _client_instance.active_chat != from_uin: _client_instance.contacts[from_uin]["unread"] += 1 threading.Thread(target=_client_instance.play_and_decode, args=(audio_bytes, from_uin), daemon=True).start() except Exception as e: pass @sio.event def online_statuses_response(data): if not _client_instance: return for uin, status in data.items(): if uin in _client_instance.contacts: _client_instance.contacts[uin]["status"] = status _client_instance.refresh_ui() @sio.event def error(data): if not _client_instance: return msg = data.get("message") target = data.get("target_uin") if msg == "offline" and target: if _client_instance.dialing_uin == target: _client_instance.dialing_uin = None if target in _client_instance.contacts: _client_instance.contacts[target]["status"] = "offline" _client_instance.add_to_history(target, f"[SYSTEM]: They went offline. Outgoing stack will be preserved.")