This commit is contained in:
Michael Zhang 2020-07-15 14:23:40 -05:00
commit 2ba0ad501e
Signed by: michael
GPG Key ID: BDA47A31A3C8EE6B
8 changed files with 217 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
__pycache__
*.pyc
/data.db

2
config.py Normal file
View File

@ -0,0 +1,2 @@
start_of_week = "monday"
timeout = 15 * 60

82
goalctl Executable file
View File

@ -0,0 +1,82 @@
#!/usr/bin/env python3
# kinds of goals:
# - overall
# "i want to code at least {time} per {interval}"
# - in a project
# - in a language
# - in an editor
from datetime import timedelta, date, datetime, time
import sys
import json
import sqlite3
from config import timeout
from utils import window
conn = sqlite3.connect("data.db")
if len(sys.argv) < 2:
print("provide a file", file=sys.stderr)
sys.exit(1)
filename = sys.argv[1]
with open(filename) as f:
data = json.load(f)
goal_type = data["type"]
if goal_type == "overall":
# in seconds
goal_min = int(data["goal_min"])
# figure out what timestamps to pull from
if data["interval"] == "day":
# except!
def convert_weekday(s):
s = s.lower()
return dict(
sunday=0,
monday=1,
tuesday=2,
wednesday=3,
thursday=4,
friday=5,
saturday=6,
).get(s)
excepts = list(map(convert_weekday, data["except"]))
if len(sys.argv) > 2:
# if a day is given, print that day
d = datetime.strptime(sys.argv[2], "%Y-%m-%d").date()
start_time = datetime.combine(d, time(hour=0, minute=0, second=0))
end_time = datetime.combine(d, time(hour=23, minute=59, second=59))
else:
# find the current day!
today = date.today()
start_time = datetime.combine(today, time(hour=0, minute=0, second=0))
end_time = datetime.now()
print(f"from {start_time} to {end_time}")
start_stamp = datetime.timestamp(start_time)
end_stamp = datetime.timestamp(end_time)
# get all the entries
c = conn.cursor()
curs = c.execute("""
select time from heartbeats where time > ? and time < ? order by time;
""", [start_stamp, end_stamp])
coded_secs = 0
for (first, second) in window(curs, 2):
print(datetime.fromtimestamp(first[0]))
diff = second[0] - first[0]
if diff < timeout:
coded_secs += diff
print(coded_secs)
elif data["interval"] == "week":
# start of the week
today = date.today()
last_monday = today - timedelta(days=today.weekday())
print(last_monday)
# vim: set ft=python:

View File

@ -0,0 +1,9 @@
{
"type": "overall",
"goal_min": 3600,
"interval": "day",
"except": [
"saturday",
"sunday"
]
}

9
goals/code-a-lot.json Normal file
View File

@ -0,0 +1,9 @@
{
"type": "overall",
"goal_min": 60,
"interval": "week",
"except": [
"saturday",
"sunday"
]
}

96
server.py Normal file
View File

@ -0,0 +1,96 @@
from http.server import BaseHTTPRequestHandler
import socketserver
import sqlite3
from collections import namedtuple
import json
PORT = 5800
conn = sqlite3.connect("data.db")
c = conn.cursor()
# c.execute("""drop table if exists "heartbeats" """)
c.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)
print(data)
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()
class Server(socketserver.TCPServer):
allow_reuse_address = True
def __init__(self):
super().__init__(("", PORT), Handler)
server = Server()
try:
server.serve_forever()
except KeyboardInterrupt:
print("shutting down")
server.shutdown()
conn.close()

4
tweeter Executable file
View File

@ -0,0 +1,4 @@
#!/bin/bash
# vim: set ft=bash :

12
utils.py Normal file
View File

@ -0,0 +1,12 @@
from itertools import islice
def window(seq, n=2):
"Returns a sliding window (of width n) over data from the iterable"
" s -> (s0,s1,...s[n-1]), (s1,s2,...,sn), ... "
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result