fanout / django-grip

Django GRIP library
MIT License
68 stars 10 forks source link

unable to open websocket in django #2

Closed andy-io closed 8 years ago

andy-io commented 8 years ago

Hi,

I am trying to open a websocket using pushpin in django. I am getting the following error.

route file is * 127.0.0.1:8000,over_http

I have started the pushpin proxy server, installed django grip, configured the settings file.

i have copied the example websocket view code in readme which is:

@websocket_only
def echo(request):
print(request)
# since we used the decorator, this will always be a non-None value
ws = request.wscontext

# if this is a new connection, accept it and subscribe it to a channel
if ws.is_opening():
    ws.accept()
    ws.subscribe('test')

# here we loop over any messages
while ws.can_recv():
    message = ws.recv()

    # if return value is None, then the connection is closed
    if message is None:
        ws.close()
        break

    # echo the message
    ws.send(message)

my url config to the view is

url(r'^socket/$', echo, name="socket"),

This urlconf is included in the root urlconf for the regex starting with 'users/'

In the client side, i use an example websocket connection opening code

<script type="text/javascript">
    function WebSocketTest() {
        if ("WebSocket" in window) {
            alert("WebSocket is supported by your Browser!");

            // Let us open a web socket
            var ws = new WebSocket("ws://127.0.0.1:7999/users/socket");

            ws.onopen = function () {
                // Web Socket is connected, send data using send()
                alert("Message is sent...");
            };

            ws.onmessage = function (evt) {
                var received_msg = evt.data;
                alert("Message is received...");
            };

            ws.onclose = function () {
                // websocket is closed.
                alert("Connection is closed...");
            };
        }

        else {
            // The browser doesn't support WebSocket
            alert("WebSocket NOT supported by your Browser!");
        }
    }
</script>

<div id="sse">
    <a href="javascript:WebSocketTest()">Run WebSocket</a>
</div>

clicking on the run websocket on the browser shows the first alert that browser supports websocket and then it shows the alert that the websocket connection is closed.

The local django dev server shows the following in the terminal:

[26/Dec/2015 16:56:17] "POST /users/socket HTTP/1.1" 500 81431

Could you help me figure out where I am going wrong ?

Thanks and regards, Andy

jkarneges commented 8 years ago

Try making a websocket-events request directly to the Django app:

curl -i -H 'Content-Type: application/websocket-events' -d OPEN$'\r'$'\n' \
    http://127.0.0.1:8000/users/socket

What response do you get?

andy-io commented 8 years ago

this is the response i get:

HTTP/1.0 500 INTERNAL SERVER ERROR
Date: Sat, 26 Dec 2015 21:43:26 GMT
Server: WSGIServer/0.1 Python/2.7.10
X-Frame-Options: SAMEORIGIN
Content-Type: text/html
jkarneges commented 8 years ago

Hopefully the Django error page can tell us more. Set DEBUG = True in settings.py and pipe the output of curl to a file (e.g. > out.html) and view the file in a browser.

andy-io commented 8 years ago

I saved the error page and this is the error i see:

Exception Type: RuntimeError Exception Value:
You called this URL via POST, but the URL doesn't end in a slash and you have APPEND_SLASH set. Django can't redirect to the slash URL while maintaining POST data. Change your form to point to 127.0.0.1:8000/users/socket/ (note the trailing slash), or set APPEND_SLASH=False in your Django settings.

I added APPEND_SLASH=False in the settings.py and now i see a 404 error page.

jkarneges commented 8 years ago

A 404 error likely means a Django routing issue and not anything to do with django-grip. The error page should show the known routes so it should be easy to see why nothing matched.

andy-io commented 8 years ago

Using the URLconf defined in sxk.urls, Django tried these URL patterns, in this order:

^users/ ^socket/$ [name='socket']

The current URL, users/socket, didn't match any of these.

jkarneges commented 8 years ago

Ah, because you've got a trailing slash in the pattern. Remove that and I bet it'll work.

andy-io commented 8 years ago

I removed the trailing slash. Now its a csrf verification failed error. Forbidden (403) CSRF verification failed. Request aborted. You are seeing this message because this site requires a CSRF cookie when submitting forms. This cookie is required for security reasons, to ensure that your browser is not being hijacked by third parties. If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for 'same-origin' requests.

andy-io commented 8 years ago

should i change the route in pushpin to use without over_http ?

jkarneges commented 8 years ago

Progress! Now remove/comment-out the csrf middleware in settings.py. That's Django blocking POSTs that didn't come from a web form.

andy-io commented 8 years ago

i added a csrf exepmt decorator and i suppose it should work, will post it in a while ;-)

andy-io commented 8 years ago

working ^^ :-) i will have some more doubts still to push the data from a model into the browser using angular in front end. Let this thread be open. I will close it if i dont have any other doubts. Thanks for your wonderful support. Wishing you a happy new year mate :-)

andy-io commented 8 years ago

Should i always access my site using the pushpin port or could i access it using django's port and let my angularjs app connect with pushpin ?

  1. 127.0.0.1:7999 or
  2. 127.0.0.1:8000 and angularjs opens a socket by calling 127.0.0.1:7999/users/socket ?

When i access my site using the first approach, i see some random get requests calling some unavaliable sass files in my server, looks like some malware attack. I am unable to figure out from where these requests are coming.

Second approach works fine without any problem.

jkarneges commented 8 years ago

Pushpin is designed to be able to front an entire web service. Whether you should run all requests through Pushpin or only the WebSocket stuff is a matter of how much you care about having a single base URL for everything.

The random GET requests seems strange. Is it reproducible?

andy-io commented 8 years ago

ok got it, the random get requests seem to arise from my front front end components which i am still trying to figure out. They are not from push pin.

andy-io commented 8 years ago

Is it possible to publish events when using websockets using django grip ? At the moment, all events are sent with type message.

jkarneges commented 8 years ago

What do you mean "sent with type message"?

andy-io commented 8 years ago

i publish messages to a channel like this: publish("channel", WebSocketMessageFormat(message))

Examining this message in console as log shows that event type is message. How to send different types of events ?

jkarneges commented 8 years ago

Ah, you mean the argument sent to the onmessage handler? I believe the type is always "message" here and there is no way for the server to affect this. If you want to differentiate types of messages you'll need to include that information in the message data itself.

andy-io commented 8 years ago

Thanks I did the same by sending it in the message itself. How to broadcast a message to all subscribed channels ?

jkarneges commented 8 years ago

Published messages are sent to all subscribers of a channel. If you want to broadcast to all connected clients, make sure all connections are also subscribed to a common channel (e.g. "all"), and then publish to that channel.

andy-io commented 8 years ago

Super. I didnt think of an easy way of subscribing to a common channel. Thanks for your support and time.