X-Git-Url: http://www.average.org/gitweb/?a=blobdiff_plain;f=gps303%2Fevstore.py;h=2b23e8e92ef98e4c5ff21a584be786df179859ad;hb=0c4137370f3ff2f29bde55d5473f8568be52eff9;hp=1b1ae2dc398f29063ffcddf2716da7b2424de01c;hpb=d75412f9c32046da5659728e82adaa9607dd0b74;p=loctrkd.git diff --git a/gps303/evstore.py b/gps303/evstore.py index 1b1ae2d..2b23e8e 100644 --- a/gps303/evstore.py +++ b/gps303/evstore.py @@ -1,40 +1,76 @@ -from logging import getLogger -from sqlite3 import connect +""" sqlite event store """ -__all__ = ("initdb", "stow") +from sqlite3 import connect, OperationalError +from typing import Any, List, Tuple -log = getLogger("gps303") +__all__ = "fetch", "initdb", "stow" DB = None SCHEMA = """create table if not exists events ( - timestamp real not null, + tstamp real not null, imei text, - clntaddr text not null, + peeraddr text not null, + is_incoming int not null default TRUE, proto int not null, - payload blob + packet blob )""" -def initdb(dbname): +def initdb(dbname: str) -> None: global DB DB = connect(dbname) - DB.execute(SCHEMA) + try: + DB.execute( + """alter table events add column + is_incoming int not null default TRUE""" + ) + except OperationalError: + DB.execute(SCHEMA) -def stow(clntaddr, timestamp, imei, proto, payload): +def stow(**kwargs: Any) -> None: assert DB is not None - parms = dict( - zip( - ("clntaddr", "timestamp", "imei", "proto", "payload"), - (str(clntaddr), timestamp, imei, proto, payload), + 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", -1), + ("packet", b""), ) - ) - log.debug("inserting %s", parms) + } + assert len(kwargs) <= len(parms) DB.execute( """insert or ignore into events - (timestamp, imei, clntaddr, proto, payload) - values (:timestamp, :imei, :clntaddr, :proto, :payload)""", + (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, int]], 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))