Как мы можем поделиться потребителем канала как API? - PullRequest
0 голосов
/ 29 апреля 2020

Я создал канал, который реализует некоторые текстовые операции, используя общую задачу, которая возвращает ответ обратно на канальный слой.

#consumers.py

import json
import pdb
from asgiref.sync import async_to_sync
from channels.generic.websocket import AsyncWebsocketConsumer

from . import tasks

COMMANDS = {
    'help': {
        'help': 'Display help message.',
    },
    'sum': {
        'args': 2,
        'help': 'Calculate sum of two integer arguments. Example: `sum 12 32`.',
        'task': 'add'
    },
    'status': {
        'args': 1,
        'help': 'Check website status. Example: `status twitter.com`.',
        'task': 'url_status'
    },
}

class Consumer(AsyncWebsocketConsumer):
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # response_message = 'Please type `help` for the list of the commands.'
        message_parts = message.split()
        if message_parts:
            command = message_parts[0].lower()
            if command == 'help':
                response_message = 'List of the available commands:\n' + '\n'.join([f'{command} - {params["help"]} ' for command, params in COMMANDS.items()])
            elif command in COMMANDS:
                if len(message_parts[1:]) != COMMANDS[command]['args']:
                    response_message = f'Wrong arguments for the command `{command}`.'
                else:
                    getattr(tasks, COMMANDS[command]['task']).delay(self.channel_name, *message_parts[1:])
                    # response_message = f'Command `{command}` received.'
        response_message = message
        await self.channel_layer.send(
                self.channel_name,
                {
                    'type': 'chat_message',
                    'message': response_message
                }
            )

#tasks.py
@shared_task
def add(channel_layer, x, y):
    message = '{}+{}={}'.format(x, y, int(x) + int(y))
    async_to_sync(channel_layer.send)({"type": "chat.message", "message": message})

Я хочу поделиться этим каналом как API, к которому можно получить доступ, используя http запрос. для которого я написал следующие представления.

views.py
@csrf_exempt
@api_view(['POST'])
def api(request):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.send)('test_channel', {'type': 'hello'})
    ret = async_to_sync(channel_layer.receive)(channel_name)
    return JsonResponse({"msg":ret})

При получении из представлений я получаю то же самое сообщение, которое отправил. Как я могу поделиться каналом или обработать входящие сообщения без подключения с помощью WebSockets из шаблона?

1 Ответ

1 голос
/ 29 апреля 2020

Если вы просто хотите, чтобы запрос POST отправил сообщение

views.py
@csrf_exempt
@api_view(['POST'])
def api(request):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.send)('test_channel', {'type': 'chat.message'})
    return JsonResponse({"msg":"sent"})

Вам необходимо убедиться, что вы подписались на test_channel у своего потребителя. И вам понадобится метод для этого потребителя chat_message.

Если вы хотите получить ответ в своем посте

, вы не сможете сделать это, используя channel_layer.send, так как это асин c до такой степени, что у вас нет никакой концепции ответа. Кроме того, может даже не быть запущенного экземпляра вашего потребителя, так как Channels создает экземпляры, только когда у него есть открытые соединения веб-сокетов, которые направляют к ним.

, поэтому я думаю, что вы можете сделать либо:

Для создать экземпляр вашего потребителя и отправить ему сообщение от синхронизации python код будет очень сложным. Я предлагаю вам не использовать этот подход. Он сложный, грязный и может привести к неожиданным последствиям

. Вместо этого я предлагаю переместить код , который вы хотите использовать в своем HTTP view и ваш websocket view в одном месте (не являющемся частью потребителя), где они оба могут вызывать эти функции.

...