This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Nikola's profile picture

code is acting very wonkey!

Started by Nikola, 09 August 2012 - 10:25 PM
Nikola #1
Posted 10 August 2012 - 12:26 AM
for the past week i have been developing my own client server messaging systems, and until today, things have been speeding along quite nicely. now, all of a suddend, after cleaning up some crappy
filtering function, the entire system, specificly the server end, has just simply refused to accept data from rednet.receive(), and not globally, only in specific spots, just in that newly cleaned function, which was appaling before, and now nice and clean, smart, but for some reason, the commands in it wont gather input from the wireless signal that are comming in, and once i fix one thing, something COMPLETELY unrelated, breaks, for example, i cant create a local varible anymore in a function that is more that 1 function deep, which causes problems, since im running parallel proccesses. right now, im far too fursterated to actually find what im doing wrong, and im hoping its something simple, that could be caught right away by a fresh set of eyes. here is the server code——


--login/log out
function1 = function()
  local v = 1
  rednet.open("left")
  while v do
	local ID, msg = waitForMessage("login", "logout")
	if msg == "login" then
	  rednet.send(ID, "login attemp acknowledged, send your credentials")
	  username = listenFor(ID, 0)
	  if userLookUp(username, ID) then
		password = listenFor(ID, 0)
		if passwordLookUp(username, password) then
		  verifier = math.random(1000) * 9
		  verifier = tostring(verifier)
		  loggedin[ID][1] = username
		  loggedin[ID][2] = password
		  loggedin[ID][3] = verifier
		  rednet.send(ID, verifier)
		  print("someone has logged in!")
		  print("IP address: ", ID, "password: ", password, "with verifier: ", verifier)
		else
		  errorLog(3, ID)
		end
	  else
		errorLog(2, ID)  
	  end	  
	elseif msg == "logout" then
	  if loggedin[ID][1] == "nil" then
		rednet.send(ID, "you are not logged in, that means you can't log out, silly.")
	  else
		loggedin[ID][1] = "nil"
		loggedin[ID][2] = "nil"
		loggedin[ID][3] = "nil"
		rednet.send(ID, "you have been logged out!")
	  end
	end
  end
end
--message routing
function2 = function()
  b = 1
  rednet.open("left")
  while b do
	local ID, msg, dist = rednet.receive()
	if (msg == "send message") and (isLoggedin(ID)) then
	  rednet.send(ID, "send verifier")
	  verifier1 = listenFor(ID, 0)
	  username1 = getUsername(ID)
	  verifier1 = tostring(verifier1)
	  print(verifier1)
	  if verifierLookUp(username1, verifier1) then
		rednet.send(ID, "send destination")
	  elseif verifier == "connection timed out" then
		errorLog(1)
		break
	  else
		errorLog(5)
		break
	  end		
	  dest = listenFor(ID, 1)
	  if dest ~= "connection timed out" then
		rednet.send(ID, "transfere data")
	  elseif dest == "connection timed out" then
		errorLog(1)
		break
	  end
	  msg = listenFor(ID, 1)
	  if msg ~= "connection timed out" then
		dest = tonumber(dest)
		rednet.send(dest, msg)
	  elseif msg == "connection timed out" then
		errorLog(1)
		break
	  end
	  reply = listenFor(dest, 1)
	  if reply == "received message" then
		rednet.send(ID, "your message has arrived at its destination")
	  elseif reply == "connection timed out" then
		rednet.send(ID, "your message has failed to arrive at its destination")
	  end
	end
  end
end
--terminal section
function3 = function()
  print("welcome to the network manager!")
  print("for help, type in the help command")
  local h = 1
  while h do
	command = read()
	-- commandParser(command)
	if command == "help" then
	-- need to learn file io so i can load out help from a file instead of placeing it inside of the program
	elseif command == "newUser" then
	-- allows the admin to add a new user profile
	  print("type in the new user's name, then password")
	  c = 0
	  local username = read()
	  local password = read()
	  repeat
		c = c + 1
	  until users[c][1] == "nil"
	  users[c][1] = username
	  users[c][2] = password  
	elseif command == "sendMessage" then
	-- allows the admin to send a message to anyone on the network, with options to send one to multiple users
	elseif command == "pingUsers" then
	-- sends a request to all active users to send their unique verifier, if an active user doesn't respond, the user
	-- is automaticly logged out.  
	  for q = 1, (#loggedin/5) do
		if loggedin[q][1] ~= "nil" then
		  rednet.send(q, "ping")
		  local msg = listenFor(q, 1)
		  if msg == "connection timed out" then
			--logs out the unresponsive user
			loggedin[ID][1] = "nil"
			loggedin[ID][2] = "nil"
			loggedin[ID][3] = "nil"
		  end
		end
	  end
	elseif command == "changeEncryptionCode" then
	-- this allows the network encryption to be changed at anytime, just in case someone is listening to
	-- network traffic and they shouldn't be, and makes sure that people with clients that don't meet the specs
	-- are forced off the network at the next pingUsers event.
	elseif command == "displayUsers" then
	  local out = ""
	  for q = 1, (#users/5) do
		out = ""
		islogged = "no"
		if users[q][1] ~= "nil" then
		  out = out..users[q][1].."  "
		  out = out..users[q][2].."  "
		  for w = 1, (#loggedin/5) do
			if loggedin[w][1] == users[q][1] then
			  out = out.."logged in".."  "
			  islogged = "yes"
			  break
			end
		  end
		  if islogged ==  "no" then
			out = out.."not logged in".."  "
		  end
		  print(out)
		end
	  end
	-- lists all the users that have been registered.
	elseif command == "getLocation" then
	-- sends a command to a client to return their location by using what ever means availible.
	elseif command == "schedualEvent" then
	-- allows the admin to schedual an automated event, like a pingUsers command, or getLocation, or to shutdown the server
	-- and really, automaticly use any server command, with any parameters, at any time.
	elseif command == "flushBuffer" then
	  for q = 1, 10 do
		print(rednet.receive(1))
	  end
	else
	  errorLog(4)
	end
  end
end

function commandParser(stuff)
  -- need to learn more about sting commands in lua to build a parser
  -- the parser will return a table 'argutable', and a command so
  -- length = len(stuff)
  -- for q = 1 to length
  --   char$ = mid$(stuff, 1 q)
  --   if char$ = isnumber then argutable(z) = convert.$->#(stuff, q): goto 1
  --   if char$ ~= " " then argutable$(z) = argutable$(z) + char$
  --   if char$ = " "  then z = z + 1
  -- 1 next q
  -- function convert.$->#(string$, place)
  --   while (mid$(string$, 1, q) = is#)
  --	 w = w + 1
  --	 num(w) = asc(mid$(string$, 1 q) - 56
  --   wend
  --   for q = 1 to #num
  --	 if q = 1 then  number = num(q)
  --	 if q ~= 1 then number = number + (num(q) * 10^q)
  --   next q
  -- return number
  -- end
end

function shakeHands(IP, argument, timeOut)
  verifier = ListenFor(IP, 1)
  if verifier == argument then
	return true
  elseif verifier == "connection timed out" then
	errorLog(1)
	return false
  end  
end
--error handeling
function errorLog(x, ID)
  if x == 1 then
	print("error #1: client ", ID, "took too long to respond")
  elseif x == 2 then
	print("error #2: client ", ID, "has submitted an unregistered username")
	rednet.send(ID, "the username you have submitted is unregistered!")
  elseif x == 3 then
	print("error #3: client ", ID, "has submitted an invalid password")
	rednet.send(ID, "the passwword you have submitted is invalid")
  elseif x == 4 then
	print("error #4: terminal, you have entered in an unknown command")
  elseif x == 5 then
	print("unauthorized attempt to access server, invalid verification code: ", verifier)
  elseif x == 6 then
	print("user already logged in on this account!")
	rednet.send(ID, "you are already logged in!")
  else
	print("error ?: unknown error! Contact the author!")
  end
end

function userLookUp(username, ID)
  print("looking up the username")
  print(username)
  for e = 1, #users do
	if username == users[e][1] then
	  print("found username")
	  if username == loggedin[ID][1] then
		errorLog(6, ID)
		return false
	  end
	  return true
	end
  end
  return false
end

function isLoggedin(ID)
  if loggedin[ID][1] ~= "nil" then
	return true
  else
	return false
  end
end

function passwordLookUp(username, password)
  local t = 0
  repeat
	t = t + 1
	user = users[t][1]
  until (username == user) or (t == #users)
  if (user == username) and (t == #users) then
	if users[t][2] == password then
	  return true
	else
	  return false
	end
  elseif user == username then
	if users[t][2] == password then
	  return true
	else
	  return false
	end
  else
	return false
  end
end

function verifierLookUp(username, verifier)
  print("username: ", username, " verifier: ", verifier)
  for e = 1, #users do
	if username == loggedin[e][1] then
	  print("user is logged in!")
	  ID2 = e
	  break
	end
  end
  print(ID2)
  print(loggedin[ID2][3])
  if loggedin[ID2][3] == verifier then
	return true
  else
	return false
  end
end

function getUsername(ID)
  return loggedin[ID][1]
end
--this is the function causing the problems, i think...
[color=#800080]function listenFor(IP, time)
  for q = 1, 5 do
	if time == 0 then
	  ID1, msg1, dist1 = rednet.receive()
	else
	  ID1, msg1, dist1 = rednet.receive(time)
	end
	if ID1 == IP then
	  return msg1
	end
  end
	return "connection timed out"
end[/color]

function waitForMessage(x, y)
  a = 0
  repeat
	local ID, msg, dist = rednet.receive()
	if msg == x then
	  return ID, x
	elseif msg == y then	
	  return ID, y
	end
  until a
end


users = {}		  
for i=1,1000 do
  users[i] = {}	
  for j=1,5 do
	users[i][j] = "nil"
  end
end

argutable = {}		  
for k=1,1000 do
  argutable[k] = {}	
  for l=1,5 do
	argutable[k][l] = "nil"
  end
end

loggedin = {}		  
for n=1,1000 do
  loggedin[n] = {}	
  for m=1,5 do
	loggedin[n][m] = "nil"
  end
end


parallel.waitForAny(function1, function2, function3)[/i]



and here is the client code———————————————————————————————

function send()
  local IP = ID
  local v = 1
  local verifier = tostring(msg)
  while v do
	print("type in you message, then you destinaion")
	message = read()
	dest = read()
	dest = tostring(dest)
	rednet.send(IP, "send message")
	rednet.send(IP, verifier)
	rednet.send(IP, dest)
	rednet.send(IP, message)
	msg = listenFor(IP, 1)
	print(msg)
	if msg == "your message has failed to arrive at its destination" then
	  print("delivery failed")
	end
  end
end

function listen()
  local IP = ID
  local v = 1
  while v do
	msg = listenFor(IP, 0)
	print(msg)
	rednet.send(ID, "received message")
  end
end

function listenFor(IP, time)
  rednet.open("left")
  for q = 1, 5 do
	if time == 0 then
	  ID1, msg1, dist1 = rednet.receive()
	else
	  ID1, msg1, dist1 = rednet.receive(time)
	end
	if ID1 == IP then
	  return msg1
	end
  end
  if msg == nil then
	return "connection timed out"
  end
end


rednet.open("top")
local username = read()
local password = read()
--add a UI for the login entry fields
rednet.broadcast("login")
local ID, msg, dist = rednet.receive()
print(msg)
--replace above line with a waitFormessage() function
print("Server ID: ", ID)
rednet.send(ID, username)
rednet.send(ID, password)
msg = listenFor(ID, 1)
print(msg)
parallel.waitForAny(listen, send)


there is still a truck load of more features that i need to add, like the ablility to have a server connect
to another server on behalf of a client in order to contact a client outside of the imediate network.
and btw, this is all my own code, the only way i could make it more original at this point is to rewrite all of the rednet api… which actually might be fun…. i do plan to make this into an api, to simplify setting up complex, and very large networks with roaming profiles.

i know its alot, but i really do need some help from a Pro. (and sorry for the caps)
also,

The Error == the code has its own way of handleing errors, and right now, it refuses to pass a message from one computer to another, mainly because the verification code sent by the client near the begining of the message sending process isnt actually being picked up be the server. this means that when the message routing portion of the server, function2, checks the verification code sent by the client, it doesnt actually have anything to check it against, that issue occurs in the function verificationLookUp(username, verifier) so, when that function fails, the message cant go through, the purpose of that is ensure complience with the server standards.

damn, didn't realize the spacing was screwed up when i posted, sorry
Cranium #2
Posted 10 August 2012 - 12:37 AM
I see several times that you are declaring something like function 1 = function(). Is that the way that you intend to create a function? If so, why? Functions are usually declared like this:

function test()--function says that this is a function, and test is the name of the function
print("test")
--other code here
end  --must end your functions.

edit: and I think you may have fudged on the copy/paste a little. Could you post your code with code tags?
Nikola #3
Posted 10 August 2012 - 12:45 AM
you're completely right, but for some reason, i discovered very early on in testing that defining the function normally would cause parallelWaitForAny/All() to fail to execute the functions enclosed unless i did so. and for some reason, the wiki also show an example of how to use parallelWaitForAny/All() in the same way, it works, so i haven't messed with it
Cranium #4
Posted 10 August 2012 - 01:45 AM
I was told that you can just drop the () off of the name of a function you create, and the parallel API would run it. The main concern I have(and if I'm wrong, I hope the actual Pro's will correct me…) is that the functions you're creating have the same name. Mainly they are listing just function(), with no name attached. Does that actually work with multiple ones? Seems to me that they would conflict.
Nikola #5
Posted 10 August 2012 - 02:14 AM
it doesn't appear so, my issue is that listenFor() wont work all of the time, some times it works, like in the log in, other times it wont, like during message routing
ps: nice signature!
pps: the reason you can do that is because you can assign a function to a varible, kind of like a shortcut in this case
Lyqyd #6
Posted 10 August 2012 - 02:38 AM
These are equivalent. The first is syntactic sugar for the second.


function bar()
bar = function()
Nikola #7
Posted 10 August 2012 - 02:44 AM
im not sure if that helps me…
Lyqyd #8
Posted 10 August 2012 - 04:02 AM
It doesn't; I was clarifying for craniumkid22, in reference to his first post on the thread. And honestly, I would design something like this such that it doesn't need the parallel API. I'm not entirely certain on how the parallel API determines which function to send events to, so I avoid it.
Cranium #9
Posted 10 August 2012 - 04:29 AM
These are equivalent. The first is syntactic sugar for the second.


function bar()
bar = function()
I did not know that!
Nikola #10
Posted 12 August 2012 - 01:56 AM
it seems that each function reads from a global stream of events, so if one function receives a rednet message, they all do, which is why i wrote the program the way i did, i wanted to keep things fast and effiecent, and before i cleaned up the code, its behavior was very predictable, and i thought that i would be able to make this one of the greatest networking programs the world of minecraft had ever seen, but, once i did that cleanup, it seems that that idea flew through a window…