My chat user are not connecting each other

i am building a a private chat and calls both voice and video that preach privacy, with full privacy end to end, no message stored or saved to the backend, and every message is encrypted, so no one could breach it, every user has been given the power to thier own chat, now no matter what i do the chat isnt working i feel like my my consumer.py is not well written, i want user to chat and video call each other, but they are not chatting for example a user is not connecting with each other, its like they are not in a room together

class SecureChatConsumer(AsyncWebsocketConsumer):

async def connect(self):
    self.user = self.scope['user']
    self.friend_username = self.scope['url_route']['kwargs']['username']

    if not self.user.is_authenticated:
        await self.close()
        return

    try:
        # Create a shared room name between both users for proper communication
        self.room_name = f"chat_{'_'.join(sorted([self.user.username, self.friend_username]))}"
        
        await self.channel_layer.group_add(self.room_name, self.channel_name)
        await self.update_user_status(online=True)
        await self.accept()
        logger.info(f"WebSocket connection established for user {self.user.username} in room {self.room_name}")
    except Exception as e:
        logger.error(f"Error during WebSocket connection: {e}")
        await self.close()

async def disconnect(self, close_code):
    await self.channel_layer.group_discard(self.room_name, self.channel_name)
    await self.update_user_status(online=False)
    logger.info(f"WebSocket disconnected for user {self.user.username}")

async def receive(self, text_data):
    """
    Handle incoming WebSocket messages. Distinguish between message events and WebRTC events.
    """
    try:
        data = json.loads(text_data)
        message_type = data.get('type')
        logger.info(f"Received message of type '{message_type}' from {self.user.username}")
    except json.JSONDecodeError as e:
        logger.error(f"Error parsing message data: {e}")
        await self.send_error("Invalid JSON format.")
        return

    if message_type == 'message':
        await self.handle_message_event(data)
    elif message_type in ['call-offer', 'call-answer', 'ice-candidate']:
        await self.handle_webrtc_event(data)
    elif message_type == 'public-key':
        await self.handle_key_exchange(data)
    else:
        logger.warning(f"Unknown message type received: {message_type}")
        await self.send_error("Unknown message type.")

async def handle_message_event(self, data):
    """
    Handle secure chat message events between two users using end-to-end encryption.
    """
    message = data.get('message')
    recipient_username = data.get('to')

    if message and recipient_username:
        logger.info(f"Forwarding encrypted message from {self.user.username} to {recipient_username}")
        await self.send_encrypted_message(recipient_username, message)

async def handle_webrtc_event(self, data):
    """
    Handle WebRTC signaling for peer-to-peer voice and video calls.
    """
    recipient_username = data.get('to')
    event_type = data['type']
    event_data = data['data']

    logger.info(f"Forwarding WebRTC signal '{event_type}' from {self.user.username} to {recipient_username}")
    await self.forward_webrtc_signal(recipient_username, event_type, event_data)

async def handle_key_exchange(self, data):
    """
    Handle the exchange of public keys for secure messaging.
    """
    recipient_username = data.get('to')
    public_key = data.get('publicKey')

    if public_key and recipient_username:
        logger.info(f"Forwarding public key from {self.user.username} to {recipient_username}")
        await self.send_public_key(recipient_username, public_key)

async def send_encrypted_message(self, recipient_username, message):
    """
    Send an encrypted message to the recipient via the WebSocket group.
    """
    await self.channel_layer.group_send(
        f"chat_{'_'.join(sorted([self.user.username, recipient_username]))}",
        {
            'type': 'chat_message',
            'message': message,
            'sender': self.user.username
        }
    )

async def chat_message(self, event):
    """
    Deliver the chat message to the WebSocket client.
    """
    await self.send(text_data=json.dumps({
        'type': 'message',
        'message': event['message'],
        'sender': event['sender']
    }))

async def forward_webrtc_signal(self, recipient_username, signal_type, data):
    """
    Forward WebRTC signaling data to the specified recipient.
    """
    await self.channel_layer.group_send(
        f"chat_{'_'.join(sorted([self.user.username, recipient_username]))}",
        {
            'type': signal_type,
            'data': data,
            'sender': self.user.username
        }
    )

async def call_offer(self, event):
    """
    Send a WebRTC call offer to the recipient.
    """
    await self.send(text_data=json.dumps({
        'type': 'call-offer',
        'offer': event['data'],
        'from': event['sender']
    }))

async def call_answer(self, event):
    """
    Send a WebRTC call answer to the recipient.
    """
    await self.send(text_data=json.dumps({
        'type': 'call-answer',
        'answer': event['data'],
        'from': event['sender']
    }))

async def ice_candidate(self, event):
    """
    Send an ICE candidate to the recipient to assist in the WebRTC connection setup.
    """
    await self.send(text_data=json.dumps({
        'type': 'ice-candidate',
        'candidate': event['data'],
        'from': event['sender']
    }))

async def send_public_key(self, recipient_username, public_key):
    """
    Send the public key to the recipient via the WebSocket group.
    """
    await self.channel_layer.group_send(
        f"chat_{'_'.join(sorted([self.user.username, recipient_username]))}",
        {
            'type': 'public-key',
            'publicKey': public_key,
            'sender': self.user.username
        }
    )

async def public_key(self, event):
    """
    Deliver the public key to the WebSocket client.
    """
    await self.send(text_data=json.dumps({
        'type': 'public-key',
        'publicKey': event['publicKey'],
        'sender': event['sender']
    }))

@database_sync_to_async
def update_user_status(self, online):
    """
    Update the user's online status in the database.
    """
    try:
        user_profile = UserProfile.objects.get(username=self.user.username)
        user_profile.online = online
        user_profile.save()
    except UserProfile.DoesNotExist:
        logger.error(f"User profile not found for {self.user.username}")

async def send_error(self, message):
    """
    Send an error message to the client.
    """
    await self.send(text_data=json.dumps({
        'status': 'error',
        'message': message
    }))

this is my javascript code also,

document.addEventListener("DOMContentLoaded", function () {
// WebSocket connection setup
const socketProtocol = window.location.protocol === "https:" ? "wss" : "ws";
const chatSocket = new WebSocket(`${socketProtocol}://${window.location.host}/ws/chat/${friendUsername}/`);

chatSocket.onopen = () => {
    console.log("WebSocket connection established.");
    const userStatusElement = document.getElementById(`status-${friendUsername}`);
    if (userStatusElement) {
        userStatusElement.textContent = 'Online';
    }
};

chatSocket.onclose = () => {
    console.log("WebSocket connection closed.");
    const userStatusElement = document.getElementById(`status-${friendUsername}`);
    if (userStatusElement) {
        userStatusElement.textContent = 'Offline';
    }
};

chatSocket.onerror = (error) => {
    console.error("WebSocket error:", error);
};

// WebRTC configuration
const peerConnectionConfig = {
    iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
};
let peerConnection = new RTCPeerConnection(peerConnectionConfig);

// Handle ICE candidate events
peerConnection.onicecandidate = (event) => {
    if (event.candidate) {
        chatSocket.send(JSON.stringify({
            type: 'ice-candidate',
            data: event.candidate,
            to: friendUsername
        }));
    }
};

// Handle remote video stream
peerConnection.ontrack = (event) => {
    const remoteStream = event.streams[0];
    const remoteVideo = document.getElementById('remoteVideo');
    remoteVideo.srcObject = remoteStream;
    remoteVideo.play();
};

// Function to securely exchange public keys with the other user
async function securelyExchangeKeys() {
    const keyPair = await generateECDHKeys();
    localECDHPrivateKey = keyPair.privateKey;
    const exportedPublicKey = await window.crypto.subtle.exportKey('raw', keyPair.publicKey);

    // Send the public key to the friend via WebSocket for exchange
    chatSocket.send(JSON.stringify({
        type: 'public-key',
        publicKey: Array.from(new Uint8Array(exportedPublicKey)), // Converting to array for transmission
        to: friendUsername
    }));
    console.log('Public key sent to the friend for secure key exchange.');
}

// Function to send an encrypted message to the server
function sendMessageToServer(ciphertext, iv) {
    if (chatSocket.readyState === WebSocket.OPEN) {
        chatSocket.send(JSON.stringify({
            type: 'message',
            message: ciphertext,
            iv: iv,
            to: friendUsername
        }));
        console.log("Message sent to the server.");
    } else {
        console.error("WebSocket is not open. Unable to send message.");
        alert("Connection lost. Please wait while we try to reconnect.");
    }
}

// Send encrypted chat message when the send button is clicked
document.getElementById('send-button').addEventListener('click', async () => {
    const messageInput = document.getElementById('message-input');
    const message = messageInput.value.trim();

    if (message !== '') {
        try {
            if (!sharedKey) {
                console.error("Shared key is not defined. Cannot encrypt the message.");
                alert("Encryption key not ready. Please wait before sending messages.");
                return;
            }
            const { ciphertext, iv } = await encryptMessage(sharedKey, message);
            sendMessageToServer(ciphertext, iv);
            messageInput.value = ''; // Clear the input field
            displayLocalMessage(message); // Display the message in the sender's chat log
        } catch (encryptionError) {
            console.error("Error during message encryption:", encryptionError);
            alert("Failed to send message. Please try again.");
        }
    }
});

// WebSocket message handling
chatSocket.onmessage = async function (event) {
    const data = JSON.parse(event.data);

    if (data.type === 'public-key') {
        console.log('Received public key from the friend.');
        const publicKeyArray = new Uint8Array(data.publicKey);
        try {
            const importedPublicKey = await window.crypto.subtle.importKey(
                'raw',
                publicKeyArray.buffer,
                { name: 'ECDH', namedCurve: 'P-256' },
                true,
                []
            );
            sharedKey = await deriveSharedSecret(localECDHPrivateKey, importedPublicKey);
            console.log('Shared key successfully derived for secure messaging!');
        } catch (keyError) {
            console.error("Error deriving shared key:", keyError);
        }
    } else if (data.type === 'message') {
        if (sharedKey) {
            const decryptedMessage = await decryptMessage(sharedKey, data.message, data.iv);
            displayDecryptedMessage(data.sender, decryptedMessage);
        } else {
            console.error("Shared key is not defined. Cannot decrypt the message.");
        }
    } else {
        handleWebRTCSignal(data); // Handle WebRTC signals like calls, answers, etc.
    }
};

// Event listeners for audio and video calls
document.getElementById('voice-call').addEventListener('click', startVoiceCall);
document.getElementById('video-call').addEventListener('click', startVideoCall);

// Start a video call
async function startVideoCall() {
    const localStream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
    localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));
    displayLocalVideoStream(localStream);

    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);

    chatSocket.send(JSON.stringify({
        type: 'call-offer',
        data: offer,
        to: friendUsername
    }));
}

// Start a voice call
async function startVoiceCall() {
    const localStream = await navigator.mediaDevices.getUserMedia({ audio: true });
    localStream.getTracks().forEach(track => peerConnection.addTrack(track, localStream));
    displayLocalVideoStream(localStream);

    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);

    chatSocket.send(JSON.stringify({
        type: 'call-offer',
        data: offer,
        to: friendUsername
    }));
}

// Handle WebRTC signaling messages for the call
async function handleWebRTCSignal(data) {
    switch (data.type) {
        case 'call-offer':
            await peerConnection.setRemoteDescription(new RTCSessionDescription(data.data));
            const answer = await peerConnection.createAnswer();
            await peerConnection.setLocalDescription(answer);
            chatSocket.send(JSON.stringify({
                type: 'call-answer',
                data: answer,
                to: friendUsername
            }));
            break;
        case 'call-answer':
            await peerConnection.setRemoteDescription(new RTCSessionDescription(data.data));
            break;
        case 'ice-candidate':
            if (data.data) {
                await peerConnection.addIceCandidate(new RTCIceCandidate(data.data));
            }
            break;
        default:
            console.warn("Unhandled WebRTC signal:", data.type);
    }
}

// Display local video stream
function displayLocalVideoStream(stream) {
    const localVideo = document.getElementById('localVideo');
    localVideo.srcObject = stream;
    localVideo.play();
}

// Cleanup on page unload
window.addEventListener('beforeunload', () => {
    sessionStorage.clear();
    peerConnection.close();
});});

this is my chats.html also

{% extends "chat/Base.html" %}
{% load static %}

{% block content %}
<link rel="stylesheet" href="{% static 'css/chat/chats.css' %}">

<body class="dark-theme">

<!-- Chat Container -->
<div class="chat-container">
    <!-- Chat Header Section -->
    <div class="chat-header">
        <button class="back-button" 
     onclick="window.location.href='{% url 'chat:dashboard' %}'">
            <i class="fas fa-arrow-left"></i> Friends
        </button>
        <div class="chat-user-info">
            <div class="user-avatar">
                <img src="https://api.dicebear.com/9.x/adventurer/png?seed={{ friend.name }}" alt="User Avatar">
            </div>
            <div class="user-details">
                <h3 id="friend-name">{{ friend.name }}</h3>
                <p class="user-status" id="status-{{ friend.username }}">Offline</p>
            </div>
        </div>
        <div class="chat-actions">
            <button class="icon-button" id="voice-call" title="Voice Call">
                <i class="fas fa-phone-alt"></i>
            </button>
            <button class="icon-button" id="video-call" title="Video Call">
                <i class="fas fa-video"></i>
            </button>
        </div>
    </div>

    <!-- Video Call Container -->
    <div class="video-container">
        <video id="localVideo" autoplay muted></video>
        <video id="remoteVideo" autoplay></video>
    </div>

    <!-- Chat Messages Section -->
    <div class="chat-messages" id="chat-log"></div>

    <!-- Message Input Section -->
    <div class="chat-input-section">
        <input type="text" id="message-input" placeholder="Type your message..." autocomplete="off">
        <button id="send-button" class="send-button"><i class="fas fa-paper-plane"></i></button>
    </div>
</div>

<script>
    const friendUsername = "{{ friend.username }}"; // Assign friend's username to a JS variable
</script>
<script src="{% static 'js/chat/chats.js' %}"></script>
{% endblock %}
Вернуться на верх