You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
129 lines
4.3 KiB
129 lines
4.3 KiB
from datetime import datetime, timedelta, date, time
|
|
import math
|
|
|
|
from django.db import models, connection, ProgrammingError
|
|
from django.utils.timezone import now
|
|
from .fields import UnixDateTimeField
|
|
|
|
|
|
def get_dates():
|
|
tables = connection.introspection.table_names()
|
|
tables = (t.replace('flowstat_', '') for t in tables if t.startswith('flowstat_'))
|
|
return tuple(datetime.strptime(t, '%d%m%Y').date() for t in tables)
|
|
|
|
|
|
class StatManager(models.Manager):
|
|
def chart(self, user, count_of_parts=12, want_date=date.today()):
|
|
def byte_to_mbit(x):
|
|
return ((x / 60) * 8) / 2 ** 20
|
|
|
|
def split_list(lst, chunk_count):
|
|
chunk_size = len(lst) // chunk_count
|
|
if chunk_size == 0:
|
|
chunk_size = 1
|
|
return tuple(lst[i:i + chunk_size] for i in range(0, len(lst), chunk_size))
|
|
|
|
def avarage(elements):
|
|
return sum(elements) / len(elements)
|
|
|
|
try:
|
|
charts_data = self.filter(abon=user)
|
|
charts_times = tuple(cd.cur_time.timestamp() * 1000 for cd in charts_data)
|
|
charts_octets = tuple(cd.octets for cd in charts_data)
|
|
if len(charts_octets) > 0 and len(charts_octets) == len(charts_times):
|
|
charts_octets = split_list(charts_octets, count_of_parts)
|
|
charts_octets = (byte_to_mbit(avarage(c)) for c in charts_octets)
|
|
|
|
charts_times = split_list(charts_times, count_of_parts)
|
|
charts_times = tuple(avarage(t) for t in charts_times)
|
|
|
|
charts_data = zip(charts_times, charts_octets)
|
|
charts_data = ["{x: new Date(%d), y: %.2f}" % (cd[0], cd[1]) for cd in charts_data]
|
|
midnight = datetime.combine(want_date, time.min)
|
|
charts_data.append("{x:new Date(%d),y:0}" % (int(charts_times[-1:][0]) + 1))
|
|
charts_data.append("{x:new Date(%d),y:0}" % (int((midnight + timedelta(days=1)).timestamp()) * 1000))
|
|
return charts_data
|
|
else:
|
|
return
|
|
except ProgrammingError as e:
|
|
if "flowstat" in str(e):
|
|
return
|
|
|
|
|
|
class StatElem(models.Model):
|
|
cur_time = UnixDateTimeField(primary_key=True)
|
|
abon = models.ForeignKey('abonapp.Abon', on_delete=models.CASCADE, null=True, default=None, blank=True)
|
|
ip = models.PositiveIntegerField()
|
|
octets = models.PositiveIntegerField(default=0)
|
|
packets = models.PositiveIntegerField(default=0)
|
|
|
|
objects = StatManager()
|
|
|
|
# ReadOnly
|
|
def save(self, *args, **kwargs):
|
|
pass
|
|
|
|
# ReadOnly
|
|
def delete(self, *args, **kwargs):
|
|
pass
|
|
|
|
@property
|
|
def table_name(self):
|
|
return self._meta.db_table
|
|
|
|
def delete_month(self):
|
|
cursor = connection.cursor()
|
|
table_name = self._meta.db_table
|
|
sql = "DROP TABLE %s;" % table_name
|
|
cursor.execute(sql)
|
|
|
|
@staticmethod
|
|
def percentile(N, percent, key=lambda x: x):
|
|
"""
|
|
Find the percentile of a list of values.
|
|
|
|
@parameter N - is a list of values. Note N MUST BE already sorted.
|
|
@parameter percent - a float value from 0.0 to 1.0.
|
|
@parameter key - optional key function to compute value from each element of N.
|
|
|
|
@return - the percentile of the values
|
|
"""
|
|
if not N:
|
|
return None
|
|
k = (len(N) - 1) * percent
|
|
f = math.floor(k)
|
|
c = math.ceil(k)
|
|
if f == c:
|
|
return key(N[int(k)])
|
|
d0 = key(N[int(f)]) * (c - k)
|
|
d1 = key(N[int(c)]) * (k - f)
|
|
return d0 + d1
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
|
|
def getModel(want_date=now()):
|
|
class DynamicStatElem(StatElem):
|
|
class Meta:
|
|
db_table = 'flowstat_%s' % want_date.strftime("%d%m%Y")
|
|
abstract = False
|
|
|
|
return DynamicStatElem
|
|
|
|
|
|
class StatCache(models.Model):
|
|
last_time = UnixDateTimeField()
|
|
abon = models.OneToOneField('abonapp.Abon', on_delete=models.CASCADE, primary_key=True)
|
|
octets = models.PositiveIntegerField(default=0)
|
|
packets = models.PositiveIntegerField(default=0)
|
|
|
|
def is_online(self):
|
|
return self.last_time > now() - timedelta(minutes=55)
|
|
|
|
def is_today(self):
|
|
return date.today() == self.last_time.date()
|
|
|
|
class Meta:
|
|
db_table = 'flowcache'
|
|
ordering = ('-last_time',)
|