Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
outputting a .txt file which usually updates itself — Gideros Forum

outputting a .txt file which usually updates itself

loves_oiloves_oi Member
edited August 2012 in General questions
This code outputs the txt file in a url.
 
local loader = UrlLoader.new("<a href="http://www.catonmat.net/download/awk.cheat.sheet.txt&quot" rel="nofollow">http://www.catonmat.net/download/awk.cheat.sheet.txt&quot</a><img class="emoji" src="http://forum.giderosmobile.com/resources/emoji/wink.png" title=";)" alt=";)" height="20" />
local function onComplete(event)
 
	local myString=event.data      -- We got the string here.
 
        --local timer = Timer.new(1000, 8)
	--timer:addEventListener(Event.TIMER, onComplete)---
 
	local length = string.len(myString)
	local i = 1
 
	local echoString = ""
	while (i < length+1) do
 
		echoString = echoString .. string.sub(myString,i,i)
 
		i = i+1;
	end
	print (echoString)
 
	--timer:start()
 
end
 
local function onError()
    print("error")
end
 
local function onProgress(event)
    print("progress: " .. event.bytesLoaded .. " of " .. event.bytesTotal)
end
 
loader:addEventListener(Event.COMPLETE, onComplete)
loader:addEventListener(Event.ERROR, onError)
loader:addEventListener(Event.PROGRESS, onProgress)
I want to add a timer to the code and it is the code with timer.
 
local loader = UrlLoader.new("<a href="http://www.catonmat.net/download/awk.cheat.sheet.txt&quot" rel="nofollow">http://www.catonmat.net/download/awk.cheat.sheet.txt&quot</a><img class="emoji" src="http://forum.giderosmobile.com/resources/emoji/wink.png" title=";)" alt=";)" height="20" />
local function onComplete(event)
 
	local myString=event.data      -- We got the string here.
 
        local timer = Timer.new(1000, 8)
	timer:addEventListener(Event.TIMER, onComplete)---
 
	local length = string.len(myString)
	local i = 1
 
	local echoString = ""
	while (i < length) do
 
		echoString = echoString .. string.sub(myString,i,i)
 
		i = i+1;
	end
	print (echoString)
 
	timer:start()
 
end
 
local function onError()
    print("error")
end
 
local function onProgress(event)
    print("progress: " .. event.bytesLoaded .. " of " .. event.bytesTotal)
end
 
loader:addEventListener(Event.COMPLETE, onComplete)
loader:addEventListener(Event.ERROR, onError)
loader:addEventListener(Event.PROGRESS, onProgress)
It outputs the results correctly and then suddenly gave the error :

main.lua:9: bad argument #1 to 'len' (string expected, got nil)
stack traceback:

Why i'm taking this error? How could i fix it?
Thanks in advance
«1

Comments

  • You get this error because event.data contains no STRING. What puzzles me is why do you add another event listener to the onComplete event inside the onComplete function? I think it has something to do with this.
  • Did you mean the lines :

    timer:addEventListener(Event.TIMER, onComplete)
    and
    loader:addEventListener(Event.COMPLETE, onComplete)
    ?

    When i did

    --timer:addEventListener(Event.TIMER, onComplete)
    and
    loader:addEventListener(Event.COMPLETE, onComplete)

    It gives the output correctly but doesn't update.

    When i did

    timer:addEventListener(Event.TIMER, onComplete)
    and
    --loader:addEventListener(Event.COMPLETE, onComplete)

    There is no error but there is no output ,either.
  • MikeHartMikeHart Guru
    edited August 2012
    Stupid me. I didn't see that you tried to used the same handler for the Url and the timer. Within the handler, I think onComplete is NIL when LUA parses the file. If you need to have to use the same handler on different objects, then I would do this
    local onComplete
    ...
    onComplete = function(event)
  • And as you use the same handler for 2 different events, make sure you check if the string is not NIL when you determine the length.
  • looks like a simple forward referencing problem - I always declare my function handlers the way @MikeHart suggests because often I assign handlers to both the COMPLETE and ERROR events and want each one to be able to remove both when they get called.
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • loves_oiloves_oi Member
    edited August 2012
    You mean this ?
    local loader = UrlLoader.new("<a href="http://www.catonmat.net/download/awk.cheat.sheet.txt&quot" rel="nofollow">http://www.catonmat.net/download/awk.cheat.sheet.txt&quot</a><img class="emoji" src="http://forum.giderosmobile.com/resources/emoji/wink.png" title=";)" alt=";)" height="20" />
     
    local onComplete
     
    --local function onComplete(event)
    onComplete = function(event)
    	local myString=event.data      
    	--print (onComplete)
    	print (myString)	
    end
     
    local timer = Timer.new(10000,100)
    timer:addEventListener(Event.TIMER, onComplete)
    timer:start()
     
    local function onError()
        print("error")
    end
     
    local function onProgress(event)
        print("progress: " .. event.bytesLoaded .. " of " .. event.bytesTotal)
    end
     
    loader:addEventListener(Event.COMPLETE, onComplete)
    loader:addEventListener(Event.ERROR, onError)
    loader:addEventListener(Event.PROGRESS, onProgress)
    This change doesn't seems to change anything @techdojo .
    I'M outputting the myString , and you are right @MikeHart . myString gives the output correctly at first trying but then it only outputs nil .Namely:
    (Correct Output)
    nil
    nil
    nil
    nil
    nil
    nil
    nil
    .
    .
    .
    So interesting.. Why can't it get the txt file from the url after first trying? I would expect that it outputs the text again and again.
    Thanks in advance
  • what should i do ?
  • take up basket weaving? :)
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • This is an snapshot while i am working :D
    images.jpg
    285 x 177 - 10K
  • I wish mine could get that complex :)

    I'm also having problems with the UrlLoader class - making multiple calls seems to really mess things up for me.

    Am I right in thinking you want to periodically download the file and dump it's contents. it's something similar to what I'm currently trying (and failing) to do
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • Yeah. There is a txt file which is usually updated . I want to output it and make it update itself ;)
  • Maybe I'm looking at this all wrong but shouldn't onComplete only get called once, when the file has finished downloading?

    When onComplete is called the complete downloaded file should be in event.data. If this is the only file to download then the loader:eventListeners should be removed.

    I think that once a file is finished loading, it is sent to the Event.COMPLETE listener and then the string is cleared. If the listener is called again then this nil string is what will be sent. I may have this wrong but it makes sense in my head :D
  • By update itself - do you mean ensure the local copy always contains the latest info.

    What I would say is use a different function for the Timer on complete event as opposed to the download on complete event (also makes the code easier to read).

    I'm also struggling with multiple downloads using a single connection (which is basically what your doing). If I get any more info I'll post some more.

    I was hoping @Atilim (or @Gorkem ) might jump in with the single bit of info I need to make it all work flawlessly but I guess they're a bit busy at the moment.

    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • By update itself - do you mean ensure the local copy always contains the latest info.
    Exactly
  • loves_oiloves_oi Member
    edited August 2012
    @Scouser
    When i remove the line :

    loader:addEventListener(Event.COMPLETE, onComplete)

    It never give correct output , give all nil .

    unless i remove , it gives at least one Correct output if we don't mind rest of it is all nil :D
  • If you remove the handler that get's called when the download completes then you'll not get any notification at all.

    Something weird is going on here - I've been at this all day - making multiple calls to the same UrlLoader instance doesn't appear to work, after the second call to :load() is made, none of the event listeners seem to get called - can anyone else confirm this?
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • Are you debugging with the player on a PC or on a mobile device? A few weeks back I had been testing stuff using the REST API and noticed I got errors whenever running on a device, but no issues on the player on my PC.
  • Ok - well I've got something sorted at least but I suspect it won't help @loves_oi too much.

    To download a single file you must create an instance of a UrlLoader and assign the appropriate event handlers to it.

    Once the download is complete you are free to work with the data - BUT you can't reuse the connection (ie make a subsequent :load() call), other than removing the event handlers you also CAN'T do anything with the instance of the connection (ie the original return value from UrlLoader:new()) - you certainly can't create a NEW connection and assign it to the variable (don't ask me why!) otherwise the any attempt to download will just cause it to crash.

    The way I got round the problem was to have a table of UrlLoader instances and create one per file.

    Initially the table was empty - and I used a onEnterFrame listener to watch the state of a flag that was set each time a download completed and was then used to trigger the next load from the onEnterFrame listener.

    Once all the files had been downloaded I then set a different flag which caused the onEnterFrame listener to pickup the fact that all the files had been downloaded and then nil out all the references to the UrlLoader instances before continuing.

    I'm not sure if this the best method to use but until I get official word from those "in the know" it'll do.

    I'll cross post this in the thread I started in case anyone else is struggling with this...

    :(
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • I am kind of confused at what you want. Here's what I think you want, you want a file to be downloaded/refreshed from the internet every so often to keep the contents fresh/updated, is that right?

    if it is, then have two functions,
    1. To download the file from the internet
    2. A timer that will keep calling this function every XX period.

    You will have to also keep in mind to start the timer only when the download is complete, so XX after the file download is completed. That way you will not have an overlap.

    Hope that helps, BTW, Basket Weaving is quite an impressive task ;)
    twitter: @ozapps | http://www.oz-apps.com | http://howto.oz-apps.com | http://reviewme.oz-apps.com
    Author of Learn Lua for iOS Game Development from Apress ( http://www.apress.com/9781430246626 )
    Cool Vizify Profile at https://www.vizify.com/oz-apps
  • loves_oiloves_oi Member
    edited August 2012
    @zvardin , nope i'm testing on pc , not mobile phone.
    @techdojo , you make me thought that it is impossible to do it :S
    @OZApps ,you understand right. Moreover, I almost tried everywhere.I put the timer everywhere but didn't work . When i change the place of timer , the order of correct output change but it gives still only one correct output and rest all nil.For instance:

    (correct output)
    nil
    nil
    nil
    .
    .
    .

    or

    nil
    nil
    (correct output)
    nil
    nil
    .
    .
    .

    or etc. ;)
  • @loves_oi - @OzApps is bang on with his description. My advice to you - keep it as simple as possible.

    You've already done the bit with the download - separate out the timer stuff and try and keep each section of your code as separate as possible, write a function that just get's called on a timer and do a print so that you know it's working ok, then look at calling your download function from within that timer callback. Just remember to create a NEW UrlLoader instance each time you want to download and DON'T try and schedule anything to do with the current UrlLoader instance from within the download complete callback.
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • atilimatilim Maintainer
    Hi,

    Yes you're right. Second call to load doesn't seem to work. It's a bug. The workaround is creating a new UrlLoader for each load:
    local load = nil
     
    local function onComplete(event)
     	print("size:", #event.data)
    	load()
    end
     
    local function onError()
        print("error")
    end
     
    local function onProgress(event)
    end
     
    load = function()
    	local loader = UrlLoader.new("<a href="http://www.catonmat.net/download/awk.cheat.sheet.txt&quot" rel="nofollow">http://www.catonmat.net/download/awk.cheat.sheet.txt&quot</a><img class="emoji" src="http://forum.giderosmobile.com/resources/emoji/wink.png" title=";)" alt=";)" height="20" />
    	loader:addEventListener(Event.COMPLETE, onComplete)
    	loader:addEventListener(Event.ERROR, onError)
    	loader:addEventListener(Event.PROGRESS, onProgress)
    end
     
    load()
  • loves_oiloves_oi Member
    edited August 2012
    @atilim , it works correctly but , it updates every seconds. I want to update the file every minute etc. , not every second :S it may cause server crash :(
  • See my comment in my other thread about UrlLoader - looks like I "accidentally" tripped over the workaround when I tried to create an example that doesn't work :)

    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • atilimatilim Maintainer
    oh I see.. this loads the file every minute:
    local alreadyLoading = false
     
    local function onComplete(event)
    	print("size:", #event.data)
    	alreadyLoading = false
    end
     
    local function onError()
    	print("error")
    	alreadyLoading = false
    end
     
    local function load()
    	if not alreadyLoading then
    		local loader = UrlLoader.new("<a href="http://www.catonmat.net/download/awk.cheat.sheet.txt&quot" rel="nofollow">http://www.catonmat.net/download/awk.cheat.sheet.txt&quot</a><img class="emoji" src="http://forum.giderosmobile.com/resources/emoji/wink.png" title=";)" alt=";)" height="20" />
    		loader:addEventListener(Event.COMPLETE, onComplete)
    		loader:addEventListener(Event.ERROR, onError)
    		alreadyLoading = true
    	end
    end
     
    local timer = Timer.new(60 * 1000, 0)
    timer:addEventListener(Event.TIMER, load)
    timer:start()
    load()
  • loves_oiloves_oi Member
    edited August 2012
    @techdojo , i was trying what you said , but i couldn't do it :(
    @atilim , it worked correctly , but it cause a new problem when It gives output on Simulator.
    When it is updated with a new one , old and new textfields are seen . I should delete old one in every cycle . For this reason , where should i put " stage:removeChild(text) " I can't already put it in onComplete function .Also, I tried outside but it gives errors
    local alreadyLoading = false
     
    local function onComplete(event)
    	local x = #event.data
    	print("size:", x )
     
    	local text = TextField.new(nil,"size : " .. x )
    	text:setPosition(10, 265)
    	text:setTextColor(0x007B25)
    	stage:addChild(text)
     
    	alreadyLoading = false
    end
     
    -- stage:removeChild(text)  ??????????
     
    local function onError()
    	print("error")
    	alreadyLoading = false
    end
     
    local function load()
    	if not alreadyLoading then
    		local loader = UrlLoader.new("<a href="http://www.catonmat.net/download/awk.cheat.sheet.txt&quot" rel="nofollow">http://www.catonmat.net/download/awk.cheat.sheet.txt&quot</a><img class="emoji" src="http://forum.giderosmobile.com/resources/emoji/wink.png" title=";)" alt=";)" height="20" />
    		loader:addEventListener(Event.COMPLETE, onComplete)
    		loader:addEventListener(Event.ERROR, onError)
    		alreadyLoading = true
    	end
    end
     
    local timer = Timer.new(60 * 1000, 0)  --it is updated every minute 
    timer:addEventListener(Event.TIMER, load)
    timer:start()
    load()
  • @Atilim - re your example don't you need to remove the eventListener's once they've been accessed or will that not cause a memory leak?
    WhiteTree Games - Home, home on the web, where the bits and bytes they do play!
    #MakeABetterGame! "Never give up, Never NEVER give up!" - Winston Churchill
  • ScouserScouser Guru
    edited August 2012
    @loves_oi: Your errors might be because text is defined as local to your onComplete function. Try something like:
    local alreadyLoading = false
    -- This is now your text
    local sizeText=nil
     
    local function onComplete(event)
    	local x = #event.data
    	print("size:", x )
     
    	-- If the text is on the stage already then remove it 
    	if stage:contains(sizeText) then stage:removeChild(sizeText) end
    	-- now create your new text
    	sizeText = TextField.new(nil,"size : " .. x )
    	sizeText:setPosition(10, 265)
    	sizeText:setTextColor(0x007B25)
    	stage:addChild(sizeText)
     
    	alreadyLoading = false
    end
     
    -- stage:removeChild(text)  ??????????
     
    local function onError()
    	print("error")
    	alreadyLoading = false
    end
     
    local function load()
    	if not alreadyLoading then
    		local loader = UrlLoader.new("<a href="http://www.catonmat.net/download/awk.cheat.sheet.txt&quot" rel="nofollow">http://www.catonmat.net/download/awk.cheat.sheet.txt&quot</a><img class="emoji" src="http://forum.giderosmobile.com/resources/emoji/wink.png" title=";)" alt=";)" height="20" />
    		loader:addEventListener(Event.COMPLETE, onComplete)
    		loader:addEventListener(Event.ERROR, onError)
    		alreadyLoading = true
    	end
    end
     
    local timer = Timer.new(60 * 1000, 0)  --it is updated every minute 
    timer:addEventListener(Event.TIMER, load)
    timer:start()
    load()
  • loves_oiloves_oi Member
    edited August 2012
    @Scouser , it doesn't compile. It gives the error:
    main.lua:10: bad argument #1 to 'contains' (Sprite expected, got nil)
    stack traceback:

    When i define a new function and call it from somewhere, it gives the similar error:
    Here is the code
     
    local alreadyLoading = false
     
    local function onComplete(event)
    	local i = event.data
    	print (i)
     
    	text1 = TextField.new(nil,"size : " .. i )
    	text1:setPosition(10, 125)
            text1:setTextColor(0x007B25)
            stage:addChild(text1)
    	alreadyLoading = false
    end
     
    local function helper()
    		stage:removeChild(text1)
    end
    	--stage:removeChild(text1)
     
    local function onError()
    	print("error")
    	alreadyLoading = false
    end
     
    local function load()
    	if not alreadyLoading then 
    		local loader = UrlLoader.new("<a href="http://www.catonmat.net/download/awk.cheat.sheet.txt&quot" rel="nofollow">http://www.catonmat.net/download/awk.cheat.sheet.txt&quot</a><img class="emoji" src="http://forum.giderosmobile.com/resources/emoji/wink.png" title=";)" alt=";)" height="20" />
    		loader:addEventListener(Event.COMPLETE, onComplete)
    		loader:addEventListener(Event.ERROR, onError)
    		alreadyLoading = true
    	end
    end
     
    local timer = Timer.new(30 * 1000, 0)  --it is updated every minute 
    timer:addEventListener(Event.TIMER, load)
    timer:start()
    helper()
    load()
    It gives the error:
    main.lua:20: bad argument #1 to 'removeChild' (Sprite expected, got nil)
    stack traceback:

    --- I hate nil :( ---
    --- Maybe my brain dream it as if it was python :S ---
  • @loves_oi
    but you try to remove text2:
    stage:removeChild(text2)
    Although you defined only variable text1
    So text2 is nil
    :)
Sign In or Register to comment.