Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local clientAssignmentDirectory = "usr/"
- local userList = "user_list"
- local adminUser = "KillaVanilla"
- local adminPass = "something"
- local lastAccessTimes = {}
- local logfile = "server.log"
- local logServ = 117
- function log(stuff)
- local lHandle = fs.open(logfile, "a")
- lHandle.writeLine(stuff)
- lHandle.close()
- end
- local function spec_print(...)
- local args2 = {...}
- local str = ""
- for i,v in ipairs(args2) do
- str = str..v
- end
- rednet.send(logServ, textutils.serialize({"LOGSERV", "GradeServ", str}))
- if http then
- local wHandle = http.get("http://timeapi.org/utc/now")
- if wHandle then
- str = "[ RL TIME: "..wHandle.readAll().." UTC] "..str
- else
- str = "[ MC TIME: Day "..os.day().." @ "..textutils.formatTime(os.time()).."} "..str
- end
- end
- print(str)
- log(str)
- end
- local successMsg = textutils.serialize({"assignment", "return_code", "success"})
- assert(fs.exists(userList), userList.." does not exist!")
- for i,v in ipairs(rs.getSides()) do
- if peripheral.getType(v) == "modem" then
- rednet.open(v)
- end
- end
- if not fs.exists(clientAssignmentDirectory) then
- fs.makeDir(clientAssignmentDirectory)
- end
- local handle = io.open(userList, "r")
- local cred_table = {}
- for line in handle:lines() do
- string.gsub(line, "([%a%p%d]+)%s+([%a%p%d]+)", function(user, pass) cred_table[user] = pass if not fs.exists(fs.combine(clientAssignmentDirectory, user)) then fs.makeDir(fs.combine(clientAssignmentDirectory, user)) end end)
- end
- cred_table[adminUser] = adminPass
- handle:close()
- local function runTests(inputFile) -- run a simple pair of tests designed to catch (lazy) cheaters and weed out obviously-wrong answers.
- if not fs.exists(inputFile) then
- spec_print("Attempted to run test on nonexistent file: "..input)
- return "false", "File does not exist"
- end
- local iHandle = fs.open(inputFile, "r")
- local input = iHandle.readAll()
- iHandle.close()
- for i,v in ipairs(fs.list(clientAssignmentDirectory)) do
- if fs.isDir(fs.combine(clientAssignmentDirectory, v)) then
- for i,file in ipairs(fs.list(fs.combine(clientAssignmentDirectory, v))) do
- if file ~= "SanityTests.log" then
- local handle = fs.open(fs.combine(fs.combine(clientAssignmentDirectory, v), file), "r")
- if handle.readAll() == input then
- handle.close()
- return "false" -- cheater!
- end
- handle.close()
- end
- end
- end
- end
- local ok, err = pcall(loadstring(input))
- return tostring(ok)
- end
- local function getLoginCredent(id)
- for i,v in pairs(lastAccessTimes) do
- if v[2] == id then
- return true, i
- end
- end
- end
- local function runSanityTests()
- for userID,user in ipairs(fs.list(clientAssignmentDirectory)) do
- if fs.isDir(fs.combine(clientAssignmentDirectory, user)) then
- local sanityLog = fs.open(fs.combine(fs.combine(clientAssignmentDirectory, user), "SanityTests.log"), "w")
- for fileID, fileName in ipairs(fs.list(fs.combine(clientAssignmentDirectory, user))) do
- if fileName ~= "SanityTests.log" then
- sanityLog.writeLine(fileName..": "..runTests(fs.combine(fs.combine(clientAssignmentDirectory, user), fileName)))
- end
- end
- sanityLog.close()
- end
- end
- end
- local function listenerThread()
- while true do
- local id, msg = rednet.receive()
- msg = textutils.unserialize(msg)
- if msg then
- local hasLoggedIn, user = getLoginCredent(id)
- local isAdmin = false
- if hasLoggedIn then
- isAdmin = (user == adminUser)
- end
- if msg[1] == "assignment" then
- if msg[2] == "login" then
- if cred_table[msg[3]] == msg[4] then
- if msg[3] == adminUser then
- spec_print("ID "..id.." logged in as "..msg[3]..". (admin account)")
- else
- spec_print("ID "..id.." logged in as "..msg[3]..". (student account)")
- end
- lastAccessTimes[msg[3]] = {os.clock(), id}
- rednet.send(id, successMsg)
- end
- elseif hasLoggedIn then
- if msg[2] == "logout" then
- spec_print("ID "..id.." ("..user..") logged out.")
- lastAccessTimes[user] = nil
- rednet.send(id, successMsg)
- elseif msg[2] == "submit" then
- if not fs.exists(fs.combine(clientAssignmentDirectory..user, msg[3])) then
- local file = fs.open(fs.combine(clientAssignmentDirectory..user, msg[3]), "w")
- file.write(msg[4])
- file.close()
- spec_print("ID "..id.." ("..user..") submitted an assignment as file "..msg[3].." ("..fs.getSize(fs.combine(clientAssignmentDirectory..user, msg[3])).." bytes written).")
- rednet.send(id, successMsg)
- end
- lastAccessTimes[user][1] = os.clock()
- elseif msg[2] == "get_results" then
- spec_print("ID "..id.." ("..user..") downloaded his/her test results.")
- local file = fs.open(fs.combine(clientAssignmentDirectory..user, "SanityTests.log"), "r")
- rednet.send(id, textutils.serialize({"assignment", "results", file.readAll()}))
- file.close()
- lastAccessTimes[user][1] = os.clock()
- elseif isAdmin then
- local fullFileName = fs.combine(clientAssignmentDirectory, msg[3])
- if msg[2] == "get" then
- if fs.exists(fullFileName) then
- spec_print("ID "..id.." ("..user..") downloaded file "..fullFileName..".")
- local handle = fs.open(fullFileName, "r")
- rednet.send(id, textutils.serialize({"assignment", "file", msg[3], handle.readAll()}))
- handle.close()
- end
- elseif msg[2] == "list" then
- spec_print("ID "..id.." ("..user..") requested directory listing for "..fullFileName..".")
- if fs.exists(fullFileName) and fs.isDir(fullFileName) then
- rednet.send(id, textutils.serialize({"assignment", "list", msg[3], fs.list(fullFileName)}))
- end
- elseif msg[2] == "put" then
- local handle = fs.open(fullFileName, "w")
- handle.write(msg[4])
- handle.close()
- spec_print("ID "..id.." ("..user..") uploaded file "..fullFileName.." ("..fs.getSize(fullFileName).." bytes written).")
- rednet.send(id, successMsg)
- elseif msg[2] == "delete" then
- if fs.exists(fullfileName) then
- fs.delete(fullFileName)
- spec_print("ID "..id.." ("..user..") deleted file "..fullFileName..".")
- end
- end
- end
- end
- end
- end
- end
- end
- local function timedEventThread()
- local sanityTestItr = 0
- while true do
- local lastAccessTimes_clone = {}
- for i,v in pairs(lastAccessTimes) do
- if os.clock() < v[1]+300 then
- lastAccessTimes_clone[i] = v
- else
- spec_print("Automatically logging out ID "..v[2].." ("..i..") due to inactivity.")
- end
- end
- lastAccessTimes = lastAccessTimes_clone
- sanityTestItr = sanityTestItr+1
- if sanityTestItr >= 30 then
- runSanityTests()
- sanityTestItr = 0
- end
- os.sleep(1)
- end
- end
- spec_print("GradeServ V1.2 is ONLINE!")
- parallel.waitForAll(listenerThread, timedEventThread)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement