Vijay Ande
Vijay Ande

Reputation: 111

sending response to particular django websocket client from rest api or a server

consumer.py

    # accept websocket connection
    def connect(self):
    self.accept()

    # Receive message from WebSocket
    def receive(self, text_data):
     text_data_json = json.loads(text_data)
     command = text_data_json['command']
     job_id = text_data_json['job_id']
     if command == 'subscribe':
        self.subscribe(job_id)
     elif command == 'unsubscribe':
        self.unsubscribe(job_id)
     else:
        self.send({
            'error': 'unknown command'
        })

   # Subscribe the client to a particular 'job_id'
   def subscribe(self, job_id):
    self.channel_layer.group_add(
        'job_{0}'.format(job_id),
        self.channel_name
    )       

   # call this method from rest api to get the status of a job
   def send_job_notification(self, message, job_id):
    channel_layer = get_channel_layer()
    group_name = 'job_{0}'.format(job_id)
    channel_layer.group_send(
    group_name,
    {
        "type": "send.notification", 
        "message": message, 
    }
)   

# Receive message from room group
def send_notification(self, event):
    message = event['message']
    # Send message to WebSocket
    self.send(text_data=json.dumps(
     message))

In the above code what I am trying to do is connect clients to the socket and subscribe clients to a particular "job_id" by creating a group called "job_1" using "subscribe" method and add it to the channel layer. Creation of groups are dynamic.

I am using below "simple websocket client extension" from Google to connect to the above websocket. I am able to make a connection with the websocket and send request to it as shown in the picture below.

enter image description here

Now since the client is connected and subscribed to a particular "job_id", I am using "Postman" to send notification to the above connected client(simple websocket client extension) subscribed to particular "job_id" by passing in the job_id in the request as highlighted in yellow below.

when I do a post to the "REST-API" I am calling "send_job_notification(self, message, job_id)" method of "consumer.py" file along with the "job_id" as '1' shown in the picture below in yellow

enter image description here

After doing all this I don't see any message sent to the connected client subscribed to a "job_id" from the "REST-API" call.

Any help would be highly appreciated as it has been dragging on for a long time.

Edit:

thank you for the suggestion Ken its worth to make the method as "@staticmethod" but Ken how do I make the API send job status updates to the connected Clients because my long running jobs would run in some process and send update messages back to the backend via REST-API and the updates then need to be sent to the correct Client (via websockets).

My API call to the socket consumer is as below:

from websocket_consumer import consumers class websocket_connect(APIView): def post(self, request, id): consumers.ChatConsumer.send_job_notification("hello",id)

My socket consumer code is as below: enter image description here

Edit

`CHANNEL_LAYERS = {
"default": {
    "BACKEND": "channels_redis.core.RedisChannelLayer",
    "CONFIG": {
        "hosts": [("localhost", 6379)],
    },
},

}` As you can see 'Redis' service is also running enter image description here

Edit-1

enter image description here

Upvotes: 3

Views: 2489

Answers (1)

Ken4scholars
Ken4scholars

Reputation: 6296

You cannot call the method in the consumer directly from an external code because you need to get the particular consumer instance connected to your client. This is the job of the channel layer achieved by using a message passing system or broker as reddis. From what I can see, you're already going towards the right direction, except that the send_job_notification is an instance method which will require instantiating the consumer. Make it a static method instead, so you can call it directly without a consumer instance

@staticmethod
def send_job_notification(message, job_id):
    channel_layer = get_channel_layer()
    group_name = 'job_{0}'.format(job_id)
    channel_layer.group_send(
    group_name,
    {
        "type": "send.notification", 
        "message": message, 
    }

And in your API view, you can simply call it as: ChatConsumer.send_job_notification(message, job_id)

Upvotes: 1

Related Questions