AHDX: Apple Health exporter with SQLite + Grafana dashboard (MIT)
This commit is contained in:
+67
@@ -0,0 +1,67 @@
|
||||
"""
|
||||
Background watcher for the inbox folder.
|
||||
|
||||
Every AHDX_SCAN_INTERVAL seconds it looks in data/inbox/ for a new export.zip or
|
||||
export.xml, merges it into the active database, and moves the file to
|
||||
data/inbox/done/ so it isn't picked up again. Drop exports there by hand or point
|
||||
a synced folder at it, and imports happen without anyone clicking a button.
|
||||
|
||||
Set AHDX_SCAN_INTERVAL to 0 to turn the watcher off.
|
||||
"""
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
|
||||
import db
|
||||
import jobs
|
||||
|
||||
DEFAULT_INTERVAL = 1800 # 30 minutes
|
||||
|
||||
|
||||
def start():
|
||||
interval = int(os.environ.get("AHDX_SCAN_INTERVAL", DEFAULT_INTERVAL))
|
||||
if interval <= 0:
|
||||
return
|
||||
threading.Thread(target=_loop, args=(interval,), daemon=True).start()
|
||||
|
||||
|
||||
def _loop(interval):
|
||||
while True:
|
||||
try:
|
||||
scan_once()
|
||||
except Exception:
|
||||
# A bad file or a locked database shouldn't kill the watcher; it'll
|
||||
# try again next tick.
|
||||
pass
|
||||
time.sleep(interval)
|
||||
|
||||
|
||||
def scan_once():
|
||||
"""Import every pending file, oldest name first. Returns how many it took."""
|
||||
done = 0
|
||||
for path in _pending():
|
||||
if jobs.run_import(path, source="inbox:" + os.path.basename(path)):
|
||||
_move_to_done(path)
|
||||
done += 1
|
||||
return done
|
||||
|
||||
|
||||
def _pending():
|
||||
files = []
|
||||
for name in sorted(os.listdir(db.INBOX_DIR)):
|
||||
p = os.path.join(db.INBOX_DIR, name)
|
||||
if os.path.isfile(p) and name.lower().endswith((".zip", ".xml")):
|
||||
files.append(p)
|
||||
return files
|
||||
|
||||
|
||||
def _move_to_done(path):
|
||||
name = os.path.basename(path)
|
||||
dest = os.path.join(db.INBOX_DONE, name)
|
||||
# Don't clobber an earlier file of the same name.
|
||||
n = 1
|
||||
stem, ext = os.path.splitext(name)
|
||||
while os.path.exists(dest):
|
||||
dest = os.path.join(db.INBOX_DONE, f"{stem}-{n}{ext}")
|
||||
n += 1
|
||||
os.replace(path, dest)
|
||||
Reference in New Issue
Block a user