Exemplo n.º 1
0
def send_judge_through_http(server,
                            code,
                            lang,
                            max_time,
                            max_memory,
                            run_until_complete,
                            cases,
                            checker,
                            interactor,
                            callback,
                            timeout=900):
    server.last_seen_time = datetime.now()
    server.save(update_fields=['last_seen_time'])
    data = _prepare_judge_json_data(code, lang, max_time, max_memory,
                                    run_until_complete, cases, checker,
                                    interactor)
    url = server.http_address + '/judge'
    try:
        callback(
            add_timestamp_to_reply(
                requests.post(url,
                              json=data,
                              auth=(DEFAULT_USERNAME, server.token),
                              timeout=timeout).json()))
    except:
        callback(response_fail_with_timestamp())
Exemplo n.º 2
0
def send_judge_through_watch(server,
                             code,
                             lang,
                             max_time,
                             max_memory,
                             run_until_complete,
                             cases,
                             checker,
                             interactor,
                             callback,
                             timeout=600,
                             fallback=True,
                             report_file_path=None):
    """
    :param interactor: None or '' if there is no interactor
    :param callback: function, to call when something is returned (possibly preliminary results)
                     callback should return True when it thinks the result is final result, return False otherwise
                     callback will receive exactly one param, which is the data returned by judge server as a dict
    :param timeout: will fail if it has not heard from judge server for `timeout` seconds
    :param fallback: this method automatically provides a fallback called send_judge_through_http, in case it fails.
                     setting fallback to False will disable such fallback
    """

    # server.last_seen_time = datetime.now()
    # server.save(update_fields=['last_seen_time'])

    data = _prepare_judge_json_data(code, lang, max_time, max_memory,
                                    run_until_complete, cases, checker,
                                    interactor)
    data.update(hold=False)
    judge_url = server.http_address + '/judge'
    watch_url = server.http_address + '/query'
    watch_report = server.http_address + '/query/report'
    timeout_count = 0

    try:
        response = add_timestamp_to_reply(
            requests.post(judge_url,
                          json=data,
                          auth=(DEFAULT_USERNAME, server.token),
                          timeout=timeout).json())
        if response.get('status') != 'received':
            callback(response)
        while timeout_count < timeout:
            interval = 0.5
            time.sleep(interval)
            response = add_timestamp_to_reply(
                requests.get(watch_url,
                             json={
                                 'fingerprint': data['fingerprint']
                             },
                             auth=(DEFAULT_USERNAME, server.token),
                             timeout=timeout).json())
            if callback(response):
                if report_file_path:
                    with open(report_file_path, 'w') as handler:
                        handler.write(
                            requests.get(watch_report,
                                         json={
                                             'fingerprint': data['fingerprint']
                                         },
                                         auth=(DEFAULT_USERNAME, server.token),
                                         timeout=timeout).text)
                break
            timeout_count += interval
        if timeout_count >= timeout:
            raise RuntimeError("Send judge through socketio timed out.")
    except:
        if fallback:
            msg = traceback.format_exc()
            send_mail(subject="Submit fail notice",
                      message=msg,
                      from_email=None,
                      recipient_list=settings.ADMIN_EMAIL_LIST,
                      fail_silently=True)
            print(msg)
            send_judge_through_http(server, code, lang, max_time, max_memory,
                                    run_until_complete, cases, checker,
                                    interactor, callback)
        else:
            callback(response_fail_with_timestamp())
Exemplo n.º 3
0
def judge_submission_on_problem(submission, callback=None, **kwargs):
    """
    :type submission: Submission
    :param callback: function, call when judge result is received
    :param status_private: make the status private only (when the contest scoreboard is frozen)
    :param case: can be pretest or sample or all
    :return:
    """

    problem = submission.problem
    case_list = []
    if kwargs.get('case') == 'pretest':
        case_list = problem.pretest_list
    elif kwargs.get('case') == 'sample':
        case_list = problem.sample_list
    if not case_list:  # case list is empty (e.g. something wrong with pretest list)
        case_list = problem.case_list
    point_query = dict(zip(problem.case_list, problem.point_list))
    total_score = max(1, sum(map(lambda x: point_query.get(x, 10), case_list)))
    status_for_pretest = kwargs.get('status_for_pretest', False)

    def process_accepted(status):
        if status == SubmissionStatus.ACCEPTED and status_for_pretest:
            return SubmissionStatus.PRETEST_PASSED
        else:
            return status

    def on_receive_data(data):
        judge_time = datetime.fromtimestamp(data['timestamp'])
        if submission.judge_end_time and judge_time < submission.judge_end_time:
            return True
        if data.get('status') == 'received':
            if 'message' in data:
                submission.status_message = data['message']
            else:
                submission.status_message = ''
            submission.status_private = process_accepted(
                data.get('verdict', SubmissionStatus.JUDGING))
            if not kwargs.get('status_private'):
                submission.status = process_accepted(
                    data.get('verdict', SubmissionStatus.JUDGING))
            else:
                submission.status = SubmissionStatus.SUBMITTED

            details = data.get('detail', [])
            # Add points to details
            score = 0
            for index, detail in enumerate(details):
                if detail.get('verdict') == 0:
                    score += point_query.get(case_list[index], 10)
            submission.status_percent = score / total_score * 100
            submission.status_detail_list = details
            submission.status_detail_list += [{}] * max(
                0,
                len(case_list) - len(submission.status_detail_list))
            submission.save(update_fields=[
                'status_message', 'status_detail', 'status', 'status_private',
                'status_percent'
            ])

            if SubmissionStatus.is_judged(data.get('verdict')):
                submission.status_time = max(
                    map(lambda d: d.get('time', 0.0),
                        submission.status_detail_list))
                submission.judge_end_time = judge_time
                submission.save(
                    update_fields=['status_time', 'judge_end_time'])
                invalidate_user(submission.author_id, submission.contest_id)

                if submission.status == SubmissionStatus.ACCEPTED:
                    # Add reward
                    if not submission.rewarded and \
                            not Submission.objects.filter(author_id=submission.author_id,
                                                          problem_id=submission.problem_id,
                                                          status=SubmissionStatus.ACCEPTED, rewarded=True).exists():
                        if submission.contest_id:
                            reward_contest_ac(
                                submission.author,
                                get_problem_difficulty(submission.problem_id),
                                submission.contest_id)
                        else:
                            reward_problem_ac(
                                submission.author,
                                get_problem_difficulty(submission.problem_id),
                                submission.problem_id)
                        submission.rewarded = True
                        submission.save(update_fields=["rewarded"])
                if callback:
                    Thread(target=callback).start()
                return True
            return False
        else:
            submission.status = submission.status_private = SubmissionStatus.SYSTEM_ERROR
            submission.status_message = data['message']
            submission.save(
                update_fields=['status', 'status_message', 'status_private'])
            return True

    try:
        servers = Server.objects.filter(enabled=True)
        server = random.choice(servers)
        Thread(target=send_judge_through_watch, args=(server, submission.code, submission.lang, problem.time_limit,
                                                      problem.memory_limit, kwargs.get('run_until_complete', False),
                                                      problem.case_list, problem.checker, problem.interactor,
                                                      on_receive_data),
               kwargs={'report_file_path': path.join(settings.GENERATE_DIR,
                                                     'submission-%d' % submission.pk)}) \
            .start()
    except:
        on_receive_data(response_fail_with_timestamp())
Exemplo n.º 4
0
def judge_submission_on_problem(submission, callback=None, **kwargs):
    """
    :type submission: Submission
    :param callback: function, call when judge result is received
    :param case: can be pretest or sample or all
    :return:
    """

    problem = submission.problem
    code = submission.code

    # concat code for template judging
    templates = problem.template_dict
    if submission.lang in templates:
        grader_code = templates[submission.lang]["grader"]
        insert_indicator = "$$template$$"
        if insert_indicator in grader_code:
            code = grader_code.replace(insert_indicator, code)
        else:
            code = code + '\n\n' + grader_code

    case_list = []
    group_config = {"on": False}
    if kwargs.get('case') == 'pretest':
        case_list = problem.pretest_list
    elif kwargs.get('case') == 'sample':
        case_list = problem.sample_list
    if not case_list:  # case list is empty (e.g. something wrong with pretest list)
        case_list = problem.case_list
        if problem.group_enabled:
            # enable group testing only when using whole testset mode
            group_config["on"] = True
            group_config["group_list"] = problem.group_list
            group_config["group_count"] = max(group_config["group_list"])
            group_config["group_dependencies"] = problem.group_dependencies

    if group_config["on"]:
        point_query = list(problem.point_list)
        total_score = max(1, sum(point_query))
    else:
        point_query = dict(zip(problem.case_list, problem.point_list))
        total_score = max(1, sum(map(lambda x: point_query.get(x, 10), case_list)))
    status_for_pretest = kwargs.get('status_for_pretest', False)

    def process_accepted(status):
        if status == SubmissionStatus.ACCEPTED and status_for_pretest:
            return SubmissionStatus.PRETEST_PASSED
        else:
            return status

    def on_receive_data(data):
        judge_time = datetime.fromtimestamp(data['timestamp'])
        if submission.judge_end_time and judge_time < submission.judge_end_time:
            return True
        if data.get('status') == 'received':
            if 'message' in data:
                submission.status_message = data['message']
            else:
                submission.status_message = ''
            submission.status = process_accepted(data.get('verdict', SubmissionStatus.JUDGING))

            details = data.get('detail', [])
            if not group_config["on"]:
                # Add points to details
                score = 0
                try:
                    for index, detail in enumerate(details):
                        if 'point' not in detail:
                            if detail.get('verdict') == 0:
                                detail['point'] = point_query.get(case_list[index], 10) / total_score * 100
                        score += detail.get('point', 0)
                except:
                    pass
                submission.status_percent = score
            display_details = details + [{}] * max(0, len(case_list) - len(details))
            submission.status_detail_list = display_details
            submission.status_test = process_failed_test(display_details)
            submission.judge_server = data.get('server', 0)
            submission.save(update_fields=['status_message', 'status_detail','status',
                                           'status_percent', 'status_test', 'judge_server'])

            if SubmissionStatus.is_judged(data.get('verdict')):
                if group_config["on"] and data.get('verdict') != SubmissionStatus.COMPILE_ERROR:
                    score = 0
                    records = []
                    accept_case_counter, total_case_counter = Counter(), Counter()
                    for index, detail in enumerate(details):
                        group_id = group_config["group_list"][index]
                        if detail.get('verdict') == 0:
                            accept_case_counter[group_id] += 1
                        total_case_counter[group_id] += 1
                    for group_id in range(1, group_config["group_count"] + 1):
                        get_score = 0
                        if accept_case_counter[group_id] == total_case_counter[group_id] and \
                                total_case_counter[group_id] > 0:
                            get_score = point_query[group_id - 1]
                        score += get_score
                        records.append("Subtask #%d: " % group_id +
                                       "%d/%d cases passed. %d points." % (accept_case_counter[group_id],
                                                                           total_case_counter[group_id],
                                                                           get_score))
                    records.append("Total: %d/%d" % (score, total_score))
                    submission.status_message = "\n".join(records)
                    submission.status_percent = score / total_score * 100

                try:
                    submission.status_time = max(map(lambda d: d.get('time', 0.0), submission.status_detail_list))
                except ValueError: pass
                submission.judge_end_time = judge_time

                submission.save(update_fields=['status_time', 'judge_end_time', 'status_message', 'status_percent'])

                if submission.status == SubmissionStatus.ACCEPTED:
                    # Add reward
                    _, created = ProblemRewardStatus.objects.get_or_create(problem_id=submission.problem_id,
                                                                           user_id=submission.author_id)
                    if created:
                        if submission.contest_time is not None:
                            reward_contest_ac(submission.author, 4 * problem.level ** 2, submission.contest_id)
                        else:
                            reward_problem_ac(submission.author, problem.reward, submission.problem_id)

                invalidate_user(submission.author_id, submission.contest_id)
                invalidate_problem(submission.problem)
                if callback:
                    callback()
                return True
            return False
        else:
            submission.status = SubmissionStatus.SYSTEM_ERROR
            submission.status_message = data['message']
            submission.save(update_fields=['status', 'status_message'])
            return True

    try:
        report_instance, _ = SubmissionReport.objects.get_or_create(submission=submission)
        report_instance.content = ""
        report_instance.save()
        send_judge_through_watch(code, submission.lang, problem.time_limit,
                                 problem.memory_limit, kwargs.get('run_until_complete', False),
                                 case_list, problem.checker, problem.interactor, group_config,
                                 on_receive_data, report_instance=report_instance)
    except:
        on_receive_data(response_fail_with_timestamp())