Esempio n. 1
0
    def __init__(self, import_source, cws_address, no_import=False,
                 start_from=0):
        self.import_source = import_source
        self.cws_address = cws_address
        self.no_import = no_import
        self.start_from = start_from

        self.start = None
        self.speed = 1
        self.speed_lock = RLock()
        self.events = []

        self.importer = ContestImporter(drop=False,
                                        import_source=import_source,
                                        only_files=False, no_files=False,
                                        no_submissions=True)
Esempio n. 2
0
    def __init__(self, import_source, cws_address, no_import=False, start_from=0):
        self.import_source = import_source
        self.cws_address = cws_address
        self.no_import = no_import
        self.start_from = start_from

        self.start = None
        self.speed = 1
        self.speed_lock = RLock()
        self.events = []

        self.importer = ContestImporter(
            drop=False, import_source=import_source, only_files=False, no_files=False, no_submissions=True
        )
Esempio n. 3
0
class ContestReplayer(object):

    def __init__(self, import_source, cws_address, no_import=False,
                 start_from=0):
        self.import_source = import_source
        self.cws_address = cws_address
        self.no_import = no_import
        self.start_from = start_from

        self.start = None
        self.speed = 1
        self.speed_lock = RLock()
        self.events = []

        self.importer = ContestImporter(drop=False,
                                        import_source=import_source,
                                        only_files=False, no_files=False,
                                        no_submissions=True)

    def run(self):
        """Main routine for replaying a contest, handling arguments from
        command line, and managing the speed of the replayer.

        """
        if not self.no_import:
            logger.info("Importing contest...")
            self.importer.run()
            logger.info("Contest imported.")

        logger.info("Please run CMS against the contest (with ip_lock=False).")
        logger.info("Please ensure that:")
        logger.info("- the contest is active (we are between start and stop);")
        logger.info("- the minimum interval for submissions and usertests ")
        logger.info("  (contest- and task-wise) is None.")
        logger.info("Then press enter to start.")
        raw_input()

        with io.open(os.path.join(self.import_source, "contest.json"),
                     "rt", encoding="utf-8") as fin:
            self.compute_events(json.load(fin))

        thread = Thread(target=self.replay)
        thread.daemon = True
        thread.start()

        logger.info("Loading submission data...")
        while self.start is None:
            time.sleep(1)
        while thread.isAlive():
            new_speed = raw_input("Write the speed multiplier or q to quit "
                                  "(time %s, multiplier %s):\n" %
                                  (to_time((time.time() - self.start) *
                                           self.speed),
                                   self.speed))
            if new_speed == "q":
                return 0
            elif new_speed != "":
                try:
                    new_speed = int(new_speed)
                except ValueError:
                    logger.warning("Speed multiplier could not be parsed.")
                else:
                    self.recompute_start(new_speed)
        return 0

    def compute_events(self, contest):
        tasks = dict((task["name"], task["num"]) for task in contest["tasks"])
        for user in contest["users"]:
            tasks_num = dict((task["name"], 1) for task in contest["tasks"])
            for submission in sorted(user["submissions"],
                                     key=lambda x: x["timestamp"]):
                num = tasks_num[submission["task"]]
                tasks_num[submission["task"]] += 1
                self.events.append([
                    submission["timestamp"] - contest["start"],
                    user["username"],
                    user["password"],
                    tasks[submission["task"]],
                    submission["task"],
                    "s",  # For submit events.
                    (submission["files"], submission["language"]),
                    ])
                if submission["token"] is not None:
                    self.events.append([
                        submission["token"]["timestamp"] - contest["start"],
                        user["username"],
                        user["password"],
                        tasks[submission["task"]],
                        submission["task"],
                        "t",  # For token events.
                        num,
                        ])
        # TODO: add user test events.
        self.events.sort()

    def recompute_start(self, new_speed):
        """Utility to recompute the start time of a contest passing
        from a speed of self.speed to a speed of new_speed.

        new_speed(int): the new speed for the contest replayer.

        """
        with self.speed_lock:
            if self.speed != new_speed:
                self.start = self.start \
                    + (time.time() - self.start) * (new_speed - self.speed) \
                    * 1.0 / new_speed
                self.speed = new_speed

    def submit(self, timestamp, username, password, t_id, t_short,
               files, language):
        """Execute the request for a submission.

        timestamp (int): seconds from the start.
        username (string): username issuing the submission.
        password (string): password of username.
        t_id (string): id of the task.
        t_short (string): short name of the task.
        files ([dict]): list of dictionaries with keys 'filename' and
                        'digest'.
        language (string): the extension the files should have.

        """
        logger.info("%s - Submitting for %s on task %s."
                    % (to_time(timestamp), username, t_short))
        if len(files) != 1:
            logger.error("We cannot submit more than one file.")
            return

        # Copying submission files into a temporary directory with the
        # correct name. Otherwise, SubmissionRequest does not know how
        # to interpret the file (and which language are they in).
        temp_dir = tempfile.mkdtemp(dir=config.temp_dir)
        for file_ in files:
            temp_filename = os.path.join(temp_dir,
                                         file_["filename"].replace("%l",
                                                                   language))
            shutil.copy(
                os.path.join(self.import_source, "files", files[0]["digest"]),
                temp_filename
                )
            file_["filename"] = temp_filename

        filename = os.path.join(files[0]["filename"])
        browser = Browser()
        browser.set_handle_robots(False)
        step(LoginRequest(browser, username, password,
                          base_url=self.cws_address))
        step(SubmitRequest(browser,
                           (int(t_id), t_short),
                           filename=filename,
                           base_url=self.cws_address))
        shutil.rmtree(temp_dir)

    def token(self, timestamp, username, password, t_id, t_short,
              submission_num):
        """Execute the request for releasing test a submission.

        timestamp (int): seconds from the start.
        username (string): username issuing the submission.
        password (string): password of username.
        t_id (string): id of the task.
        t_short (string): short name of the task.
        submission_num (string): id of the submission to release test.

        """
        logger.info("%s - Playing token for %s on task %s"
                    % (to_time(timestamp), username, t_short))
        browser = Browser()
        browser.set_handle_robots(False)
        step(LoginRequest(browser, username, password,
                          base_url=self.cws_address))
        step(TokenRequest(browser,
                          (int(t_id), t_short),
                          submission_num=submission_num,
                          base_url=self.cws_address))

    def replay(self):
        """Start replaying the events in source on the CWS at the
        specified address.

        """
        with self.speed_lock:
            index = 0
            if self.start_from is not None:
                while index < len(self.events) \
                        and float(self.events[index][0]) < self.start_from:
                    index += 1
                self.start = time.time() - self.start_from
            else:
                self.start = time.time()

        while index < len(self.events):
            timestamp, username, password, task_id, task_name, type_, data \
                = self.events[index]
            to_wait = (timestamp / self.speed - (time.time() - self.start))
            while to_wait > .5:
                if 0 < to_wait % 10 <= .5:
                    logger.info("Next event in %d seconds." % int(to_wait))
                time.sleep(.5)
                to_wait = (timestamp / self.speed - (time.time() - self.start))
            if to_wait > 0:
                time.sleep(to_wait)

            if type_ == "s":  # Submit.
                files, language = data
                self.submit(timestamp=timestamp,
                            username=username,
                            password=password,
                            t_id=task_id,
                            t_short=task_name,
                            files=files,
                            language=language)
            elif type_ == "t":  # Token.
                self.token(timestamp=timestamp,
                           username=username,
                           password=password,
                           t_id=task_id,
                           t_short=task_name,
                           submission_num=data)
            else:
                logger.warning("Unexpected type `%s', ignoring." % type_)

            index += 1
Esempio n. 4
0
class ContestReplayer(object):
    def __init__(self,
                 import_source,
                 cws_address,
                 no_import=False,
                 start_from=0):
        self.import_source = import_source
        self.cws_address = cws_address
        self.no_import = no_import
        self.start_from = start_from

        self.start = None
        self.speed = 1
        self.speed_lock = RLock()
        self.events = []

        self.importer = ContestImporter(drop=False,
                                        import_source=import_source,
                                        only_files=False,
                                        no_files=False,
                                        no_submissions=True)

    def run(self):
        """Main routine for replaying a contest, handling arguments from
        command line, and managing the speed of the replayer.

        """
        if not self.no_import:
            logger.info("Importing contest...")
            self.importer.run()
            logger.info("Contest imported.")

        logger.info("Please run CMS against the contest (with ip_lock=False).")
        logger.info("Please ensure that:")
        logger.info("- the contest is active (we are between start and stop);")
        logger.info("- the minimum interval for submissions and usertests ")
        logger.info("  (contest- and task-wise) is None.")
        logger.info("Then press enter to start.")
        raw_input()

        with open(os.path.join(self.import_source, "contest.json")) as fin:
            self.compute_events(json.load(fin))

        thread = Thread(target=self.replay)
        thread.daemon = True
        thread.start()

        logger.info("Loading submission data...")
        while self.start is None:
            time.sleep(1)
        while thread.isAlive():
            new_speed = raw_input(
                "Write the speed multiplier or q to quit "
                "(time %s, multiplier %s):\n" % (to_time(
                    (time.time() - self.start) * self.speed), self.speed))
            if new_speed == "q":
                return 0
            elif new_speed != "":
                try:
                    new_speed = int(new_speed)
                except ValueError:
                    logger.warning("Speed multiplier could not be parsed.")
                else:
                    self.recompute_start(new_speed)
        return 0

    def compute_events(self, contest):
        tasks = dict((task["name"], task["num"]) for task in contest["tasks"])
        for user in contest["users"]:
            tasks_num = dict((task["name"], 1) for task in contest["tasks"])
            for submission in sorted(user["submissions"],
                                     key=lambda x: x["timestamp"]):
                num = tasks_num[submission["task"]]
                tasks_num[submission["task"]] += 1
                self.events.append([
                    submission["timestamp"] - contest["start"],
                    user["username"],
                    user["password"],
                    tasks[submission["task"]],
                    submission["task"],
                    "s",  # For submit events.
                    (submission["files"], submission["language"]),
                ])
                if submission["token"] is not None:
                    self.events.append([
                        submission["token"]["timestamp"] - contest["start"],
                        user["username"],
                        user["password"],
                        tasks[submission["task"]],
                        submission["task"],
                        "t",  # For token events.
                        num,
                    ])
        # TODO: add user test events.
        self.events.sort()

    def recompute_start(self, new_speed):
        """Utility to recompute the start time of a contest passing
        from a speed of self.speed to a speed of new_speed.

        new_speed(int): the new speed for the contest replayer.

        """
        with self.speed_lock:
            if self.speed != new_speed:
                self.start = self.start \
                    + (time.time() - self.start) * (new_speed - self.speed) \
                    * 1.0 / new_speed
                self.speed = new_speed

    def submit(self, timestamp, username, password, t_id, t_short, files,
               language):
        """Execute the request for a submission.

        timestamp (int): seconds from the start.
        username (string): username issuing the submission.
        password (string): password of username.
        t_id (string): id of the task.
        t_short (string): short name of the task.
        files ([dict]): list of dictionaries with keys 'filename' and
                        'digest'.
        language (string): the extension the files should have.

        """
        logger.info("%s - Submitting for %s on task %s." %
                    (to_time(timestamp), username, t_short))
        if len(files) != 1:
            logger.error("We cannot submit more than one file.")
            return

        # Copying submission files into a temporary directory with the
        # correct name. Otherwise, SubmissionRequest does not know how
        # to interpret the file (and which language are they in).
        temp_dir = tempfile.mkdtemp(dir=config.temp_dir)
        for file_ in files:
            temp_filename = os.path.join(
                temp_dir, file_["filename"].replace("%l", language))
            shutil.copy(
                os.path.join(self.import_source, "files", files[0]["digest"]),
                temp_filename)
            file_["filename"] = temp_filename

        filename = os.path.join(files[0]["filename"])
        browser = Browser()
        browser.set_handle_robots(False)
        step(
            LoginRequest(browser,
                         username,
                         password,
                         base_url=self.cws_address))
        step(
            SubmitRequest(browser, (int(t_id), t_short),
                          filename=filename,
                          base_url=self.cws_address))
        shutil.rmtree(temp_dir)

    def token(self, timestamp, username, password, t_id, t_short,
              submission_num):
        """Execute the request for releasing test a submission.

        timestamp (int): seconds from the start.
        username (string): username issuing the submission.
        password (string): password of username.
        t_id (string): id of the task.
        t_short (string): short name of the task.
        submission_num (string): id of the submission to release test.

        """
        logger.info("%s - Playing token for %s on task %s" %
                    (to_time(timestamp), username, t_short))
        browser = Browser()
        browser.set_handle_robots(False)
        step(
            LoginRequest(browser,
                         username,
                         password,
                         base_url=self.cws_address))
        step(
            TokenRequest(browser, (int(t_id), t_short),
                         submission_num=submission_num,
                         base_url=self.cws_address))

    def replay(self):
        """Start replaying the events in source on the CWS at the
        specified address.

        """
        with self.speed_lock:
            index = 0
            if self.start_from is not None:
                while index < len(self.events) \
                        and float(self.events[index][0]) < self.start_from:
                    index += 1
                self.start = time.time() - self.start_from
            else:
                self.start = time.time()

        while index < len(self.events):
            timestamp, username, password, task_id, task_name, type_, data \
                = self.events[index]
            to_wait = (timestamp / self.speed - (time.time() - self.start))
            while to_wait > .5:
                if 0 < to_wait % 10 <= .5:
                    logger.info("Next event in %d seconds." % int(to_wait))
                time.sleep(.5)
                to_wait = (timestamp / self.speed - (time.time() - self.start))
            if to_wait > 0:
                time.sleep(to_wait)

            if type_ == "s":  # Submit.
                files, language = data
                self.submit(timestamp=timestamp,
                            username=username,
                            password=password,
                            t_id=task_id,
                            t_short=task_name,
                            files=files,
                            language=language)
            elif type_ == "t":  # Token.
                self.token(timestamp=timestamp,
                           username=username,
                           password=password,
                           t_id=task_id,
                           t_short=task_name,
                           submission_num=data)
            else:
                logger.warning("Unexpected type `%s', ignoring." % type_)

            index += 1