Page 3 of 5 FirstFirst 12345 LastLast
Results 21 to 30 of 49

Thread: Implementing comet long polling...

  1. #21
    Join Date
    Oct 2005
    Posts
    296

    Default

    Are the methods included the md5 library you provided to compute the 'string hashed by SHA1' and then 'base64 encoded'? If so, what are they (I can't find the API anywhere)? This would allow me to get protocol 6 working which covers Chrome, IE9+, and Firefox. Safari and Mobile Safari use protocol 0 and that is what I have working...

    What is going to be the best way to package this? Right now, I just have three scripting actions in a folder in my GML: server (fires on fileloaded and scriptenable),broadcaster (server started),closer(fires on fileclose). I was thinking one file with all the code and just have script actions to call functions. Or is there a better way?
    Last edited by shaun5; February 20th, 2012 at 11:13 PM.

  2. #22
    Join Date
    Jan 2000
    Location
    Jupiter, FL
    Posts
    11,346

    Default

    md5 doesn't do sha1/base64. I'll see if I can put together something cleaner for more permanent use.
    Ron
    No support through PM

  3. #23
    Join Date
    Oct 2005
    Posts
    296

    Default

    Ron, I need to store a json string or two per client and have gotten stuck. How do I reference the p1 object name within the p1:callback function? I had envisioned something like WSclients[p1]['data1'] = cp1, but not sure if that will work if I had the object name... Attached is a .zip with websocket.GML, client.html, and the referenced jQuery file so you can see the basic functionality in Safari. You'll have to change the IP within the client.html file to your Girder IP. 'Onload' websocket.GML setups up the websocket server using port 8080. The 'basic send' script action will broadcast a message to all the connected clients.

    Anyone wanting to give this a try will need the bit.dll file Ron posted on page 2 dropped into the Girder5 directory...
    Attached Files Attached Files

  4. #24
    Join Date
    Jan 2000
    Location
    Jupiter, FL
    Posts
    11,346

    Default

    Code:
    function dehex(str) 
        str = string.gsub(str,'[^%a-zA-Z0-9]','')
        return (string.gsub(str, '..', function (cc) return string.char(tonumber(cc, 16)) end)) 
    end
    function fixkey(str)
        local num = ""
        string.gsub(str,'%d', function(d) num = num .. d end)
        local _,n = string.gsub(str, ' ', ' ')
        local i = tonumber(num)/n
        return string.char(math.mod(i/256^3,256), math.mod(i/256^2,256), math.mod(i/256,256),math.mod(i,256))
    end
    function websocketresponse(key1, key2, end8)
        require('bit')
        local cat = fixkey(key1) .. fixkey(key2) .. end8
        local md5 = bit.newMD5()
        md5:update(cat)
        return dehex(md5:final())
    end
    
    function WScallback(p1,p2)
        if ( p2 == transport.constants.event.CONNECTIONCLOSED ) then
            print("WEBSOCKET Connection Closed by Girder")
            return
        end
        if ( p2 == transport.constants.event.NEWCONNECTION ) then
            print("WEBSOCKET New Connection")
            WSclients[p1]=true
            --actually need two different terminators \r\n for header and string.char(255) once the websocket is open...
            p1:Callback(transport.constants.parser.TERMINATED,string.char(255), 2000, function (cp1,cp2)
                if ( cp2 == transport.constants.event.CONNECTIONCLOSED ) then
                    print("WEBSOCKET Connection Closed by client (can be the response to Girder sending closing message)")
                    p1:Close()
                    WSclients[p1]=nil
                elseif (cp2 == transport.constants.event.INCOMPLETERESPONSETIMEOUT) then
                    local connecting = string.Split(string.gsub(cp1,'\r',''),"\n")
                    local response = 'HTTP/1.1 101 WebSocket Protocol Handshake\r\n'
                    response = response .. 'Upgrade: WebSocket\r\n'
                    response = response .. 'Connection: Upgrade\r\n'
                    --response = response .. 'Sec-WebSocket-Protocol: chat\r\n'
                    for i in connecting do
                        if(string.sub(connecting[i],1,6) == 'Host: ') then
                            response = response .. 'Sec-WebSocket-Location: ws://'..string.sub(connecting[i],7)..'/\r\n'
                        elseif(string.sub(connecting[i],1,8) == 'Origin: ') then
                            response = response .. 'Sec-WebSocket-'..connecting[i]..'\r\n'
                        elseif (string.find(connecting[i],'Key1') ~= nil) then
                            websocket_key1 = string.sub(connecting[i],string.find(connecting[i],':',1)+2)
                        elseif (string.find(connecting[i],'Key2') ~= nil) then
                            websocket_key2 = string.sub(connecting[i],string.find(connecting[i],':',1)+2)
                        elseif (string.len(connecting[i]) == 8) then
                            ending8 = connecting[i]
                        end
                    end
                    p1:Write(response)
                    p1:Write('\r\n')
                    p1:Write(websocketresponse(websocket_key1, websocket_key2, ending8))
                    print('WEBSOCKET Client Connected.')
                elseif (cp2 == transport.constants.event.RXCHAR) then
                    --need to save a client's string
                    print('WEBSOCKET Client Sent: ' .. string.sub(cp1,2))
                end
            end)
            return
        end
    end
    if ( WSclients ) then
        for c,v in pairs(WSclients) do
            c:Close()
        end
    end
    if ( WSt ) then
        WSt:Close()
        win.Sleep(1000)
    end
    WSclients = {}        
    WSt = transport.New(transport.constants.transport.GIPLISTEN)
    if not WSt:Open(nil, 8080) then
        print("Could not create WEBSOCKET Server.")
        WSt:Close();
        WSt = nil;
    end
    WSt:Callback(transport.constants.parser.TERMINATED, '\r\n', 2000, WScallback)
    print("Starting WEBSOCKET Server...")
    --gir.TriggerEvent("WS_broadcast", "100", 0)
    In this code? Looks like you are already doing that reference?
    Ron
    No support through PM

  5. #25
    Join Date
    Oct 2005
    Posts
    296

    Default

    Your right. I think I tried to nest additional tables without first defining WSclients[p1]={}. I'll rewrite it and let you know.

    Did you try the demo?

  6. #26
    Join Date
    Jan 2000
    Location
    Jupiter, FL
    Posts
    11,346

    Default

    I'm sorry I didn't try yet. It's crazy how little time there is in a day.
    Ron
    No support through PM

  7. #27
    Join Date
    Oct 2005
    Posts
    296

    Default

    No problem! The correction worked. I now have an additional function (working in its own thread) that loops every 250ms to send differential json data updates (just like the cometreqjson) to open clients. The data monitored is defined individually by each client. Clients without websockets degrade to Ajax automatically.

    If the same data is requested to be monitored by multiple clients, Girder still copies and monitors the data per client (so this could be improved if you had 4+ clients - it would just require a common data pool that is updated as clients open and close connections). The solution presented is probably best case for up to 3 or 4 simultaneous clients. Any more and the overhead of the pool will become negligible compared to the individual data copy comparisons.

    I have a client side update cache to write then I will present the complete solution. The update cache will allow the client to ignore ignore updates while the client fiddles with the interface. This is nessessary to accomodate latency between everything involved in the chain (client, network, Girder, equipment)

  8. #28
    Join Date
    Oct 2005
    Posts
    296

    Default

    Everything is done (excluding the additional browser support - still need the Lua library) and running. I'm still on the fence on adding a common data pool (I'll add it with if there is any interest). If someone is interested in using websockets, let me know and I'll upload everything and write it up.

  9. #29
    Join Date
    Jan 2000
    Location
    Jupiter, FL
    Posts
    11,346

    Default

    That's very cool. Which functionality do you need again? Just SHA-1 and Base64?
    Ron
    No support through PM

  10. #30
    Join Date
    Oct 2005
    Posts
    296

    Default

    Ron, that is correct.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •