←  Ask a Pro

ComputerCraft | Programmable Computers for Minecraft

»

[Coroutines] Coroutine Dies Each Time it P...

Geforce Fan's Photo Geforce Fan 05 Jun 2014

Basicly, my coroutine is dieting every time it pulls an event Note that it is actually running this code
Here's the pastebin to my code
Here's the code:
(some of the functions are useless, this is going through massive restructoring
if OneOS then
  if shell.getRunningProgram() == "startup" then
	--to make sure they're not running this in shell
	--because if they are it'll crash.
	OneOS.ToolBarColour = colours.lightGrey
  end
end
--Credits:
--Developers:
--Hithere

--APIs

--Special thanks to:
--oeed, for OneOS, the OS Sapphari was
--designed for
--DEVELOPER CONFIG
local waitForMessage =  false

--------------------------------------------------
  sapphariVersionString = "1.0"
  sapphariVersionNumber = 1

  sapphariSites = {}
  sapphariBlacklist = {}
--TESTS:
--might fix some crashes
--+function error()




	--The script sets the news, then sets the url vars
shell.run("rom/programs/http/pastebin run Jg8D7mLi")
--print("--------------------------------------------------")
--It would seem I don't need to kill any functions as OneOS handles that for me :D/>/>
--Internal functions
local sapphInt = {}
function sapphInt.redrawUI()
  term.setBackgroundColor(colors.white)
  term.setTextColor(colors.black)
  local termX, termY = term.getSize()
  for i=1,2 do
	paintutils.drawLine(1,i,termX,i,colors.lightGray)
  end
  paintutils.drawLine(2,1,termX/3,1,colors.white)
  paintutils.drawLine(termX/3+2,1,termX/3+3,1,colors.green)
  --this is the last thing getting drawn,
  --we do not need to specify length.
  --writing on it takes care of it
  term.setCursorPos(termX/3+2,1)
  term.write("Refresh")
  --now it's the right length.
end
--this function will get the data for a site,
--however, will not run it.
function sapphInt.getSite(pasteID)
  local responce = http.get("http://pastebin.com/raw.php?i="..pasteID)
  if responce then
	return loadstring(responce.readAll())
  else
	return false
  end
end
function sapphInt.handleMenu(typeClick, clickX, clickY)
  --handle the user   clicking the menu
  print"cal1"
  local termX,termY=term.getSize()
  if typeClick == 1 then
	--okay, it's a left click, passes first one'
	if clickX>1 then --okay, in somewhere special
	  if clickX<termX/3+1 then
		--okay, the user wants to change the url.
		term.setCursorPos(2,1)
		print"cal"
		input = read()
		print"dun"
		--we will return the input which will
		--be returned until the program must
		--end, then it will be a temporary
		--global variable and read by safari
		--again. Complicated? True.
		return input
	  end
	end
	if clickX>termX/3+1 then
	  if clickX<termX/3+8 then
		--need to refresh page nao
		return currentSite
	  end
	end
  end
end
function sapphInt.decodeHumanReadableURL(HRURL)
  --this is where we attempt to decode a
  --human readable url. If fails, will tell
  --calling function to attempt to use the
  --plain url instead.
  if sapphariSites[HRURL] then
	--this must be an HRURL, so we'll give them'
	--the pasteID
	currentSite = sapphariSites[HRURL]
	return sapphariSites[HRURL]
  else
	currentSite = HRURL
	return HRURL
	--this must be a PasteID then
  end
end
--WEBSITE FUNCTON
--sapphutils, MUST be global!!!
sapphUtils = {}
function sapphUtils.pullEvent(filter)
  print"f"
  termX,termY=term.getSize()
  print"redaw"
  sapphInt.redrawUI()
  while true do
	local event, p1, p2, p3,  p4, p5, p6, p7 = os.pullEventRaw()
	--note that pullEvent yields
	--so we have to make sure we don't
	--kill the routine while it's checking
	--for events
	if event == "mouse_click" and p3==1 then
	  print"handling"
	  if p1 == 1 and p3 == 1 then
		  if p2>1 and p2<termX/3+1 then
			print"menu"
			term.setCursorPos(5,5)
			newSiteq=true
			clickx=p2
			clicky=p3
			--okay, it'll be
		  elseif p2>termX/3+1 and p3<termX/3+8 then
			newSiteq=true
			clickx=p2
			clicky=p3
			--okay, it'll be Refresh then.
		  end
	  end
	  if newSiteq then
		print"die"
	  coroutine.yeild()
	  end
	end
	if filter then
	  if event == filter then
		return event, p1, p2, p3, p4, p5, p6, p7
	  end
	else
	  return event, p1, p2, p3, p4, p5, p6, p7
	end
	--if they changed sites, we'll never get here.
  end
end
  
function sapphUtils.read(startx, starty, endx, endy)
  while true do
	evt, text = os.pullEvent()
	if evt == "key" then

	end
  end
end
--this must get  the pasteid, not the human
--redable url
function sapphInt.handleWebsite(url)
  print"Aliv fn"

  local rurl = sapphInt.decodeHumanReadableURL(url)
  print"stil"
  local site = sapphInt.getSite(rurl)
  print"loadin sit"
  coSite = coroutine.create(site)
end
function sapphInt.handleSapphari()
  local site = sapphInt.handleWebsite("homepage")
  --coSite = coroutine.create(site)
  --handleWebsite does this
  while coroutine.status(coSite) == "suspended" do
	coroutine.resume(coSite)
  end
  print("it diedz")
  print(coroutine.status(coSite))
end
---------------------------------------------------

sapphInt.handleSapphari()

Edited by Geforce Fan, 05 June 2014 - 01:56 AM.
Quote

theoriginalbit's Photo theoriginalbit 05 Jun 2014

okay so I reduced your code down to the code that actually runs just to make sure of my findings. here is the code that actually runs (I also removed the decodeHumanReadableURL function and passed the pastebin code instead of "homepage")

The Code

from this code it is very evident that you don't know how coroutines work, you're grabbing the pastebin code, wrapping it in a coroutine, and running it. However whenever you resume this coroutine you're not giving it any event data so it will never function correctly, nor is your own code yielding meaning the program will eventually be killed. I would suggest having a read up on coroutines and learning how they work, Bubba has a tutorial that will help.
Quote

Geforce Fan's Photo Geforce Fan 05 Jun 2014

First of all I'd like to mention you have removed the almost entire code. A lot of function where temporally "disabled" and where some of the core functions of this before I introduced Coroutines. In short, you can't switch sites anymore, nor will you see the menu bar. You also removed the functionality for Human Readable URLS, a core function of this program.(admittantly, they where not active in the code I showed. Basicly, this code use to work by making a new version of pullEvent and "injecting" the code inside there)

didn't read the top bit

Second of all, I did read up on that. I thought pullEvent yielded the coroutine of the event you asked for, not your coroutine.
Edited by Geforce Fan, 05 June 2014 - 03:23 AM.
Quote

theoriginalbit's Photo theoriginalbit 05 Jun 2014

 Geforce Fan, on 05 June 2014 - 03:21 AM, said:

First of all I'd like to mention you have removed the almost entire code.
Precisely, the code I posted there was the code that was running. none of the other code was actually running. sometimes the easiest ways to see what is wrong is to reduce the noise, and there was a lot of noise in there. I wasn't saying use that code, I was reducing it down so it could be easily seen what is actually happening.

 Geforce Fan, on 05 June 2014 - 03:21 AM, said:

Second of all, I did read up on that. I thought pullEvent yielded the coroutine of the event you asked for, not your coroutine.
Yes and no. os.pullEvent is a wrapper of os.pullEventRaw (with the logic of dealing with terminate events), and os.pullEventRaw is literally just a wrapper of coroutine.yield
so when a website script will yield via one of those 3 methods (doesn't matter which) if they supply an argument (i.e. an event they wish to wait for) it is returned from the coroutine.resume you used to resume that routine. So to get this desired event you'd do
local ok, evt = coroutine.resume(coSite)
now that the coroutine has yielded, it's time for your script to yield too. now another thing to note, like i said before, is when you resume the routine you're not giving it event data, and this is mainly because you're not yielding. So making sure you yield and that you give the event data, would create a while loop like this
coroutine.resume(coSite) --# need to start the routine, now it will be yielding waiting for an event

while coroutine.status(coSite) ~= "dead" do --# checking its not dead is a little better
  local event = { os.pullEvent() }
  coroutine.resume(coSite, unpack(event))
end
this will resume the coroutine giving it any event data, however it still doesn't respect any filters that were provided, so you'd do something like this

coroutine.resume(coSite) --# need to start the routine, now it will be yielding waiting for an event

local _, filter
while coroutine.status(coSite) ~= "dead" do --# checking its not dead is a little better
  local event = { os.pullEvent( filter ) } --# we don't need to always resume, only if the site needs to resume do we need to
  _, filter = coroutine.resume(coSite, unpack(event))
end

now there's one last problem and that is if any error is risen in the site it won't be displayed, and that is what the first return value from coroutine.resume is for.
coroutine.resume(coSite) --# need to start the routine, now it will be yielding waiting for an event

local ok, filter
while coroutine.status(coSite) ~= "dead" do --# checking its not dead is a little better
  local event = { os.pullEvent( filter ) }
  ok, filter = coroutine.resume(coSite, unpack(event))
  if not ok then
    error( filter, 0 )
  end
end

all in all, I'm not too sure why you're running the site in a coroutine, as it currently stands all the code I posted above could be removed and you could simply just run the site code, however I assume you may be doing some extra logic once the site has yielded, like rendering or something.
Quote

Geforce Fan's Photo Geforce Fan 06 Jun 2014

Thanks for the help. This REALLY helps explain coroutines. I was about ready to give up the project but now I can continue!

Actually, it's so that I can start making multiple tabs, like a normal web browser or a computer craft operating system. Also to render the top bar once I start calling those functions in that area.
Quote