X-Git-Url: http://average.org/gitweb/?a=blobdiff_plain;f=loctrkd%2Fevstore.py;fp=loctrkd%2Fevstore.py;h=07b6dc4b760b7de08349611e844168ab0e80470a;hb=dbdf9d63af31770ad57302e16b17a2fdc526773f;hp=0000000000000000000000000000000000000000;hpb=bf48ccad4b4b91e7d7e09d1087f5953bc2db97d7;p=loctrkd.git diff --git a/loctrkd/evstore.py b/loctrkd/evstore.py new file mode 100644 index 0000000..07b6dc4 --- /dev/null +++ b/loctrkd/evstore.py @@ -0,0 +1,76 @@ +""" sqlite event store """ + +from sqlite3 import connect, OperationalError +from typing import Any, List, Tuple + +__all__ = "fetch", "initdb", "stow" + +DB = None + +SCHEMA = """create table if not exists events ( + tstamp real not null, + imei text, + peeraddr text not null, + is_incoming int not null default TRUE, + proto text not null, + packet blob +)""" + + +def initdb(dbname: str) -> None: + global DB + DB = connect(dbname) + try: + DB.execute( + """alter table events add column + is_incoming int not null default TRUE""" + ) + except OperationalError: + DB.execute(SCHEMA) + + +def stow(**kwargs: Any) -> None: + assert DB is not None + parms = { + k: kwargs[k] if k in kwargs else v + for k, v in ( + ("is_incoming", True), + ("peeraddr", None), + ("when", 0.0), + ("imei", None), + ("proto", "UNKNOWN"), + ("packet", b""), + ) + } + assert len(kwargs) <= len(parms) + DB.execute( + """insert or ignore into events + (tstamp, imei, peeraddr, proto, packet, is_incoming) + values + (:when, :imei, :peeraddr, :proto, :packet, :is_incoming) + """, + parms, + ) + DB.commit() + + +def fetch( + imei: str, matchlist: List[Tuple[bool, str]], backlog: int +) -> List[Tuple[bool, float, bytes]]: + # matchlist is a list of tuples (is_incoming, proto) + # returns a list of tuples (is_incoming, timestamp, packet) + assert DB is not None + selector = " or ".join( + (f"(is_incoming = ? and proto = ?)" for _ in range(len(matchlist))) + ) + cur = DB.cursor() + cur.execute( + f"""select is_incoming, tstamp, packet from events + where ({selector}) and imei = ? + order by tstamp desc limit ?""", + tuple(item for sublist in matchlist for item in sublist) + + (imei, backlog), + ) + result = list(cur) + cur.close() + return list(reversed(result))