Django Каналы - получение JSON объектов - PullRequest
0 голосов
/ 21 января 2020

для проекта WebRTC, мне нужно создать механизм сигнализации. Я использую Django Channels для этой работы. Как вы, возможно, знаете в WebRTC, есть Session Description объекты, которые будут передаваться взад и вперед как «предложение» / «ответ», а также есть ICE candidate объекты, которые также будут передаваться между двумя (или более) клиентами , Немного поиграв с Django Channels, я написал следующего потребителя:

'''
A basic consumer that accepts WebSocket connections on the path
/ws/chat/ROOM_NAME/ that takes any message it receives on the
WebSocket and echos it back to the same WebSocket.

we want to have multiple instances of SignallingConsumer in the same room communicate
with each other. To do that we will have each SignallingConsumer add its channel
to a group whose name is based on the room name. That will allow SignallingConsumers
to transmit messages to all other SignallingConsumers in the same room.
'''
class SignallingConsumer(WebsocketConsumer):

    def connect(self):
        print("connect() is called.")

        '''
        Obtains the 'room_name' parameter from the URL route in chat/routing.py
        that opened the WebSocket connection to the consumer.
        Every consumer has a scope that contains information about its connection,
        including in particular any positional or keyword arguments from the URL route
        and the currently authenticated user if any.
        '''
        self.room_name = self.scope['url_route']['kwargs']['room_name']

        '''
        Constructs a Channels group name directly from the user-specified room name,
        without any quoting or escaping.
        Group names may only contain letters, digits, hyphens, and periods.
        Therefore this example code will fail on room names that have other characters.
        '''
        self.room_group_name = 'chat_%s' % self.room_name



        '''
        Join room group by adding the channel name to the group.
        The async_to_sync(…) wrapper is required because ChatConsumer is a synchronous
        WebsocketConsumer but it is calling an asynchronous channel layer method.
        (All channel layer methods are asynchronous.)
        Group names are restricted to ASCII alphanumerics, hyphens, and periods only.
        Since this code constructs a group name directly from the room name, it will
        fail if the room name contains any characters that aren’t valid in a group
        name.
        '''
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name
        )


        '''
        Accepts the WebSocket connection.
        If you do not call accept() within the connect() method then the
        connection will be rejected and closed. You might want to reject a
        connection for example because the requesting user is not authorized
        to perform the requested action.
        It is recommended that accept() be called as the last action
        in connect() if you choose to accept the connection.
        '''
        self.accept()

    def disconnect(self, close_code):
        print("disconnect() is called.")

        # Leave room group
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name
        )

    # Receive message from WebSocket
    # text_data is of type String 
    def receive(self, text_data):
        print("Received data: " + text_data)

        # json.loads(): takes in a String and returns a JSON object
        # text_data_json is of type JSONObject
        text_data_json = json.loads(text_data)

        async_to_sync(self.channel_layer.group_send)(
                self.room_group_name,
                {
                    'type': 'offer_answer_message',
                    'data': text_data_json
                }
        )


    def offer_answer_message(self, event):
        # we access the JSONObject via event['data'] and
        # store it into data variable
        data = event['data']


        # json.dumps(): takes in a JSONObject and returns a String
        self.send(json.dumps(data))

Комментарии в основном для меня. Я немного подправил код с официального сайта Django Channels для моей цели. На мой вопрос, метод receive() очень важен. Вопросы, касающиеся этого, следующие:

  1. Итак, потребитель должен передать предложение (или ответ) от клиента A (или клиента B) другому удаленному партнеру. Это работает здесь?
  2. Кроме того, ICE candidates, который содержит информацию о сети об одноранговом узле, также должен быть передан удаленному узлу. Это работает здесь?
  3. Метод receive() принимает в качестве параметра строку. По этой причине мне нужно преобразовать мои JSON объекты в строки на стороне клиента перед их отправкой. Мне не нравится это решение. Я бы предпочел передать объекты JSON непосредственно методу receive() на стороне сервера. Как бы я это сделал?

1 Ответ

0 голосов
/ 12 апреля 2020
  1. Да, вы можете получить предложение или ответ, используя этот метод получения, скажем, один хост, другой равноправный, вы уже создали группу ... так что просто пересылайте предложение / ответ в соответствии с требуемым потребителем Следите за типом сообщения, то есть его предложением / ответом.

  2. Аналогично, когда вы устанавливаете удаленное описание или локальное описание на стороне клиента, событие onicecandidate должно быть обрабатывается путем отправки информации о кандидате другому клиенту так же, как предложение и ответ.

PC.onicecandidate = (event)=>{ if(iceCand){ await Socket.send(JSON.stringify({ "who" : "user1", "for" : "user2", "candidate" : event.candidate })); } };

Вам нужно получить его через JSON ... в противном случае вы не получите никаких данных для ключа-кандидата в dict, указанном в приведенном выше коде ... но для AsyncConsumer или SyncConsumer метод приема принимает в качестве dict Насколько я знаю, диктовать, как указано ниже:

event = {"type" : "websocket.receive", "text" : data}

...