2
votes

I'm having difficulty with the Channel API, but only on production. On the dev server this works, but on production I'm getting an Invalid+token error in my javascript, and somehow blank errors in my Python.

Here's my server side code. 'channel_test' is my controller, 'do_send_message' is a function that is deferred, and 'send_message' is a wrapper with a try-except block. Basically it's creating the channel, setting the token as a cookie, and calling deferred tasks until a counter goes up to 100. Each time a task is run, it sends a message over the channel.

def channel_test(self, key):
    if not users.is_current_user_admin(): return 403
    client_id = self.user.email()+key
    token = channel.create_channel(client_id, duration_minutes=10)
    print 'token: %s' % token
    self.response.set_cookie('token', urllib.quote(token))
    deferred.defer(do_send_message, client_id, _queue='retry')

# channel communication
def send_message(client_id, msg):
    """
    msg is a dict
    """
    if client_id:
        print 'client_id: ', client_id
        try:
            channel.send_message(client_id, json.dumps(msg))
            print 'sent message %s' % msg
        except Exception as e:
            print 'something went wrong with msg, %s: %s, %s' % (msg, e, e.__str__())
    else:
        print 'not sending message; no client id'

def do_send_message(client_id, x=10):
    time.sleep(1)

    text = "here's a message! %s" % x
    if x >= 100:
        text = "Done!"
    msg = {"text":text, "percent":x}
    send_message(client_id, msg)

    if x < 100:
        deferred.defer(do_send_message, client_id, x+10, _queue='retry')

Each time 'send_message' is called, it fails, but 'e' doesn't print anything out. Here's the output in the log:

something went wrong with msg, {'text': "here's a message! 10", 'percent': 10}: , 

Furthermore, my client side javascript fails to open the connection. It just get the error 'Invalide+token'. This basically reads the token from the cookie, opens a connection, and each time a message is passed, it writes the message to a notification tray, until the message == 'Done!' and then reloads the page. But, as a said, it fails immediately and onError prints 'Object {description: "Invalid+token.", code: "401"}'.

// globals
var channel, socket, hide;
var $msg = $('#channel-message');
var $bar = $('#notification-tray .progress-bar');


onMessage = function(obj){
    var message = JSON.parse(obj.data);
    if (message.percent !== undefined){
        $bar.css('width', message.percent+'%');
    }
    switchMsg(message.text);
};

onOpen = function(){
    $('#notification-tray').fadeIn();
    $bar.css('width', '10%');
};

onClose = function(){
    $('#notification-tray').fadeOut();
};

onError = function(err){
    $('#notification-tray').fadeOut();
    console.log(err);
};


function closeAndReload(){
    socket.close();
    $.removeCookie('token', {path:'/'});
    $.removeCookie('hide', {path:'/'});
    location.reload();
}

function switchMsg(msg){
    $msg.fadeOut(function(){
        $msg.html(msg);
        $msg.fadeIn(function(){
            if (msg == 'Done!'){
                closeAndReload();
            }
        });
    });
}

function initializeChannel(){
    channel = new goog.appengine.Channel(token);
    socket = channel.open();
    socket.onmessage = onMessage;
    socket.onopen = onOpen;
    socket.onclose = onClose;
    socket.onerror = onError;
}


$(function(){
    token = $.cookie('token');
    if (token !== undefined && token != ""){
        initializeChannel();
    }
});

This works perfectly on my dev server, even though I get this issues in production.

Thanks in advance.

1

1 Answers

2
votes

Okay this is frustrating, but I think I've figured out that the token has a certain undocumented maximum length. I set the client_id to

client_id = self.user.email()+key[0:10]

instead of

client_id = self.user.email()+key

and it now works. Of course it's annoying that (1) it works on the dev server and not on production and (2) the error is not very informative.