Merged branch history_model.

This commit is contained in:
A. Svensson 2015-03-08 13:28:02 +01:00
commit 50b4bcc36e
6 changed files with 58 additions and 61 deletions

View File

@ -3,6 +3,5 @@ django
django-debug-toolbar django-debug-toolbar
requests requests
beautifulsoup4 beautifulsoup4
redis
gunicorn gunicorn
fabric fabric

View File

@ -1,12 +1,10 @@
#!/usr/bin/env python #!/usr/bin/env python
import re import re
import time
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
from django.utils import timezone
from gameservers.models import Server, PlayerHistory from gameservers.models import Server, ServerHistory
import requests import requests
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
@ -88,15 +86,14 @@ class ServerParser(object):
class Command(BaseCommand): class Command(BaseCommand):
help = 'Update population stats for all ss13 servers.' help = 'Update history stats for all ss13 servers.'
def handle(self, *args, **kwargs): def handle(self, *args, **kwargs):
parser = ServerParser() parser = ServerParser()
#parser.url = './dump.html' # Use a local file instead when testing #parser.url = './dump.html' # Use a local file instead when testing
servers = parser.run() servers = parser.run()
history = PlayerHistory()
now = time.mktime(timezone.now().timetuple())
servers_handled = [] servers_handled = []
new_items = []
for data in servers: for data in servers:
# Prevent empty servers with identical names to other, active servers # Prevent empty servers with identical names to other, active servers
@ -106,10 +103,6 @@ class Command(BaseCommand):
else: else:
servers_handled.append(data['title']) servers_handled.append(data['title'])
# Keep the amount of data down in redis
history.trim_points(data['title'])
# TODO: do bulk insert instead!
server, created = Server.objects.update_or_create( server, created = Server.objects.update_or_create(
title=data['title'], title=data['title'],
defaults= dict( defaults= dict(
@ -119,8 +112,9 @@ class Command(BaseCommand):
) )
) )
# Update the player history history = ServerHistory(server=server, players=data['player_count'])
history.add_point(server, now, data['player_count']) new_items.append(history)
ServerHistory.objects.bulk_create(new_items)
Server.remove_old_servers() Server.remove_old_servers()

View File

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('gameservers', '0010_auto_20150223_1927'),
]
operations = [
migrations.CreateModel(
name='ServerHistory',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', models.DateTimeField(default=django.utils.timezone.now)),
('players', models.PositiveIntegerField(default=0)),
('server', models.ForeignKey(to='gameservers.Server')),
],
options={
'ordering': ['-created', 'server'],
},
bases=(models.Model,),
),
]

View File

@ -2,8 +2,6 @@
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
import redis
class Server(models.Model): class Server(models.Model):
title = models.CharField(max_length=255) title = models.CharField(max_length=255)
@ -28,32 +26,14 @@ class Server(models.Model):
server.delete() server.delete()
class PlayerHistory(object): class ServerHistory(models.Model):
def __init__(self, redis_settings=dict(host='localhost', port=6379, db=0)): server = models.ForeignKey(Server)
self.redis = redis.StrictRedis(**redis_settings) created = models.DateTimeField(default=timezone.now)
players = models.PositiveIntegerField(default=0)
# 32256 = 4 times per hour * 24 hours * 7 days * 4 weeks * 12 months class Meta:
self.max_items = 32256 ordering = ['-created', 'server']
def add_point(self, server, time, players): def __str__(self):
'''Add a new point in the player history.''' return 'History for {} at {}.'.format(self.server, self.created)
self.redis.lpush(server, '{},{}'.format(time, players))
def trim_points(self, server):
'''Trim away too old points and servers in the player history.'''
self.redis.ltrim(server, 0, self.max_items)
# let the list expire after a week without updates
self.redis.expire(server, 604800)
def get_history(self, server, days=7):
'''Get a range of days in a server's player history.'''
# 96 = 4 times per hour * 24 hours
max_items = days * 96
items = []
for tmp in self.redis.lrange(server, 0, max_items):
time, players = tmp.split(',')
time, players = float(time), int(players)
items.append((time, players))
return items

View File

@ -1,8 +1,11 @@
from datetime import timedelta
from django.shortcuts import render from django.shortcuts import render
from django.views import generic from django.views import generic
from django.utils import timezone
from .models import Server, PlayerHistory from .models import Server, ServerHistory
class ServerListView(generic.ListView): class ServerListView(generic.ListView):
model = Server model = Server
@ -13,25 +16,24 @@ class ServerDetailView(generic.DetailView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(ServerDetailView, self).get_context_data(**kwargs) context = super(ServerDetailView, self).get_context_data(**kwargs)
server = context['server'] server = context['server']
history = PlayerHistory()
items = history.get_history(server) weekly_history = ServerHistory.objects.filter(
context['player_history'] = items server=server,
created__gte=timezone.now() - timedelta(days=7),
)
context['weekly_history'] = weekly_history
# Moving average for the last day # Moving average for the last day
# TODO: remove the hardcoded value tmp = [tmp.players for tmp in ServerHistory.objects.filter(
tmp = [players for time, players in items[-96:]] server=server,
created__gte=timezone.now() - timedelta(days=1))]
context['daily_average'] = sum(tmp) / float(len(tmp)) context['daily_average'] = sum(tmp) / float(len(tmp))
context['daily_min'] = min(tmp) context['daily_min'] = min(tmp)
context['daily_max'] = max(tmp) context['daily_max'] = max(tmp)
tmp = [players for time, players in items[-96*7:]] tmp = [tmp.players for tmp in weekly_history]
context['weekly_average'] = sum(tmp) / float(len(tmp)) context['weekly_average'] = sum(tmp) / float(len(tmp))
context['weekly_min'] = min(tmp) context['weekly_min'] = min(tmp)
context['weekly_max'] = max(tmp) context['weekly_max'] = max(tmp)
tmp = [players for time, players in items]
context['total_average'] = sum(tmp) / float(len(tmp))
context['total_min'] = min(tmp)
context['total_max'] = max(tmp)
return context return context

View File

@ -45,12 +45,6 @@
<th>{{weekly_min}}</th> <th>{{weekly_min}}</th>
<th>{{weekly_max}}</th> <th>{{weekly_max}}</th>
</tr> </tr>
<tr>
<th>Total</th>
<th>{{total_average|floatformat}}</th>
<th>{{total_min}}</th>
<th>{{total_max}}</th>
</tr>
</table> </table>
<div id="chart"></div> <div id="chart"></div>
@ -62,8 +56,8 @@
$(function() { $(function() {
var series = [ var series = [
{# convert timestamp to ms, because javascript... #} {# convert timestamp to ms, because javascript... #}
{% for timestamp, players in player_history %} {% for item in weekly_history %}
[{{timestamp}} * 1000, {{players}}], [{{item.created|date:'U'}} * 1000, {{item.players}}],
{% endfor %} {% endfor %}
]; ];