diff --git a/README.md b/README.md index 911ce17..c454b85 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ -NTHUOJ_backend -============== +python code is in the ojbackend directory diff --git a/ojbackend/ReadMe b/ojbackend/ReadMe new file mode 100644 index 0000000..e121ab1 --- /dev/null +++ b/ojbackend/ReadMe @@ -0,0 +1,2 @@ +1. execute install.py to set up machine.config and ojdatase.config +2. execute dispatcher.py as daemon and it will check if there are new submissions need to be judged diff --git a/ojbackend/dispatcher.py b/ojbackend/dispatcher.py new file mode 100644 index 0000000..7a12c4e --- /dev/null +++ b/ojbackend/dispatcher.py @@ -0,0 +1,105 @@ +""" + dispatcher.py + This process continuously checks whether there exist unjudged submissions. +""" + +from dispatcherFunc import * +import time +import logging +import subprocess, sys +logging.basicConfig(filename = 'dispatcher.log', + level = logging.INFO, + format = '%(asctime)s ::%(message)s', + datafmt = '%m/%d/%Y %I:%M:%S %p') +logging.info('==========Dispatcher Started==========') + +machineInfo = getMachine() +if machineInfo != None: + initMachine(machineInfo) + logging.info('getMachine Success') +else: + logging.info('getMachine Error') + logging.info('Please check the file machineInfo.config to check the settings') + logging.info('==========Dispatcher Finished==========') + exit(0) + +dbIP, dbUser, dbPasswd, dbName = getdbInfo() +if dbIP == None or dbUser == None or dbPasswd == None or dbName == None: + logging.info('getdbInfo Error') + logging.info('Please check the settings in ojdatabase.config') + logging.info('==========Dispatcher Finished==========') + exit(0) +logging.info('connect to database') +DB = connectDB(dbIP, dbUser, dbPasswd, dbName) +while True: + + if DB == None: + logging.info('connect database error') + logging.info('Please check the settings in ojdatabase.config') + logging.info('==========Dispatcher Finished==========') + exit(0) + submissionStat = " \ + SELECT * FROM problem_submission \ + WHERE status = \'WAIT\' \ + ORDER BY id ASC \ + LIMIT 100; \ + " + cur = DB.cursor() + cur.execute("USE nthuoj;") + cur.execute(submissionStat) + sidQuery = cur.fetchone() + + while sidQuery != None: + sid = sidQuery[0] + pid = sidQuery[1] + logging.info('sidQuery Success!') + logging.info('sid = %d, pid = %d' % (sid, pid)) + problemID = " \ + SELECT * FROM problem_problem where id = \'%d\'; \ + " + cur.execute(problemID % pid) + pidQuery = cur.fetchone() + judgeSource = pidQuery[11] + judgeType = pidQuery[12] + judgeLanguage = pidQuery[13] + logging.info('pidQuery Success!') + logging.info('judgeSource = %s, judgeType = %s, judgeLanguage = %s' + % (judgeSource, judgeType, judgeLanguage)) + + if judgeSource == "LOCAL": + idleMachine = None + logging.info('get idleMachine') + while idleMachine == None: + time.sleep(1) + idleMachine = getIdleMachine() + logging.info('idleMachine = %s' % idleMachine) + updatesidStat = " \ + UPDATE problem_submission \ + SET status = \'JUDGING\' \ + WHERE id = \'%d\'; \ + " + cur.execute(updatesidStat % sid) + DB.commit() + judgeIP = machineInfo[idleMachine] + judgeURL = judgeIP + "/interface.py" + logging.info('get judgeURL = %s' % judgeURL) + else : + updatesidStat = " \ + UPDATE problem_submission \ + SET status = \'JUDGING\' \ + WHERE id = \'%d\'; \ + " + cur.execute(updatesidStat % sid) + logging.info('send info to other judge') + arg = judgeLanguage + " " + pid + " " + judgeURL + " " + sid + + if os.path.exists("/var/nthuoj/outsideConnection/sendToOtherJudge.sh"): + handle = popen("/var/nthuoj/outsideConnection/sendToOtherJudge.sh " + + arg + " & >> output.html", "w") + pclose(handle) + else : + logging.info('Send to other judge ERROR(No Judge)') + + sidQuery = cur.fetchone() + time.sleep(1) + diff --git a/ojbackend/dispatcherFunc.py b/ojbackend/dispatcherFunc.py new file mode 100644 index 0000000..05910fd --- /dev/null +++ b/ojbackend/dispatcherFunc.py @@ -0,0 +1,83 @@ +""" + dispatcherFunc.py + This file provides related functions for dispatcher.py. +""" +from bash import bash +import MySQLdb + + +def getMachine(): + #load judge information from judge.config + #the information include judge name, ip address + machineInfo = {} + with open("machineInfo.config",'r') as f: + try: + for line in f: + (machine, ip) = line.split() + machineInfo[machine] = ip + return machineInfo + except: + print "encounter troubles when opening machineInfo.config" + return None + + +def initMachine(machineInfo): + #create a dir and a file for machineStatus + #0 means availabe, 1 means occupied + try: + bash('test -d machineStatusDir && rm -r machineStatusDir') + bash('mkdir machineStatusDir') + with open("machineStatusDir/machineStatus.config",'w') as f: + for machineName in machineInfo.keys(): + f.write(machineName + " 0\n") + except: + print "encounter troubles when rm machineStatusDir or mkdir machineStatusDir" + return None + + +def getIdleMachine(): + #to get the machine which is available for judging + machinePosition = 0 + IdleMachine = '' + try: + with open("machineStatusDir/machineStatus.config",'r+') as f: + for line in f: + if(line.split()[1] == '0'): + machineName = line.split()[0] + f.seek(machinePosition + len(machineName) + 1, 0) + f.write('1') + IdleMachine = machineName + return IdleMachine + break + machinePosition = machinePosition + len(line) + return None + except: + return None + + +def getdbInfo(): + with open("ojdatabase.config",'r') as f: + try: + for line in f: + if(line.split()[0] == "host"): + dbIP = line.split()[2] + elif(line.split()[0] == "user"): + dbUser = line.split()[2] + elif(line.split()[0] == "passwd"): + dbPasswd = line.split()[2] + elif(line.split()[0] == "db"): + dbName = line.split()[2] + except: + print "Log dbInfo Error\nPlease check ojdatabase.config" + return None, None, None, None + return dbIP, dbUser, dbPasswd, dbName + + +def connectDB(dbIP, dbUser, dbPasswd, dbName): + try: + DB = MySQLdb.connect(host = dbIP, user = dbUser, passwd = dbPasswd, db = dbName) + print "connect db success\n" + return DB + except: + print "connect DB error\n" + return None diff --git a/ojbackend/install.py b/ojbackend/install.py new file mode 100644 index 0000000..acfd4fd --- /dev/null +++ b/ojbackend/install.py @@ -0,0 +1,40 @@ +""" + install.py + This file let users to set up machineInfo.config and ojdatabase.config file +""" + +from bash import bash +def set_MachineInfo(): + + bash('test -d machineInfo.config && rm -r machineInfo.config') + num = raw_input("Please input the total number of the judges:\n") + if num > 0: + try: + with open("machineInfo.config",'w') as f: + for i in range(0,int(num)): + judgeName = raw_input("Please input the judge's name:\n") + judgeIP = raw_input("Please input the judge's ip:\n") + f.write(judgeName + " " + judgeIP + "\n") + except: + print "Error occurs when setting machineInfo.config\n" + exit(0) + +def set_OjDatabase(): + bash('test -d ojdatabase.config && rm -r ojdatabase.config') + try: + with open("ojdatabase.config",'w') as f: + host = raw_input("Please input the ip of the database:\n") + user = raw_input("Please input the username:\n") + passwd = raw_input("Please input the password:\n") + db = raw_input("Please input the name of the database:\n") + f.write("host = " + host + "\n") + f.write("user = " + user + "\n") + f.write("passwd = " + passwd + "\n") + f.write("db = " + db + "\n") + except: + print "Error occurs when setting ojdatabase.config\n" + exit(0) + +set_OjDatabase() +set_MachineInfo() +