#!/usr/bin/env python3 from http.server import BaseHTTPRequestHandler, HTTPServer import socketserver import sqlite3 import json import configparser from collections import namedtuple PORT = 5800 conn = sqlite3.connect("data.db") def post_heartbeat_hook(): pass c0 = conn.cursor() # c.execute("""drop table if exists "heartbeats" """) c0.execute(""" create table if not exists "heartbeats" ( id int primary key, entity text, type text, category text, time real, project text, branch text, language text, dependencies text, lines int, lineno int, cursorpos int, is_write boolean, user_agent text ); """) conn.commit() class Handler(BaseHTTPRequestHandler): def do_GET(self): pass def do_POST(self): if self.path == "/api/v1/heartbeats.bulk": content_len = int(self.headers.get("Content-Length")) # TODO: cap this or potential vuln? body = self.rfile.read(content_len) def object_hook(d): return namedtuple( "heartbeat", d.keys() )(*d.values()) data = json.loads(body, object_hook=object_hook) c = conn.cursor() for heartbeat in data: c.execute( """ insert into "heartbeats" (entity, type, category, time, project, branch, language, dependencies, lines, lineno, cursorpos, is_write, user_agent) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, [ heartbeat.entity, heartbeat.type, heartbeat.category, heartbeat.time, heartbeat.project, heartbeat.branch, heartbeat.language, ",".join(heartbeat.dependencies), heartbeat.lines, heartbeat.lineno, heartbeat.cursorpos, heartbeat.is_write, heartbeat.user_agent, ], ) conn.commit() # run hooks post_heartbeat_hook() class Server(HTTPServer): allow_reuse_address = True def __init__(self): super().__init__(("127.0.0.1", PORT), Handler) if __name__ == "__main__": server = Server() try: server.serve_forever() except KeyboardInterrupt: print("shutting down") server.shutdown() conn.close()