[Python] why does python socketio sio.emit() not work?

Discussão em 'Python' iniciado por Stack, Julho 25, 2025.

  1. Stack

    Stack Membro Participativo

    i apologize if this isn't the right place for this or if i made a mistake. but i need help with my python desktop app,

    the issue is that i have setup the clipboard_button from the main.py to trigger the send_message_test function in the Server class, the function is being ran clearely because the two print functions ("[server] ran send_message_test" and "[server] done running send_message_test") (the self.connected_sid is valid and correct)

    however the self.sio.emit("test", "test", room=self.connected_sid) doesn't seem to do anything, the connection is valid and the file-ack emit works just fine! i already searched everywhere for a solution and tried many different ways but none seemed to help.

    main.py:


    import sys
    import threading
    import time
    import json
    import qrcode
    import pyperclip
    from PIL.ImageQt import ImageQt
    from PySide6.QtCore import (
    Qt, Property, QEasingCurve, QPropertyAnimation, Signal, QSize
    )
    from PySide6.QtGui import QCursor, QColor, QEnterEvent, QFont, QFontDatabase, QIcon, QPixmap
    from PySide6.QtWidgets import (
    QApplication, QWidget, QPushButton, QLabel,
    QHBoxLayout, QVBoxLayout
    )
    from server import Server
    from win10toast import ToastNotifier
    from PySide6.QtWidgets import QLabel

    toaster = ToastNotifier()



    class AnimatedButton(QPushButton):
    def __init__(self, text):
    super().__init__(text)
    self._color = QColor("#4C4C4C")
    self.setStyleSheet(f"background-color: {self._color.name()}")
    self.animation = QPropertyAnimation(self, b"bgColor")
    self.animation.setDuration(140)
    self.animation.setEasingCurve(QEasingCurve.InOutQuad)

    def enterEvent(self, event: QEnterEvent):
    self.animate_to(QColor("#2D2D2D"))
    super().enterEvent(event)

    def leaveEvent(self, event):
    self.animate_to(QColor("#4C4C4C"))
    super().leaveEvent(event)

    def animate_to(self, color):
    self.animation.stop()
    self.animation.setStartValue(self._color)
    self.animation.setEndValue(color)
    self.animation.start()

    def get_bg_color(self):
    return self._color

    def set_bg_color(self, color):
    self._color = color
    self.setStyleSheet(f"background-color: {color.name()};")

    bgColor = Property(QColor, get_bg_color, set_bg_color)

    class MainWindow(QWidget):
    file_received_signal = Signal(dict)
    clipboard_received_signal = Signal(str)
    text_received_signal = Signal(str)
    test_button_clicked_signal = Signal(any)

    def __init__(self):
    super().__init__()
    self.server = server
    self.setWindowTitle("Connection Button")
    self.setFixedSize(846, 520)

    # Status bar unfinished
    # self.status_bar = QWidget()
    # self.status_bar.setObjectName("status_bar")
    # self.status_bar.setFixedSize(758, 112)
    # self.status_bar_layout = QHBoxLayout(self.status_bar)
    # self.status_label = QLabel("Status: Waiting...")
    # self.status_label.setAlignment(Qt.AlignCenter)
    # self.status_bar_layout.addWidget(self.status_label)

    # Clipboard button
    self.clipboard_button = AnimatedButton("Clipboard")
    self.clipboard_button.setObjectName("clipboardButton")
    self.clipboard_button.setFixedSize(352, 112)
    self.clipboard_button.setCursor(QCursor(Qt.PointingHandCursor))
    self.clipboard_button.setIcon(QIcon("assets/icons/Paperclip.svg"))
    self.clipboard_button.setIconSize(QSize(32, 32))
    self.clipboard_button.setLayoutDirection(Qt.RightToLeft)




    # Filesharing button
    self.filesharing_button = AnimatedButton("Filesharing")
    self.filesharing_button.setObjectName("filesharingButton")
    self.filesharing_button.setFixedSize(352, 112)
    self.filesharing_button.setCursor(QCursor(Qt.PointingHandCursor))
    self.filesharing_button.setIcon(QIcon("assets/icons/file.svg"))
    self.filesharing_button.setIconSize(QSize(32, 32))
    self.filesharing_button.setLayoutDirection(Qt.RightToLeft)

    # Share text button
    self.text_button = AnimatedButton("Share text")
    self.text_button.setObjectName("textButton")
    self.text_button.setFixedSize(352, 112)
    self.text_button.setCursor(QCursor(Qt.PointingHandCursor))
    self.text_button.setIcon(QIcon("assets/icons/placeholder.svg"))
    self.text_button.setIconSize(QSize(32, 32))
    self.text_button.setLayoutDirection(Qt.RightToLeft)

    # QR box
    self.qrbox = QWidget()
    self.qrbox.setObjectName("box")
    self.qrbox.setFixedSize(382, 382)
    self.qrbox_layout = QVBoxLayout(self.qrbox)


    # Layout
    buttons_layout = QVBoxLayout()
    buttons_layout.addWidget(self.clipboard_button)
    buttons_layout.addWidget(self.filesharing_button)
    buttons_layout.addWidget(self.text_button)
    buttons_layout.setSpacing(24)

    button_box_layout = QHBoxLayout()
    button_box_layout.addWidget(self.qrbox)
    button_box_layout.addLayout(buttons_layout)
    button_box_layout.setSpacing(24)
    button_box_layout.setAlignment(Qt.AlignCenter)

    layout = QVBoxLayout(self)
    # layout.addWidget(self.status_bar)
    layout.setAlignment(Qt.AlignCenter)
    layout.addSpacing(24)
    layout.addLayout(button_box_layout)

    #signals
    self.file_received_signal.connect(self.handle_file)
    self.clipboard_received_signal.connect(self.handle_clipboard)
    self.text_received_signal.connect(self.handle_text)

    self.test_button_clicked_signal.connect(self.server.send_message_test)

    self.clipboard_button.clicked.connect(self.test_button_clicked_signal)
    # self.clipboard_button.clicked.connect(self.text_received_signal)
    def send_clipboard_to_phone(self):
    text = pyperclip.paste()
    if text:
    # self.server.send_clipboard(text=text)
    pass
    else:
    print("clipboard is empty")


    def handle_callback(self, msg_type, content):
    if msg_type == "file":
    self.file_received_signal.emit(content)
    elif msg_type == "clipboard":
    self.clipboard_received_signal.emit(content)
    elif msg_type == "text":
    self.text_received_signal.emit(content)
    else:
    print(f"Unknown type: {msg_type}")

    def handle_file(self, file_info):
    fname = file_info.get("filename", "unknown")
    ftype = file_info.get("filetype", "unknown")
    toaster.show_toast(f"Received {ftype}", fname)

    def handle_clipboard(self, text):
    pyperclip.copy(text)
    toaster.show_toast("Copied to clipboard", text)
    while toaster.notification_active(): time.sleep(0.1)

    def handle_text(self, text):
    print(f"UI: Text received - {text}")

    def update_qr(self, data: dict,
    fill_color: str = "#000",
    back_color: str = "#000"):
    for i in reversed(range(self.qrbox_layout.count())):
    w = self.qrbox_layout.itemAt(i).widget()
    if w:
    w.setParent(None)
    payload = json.dumps(data, separators=(',', ':'))
    qr = qrcode.QRCode(
    version=1, error_correction=qrcode.constants.ERROR_CORRECT_L,
    box_size=10, border=4
    )
    qr.add_data(payload)
    qr.make(fit=True)
    pil_img = qr.make_image(fill_color=fill_color, back_color=back_color).convert("RGB")
    qt_img = ImageQt(pil_img)
    pix = QPixmap.fromImage(qt_img)
    lbl = QLabel(alignment=Qt.AlignCenter)
    lbl.setPixmap(pix.scaled(400, 400, Qt.KeepAspectRatio))
    lbl.setStyleSheet("background: transparent;")
    self.qrbox_layout.addWidget(lbl)



    if __name__ == "__main__":

    server = Server()
    app = QApplication(sys.argv)
    font_id = QFontDatabase.addApplicationFont("assets/fonts/poppins-v23-latin-700.ttf")
    if font_id != -1:
    app.setFont(QFontDatabase.applicationFontFamilies(font_id)[0])
    with open("styles/theme.qss", "r") as f:
    app.setStyleSheet(f.read())
    win = MainWindow()
    win.update_qr({"ip": server.ip_address, "port": server.port, "authToken": server.token, "name": "pc"},
    fill_color="#2D2D2D", back_color="#D3D3D3")
    print(server.ip_address)
    server.start()
    server.register_callback('file', win.handle_file)
    server.register_callback('message', win.handle_callback)
    win.show()
    sys.exit(app.exec())



    server.py:

    import eventlet
    from eventlet import wsgi
    from urllib.parse import parse_qs
    import socket
    import socketio
    import threading
    import json
    import base64
    import random


    class Server:
    def __init__(self):
    # core socket.io server
    self.sio = socketio.Server(cors_allowed_origins='*')
    self.app = socketio.WSGIApp(self.sio)

    # track exactly one connected client
    self.connected_sid = None

    # auth token, IP, port
    self.token = self.generate_token()
    self.ip_address = self.get_local_ip()
    self.port = 5000

    # GUI callbacks (for file/text), registered later
    self._callbacks = {
    'message': None,
    'file': None,
    }

    # ——— event handlers ———
    @self.sio.event
    def connect(sid, environ):
    print(f"[CONNECT] raw sid = {sid}, qs = {environ.get('QUERY_STRING')}")
    query = parse_qs(environ.get('QUERY_STRING', ''))
    token = query.get('token', [None])[0]
    self.sio.emit("test", {}, room=sid)
    if token == self.token:
    self.connected_sid = sid
    print(f"✅ Client {sid} connected with valid token.")
    self.sio.emit("message", {})
    self.sio.emit("wtv", "wtv", room=sid)
    self.sio.emit("test", {}, room=sid)
    else:
    print(f"❌ Client {sid} invalid token: {token}")
    raise socketio.exceptions.ConnectionRefusedError('Unauthorized')
    self.sio.emit("test", {}, room=sid)


    @self.sio.event
    def disconnect(sid):
    print(f"[DISCONNECT] sid = {sid}")
    if sid == self.connected_sid:
    self.connected_sid = None
    print("→ Cleared connected_sid")

    @self.sio.event
    def file(sid, data):
    print(f"[FILE] from {sid}")
    try:
    filename = data.get("name")
    filetype = data.get("type", "application/octet-stream")
    b64 = data.get("data", "")
    content = base64.b64decode(b64)
    with open(filename, "wb") as f:
    f.write(content)
    print(f"Saved file: {filename}")

    if self._callbacks['file']:
    self._callbacks['file']({
    "filename": filename,
    "filetype": filetype,
    })

    self.sio.emit(
    "file-ack",
    {"status": "received", "filename": filename},
    room=sid
    )

    except Exception as e:
    print("Error in file handler:", e)

    @self.sio.event
    def message(sid, data):
    print(f"[MESSAGE] raw data from {sid}:", data)
    try:
    if isinstance(data, str):
    data = json.loads(data)
    msg_type = data.get("type", "text")
    content = data.get("content", "")
    if self._callbacks['message']:
    self._callbacks['message'](msg_type, content)
    except Exception as e:
    print("Error in message handler:", e)

    def generate_token(self):
    return str(random.randint(1000, 9999))


    def send_message_test(self):
    print("[server] ran send_message_test")
    print(f"[server] self: {self.connected_sid}")
    self.sio.emit("test", "test", room=self.connected_sid)
    print("[server] done running send_message_test")


    def get_local_ip(self):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    try:
    s.connect(('8.8.8.8', 80))
    return s.getsockname()[0]
    except:
    return '127.0.0.1'
    finally:
    s.close()

    def start(self):
    threading.Thread(
    target=lambda: wsgi.server(
    eventlet.listen(('0.0.0.0', self.port)), self.app
    ),
    daemon=True
    ).start()
    print(f"Server started on {self.ip_address}:{self.port}")
    print(f"Auth token = {self.token}")
    print(f"[server] {self}")

    def register_callback(self, event_name, callback):
    if event_name in self._callbacks:
    self._callbacks[event_name] = callback
    else:
    raise ValueError(f"Unknown event '{event_name}'")

    if __name__ == "__main__":
    server = Server()
    server.start()



    i'm using expo react native to connect: main.tsx:


    //#region
    // main.tsx
    import * as Clipboard from 'expo-clipboard';
    import * as DocumentPicker from 'expo-document-picker';
    import * as FileSystem from 'expo-file-system';

    import React, { useEffect, useRef, useState } from 'react';
    import { Alert, Platform, Pressable, StyleSheet, Text, View } from 'react-native';
    import 'react-native-url-polyfill/auto';
    import { Socket } from 'socket.io-client';

    import Fileicon from '../../assets/images/file.svg';
    import ClipboardIcon from '../../assets/images/Paperclip.svg';
    import PlaceHolderIcon from '../../assets/images/placeholder.svg';
    import WifiIcon from '../../assets/images/wifi.svg';

    import { useConnection } from '../(tabs)/test';

    export default function MainScreen() {
    const { activeConnection } = useConnection();
    const [message, setMessage] = useState('');
    const socketRef = useRef<Socket | null>(null);
    const [isConnected, setIsConnected] = useState(false);

    useEffect(() => {
    if (!activeConnection || !activeConnection.socket) {
    socketRef.current?.disconnect();
    socketRef.current = null;
    setIsConnected(false);
    return;
    }


    const socket = activeConnection.socket;
    socketRef.current = socket;


    socket.onAny((event, ...args) => {
    console.log(` [onAny] event=’${event}’, args=`, args);
    console.error(event, args);

    });

    socket.on('connect', () => {
    console.log('Socket connected');
    setIsConnected(true);
    });

    socket.on('disconnect', () => {
    console.log('Socket disconnected dnwd');
    setIsConnected(false);
    });

    socket.on('connect_error', (err) => {
    console.log('Socket connect error:', err);
    setIsConnected(false);
    });

    socket.on('message', (data: string) => {
    console.log('Received message:', data);
    });



    socket.on('test', ()=>{


    console.log("test");
    Alert.alert("test");
    });










    socket.on('clipboard', (data) => {
    console.log(' Received clipboard event with content:', data);
    if (data && data.content) {
    Alert.alert('Clipboard updated', `Clipboard content: ${data.content}`);
    } else {
    Alert.alert('Clipboard updated', 'Clipboard event received but content empty');
    }
    });
    socket.on('file-ack', (data: { status: string; filename: string }) => {
    console.log('File ACK:', data);
    if (data.status === 'received') {
    Alert.alert('File Uploaded', `${data.filename} was saved on the server.`);
    } else {
    Alert.alert('Upload Failed', `Server responded with status: ${data.status}`);
    }
    });

    return () => {
    // socket.off('connect');
    // socket.off('disconnect');
    // socket.off('connect_error');
    // socket.off('message');
    // socket.off('file-ack');
    // socket.off('clipboard')
    // socket.off('test')
    socket.disconnect();
    socketRef.current = null;
    setIsConnected(false);
    };
    }, [activeConnection]);

    const sendMessage = () => {
    if (!message.trim()) {
    return Alert.alert('Error', 'Please enter a message');
    }
    if (!socketRef.current?.connected) {
    return Alert.alert('Error', 'Not connected to any server');
    }

    socketRef.current.emit('message', message);
    setMessage('');
    };

    const sendClipboard = async () => {
    if (!activeConnection) {
    return Alert.alert('Error', 'Not connected to any server');
    }

    if (!socketRef.current?.connected) {
    return Alert.alert('Error', 'Not connected to any server');
    }

    const clipboardContent = await Clipboard.getStringAsync();
    if (!clipboardContent) {
    return Alert.alert('Clipboard', 'Clipboard is empty');
    }

    socketRef.current.emit(
    'message',
    { type: 'clipboard', content: clipboardContent },
    Alert.alert('clipboard sent successfully')
    );
    };

    async function pickAndSendFile() {
    if (Platform.OS === 'web') {
    return Alert.alert("File picking isn't available on web.");
    }

    try {
    const result = await DocumentPicker.getDocumentAsync({
    type: '*/*',
    copyToCacheDirectory: true,
    });

    // If user cancelled
    if (result.canceled === true) {
    return;
    }

    // Ensure assets array exists
    if (!Array.isArray(result.assets) || result.assets.length === 0) {
    return Alert.alert('Error', 'No file selected.');
    }

    const asset = result.assets[0];
    const { uri, name, mimeType } = asset;

    if (typeof uri !== 'string' || typeof name !== 'string') {
    return Alert.alert('Error', 'Invalid file data.');
    }

    await sendFile(uri, name, mimeType ?? 'application/octet-stream');
    } catch (error: any) {
    Alert.alert('Error', 'Failed to pick/send file: ' + error.message);
    }
    }

    async function sendFile(uri: string, filename: string, mimeType: string) {
    if (!socketRef.current?.connected) {
    return Alert.alert('Error', 'Not connected to any server');
    }

    try {
    const base64 = await FileSystem.readAsStringAsync(uri, {
    encoding: FileSystem.EncodingType.Base64,
    });

    socketRef.current.emit('file', {
    name: filename,
    type: mimeType,
    data: base64,
    });
    } catch (error: any) {
    Alert.alert('Error', 'Failed to read and send file: ' + error.message);
    }
    }


    return (
    <View style={styles.container}>
    {/* Connection Status */}
    <Pressable style={[styles.cardBase, activeConnection ? styles.connectionCard : styles.disconnectedCard]}>
    <View style={styles.cardRow}>
    <View>
    <Text style={styles.cardTitle}>
    {activeConnection
    ? `Connected to ${activeConnection.name}`
    : 'Not Connected'}
    </Text>
    <View style={styles.cardDetails}>
    <Text style={styles.cardSub}>
    {activeConnection ? activeConnection.ip : 'XXX.XXX.XX.XXX'}
    </Text>
    <Text style={styles.cardSub}>
    {new Date().toLocaleTimeString([], {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    })}
    </Text>
    </View>
    </View>
    <WifiIcon width={28} height={28} />
    </View>
    </Pressable>

    {/* Clipboard */}
    <Pressable onPress={sendClipboard} style={[styles.cardBase, styles.actionCard]}>
    <View style={styles.iconRow}>
    <Text style={styles.buttonText}>Send Clipboard</Text>
    <ClipboardIcon width={28} height={28} />
    </View>
    </Pressable>

    {/* File */}
    <Pressable onPress={pickAndSendFile} style={[styles.cardBase, styles.actionCard]}>
    <View style={styles.iconRow}>
    <Text style={styles.buttonText}>Send File</Text>
    <Fileicon width={28} height={28} />
    </View>
    </Pressable>

    {/* Message */}
    <Pressable onPress={sendMessage} style={[styles.cardBase, styles.actionCard]}>
    <View style={styles.iconRow}>
    <Text style={styles.buttonText}>Send Message</Text>
    <PlaceHolderIcon width={28} height={28} />
    </View>
    </Pressable>

    <Text>{activeConnection?.ip}</Text>
    </View>
    );
    }

    //#region Styles
    const styles = StyleSheet.create({
    container: {
    flex: 1,
    padding: 20,
    paddingTop: 150,
    backgroundColor: '#fff',
    alignItems: 'center',
    fontFamily: 'poppins-regular',
    },
    cardBase: {
    width: '100%',
    borderRadius: 16,
    padding: 16,
    marginBottom: 16,
    height: 112,
    justifyContent: 'center',
    },
    connectionCard: {
    backgroundColor: '#49944E',
    },
    disconnectedCard: {
    backgroundColor: '#D95353',
    },
    cardRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    paddingHorizontal: 8,
    width: '100%',
    },
    cardTitle: {
    color: '#fff',
    fontSize: 16,
    marginBottom: 6,
    fontFamily: 'poppins-500',
    },
    cardDetails: {
    flexDirection: 'row',
    gap: 16,
    },
    cardSub: {
    color: '#fff',
    fontSize: 12,
    opacity: 0.8,
    },
    actionCard: {
    backgroundColor: '#4C4C4C',
    },
    iconRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    width: '100%',
    height: '100%',
    paddingHorizontal: 8,
    },
    buttonText: {
    color: '#fff',
    fontSize: 18,
    fontFamily: 'poppins-500',
    },
    response: {
    marginTop: 20,
    fontSize: 16,
    color: '#333',
    },
    });
    //#endregion


    this works just fine besides not recieving said emit, this is a very debug version.

    again i'm very sorry if this question dosn't make sense, maybe i'm just an idiot

    Continue reading...

Compartilhe esta Página