Cloned DMOJ
This commit is contained in:
parent
f623974b58
commit
49dc9ff10c
513 changed files with 132349 additions and 39 deletions
176
judge/models/runtime.py
Normal file
176
judge/models/runtime.py
Normal file
|
@ -0,0 +1,176 @@
|
|||
from collections import OrderedDict, defaultdict
|
||||
from operator import attrgetter
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.db import models
|
||||
from django.db.models import CASCADE
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from judge.judgeapi import disconnect_judge
|
||||
|
||||
__all__ = ['Language', 'RuntimeVersion', 'Judge']
|
||||
|
||||
|
||||
class Language(models.Model):
|
||||
key = models.CharField(max_length=6, verbose_name=_('short identifier'),
|
||||
help_text=_('The identifier for this language; the same as its executor id for judges.'),
|
||||
unique=True)
|
||||
name = models.CharField(max_length=20, verbose_name=_('long name'),
|
||||
help_text=_('Longer name for the language, e.g. "Python 2" or "C++11".'))
|
||||
short_name = models.CharField(max_length=10, verbose_name=_('short name'),
|
||||
help_text=_('More readable, but short, name to display publicly; e.g. "PY2" or '
|
||||
'"C++11". If left blank, it will default to the '
|
||||
'short identifier.'),
|
||||
null=True, blank=True)
|
||||
common_name = models.CharField(max_length=10, verbose_name=_('common name'),
|
||||
help_text=_('Common name for the language. For example, the common name for C++03, '
|
||||
'C++11, and C++14 would be "C++"'))
|
||||
ace = models.CharField(max_length=20, verbose_name=_('ace mode name'),
|
||||
help_text=_('Language ID for Ace.js editor highlighting, appended to "mode-" to determine '
|
||||
'the Ace JavaScript file to use, e.g., "python".'))
|
||||
pygments = models.CharField(max_length=20, verbose_name=_('pygments name'),
|
||||
help_text=_('Language ID for Pygments highlighting in source windows.'))
|
||||
template = models.TextField(verbose_name=_('code template'),
|
||||
help_text=_('Code template to display in submission editor.'), blank=True)
|
||||
info = models.CharField(max_length=50, verbose_name=_('runtime info override'), blank=True,
|
||||
help_text=_("Do not set this unless you know what you're doing! It will override the "
|
||||
"usually more specific, judge-provided runtime info!"))
|
||||
description = models.TextField(verbose_name=_('language description'),
|
||||
help_text=_('Use this field to inform users of quirks with your environment, '
|
||||
'additional restrictions, etc.'), blank=True)
|
||||
extension = models.CharField(max_length=10, verbose_name=_('extension'),
|
||||
help_text=_('The extension of source files, e.g., "py" or "cpp".'))
|
||||
|
||||
def runtime_versions(self):
|
||||
runtimes = OrderedDict()
|
||||
# There be dragons here if two judges specify different priorities
|
||||
for runtime in self.runtimeversion_set.all():
|
||||
id = runtime.name
|
||||
if id not in runtimes:
|
||||
runtimes[id] = set()
|
||||
if not runtime.version: # empty str == error determining version on judge side
|
||||
continue
|
||||
runtimes[id].add(runtime.version)
|
||||
|
||||
lang_versions = []
|
||||
for id, version_list in runtimes.items():
|
||||
lang_versions.append((id, sorted(version_list, key=lambda a: tuple(map(int, a.split('.'))))))
|
||||
return lang_versions
|
||||
|
||||
@classmethod
|
||||
def get_common_name_map(cls):
|
||||
result = cache.get('lang:cn_map')
|
||||
if result is not None:
|
||||
return result
|
||||
result = defaultdict(set)
|
||||
for id, cn in Language.objects.values_list('id', 'common_name'):
|
||||
result[cn].add(id)
|
||||
result = {id: cns for id, cns in result.items() if len(cns) > 1}
|
||||
cache.set('lang:cn_map', result, 86400)
|
||||
return result
|
||||
|
||||
@cached_property
|
||||
def short_display_name(self):
|
||||
return self.short_name or self.key
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@cached_property
|
||||
def display_name(self):
|
||||
if self.info:
|
||||
return '%s (%s)' % (self.name, self.info)
|
||||
else:
|
||||
return self.name
|
||||
|
||||
@classmethod
|
||||
def get_python3(cls):
|
||||
# We really need a default language, and this app is in Python 3
|
||||
return Language.objects.get_or_create(key='PY3', defaults={'name': 'Python 3'})[0]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('runtime_list') + '#' + self.key
|
||||
|
||||
@classmethod
|
||||
def get_default_language(cls):
|
||||
return Language.objects.get(key=settings.DEFAULT_USER_LANGUAGE)
|
||||
|
||||
@classmethod
|
||||
def get_default_language_pk(cls):
|
||||
return cls.get_default_language().pk
|
||||
|
||||
class Meta:
|
||||
ordering = ['key']
|
||||
verbose_name = _('language')
|
||||
verbose_name_plural = _('languages')
|
||||
|
||||
|
||||
class RuntimeVersion(models.Model):
|
||||
language = models.ForeignKey(Language, verbose_name=_('language to which this runtime belongs'), on_delete=CASCADE)
|
||||
judge = models.ForeignKey('Judge', verbose_name=_('judge on which this runtime exists'), on_delete=CASCADE)
|
||||
name = models.CharField(max_length=64, verbose_name=_('runtime name'))
|
||||
version = models.CharField(max_length=64, verbose_name=_('runtime version'), blank=True)
|
||||
priority = models.IntegerField(verbose_name=_('order in which to display this runtime'), default=0)
|
||||
|
||||
|
||||
class Judge(models.Model):
|
||||
name = models.CharField(max_length=50, help_text=_('Server name, hostname-style'), unique=True)
|
||||
created = models.DateTimeField(auto_now_add=True, verbose_name=_('time of creation'))
|
||||
auth_key = models.CharField(max_length=100, help_text=_('A key to authenticate this judge'),
|
||||
verbose_name=_('authentication key'))
|
||||
is_blocked = models.BooleanField(verbose_name=_('block judge'), default=False,
|
||||
help_text=_('Whether this judge should be blocked from connecting, '
|
||||
'even if its key is correct.'))
|
||||
online = models.BooleanField(verbose_name=_('judge online status'), default=False)
|
||||
start_time = models.DateTimeField(verbose_name=_('judge start time'), null=True)
|
||||
ping = models.FloatField(verbose_name=_('response time'), null=True)
|
||||
load = models.FloatField(verbose_name=_('system load'), null=True,
|
||||
help_text=_('Load for the last minute, divided by processors to be fair.'))
|
||||
description = models.TextField(blank=True, verbose_name=_('description'))
|
||||
last_ip = models.GenericIPAddressField(verbose_name='Last connected IP', blank=True, null=True)
|
||||
problems = models.ManyToManyField('Problem', verbose_name=_('problems'), related_name='judges')
|
||||
runtimes = models.ManyToManyField(Language, verbose_name=_('judges'), related_name='judges')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def disconnect(self, force=False):
|
||||
disconnect_judge(self, force=force)
|
||||
|
||||
disconnect.alters_data = True
|
||||
|
||||
@cached_property
|
||||
def runtime_versions(self):
|
||||
qs = (self.runtimeversion_set.values('language__key', 'language__name', 'version', 'name')
|
||||
.order_by('language__key', 'priority'))
|
||||
|
||||
ret = OrderedDict()
|
||||
|
||||
for data in qs:
|
||||
key = data['language__key']
|
||||
if key not in ret:
|
||||
ret[key] = {'name': data['language__name'], 'runtime': []}
|
||||
ret[key]['runtime'].append((data['name'], (data['version'],)))
|
||||
|
||||
return list(ret.items())
|
||||
|
||||
@cached_property
|
||||
def uptime(self):
|
||||
return timezone.now() - self.start_time if self.online else 'N/A'
|
||||
|
||||
@cached_property
|
||||
def ping_ms(self):
|
||||
return self.ping * 1000 if self.ping is not None else None
|
||||
|
||||
@cached_property
|
||||
def runtime_list(self):
|
||||
return map(attrgetter('name'), self.runtimes.all())
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
verbose_name = _('judge')
|
||||
verbose_name_plural = _('judges')
|
Loading…
Add table
Add a link
Reference in a new issue