Source code for onbasca.base.models.relay

# SPDX-FileCopyrightText: 2022 The Tor Project, Inc.
#
# SPDX-License-Identifier: BSD-3-Clause

import logging

from django.core.exceptions import ObjectDoesNotExist
from django.db import models

from . import BaseModel

logger = logging.getLogger(__name__)


[docs] class RelayManagerBase(models.Manager):
[docs] def from_router_status(self, router_status, consensus=None): # relay, _ = self.update_or_create( # fingerprint=router_status.fingerprint, defaults=kwargs # ) relay, _ = self.get_or_create(fingerprint=router_status.fingerprint) relay.set_routerstatuses_bandwidth_mean() relay.set_relaydescs_min_bandwidth_mean() relay.save() if consensus: relay.consensuses.add(consensus) return relay
[docs] class RelayBase(BaseModel):
[docs] class Meta: abstract = True
objects = RelayManagerBase() fingerprint = models.CharField(primary_key=True, max_length=40) consensuses = models.ManyToManyField("Consensus") # useful for scaling _routerstatuses_bandwidth_mean = models.PositiveIntegerField( null=True, blank=True ) _relaydescs_min_bandwidth_mean = models.PositiveIntegerField( null=True, blank=True ) def __str__(self): try: self.routerstatus_set.latest() except ObjectDoesNotExist: return self.fingerprint else: return "{}, {}".format( self.fingerprint, self.routerstatus_set.latest().nickname ) # for admin web
[docs] def relaybws(self): return self.relaybw_set.all()
[docs] def relaybws_count(self): return self.relaybw_set.count()
[docs] def routerstatuses(self): return self.routerstatus_set.all()
[docs] def routerstatuses_count(self): return self.routerstatuses().count()
[docs] def routerstatus_latest(self): try: return self.routerstatus_set.latest() except ObjectDoesNotExist: # logger.warning("Relay %s without RouterStatus", self) return None
[docs] def consensuses_count(self): return self.consensuses.count()
[docs] def relaydescs(self): return self.relaydesc_set.all()
[docs] def relaydescs_count(self): return self.relaydesc_set.count()
[docs] def relaydesc_latest(self): try: return self.relaydesc_set.latest() except ObjectDoesNotExist: # logger.warning("Relay %s without RelayDesc", self) return None
# for scanner
[docs] def is_exit(self): rs_last = self.routerstatus_latest() if rs_last: return rs_last.is_exit return None
[docs] def set_routerstatuses_bandwidth_mean(self): bw = self.routerstatus_set.aggregate( models.Avg("consensus_bandwidth") )["consensus_bandwidth__avg"] self._routerstatuses_bandwidth_mean = bw self.save() return bw
[docs] def relaydescs_min_bandwidth_latest(self): # Because the descriptors created from extrainfo do not have bandwidth # values, filter by _min_bandwidth. if ( self.relaydesc_set.filter(_min_bandwidth__isnull=False) .filter(_min_bandwidth__gt=0) .latest() ): return self.relaydesc_latest().set_min_bandwidth() return None
[docs] def set_relaydescs_min_bandwidth_mean(self): # _min_bandwidth is set when saving the descriptor. self._relaydescs_min_bandwidth_mean = ( self.relaydesc_set.filter(_min_bandwidth__isnull=False) .filter(_min_bandwidth__gt=0) .aggregate(models.Avg("_min_bandwidth"))["_min_bandwidth__avg"] ) self.save() self.are_relaydescs_observed_bandwidth_0() return self._relaydescs_min_bandwidth_mean
[docs] def min_descriptor_consensus_bandwidth(self): if ( self.routerstatus_latest() and self.relaydescs_min_bandwidth_latest() is not None ): return min( self.routerstatus_latest().bandwidth, self.relaydescs_min_bandwidth_latest(), ) return None
[docs] def are_relaydescs_observed_bandwidth_0(self): """Return True if any of the descriptors have observed bandwidth. #41: This method is only to log when this happen. It will be logged when the generator scales the bandwidth. """ if not self.relaydesc_set.exclude(observed_bandwidth=0): descriptors_count = self.relaydesc_set.count() logger.info( "%s descriptors' observed bandwidth are 0 for relay %s (%s), " "published on %s.", descriptors_count, self.fingerprint, self.relaydesc_set.latest().nickname, self.relaydesc_set.latest().published, ) return True return False