how to check for new data on server on app launch

Hi

OK my simple flash card app is coming along. I now have the question and answer data in a separate json file on my web server. The app downloads this to the system.Documents directory and decodes it into a lua table.

What I’ve discovered is that the app takes a moment or two to download the file, so it doesn’t always start right way. I guess this means I need to include a local copy of the json file in my main directory so that the thing will fire up right away the first time.

But how do I get the app to look at the server file on subsequent launches to see if it’s updated, and use the updated file instead of the local file if it has been?

thanks again,

David

I would ALWAYS check the documents directory, but have a test in the load file function which defaults to the resource directory if nothing is found in the documents directory, and saves a copy in the docs directory for future use. This way it will use your default file if nothing is found in the documents directory.

This is my load file function:

loadFile = function( filename, base ) -- set default base dir to DocumentsDirectory if none specified if not base then base = system.DocumentsDirectory; end -- create a file path for corona i/o local path = system.pathForFile( filename, base ) -- will hold contents of file local contents -- io.open opens a file at path. returns nil if no file found local file = io.open( path, "r" ) --if the file exists then read all contents of file into a string if file then contents = file:read( "\*a" ) io.close( file ) -- close the file after using it else --read from resource directory instead... print("defaulting to ResourceDirectory") jsonDefaulted = true local path = system.pathForFile( filename, system.ResourceDirectory ) local file = io.open(path, "r") if file then contents = file:read( "\*a" ) io.close (file) end --...then save the file to DocumentsDirectory for future use local savePath = system.pathForFile(fileName, system.DocumentsDirectory ) local saveFile = io.open(savePath, "w") saveFile:write(contents) io.close(saveFile) print("Saved "..fileName.." to DocumentsDirectory") end return contents end

Another thing to mention is that sometimes the user may not have an internet connection, so you’ll need to account for that too (loading the default file should be fine though, depending on what your app does). 

Also it may be wise to delay going to your game scene or whichever scene uses this json data until a response is received.

You could just put the goToScene in the network listener, again you’ll need to account for the user having no internet connection though.

Hi

Thanks for this. I’m still not totally clear on what’s going on, so let me try a bit further.

So your function looks first in the documents directory. Presumably it finds there the file that was just downloaded. Does it also find the local copy of the file there as well? 

If no file is found you look in the resources directory. What would you expect to find there? Is THAT where the local copy lives? (As you can tell I am only just beginning to learn about these different directories.

I still have no clue how to get the app to compare the local file with the downloaded one and use the downloaded file if it has been updated since the last play

cheers,

david

The resource directory is another name for your main folder (ie the folder with main.lua , your images etc in it). So if you put a local copy there then yes, that’s where it would be found. In my example, I first check the documents directory for the downloaded file. NOTE: the file will only be in that location if you specify that you want to save it there while downloading, if you save it to the temporary directory then obviously my function wouldn’t find it. If my function does not find the file there, then it checks the main resource folder AND puts a copy into the documents directory. You don’t need to make this copy, but I always do. The documents directory is a permanent directory, so any files saved there will remain there until you delete them manually or delete the whole app. So when you download a copy of the file, it will overwrite the copied file and be used as the new default file until another version is downloaded. So it will always be using the most recent file, unless your code is set up to do something else. As i said before though, you will need to take into account the time needed to download the file before you open the file otherwise you may start using old data milliseconds before the new data arrives. Is there anything that is still unclear?

Thanks, this is making a lot more sense now. I think that is exactly what is happening right now in my case: the app is using the old data before the new arrives. 

I currently have a networkListener function as one of the arguments of network.download. Should I use “event.phase== ended” as a way to check that the new file has been downloaded and that the app is ready to play?

Actually this network listener is confusing me. I tested it by renaming the file on the server, and yet it shows no error message. Instead it says that  “event phase ended for json download”, even though it can’t have downloaded the file!?

local function networkListener( event )

        if ( event.isError ) then

                print( “Network error - download failed” )

        elseif ( event.phase == “began” ) then

                print( “Progress Phase: began” )

        elseif ( event.phase == “ended” ) then

                print( “event phase ended for json download” )

                

        end

en

event.isError will only be set if there was a problem like a timeout where the server could not be reached, bad server name etc.  If it successfully talked to the server, then you will get a successful return even if the file doesn’t exist.  A “File Not Found” will generate what is known as a 404 error.  Any of these error codes that start with a 4 or 5 are error conditions.  Ones that start with a 1 (pretty rare) or a 2 are successful conditions (200 being normal for downloading a file).  3’s are redirections, and shouldn’t really be seen by network.download.

See:  http://docs.coronalabs.com/api/event/networkRequest/index.html

for all the possible return values and look for event.status or event.response to contain the output or error from the web server if it exists.  Just to reiterate… event.isError means you could not talk to the server at all.  If you made any communications with the server and it’s responding as a web server, you will not get an .isError.

BTW Alan your code has a typo: you’ve used both “filename” and “fileName” in the loadfile function.

I would ALWAYS check the documents directory, but have a test in the load file function which defaults to the resource directory if nothing is found in the documents directory, and saves a copy in the docs directory for future use. This way it will use your default file if nothing is found in the documents directory.

This is my load file function:

loadFile = function( filename, base ) -- set default base dir to DocumentsDirectory if none specified if not base then base = system.DocumentsDirectory; end -- create a file path for corona i/o local path = system.pathForFile( filename, base ) -- will hold contents of file local contents -- io.open opens a file at path. returns nil if no file found local file = io.open( path, "r" ) --if the file exists then read all contents of file into a string if file then contents = file:read( "\*a" ) io.close( file ) -- close the file after using it else --read from resource directory instead... print("defaulting to ResourceDirectory") jsonDefaulted = true local path = system.pathForFile( filename, system.ResourceDirectory ) local file = io.open(path, "r") if file then contents = file:read( "\*a" ) io.close (file) end --...then save the file to DocumentsDirectory for future use local savePath = system.pathForFile(fileName, system.DocumentsDirectory ) local saveFile = io.open(savePath, "w") saveFile:write(contents) io.close(saveFile) print("Saved "..fileName.." to DocumentsDirectory") end return contents end

Another thing to mention is that sometimes the user may not have an internet connection, so you’ll need to account for that too (loading the default file should be fine though, depending on what your app does). 

Also it may be wise to delay going to your game scene or whichever scene uses this json data until a response is received.

You could just put the goToScene in the network listener, again you’ll need to account for the user having no internet connection though.

Hi

Thanks for this. I’m still not totally clear on what’s going on, so let me try a bit further.

So your function looks first in the documents directory. Presumably it finds there the file that was just downloaded. Does it also find the local copy of the file there as well? 

If no file is found you look in the resources directory. What would you expect to find there? Is THAT where the local copy lives? (As you can tell I am only just beginning to learn about these different directories.

I still have no clue how to get the app to compare the local file with the downloaded one and use the downloaded file if it has been updated since the last play

cheers,

david

The resource directory is another name for your main folder (ie the folder with main.lua , your images etc in it). So if you put a local copy there then yes, that’s where it would be found. In my example, I first check the documents directory for the downloaded file. NOTE: the file will only be in that location if you specify that you want to save it there while downloading, if you save it to the temporary directory then obviously my function wouldn’t find it. If my function does not find the file there, then it checks the main resource folder AND puts a copy into the documents directory. You don’t need to make this copy, but I always do. The documents directory is a permanent directory, so any files saved there will remain there until you delete them manually or delete the whole app. So when you download a copy of the file, it will overwrite the copied file and be used as the new default file until another version is downloaded. So it will always be using the most recent file, unless your code is set up to do something else. As i said before though, you will need to take into account the time needed to download the file before you open the file otherwise you may start using old data milliseconds before the new data arrives. Is there anything that is still unclear?

Thanks, this is making a lot more sense now. I think that is exactly what is happening right now in my case: the app is using the old data before the new arrives. 

I currently have a networkListener function as one of the arguments of network.download. Should I use “event.phase== ended” as a way to check that the new file has been downloaded and that the app is ready to play?

Actually this network listener is confusing me. I tested it by renaming the file on the server, and yet it shows no error message. Instead it says that  “event phase ended for json download”, even though it can’t have downloaded the file!?

local function networkListener( event )

        if ( event.isError ) then

                print( “Network error - download failed” )

        elseif ( event.phase == “began” ) then

                print( “Progress Phase: began” )

        elseif ( event.phase == “ended” ) then

                print( “event phase ended for json download” )

                

        end

en

event.isError will only be set if there was a problem like a timeout where the server could not be reached, bad server name etc.  If it successfully talked to the server, then you will get a successful return even if the file doesn’t exist.  A “File Not Found” will generate what is known as a 404 error.  Any of these error codes that start with a 4 or 5 are error conditions.  Ones that start with a 1 (pretty rare) or a 2 are successful conditions (200 being normal for downloading a file).  3’s are redirections, and shouldn’t really be seen by network.download.

See:  http://docs.coronalabs.com/api/event/networkRequest/index.html

for all the possible return values and look for event.status or event.response to contain the output or error from the web server if it exists.  Just to reiterate… event.isError means you could not talk to the server at all.  If you made any communications with the server and it’s responding as a web server, you will not get an .isError.

BTW Alan your code has a typo: you’ve used both “filename” and “fileName” in the loadfile function.