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

[Error] Attempt to index ? (a nil value) Save/load users.

Started by Cranium, 11 October 2012 - 07:35 PM
Cranium #1
Posted 11 October 2012 - 09:35 PM
Working on a mail system, I am encountering an error when it comes to registering and loading a user list. When I am calling back to my registration function, I keep getting an error when trying to check if a user exists.
Here is my code that pertains to saving/loading/registering users in a table:

 
--save/load
local function saveUsers(tUsers)
if type(tUsers)=='table' then
 local oFile=io.open('users','w')
 oFile:write(textutils.serialize(tUsers))
 oFile:close()
 return true
end
end
local function loadUsers()
local loading = true
if fs.exists('users') then
 local oFile=io.open('users','r')
 local tList=textutils.unserialize(oFile:read())
 oFile:close()
 return tList
else
 print("ERROR! Users file not found")
end
end
--registration
local function register(id,username,password)
print("Registration request from Computer "..id)
local tUsers=loadUsers()
if tUsers[id] then  --this is the error I receive
 rednet.send(id,"Exists")
 print("Account already registered")
else
 tUsers[id]={}
 tUsers[id].username = username
 tUsers[id].password = password
 tUsers[id].mail={}
 saveUsers(tUsers)
 print('Successfully registered Computer '..id..' as username "'..username..'"')
 rednet.send(id,"Success")
end
end

I have no other way to detect if a user exists other than this. Any help would be apprecieated.
Luanub #2
Posted 11 October 2012 - 10:12 PM
One thing I see is that you have declared tUsers local to the function register but you use it elsewhere in the program. Was that intentional? I'm going to assume so I think you know what your doing I just wanted to bring it up in case it was something you over looked. I miss the simple stuff all the time.

Is there already data in the file or is it empty? If it is empty that may be the issue, if I remember right I had an issue with that when I was making my account management system. Try setting up the program to where when it is first ran it will prompt you to setup an account and if not have it setup a default admin account or something so that the file has data in it from the time it is created(I'm assuming this is the server side??)
Lyqyd #3
Posted 11 October 2012 - 10:13 PM
I'll probably need to take a closer look at the code tonight, but try using oFile:read("*a"). Also, what does the returned tList contain?
Cozzimoto #4
Posted 11 October 2012 - 10:24 PM
Can u do a for loop to write each line of the users in the file you are saving, and when it comes to nil break the loop, and when it comes to reading the file you can do a for loop to read each line and place it in a table. Do u think at all that is possible for you to do?
remiX #5
Posted 11 October 2012 - 10:24 PM
After reading your question I decided to test if I could check if the username exists from a login system that I have (I didn't make it). I managed to get it with this simple code


function CheckUser()
    userFile = fs.open("passwordFolder/users","r")
    lineRead = userFile.readLine()
    repeat
        if lineRead == registerUser then
            textutils.slowPrint("Username '"..registerUser.."' already exists!", 20)
            registerUser = ""
            sleep(1.5)
            clear()
            RegisterUser()
            break
        end
        lineRead = userFile.readLine()
    until lineRead == nil
    RegisterPassword()
    userFile.close()
end

Just make it repeat reading the users file and have an if function within the repeat that if the lineread is equal to the username entered. Not sure if you can do it within your code though.
Cranium #6
Posted 11 October 2012 - 10:27 PM
What I have, is a server room(four computers sharing a disk drive) that will be hosting the mail system, and when it receives a request to register, it uses the registration function. for login, it uses another function.
The file is empty at this time, should I have it create an admin user/password at startup?
remiX #7
Posted 11 October 2012 - 11:12 PM
What I have, is a server room(four computers sharing a disk drive) that will be hosting the mail system, and when it receives a request to register, it uses the registration function. for login, it uses another function.
The file is empty at this time, should I have it create an admin user/password at startup?

May as well try if there's nothing else you can do so long. Test it for now
Cranium #8
Posted 11 October 2012 - 11:13 PM
I'll try it as soon as I get home after work. I'll have to encrypt it somehow, so that it can't be hacked.
remiX #9
Posted 12 October 2012 - 01:55 PM
Any luck? Can't you just have the repeat and then check if the name is equal to one within the file like I did within your register function?
Cranium #10
Posted 12 October 2012 - 05:12 PM
Alright, I no longer have the error, but the function is not saving to the file like it should.
I have a new block that checks for the users file, and if it does not exist, then it creates one with a temporary user/pass.

--users file integrity check
if not fs.exists("users") then
   local tUsers = {}
   tUsers[-1] = {}
   tUsers[-1].username = "SmartMailAdmin"
   tUsers[-1].password = "SmartMailAdminPassword"
   tUsers[-1].mail={"NONE"}
   local file = fs.open("users","w")
   file.writeLine(textutils.serialize(tUsers))
   file.close()
end
The problem is, when it calls back to the register function, it will not save the file correctly. It does receive the information from the mail client just fine, but it refuses to save it at all. Here's my current save/load/register functions:

--save/load
local function saveUsers(tUsers)
if type(tUsers)=='table' then
local oFile=io.open('users','w')
oFile:write(textutils.serialize(tUsers))
oFile:close()
return true
end
end
local function loadUsers()
local loading = true
if fs.exists('users') then
local oFile=io.open('users','r')
local tList=textutils.unserialize(oFile:read())
oFile:close()
return tList
else
print("ERROR! Users file not found")
end
end
--registration
local function register(id,user,pass)
print("Registration request from Computer "..id)
local tUsers=loadUsers()
if tUsers[id] then
rednet.send(id,"Exists")
print("Account already registered")
else
tUsers[id] = {}
tUsers[id].username = user
tUsers[id].password = pass
tUsers[id].mail = {}
saveUsers(tUsers)
print(textutils.serialize(tUsers)) --this line proves that it receives all the information
print('Successfully registered Computer '..id..' as username "'..user..'"')
rednet.send(id,"Success")
end
end
Jajnick #11
Posted 12 October 2012 - 05:50 PM

oFile:write(textutils.serialize(tUsers))
oFile:close()
You are using the colon operator instead of the dot (period). For some reason, referencing to functions in tables returned by fs.open() doesn't work as you may expect. I personally don't know much about this, since I was never interested in object-oriented programming in Lua (that's what C# and other languages are for), but I believe that those two operators behave differently.

TL;DR:
Replace ":" with ".".
Lyqyd #12
Posted 12 October 2012 - 05:55 PM

oFile:write(textutils.serialize(tUsers))
oFile:close()
You are using the colon operator instead of the dot (period). For some reason, referencing to functions in tables returned by fs.open() doesn't work as you may expect. I personally don't know much about this, since I was never interested in object-oriented programming in Lua (that's what C# and other languages are for), but I believe that those two operators behave differently.

TL;DR:
Replace ":" with ".".

This is incorrect. Functions in file handles opened with io.open() are used with colons, not periods. The usage in the code is correct.
Jajnick #13
Posted 12 October 2012 - 06:21 PM
…You haven't checked that for yourself, have you?
Cranium #14
Posted 12 October 2012 - 07:41 PM
…You haven't checked that for yourself, have you?
Lyqyd is actually correct. For the io functions, you want to use " : ", not " . "
But either way, I was able to get it to somewhat work by deleting the file before saving it again. Not sure what I had done to mess it up, but this is a useable workaround.
Jajnick #15
Posted 12 October 2012 - 07:46 PM
Oh god, I haven't noticed that you're using io.open() to open files instead of fs.open(), I failed, sorry. :F