from flask import (
    Flask,
    Response,
    abort,
    redirect,
    render_template,
    request,
)
from collections import defaultdict
from datetime import datetime
import binascii
import json
import os
import re
import redis

app = Flask('pingbin')
r = redis.Redis()

def get_token():
    while True:
        token = binascii.hexlify(os.urandom(16))
        if r.publish(token, 'check') == 0 and r.llen(token) == 0:
            return token

@app.route('/')
def slash():
    # TODO: generate a second private token used for the command
    # so anyone who can see the command still can't view the bin
    token = get_token()
    return redirect('/{}'.format(token), code=302)

def get_packets(token):
    packets = [json.loads(p) for p in r.lrange(token, 0, 999)]
    last = defaultdict(lambda :defaultdict(int))
    for packet in reversed(packets):
        typ = packet['type']
        ip = packet['ip']
        if last[typ][ip]:
            packet['rel'] = int((packet['time'] - last[typ][ip]) * 1000)
        last[ip] = packet['time']
        packet['datetime'] = datetime.utcfromtimestamp(packet['time'])
        packet['time'] = int(packet['time'] * 1000)
    return packets

clean = re.compile(r'^[a-fA-F0-9]{32}|public$')

@app.route('/<token>')
def get(token):
    if not clean.match(token):
        token = get_token()
        return redirect('/{}'.format(token), code=302)
    token = token.lower()
    packets = get_packets(token)
    return render_template('app.html', token=token, packets=packets)

@app.route('/<token>/packets')
def packets(token):
    if not clean.match(token):
        return abort(404)
    token = token.lower()
    packets = get_packets(token)
    for packet in packets:
        packet.pop('datetime', None)
    return json.dumps(packets)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5006, debug=True)
