1

I have a slightly unusual situation with SharedObject:

The situation: where we have a SWF (browser) based application running on a single local machine. The SWF accesses local content and is reloaded every XX number of seconds/minutes/hours.

The state of application has to be stored within a single SharedObject (this is using the '/' parameter to force it to global) in a JSON style.

The SWF loads the SO before it makes any state updates and correctly calls flush() immediately after to save state.

The Problem: Everything runs fine BUT occasionally there is a situation where by 2 instances of the same SWF are existing at the same in different instances and both are accessing the same SharedObject.

The 2nd has to take control of the SO from the 1st, by each SWF instance setting it's instance state to an incremented number (SWF Idx) stored in the SO.

Both are loading the file before any update is made, version number checked, and will disable themselves if the saved SWF Idx is above it's own. Unfortunately the 1st SWF instance somehow isn't loading the latest version of the SharedObject because it traces out the original number (e.g. 22) instead of the now updated one (e.g. 23). While the 2nd SWF is tracing out 23 and the SO contains 23.

Is there any way that the browser could possibly be caching the SO?

Testing I'm currently testing the situation by running one browser instance locally then launching a 2nd. Making copies of the SO before and after each state. I've also run the 1st and 2nd via IntelliJ and can see that SharedObject.getLocal is being called and checked each time.

I've included the basics of the code I'm using below where:

  • __so = is the public SharedObject variable
  • _thisSWFIdx = is the private variable inside AS3 storing the current instances SWF Index
  • __so.data.activeSWFIdx = the latest SWF Index

The SO 'get' I'm using is:

SharedObject.getLocal(_SO_ID, "/");

The check i'm doing is:

if (_thisSWFIdx < __so.data.activeSWFIdx) {
    __amActiveSWF = false;
}

The saving of the variable to SO:

__so.data.activeSWFIdx  = _thisSWFIdx;
flush();

Additonal info:

  • This is running on both mac & windows
  • FlashPlayer 10.3
  • Pure AS3
  • compiled in IntelliJ
  • same issue in FF, Chrome and IE
  • primary machine Macbook

I can't find anything within the documentation or existing threads so any help will be much appreciated.

akmozo
  • 9,829
  • 3
  • 28
  • 44
Rich
  • 970
  • 2
  • 16
  • 42
  • Smells like a race condition. – null Jul 22 '16 at 21:37
  • there's a definite risk of that for sure, which I'll need to deal with but for the above I've set up a test where I have a clear safe window of time for instance B to take control and increment the SO without instance A interacting. After this instance A interacts but still reads the old value. – Rich Jul 23 '16 at 08:49
  • @Visualife To my knowledge, browser has nothing to do with SO, it's a Flash Player concern. How did you set the value of `_thisSWFIdx` ? – akmozo Jul 23 '16 at 08:54
  • @akmozo _thisSWFIdx is a AS3 var. It is only set once per SWF, it is set to 1 if the SO doesn't contain activeSWFIdx, or set to an increment of activeSWFIdx if activeSWFIdx exists. In both cases SO is updated (an is updating). – Rich Jul 23 '16 at 09:06
  • @Visualife I think that your SWF should verify every `n` seconds (for example) if it's always the active one by getting the current ID from the SO and then disable itself if there is another active SWF ... – akmozo Jul 23 '16 at 09:18
  • @akmozo that's a good suggestion a certainly worth implementing but my problem is currently that the initial SWF isn't reading the updated value in the SO, it's fetching the old value but referencing the same file. – Rich Jul 23 '16 at 09:21
  • @Visualife I don't see how did you got that behavior (your SWF didn't get the last ID from SO), or maybe I don't understand the situation ? If your code is fine, any loaded SWF will get the last ID from SO, increment and save it to the SO ... – akmozo Jul 23 '16 at 09:35
  • @akmozo that's 100% the problem. laucnh A, reads SO, checks and increments index - continues to run, launch B reads SO, checks and increments index - continues to run. I check SO, SO has been correctly updated with A then B's value. A then checks SO and see the 'old' values, not the new one. Hence I don't know if SO is somehow being cached. If I then open C then A & B see their respective 'old' values. It's very odd behavoir. – Rich Jul 23 '16 at 09:48

1 Answers1

0

After a little test, I remarked the behavior that you've mentioned : after updating the SharedObject by a second SWF, the first one can't get the new value only after a reload.

To avoid that, I think, as a workaround, you can use a second SWF which will just work on the SharedObject by reading / writing data.

For that, take this example :

so.swf : the SWF which will read and write data.

var shared_object_name:String = 'so';
var shared_object:SharedObject = SharedObject.getLocal(shared_object_name, '/');

// get the id
function get_id(): int {
    return shared_object.data.id ? shared_object.data.id : -1;
}

// set the id
function set_id(new_id:int): void {
    shared_object.data.id = new_id;
    shared_object.flush();
}

app.swf : your global app which will use the "so.swf" to do SharedObject's operations :

var init:Boolean = true;
var swf_id:int = 1;
var swf_disabled:Boolean = false;

var loader:Loader = new Loader();
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, on_SWFLoad);
    loader.load(new URLRequest('so.swf'));  

function on_SWFLoad(e:Event): void
{   
    var loaded_swf:MovieClip = MovieClip(loader.content);
    var current_id:int = loaded_swf.get_id();

    // if it's initial run
    if(init){
        init = false;
        if(current_id > 0){
            swf_id = current_id + 1;
        }
        loaded_swf.set_id(swf_id);
    } else {  // we are verifying if there is a new active SWF
        if (swf_id <= current_id) {
            swf_disabled = true;
        }
    }
}

function stage_onPress(e:MouseEvent){
    // if this SWF is disabled, stop getting the "id"
    if(swf_disabled){
        stage.removeEventListener(MouseEvent.CLICK, stage_onPress);
        return;
    }
    // otherwise, get the "id" to verify if there is another active SWF
    loader.load(new URLRequest('so.swf'));
}
stage.addEventListener(MouseEvent.CLICK, stage_onPress);

I used MouseEvent.CLICK only for testing purposes, of course you have to use a Timer or something else to verify every n seconds (for example) that you have another active SWF to disable the current one...

Hope that can help.

akmozo
  • 9,829
  • 3
  • 28
  • 44