def open(self, resume=False): """Open the contest (connect to db, ...). Must have been created before @param resume: Whether the contest must be resumed """ if not os.path.isdir(self.directory): raise "No such contest '%s' exists - %s not found" % \ (self.name, self.directory) self.dbproxy = SqliteDBProxy(self.dbpath) self.sm = SubmissionManager(self) if not resume: self.dbproxy.clear_submissions_sync()
class Contest(object): """The contest. The server requires a (single) contest object. @ivar name: Contest name @ivar directory: Contest directory @ivar dbpath: Path to contest database @ivar avatars: Dictionary of loggedin avatars (userid=>avatar object) @ivar duration: Duration of the contest in seconds @ivar profile: Contest Profile object @ivar ts_start: Timestamp during start of contest @ivar dbproxy: The database proxy object which has methods to manipulate the database. @ivar dirs: Special directories (name=>absolute path) team - Team related files judge - Judge's files stat - Contest statistics related files """ # Properties duration = property(lambda s: s._duration) profile = property(lambda s: s._profile) ts_start = property(lambda s: s._ts_start) def __init__(self, name, directory): """ @param name : name of the contest (dir name also) @param directory : Parent directory of this contest directory """ self.name = name self.directory = abspath(join(directory, name)) self.dbpath = join(self.directory, 'repos', self.name) self.liveavatars = LiveAvatars() self._duration = None # If int, then time left to stop started contest self._profile = None # Profile object self._ts_start = None # Timestamp during start of contest dirs = {} for dr in ['repos', 'team', 'judge', 'stat']: dirs[dr] = join(self.directory, dr) self.dirs = dirs def create(self, admin_passwd, admin_email): """Create the contest. This also opens it. @param admin_passwd: Password for 'admin' account @param admin_email: Emailid of 'admin' account """ if True in [x.isspace() for x in self.name]: raise ValueError, 'contest_name must not contain any white space' # Create directories dirs = [self.directory] # Top-level dirs.extend(self.dirs.values()) # others .. [os.mkdir(dr) for dr in dirs] # Init DB dbpath = join(self.dirs['repos'], self.name) # Only one database db = sqlite.connect(dbpath, autocommit=True) cursor = db.cursor() queries = _get_queries(file(join(paths.DATA_DIR, 'contest-sqlite.sql'))) [cursor.execute(query) for query in queries] cursor.close() db.close() # Open the contest and add admin account to db self.open() # We use *_sync method as we don't use Twisted's reactor yet!! self.dbproxy.add_user_sync('admin', admin_passwd, 'Contest Admin', admin_email, USER_ADMIN) def open(self, resume=False): """Open the contest (connect to db, ...). Must have been created before @param resume: Whether the contest must be resumed """ if not os.path.isdir(self.directory): raise "No such contest '%s' exists - %s not found" % \ (self.name, self.directory) self.dbproxy = SqliteDBProxy(self.dbpath) self.sm = SubmissionManager(self) if not resume: self.dbproxy.clear_submissions_sync() def startServer(self, profile): """Start the contest server @param profile: ContestProfile object (see profile.__init__.py) """ if not hasattr(self, 'dbproxy'): raise RuntimeError, 'Contest must be opened (contest.open) first' import gateway self._profile = profile profile.setContest(self) # DEBUG - start contest now self.startContest(60*100) def getContestAge(self): "Return number of seconds since start of contest" assert self.isrunning() is True, 'Contest is not running!!' return int(time.time()) - self._ts_start def startContest(self, duration): """Start accepting submissions @param duration: Duration (in seconds) before stopping the contest""" if self.isrunning(): return self._duration = duration self._ts_start = int(time.time()) reactor.callLater(duration, self.stopContest) for avatarId, avatar in self.liveavatars.items(): avatar.contestStarted() log.info('Contest started with duration=%d seconds' % duration) def stopContest(self): """stop the contest""" if self.isrunning() is False: return self._duration = None self._ts_start = None # Tell avatars for avatarId, avatar in self.liveavatars.items(): avatar.contestStopped() log.info('Contest stopped') def isrunning(self): """Whether contest is running?""" return self._duration is not None def getTeamAvatars(self): "Return the list of all (DBid, Team AvatarIds) from database" def _cbGotUsers(teams): avatarIds = [] for dbid, team in teams.items(): avatarIds.append((dbid, team['userid'])) return avatarIds d = self.dbproxy.users_get_all({'type': str(USER_TEAM)}) return d.addCallback(_cbGotUsers) def copyFile(self, avatar, instantid, filename, filecontent): """Copy the file to user data directory within directory named instantid @param avatar: The avatar object which needs the file @param instantid: The instantid that differentiates with other instances of same avatar (eg. timestamp) @param filename: Filename to write @param filecontent: File contents @return: Created filepath """ # Create directory if doesn't exist instantid = str(instantid) userdir_parent = join(self.directory, avatar.whoami, avatar.userid) userdir = join(userdir_parent, instantid) # If the instantid is not unique, modify it by prepending it # with sequence number old_instantid, seq_num = instantid, 1 while os.path.isdir(userdir): instantid = old_instantid + '-' + str(seq_num) userdir = join(userdir_parent, instantid) seq_num = seq_num + 1 os.makedirs(userdir) # Create file named filename with content filecontent filename = join(userdir, filename) fh = file(filename, 'w') try: fh.write(filecontent) finally: fh.close() return filename