feat: Implement Music Player Service with VLC integration
- Added MusicPlayerService for managing VLC music playback with playlist support. - Implemented methods for loading playlists, controlling playback (play, pause, stop, next, previous), and managing volume and play modes. - Integrated real-time synchronization with VLC state using a background thread. - Added SocketIO event emissions for player state updates. - Enhanced logging for better debugging and tracking of player state changes. fix: Improve SocketIO service logging and event handling - Added detailed logging for SocketIO events and user authentication. - Implemented a test event handler to verify SocketIO functionality. - Enhanced error handling and logging for better traceability. chore: Update dependencies and logging configuration - Added python-vlc dependency for VLC integration. - Configured logging to show INFO and DEBUG messages for better visibility during development. - Updated main application entry point to allow unsafe Werkzeug for debugging purposes.
This commit is contained in:
@@ -9,6 +9,12 @@ from app import socketio
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Add debug print to ensure this module is loaded
|
||||
print(f"🔧 SocketIO Service: Module loaded, logger level: {logger.level}")
|
||||
print(f"🔧 SocketIO Service: Effective logger level: {logger.getEffectiveLevel()}")
|
||||
print(f"🔧 SocketIO Service: Parent logger handlers: {logger.parent.handlers}")
|
||||
print(f"🔧 SocketIO Service: Logger handlers: {logger.handlers}")
|
||||
|
||||
|
||||
class SocketIOService:
|
||||
"""Service for managing SocketIO connections and user rooms."""
|
||||
@@ -25,6 +31,15 @@ class SocketIOService:
|
||||
socketio.emit(event, data, room=room)
|
||||
logger.debug(f"Emitted {event} to user {user_id} in room {room}")
|
||||
|
||||
@staticmethod
|
||||
def emit_to_all(event: str, data: dict) -> None:
|
||||
"""Emit an event to all connected clients."""
|
||||
try:
|
||||
socketio.emit(event, data)
|
||||
logger.info(f"Successfully emitted {event} to all clients with data keys: {list(data.keys())}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to emit {event}: {e}")
|
||||
|
||||
@staticmethod
|
||||
def emit_credits_changed(user_id: int, new_credits: int) -> None:
|
||||
"""Emit credits_changed event to a user."""
|
||||
@@ -43,7 +58,10 @@ class SocketIOService:
|
||||
|
||||
# Check if we have the access_token cookie
|
||||
access_token = request.cookies.get("access_token_cookie")
|
||||
logger.debug(f"Access token from cookies: {access_token[:20] if access_token else None}...")
|
||||
|
||||
if not access_token:
|
||||
logger.debug("No access token found in cookies")
|
||||
return None
|
||||
|
||||
# Decode the JWT token manually
|
||||
@@ -51,9 +69,13 @@ class SocketIOService:
|
||||
try:
|
||||
decoded_token = decode_token(access_token)
|
||||
current_user_id = decoded_token["sub"]
|
||||
logger.debug(f"Decoded user ID: {current_user_id}")
|
||||
|
||||
if not current_user_id:
|
||||
logger.debug("No user ID in token")
|
||||
return None
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.debug(f"Token decode error: {e}")
|
||||
return None
|
||||
|
||||
# Query database for user data
|
||||
@@ -61,8 +83,10 @@ class SocketIOService:
|
||||
|
||||
user = User.query.get(int(current_user_id))
|
||||
if not user or not user.is_active:
|
||||
logger.debug(f"User not found or inactive: {current_user_id}")
|
||||
return None
|
||||
|
||||
logger.debug(f"Successfully found user: {user.email}")
|
||||
return {
|
||||
"id": str(user.id),
|
||||
"email": user.email,
|
||||
@@ -70,29 +94,41 @@ class SocketIOService:
|
||||
"role": user.role,
|
||||
"credits": user.credits,
|
||||
}
|
||||
except Exception:
|
||||
except Exception as e:
|
||||
logger.debug(f"Exception in get_user_from_socketio: {e}")
|
||||
return None
|
||||
|
||||
|
||||
@socketio.on("connect")
|
||||
def handle_connect(auth=None) -> bool:
|
||||
def handle_connect(auth=None):
|
||||
"""Handle client connection."""
|
||||
print(f"🔌 CONNECT EVENT HANDLER CALLED: {request.sid}")
|
||||
try:
|
||||
logger.info(f"SocketIO connection from {request.remote_addr}")
|
||||
return True
|
||||
logger.info(f"SocketIO connection established from {request.remote_addr}")
|
||||
logger.info(f"Session ID: {request.sid}")
|
||||
logger.info(f"Cookies: {request.cookies}")
|
||||
print(f"🔌 CONNECT SUCCESS: {request.sid}")
|
||||
|
||||
except Exception:
|
||||
logger.exception("Error handling SocketIO connection")
|
||||
print(f"🔌 CONNECT ERROR: {request.sid}")
|
||||
disconnect()
|
||||
return False
|
||||
|
||||
|
||||
@socketio.on("authenticate")
|
||||
def handle_authenticate(data):
|
||||
"""Handle authentication after connection."""
|
||||
print(f"🔐 AUTHENTICATE EVENT HANDLER CALLED: {request.sid}")
|
||||
logger.info(f"🔐 SOCKETIO EVENT: authenticate received from {request.sid}")
|
||||
logger.info(f"🔐 Auth data: {data}")
|
||||
logger.info(f"🔐 Request cookies: {dict(request.cookies)}")
|
||||
|
||||
try:
|
||||
user = SocketIOService.get_user_from_socketio()
|
||||
logger.info(f"🔐 User lookup result: {user}")
|
||||
|
||||
if not user:
|
||||
logger.warning("🔐 Authentication failed - no user found")
|
||||
emit("auth_error", {"error": "Authentication failed"})
|
||||
disconnect()
|
||||
return
|
||||
@@ -103,21 +139,30 @@ def handle_authenticate(data):
|
||||
# Join user-specific room
|
||||
join_room(user_room)
|
||||
|
||||
logger.info(f"User {user_id} authenticated and joined room {user_room}")
|
||||
logger.info(f"🔐 User {user_id} authenticated and joined room {user_room}")
|
||||
|
||||
# Send current credits on authentication
|
||||
emit("auth_success", {"user": user})
|
||||
emit("credits_changed", {"credits": user["credits"]})
|
||||
|
||||
except Exception:
|
||||
logger.exception("Error handling SocketIO authentication")
|
||||
logger.exception("🔐 Error handling SocketIO authentication")
|
||||
emit("auth_error", {"error": "Authentication failed"})
|
||||
disconnect()
|
||||
|
||||
|
||||
@socketio.on("test_event")
|
||||
def handle_test_event(data):
|
||||
"""Test handler to verify SocketIO events are working."""
|
||||
print(f"🧪 TEST EVENT HANDLER CALLED: {request.sid}")
|
||||
logger.info(f"🧪 TEST EVENT received: {data}")
|
||||
emit("test_response", {"message": "Test event received successfully"})
|
||||
|
||||
|
||||
@socketio.on("disconnect")
|
||||
def handle_disconnect() -> None:
|
||||
def handle_disconnect():
|
||||
"""Handle client disconnection."""
|
||||
print(f"🔌 DISCONNECT EVENT HANDLER CALLED: {request.sid}")
|
||||
try:
|
||||
user = SocketIOService.get_user_from_socketio()
|
||||
if user:
|
||||
@@ -132,3 +177,20 @@ def handle_disconnect() -> None:
|
||||
|
||||
# Export the service instance
|
||||
socketio_service = SocketIOService()
|
||||
|
||||
# Debug: Print registered event handlers
|
||||
try:
|
||||
print(f"🔧 SocketIO Service: Registered event handlers: {list(socketio.server.handlers.keys())}")
|
||||
print(f"🔧 SocketIO Service: Namespace handlers: {socketio.server.handlers.get('/', {})}")
|
||||
except Exception as e:
|
||||
print(f"🔧 SocketIO Service: Error accessing handlers: {e}")
|
||||
print(f"🔧 SocketIO Service: SocketIO server: {socketio.server}")
|
||||
print(f"🔧 SocketIO Service: SocketIO instance: {socketio}")
|
||||
|
||||
# Test manual event registration
|
||||
@socketio.on("manual_test")
|
||||
def handle_manual_test(data):
|
||||
"""Manual test handler."""
|
||||
print(f"🧪 MANUAL TEST EVENT: {data}")
|
||||
|
||||
print("🔧 SocketIO Service: Manual test handler registered")
|
||||
|
||||
Reference in New Issue
Block a user