I've got a web service under development that uses Django and Django 
Channels to send data across websockets to a remote application. The 
arrangement is asynchronous and I pass information between the 2 by sending 
JSON formatted commands across websockets and then receive replies back on 
the same websocket.

The problem I'm having is figuring out how to get the replies back to a 
Javascript call from a Django template that invokes a Python function to 
initiate the JSON websocket question. Since the command question & data 
reply happen in different Django areas and the originating 
Javascript/Python functions call does not have a blocking statement, the 
Q&A are basically disconnected and I can't figure out how to get the 
results back to the browser.

Right now, my idea is to use Django global variables or store the results 
in the Django models. I can get either to work, but I beleive the Django 
global variables would not scale beyond multiple workers from runserver or 
if the system was eventually spread across multiple servers. 

But since the reply data is for different purposes (for example, list of 
users waiting in a remote lobby, current debugging levels in remote system, 
etc), the database option seems unworkable because the reply data is 
varying structure. That, plus the replies are temporal and don't need to be 
permanently stored in the database.

Here's some code showing the flow. I'm open to different implementation 
recommendations or a direct answer to the question of how to share 
information between the 2 Django functions.

In the template, for testing, I just have a button defined like this:

    <button id="request_lobby">Request Lobby</button>


With a Javascript function. This function is incomplete as I've yet to do 
anything about the response (because I can't figure out how to connect it):

            $("#request_lobby").click(function(){
                $.ajax({
                    type: "POST",
                    url: "{% url 'test_panel_function' %}",
                    data: { csrfmiddlewaretoken: '{{ csrf_token }}', button:
"request_lobby" },
                    success: function(response){
                    }
                });
            });


This is the Django/Python function in views.py . The return channel for the 
remote application is pre-stored in the database as srv.server_channel when 
the websocket is initially connected (not shown):

    @login_required
    def test_panel_function(request):

        button = request.POST.get('button', '')

        if button == "request_lobby" :
            srv = Server.objects.get(server_key="1234567890")
            json_res = []
            json_res.append({"COMMAND": "REQUESTLOBBY"})
            message = ({
                "text": json.dumps(json_res)
            })
            Channel(srv.server_channel).send(message)
            return HttpResponse(button)



Later, the remote application sends the reply back on the websocket and 
it's received by a Django Channels demultiplexer in routing.py :

    class RemoteDemultiplexer(WebsocketDemultiplexer):
        mapping = {
            "gLOBBY"   : "gLOBBY.receive",
        }
        http_user = True
        slight_ordering = True
          
        
    channel_routing = [
        route_class(RemoteDemultiplexer, path=r
"^/server/(?P<server_key>[a-zA-Z0-9]+)$"),
        route("gLOBBY.receive"   , command_LOBBY),
    ]



And the consumer.py :

    @channel_session    
    def command_LOBBY(message):
        skey = message.channel_session["server_key"]
        for x in range(int(message.content['LOBBY'])):
            logger.info("USERNAME:  " + message.content[str(x)]["USERNAME"])
            logger.info("LOBBY_ID:  " + message.content[str(x)]["LOBBY_ID"])
            logger.info("OWNER_ID:  " + message.content[str(x)]["IPADDRESS"
])
            logger.info("DATETIME:  " + message.content[str(x)]["DATETIME"])


So I need to figure out how to get the reply data in command_LOBBY to the 
Javascript/Python function call in test_panel_function

Current ideas, both of which seem bad and why I think I need to ask this 
question for SO:

*1) Use Django global variables:*

Define in globals.py:

    global_async_result = {}



And include in all relevant Django modules:

    from test.globals import global_async_result


In order to make this work, when I originate the initial command in 
test_panel_function to send to the remote application (the REQUESTLOBBY), 
I'll include a randomized key in the JSON message which would be 
round-tripped back to command_LOBBY and then global_async_result dictionary 
would be indexed with the randomized key.

In test_panel_function , I would wait in a loop checking a flag for the 
results to be ready in global_async_result and then retrieve them from the 
randomized key and delete the entry in global_async_result.

Then the reply can be given back to the Javascript in the Django template.

That all makes sense to me, but uses global variables (bad), and seems that 
it wouldn't scale as the web service is spread across servers.

*2) Store replies in Django mySQL model.py table*

I could create a table in models.py to hold the replies temporarily. Since 
Django doesn't allow for dynamic or temporary table creations on the fly, 
this would have to be a pre-defined table.

Also, because the websocket replies would be different formats for 
different questions, I could not know in advance all the fields ever needed 
and even if so, most fields would not be used for differing replies.

My workable idea here is to create the reply tables using a field for the 
randomized key (which is still routed back round-trip through the 
websocket) and another large field to just store the JSON reply entirely.

Then in test_panel_function which is blocking in a loop waiting for the 
results, pull the JSON from the table, delete the row, and decode. Then the 
reply can be given back to the Javascript in the Django template.

*3) Use Django signals*

Django has a signals capability, but the response function doesn't seem to 
be able to be embedded (like inside test_panel_function) and there seems to 
be no wait() function available for an arbitrary function to just wait for 
the signal. If this were available, it would be very helpful

-- 
You received this message because you are subscribed to the Google Groups 
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-users+unsubscr...@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-users/728d41d3-2fbf-405f-bf5a-b861deaf42be%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to