from flask_jwt_extended import create_access_token, get_jwt_identity, verify_jwt_in_request, decode_token from flask_socketio import emit, disconnect from flask import current_app, request from common.extensions import socketio, kms_client from common.models.user import Tenant @socketio.on('connect') def handle_connect(): try: current_app.logger.debug(f'SocketIO: Connection handling started using {request.args}') tenant_id = request.args.get('tenantId') if not tenant_id: raise Exception("Missing Tenant ID") api_key = request.args.get('apiKey') if not api_key: raise Exception("Missing API Key") current_app.logger.info(f'SocketIO: Connection handling found Tenant {tenant_id} with API Key {api_key}') if not validate_api_key(tenant_id, api_key): raise Exception("Invalid tenant_id - api_key combination") # Create JWT token token = create_access_token(identity={"tenant_id": tenant_id, "api_key": api_key}) current_app.logger.debug(f'SocketIO: Connection handling created token: {token} for tenant {tenant_id}') # Communicate connection to client emit('connect', {'status': 'Connected', 'tenant_id': tenant_id}) emit('authenticated', {'token': token}) # Emit custom event with the token current_app.logger.debug(f'SocketIO: Connection handling sent token to client for tenant {tenant_id}') except Exception as e: current_app.logger.error(f'SocketIO: Connection failed: {e}') # communicate connection problem to client emit('connect_error', {'status': 'Connection Failed'}) disconnect() @socketio.on('disconnect') def handle_disconnect(): current_app.logger.debug('SocketIO: Client disconnected') @socketio.on('user_message') def handle_message(data): try: current_app.logger.debug(f"SocketIO: Message handling received message from tenant {data['tenantId']}: " f"{data['message']} with token {data['token']}") token = data.get('token') if not token: raise Exception("Missing token") # decoded_token = decode_token(token.split(" ")[1]) # remove "Bearer " decoded_token = decode_token(token) if not decoded_token: raise Exception("Invalid token") current_app.logger.debug(f"SocketIO: Message handling decoded token: {decoded_token}") token_sub = decoded_token.get('sub') current_tenant_id = token_sub.get('tenant_id') if not current_tenant_id: raise Exception("Missing tenant_id") current_api_key = token_sub.get('api_key') if not current_api_key: raise Exception("Missing api_key") # Store interaction in the database response = { 'tenantId': data['tenantId'], 'message': f'This is a bot response. Responding to message {data['message']} ' f'from tenant {current_tenant_id}', 'messageId': 'bot-message-id', 'algorithm': 'alg1' } current_app.logger.debug(f"SocketIO: Message handling sent bot response: {response}") emit('bot_response', response, broadcast=True) except Exception as e: current_app.logger.error(f'SocketIO: Message handling failed: {e}') disconnect() def validate_api_key(tenant_id, api_key): tenant = Tenant.query.get_or_404(tenant_id) decrypted_api_key = kms_client.decrypt_api_key(tenant.encrypted_chat_api_key) return decrypted_api_key == api_key