Javascript-Flash socket bridge with haxe

There are a bunch of solutions for making a bridge to use the flash sockets (flash.net.Socket) in javascript, notably socketBridge and jssockets. But I didn’t like the way they made you write your client code: because you can’t pass javascript function references through the ExternalInterface you usually pass your callbacks as strings representing the name of an global object. IMHO, that just sucks so I’ve made my own mix named HaxeSocketBridge.

You can write the client code like this:


    var s = new FlashSocket({
        on_data: function(data) {
            document.getElementById('datapanel').value = data;
        },
        on_io_error: function(msg) {
            alert("IO ERROR: "+msg);
        },
        on_security_error: function(msg) {
            alert("SECURITY ERROR: "+msg);
        },
        on_close: function(msg) {
            alert("Connection closed.");
        },
        on_connect: function() {
            s.write("GET / HTTP/1.0\r\n\r\n");
        }
    });
    s.connect('example.com', 80);

Here’s the whole example.

How does it work? You can execute arbitrary javascript code though the external interface, so why not execute some boilerplate code and setup a global FlashSocket class that handles all the nasty actionscript-javascript communication.  I’ve seen this arguably good idea in the SWFHttpRequest bridge. If you do something like this be careful with those damn commas/semicolons or else you’re in i-dont-know-why-it-breaks hell :)

Here’s how the guts look like (note that the language is haxe):


        ExternalInterface.addCallback("connect", connect);
        ExternalInterface.addCallback("close", close);
        ExternalInterface.addCallback("write", write);
        ExternalInterface.addCallback("CAN_I_HAS_SOCKET", CAN_I_HAS_SOCKET);
        ExternalInterface.call([
        "(function(){",
            "if (window.FlashSocket) return;",
            "var Class = function(properties){",
                "var klass = function(event_handlers){ ",
                    "for (var p in event_handlers) {",
                        "if (event_handlers.hasOwnProperty(p)) {",
                            "this[p] = event_handlers[p];",
                        "}",
                    "}",
                    "return this.init.apply(this);",
                "};",
                "klass.prototype = properties;",
                "klass.constructor = arguments.callee;",
                "return klass;",
            "};",
            "window.FlashSocket = new Class({",
                "init: function(){",
                    "this._instance = ''+window.FlashSocket._instances.length;",
                    "window.FlashSocket._instances.push(this);",
                "},",
                "close: function(){ ",
                    "window.FlashSocket._instances[this._instance] = null;",
                    "window.FlashSocket._bridge.close(this._instance );",
                "},",
                "write: function(data){ ",
                    "window.FlashSocket._bridge.write(this._instance, data);",
                "},",
                "connect: function(host, port) {",
                    "window.FlashSocket._bridge.connect(this._instance, host, port);",
                "}",
            "});",
            "window.FlashSocket._instances = [];",
            "var f = function(tag){",
                "var elems = document.getElementsByTagName(tag);",
                "for (var i=0; i<elems.length; i++) if (elems[i].CAN_I_HAS_SOCKET) return elems[i];",
            "};",
            "window.FlashSocket._bridge = f('embed') || f('object');",
        "})" ].join('') );
        if (flash.Lib.current.loaderInfo.parameters.onloadcallback != null)
            ExternalInterface.call(flash.Lib.current.loaderInfo.parameters.onloadcallback);

The trick is that we can setup a global javascript class-like object from the flash clip.

You can grab the code here. Also, if you test from a local disc you might want to adjust your flash security settings. To compile the .hx file run “haxe compile.hxml“.

Now, the only thing I miss is some buffering/readline logic.

18 Comments

  1. Posted November 29, 2008 at 8:19 pm | Permalink

    This is a much nicer javascript interface to the SWF, glad to see someone else getting involved on this problem too.

    Can’t see how you’d get multiple concurrent connections with this SWF though, as there is only ever one instance of window.FlashSocket._bridge. I know that’s an edge case though.

    Good work and a nice pattern to remember in future.

  2. Posted November 29, 2008 at 8:26 pm | Permalink

    Oh, my bad, scrap that last comment. I see there is support for multiple connections in the haxe source.

  3. Chris
    Posted December 11, 2008 at 2:10 pm | Permalink

    Hm ya there seems to be multi-connection support, but how can I use it? I thought I could do it by initiating another FlashSocket Object. But it’s not working. my first object is getting killed or better the connection gets resetted.

    Thanks,
    Chris

  4. ionelmc
    Posted December 11, 2008 at 2:24 pm | Permalink

    Can you post sample code proving the problem ?

  5. Posted March 10, 2009 at 9:01 am | Permalink

    nice every is compiled but i got a security alert
    and i don’t see what i have to set in the security settings from adobe
    thank you for your nice example

  6. Ionel Maries
    Posted March 10, 2009 at 9:16 am | Permalink

    @jean-michel, If you are testing locally you need to add a path for a trusted location in the security manager. Otherwise you usually need to have a proper policy file serving daemon running on port 843 on the servers you are making socket connections to.

  7. Posted March 13, 2009 at 10:28 am | Permalink

    sorry to disturb you again ionel and thank you for your former answer .
    but i have seen the place in adobe page to give the path for a trusted location
    i have given the place where socket_bridge.swf is , but no change i have still the
    same behaviour security error #2048
    in fact i think i don’t understand at all what means a trusted location ???
    i have read a lot of thing but …
    i give you the location on my PC http://jmg78.hd.free.fr/sock.htm

  8. Ionel Maries
    Posted March 13, 2009 at 10:36 am | Permalink

    Trusted locations work only for local files, eg: your url is like “file:///c:/bla/bla.html”

    If you are loading the page from a http webserver you need to have a additional service there listening on 843 and sending a string like this on each connection:

    assuming you want to accept connections on jmg78.hd.free.fr from any domain on port 80.

  9. Posted March 13, 2009 at 6:22 pm | Permalink

    thanks again
    you are going to think i am stupid :)
    for the moment i want to test on “localhost” but of course i use a browser to call my htm file
    i have try to put both files sock.htm and socket_bridge.swf on the trusted files list and even the whole directory

    no change

    in the second case if i use a service listening on 843
    you say i have to send a string like this : but i dont see any string
    PS i am under linux

  10. Ionel Maries
    Posted March 14, 2009 at 12:05 am | Permalink

    Drats! wordpress removed it (was some xml markup). Here is it: http://code.google.com/p/ionel-whatever-code/wiki/FlashSocket

  11. filllest
    Posted May 7, 2009 at 6:07 am | Permalink

    Hello and thanks much, good job, everything works fine, but i’ve caught some strange behaviour.
    I open localhost/test.html, flash successfuly gets policy file (i have a daemon on 843 port), socket connects to localhost:80, gets and prints content, server closes connection, i get all expected debug alerts. But then, after about 15 seconds, there’s a 2048 security error. o_O
    It looks like client tries to connect one more time to some different place (where?..) and fails to get policy file or whatever, with timeout. I’ve looked through the code, recompiled, tried >1024 port, no effect..
    win xp sp3, differect browsers
    Thanks

    • Ionel Maries
      Posted May 7, 2009 at 12:34 pm | Permalink

      Do you have a traceback for that last error?

      • filllest
        Posted May 7, 2009 at 8:38 pm | Permalink

        eer, no, how can i get it? ) i’m totally new to flash and haxe
        i put at the beginning of SocketBridge::connect this:
        ExternalInterface.call( “(function(){alert(’called ::connect’);})”);
        but it alerts only once when it’s expected

    • Ionel Maries
      Posted May 7, 2009 at 11:17 pm | Permalink

      How does your policy file look like ?

      Are you sure you serving the policy file right ? (that means send the xml, close the connection -or- prepend a null char and flash will close the connection. see: http://help.adobe.com/en_US/ActionScript/3.0_ProgrammingAS3/WS5b3ccc516d4fbf351e63e3d118a9b90204-7c60.html )

      Might want to try fetching the policy file yourself (eg, FlashSocket.loadPolicyFile(”xmlsocket://localhost:843″); )

      Still doesn’t explain why you still get the response and the security error though …

      • fillest
        Posted May 12, 2009 at 5:35 pm | Permalink

        My policy file – http://pastebin.ca/1420519 , but also i tried different params

        >Are you sure you serving the policy file right ?
        Yes, i’m sure.. At first time i used example python server from http://www.adobe.com/devnet/flashplayer/articles/socket_policy_files.html but then i wrote my own on erlang and experimented a lot. Also i installed debug flash player and set up logging, it produces little more info but still clueless..
        I also wrote another server to test client with, instead of simply connecting to the same apache that serves page-with-client. Some results:
        While connected, there is no error, and it raises after about 15 sec after server closes socket (notable that “close” event is raised by flash as expected). If flash closes socket, error doesnt rise. It seems that sometimes error doesnt rise at all.. To sum up, for disconnection i can send “command” to client that it should close the socket. Bad solution, but it works for the present..
        I’ll experiment more and post if get any results..

  12. mario
    Posted June 17, 2009 at 12:43 pm | Permalink

    hi, this really helpme out, but Ionel, please tell me what kinf of licence is this under? can i use it in my comercial site?
    other thing, i dont want people to see so direct my ip and port adress i know theres no point on hiding it because the one who wants to know it knows it esaly… but we are not all geeks….:-) soo can i modify the code to hide it?

    • Ionel Maries
      Posted June 17, 2009 at 1:01 pm | Permalink

      Yeah use it however you want. I will add a MIT license text in the source code so there won\’t be any confusion.

      • mario
        Posted June 19, 2009 at 5:28 am | Permalink

        thx…any ideia to improve security and encryption…?


One Trackback

  1. [...] Update: 5 May 2009 This post has generated a (relatively) large amount of interest so I feel I should point out the ionel is also hosting his improved version of the socketBridge. It has a nicer OO interface and might solve some issues with the javascript callbacks and setTimeouts. Might be worth a peek for all those interested: http://ionelmc.wordpress.com/2008/11/29/flash-socket-bridge-with-haxe/ [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*