]> www.average.org Git - loctrkd.git/commitdiff
rectifier: lookaside based on rectified objects
authorEugene Crosser <crosser@average.org>
Thu, 28 Jul 2022 15:54:04 +0000 (17:54 +0200)
committerEugene Crosser <crosser@average.org>
Thu, 28 Jul 2022 15:54:04 +0000 (17:54 +0200)
loctrkd/beesure.py
loctrkd/common.py
loctrkd/protomodule.py
loctrkd/rectifier.py
loctrkd/zmsg.py
loctrkd/zx303proto.py

index 93216c98ca39ce8ce570aff7cb7033ee6b556620..baf14dbee9600eb25252f9d44ea38c80fac0890a 100755 (executable)
@@ -351,29 +351,29 @@ class _LOC_DATA(BeeSurePkt):
         self.latitude = p.lat * p.nors
         self.longitude = p.lon * p.eorw
 
-    def rectified(self) -> Dict[str, Any]:  # JSON-able dict
+    def rectified(self) -> SimpleNamespace:  # JSON-able dict
         if self.gps_valid:
-            return {
-                "type": "location",
-                "devtime": str(self.devtime),
-                "battery_percentage": self.battery_percentage,
-                "accuracy": self.positioning_accuracy,
-                "altitude": self.altitude,
-                "speed": self.speed,
-                "direction": self.direction,
-                "latitude": self.latitude,
-                "longitude": self.longitude,
-            }
+            return SimpleNamespace(
+                type="location",
+                devtime=str(self.devtime),
+                battery_percentage=self.battery_percentage,
+                accuracy=self.positioning_accuracy,
+                altitude=self.altitude,
+                speed=self.speed,
+                direction=self.direction,
+                latitude=self.latitude,
+                longitude=self.longitude,
+            )
         else:
-            return {
-                "type": "approximate_location",
-                "devtime": str(self.devtime),
-                "battery_percentage": self.battery_percentage,
-                "mcc": self.mcc,
-                "mnc": self.mnc,
-                "base_stations": self.base_stations,
-                "wifi_aps": self.wifi_aps,
-            }
+            return SimpleNamespace(
+                type="approximate_location",
+                devtime=str(self.devtime),
+                battery_percentage=self.battery_percentage,
+                mcc=self.mcc,
+                mnc=self.mnc,
+                base_stations=self.base_stations,
+                wifi_aps=self.wifi_aps,
+            )
 
 
 class AL(_LOC_DATA):
index 02b520f620d7d82582df949361b572327de283ac..f112fbd53a51176e279b77c01cc05e6f32529bd2 100644 (file)
@@ -67,3 +67,12 @@ def pmod_for_proto(proto: str) -> Optional[ProtoModule]:
         if pmod.proto_handled(proto):
             return pmod
     return None
+
+
+def parse_message(proto: str, packet: bytes, is_incoming: bool = True) -> Any:
+    pmod = pmod_for_proto(proto)
+    return pmod.parse_message(packet, is_incoming) if pmod else None
+
+
+def exposed_protos() -> List[Tuple[str, bool]]:
+    return [item for pmod in pmods for item in pmod.exposed_protos()]
index 1a6f0fc5ada46a73cb83d1536c9ad0d3d717d6c6..446fec6215f77c3723744e571c5bd463f1b1115f 100644 (file)
@@ -129,6 +129,9 @@ class ProtoModule:
     def enframe(buffer: bytes, imei: Optional[str] = None) -> bytes:
         ...
 
+    class DecodeError(Exception):
+        ...
+
     @staticmethod
     def exposed_protos() -> List[Tuple[str, bool]]:
         ...
index 8ee75970aec030f771ec0555ba306ad68b1a3397..ec8baa1a5ab33afaed9fc64e56959cc4e185cd71 100644 (file)
@@ -9,8 +9,7 @@ from struct import pack
 import zmq
 
 from . import common
-from .zx303proto import parse_message, proto_name, WIFI_POSITIONING
-from .zmsg import Bcast, Resp, topic
+from .zmsg import Bcast, Report, Resp, topic
 
 log = getLogger("loctrkd/rectifier")
 
@@ -18,11 +17,13 @@ log = getLogger("loctrkd/rectifier")
 def runserver(conf: ConfigParser) -> None:
     qry = import_module("." + conf.get("rectifier", "lookaside"), __package__)
     qry.init(conf)
+    proto_needanswer = dict(common.exposed_protos())
     # Is this https://github.com/zeromq/pyzmq/issues/1627 still not fixed?!
     zctx = zmq.Context()  # type: ignore
     zsub = zctx.socket(zmq.SUB)  # type: ignore
     zsub.connect(conf.get("collector", "publishurl"))
-    zsub.setsockopt(zmq.SUBSCRIBE, topic(proto_name(WIFI_POSITIONING)))
+    for proto in proto_needanswer.keys():
+        zsub.setsockopt(zmq.SUBSCRIBE, topic(proto))
     zpush = zctx.socket(zmq.PUSH)  # type: ignore
     zpush.connect(conf.get("collector", "listenurl"))
     zpub = zctx.socket(zmq.PUB)  # type: ignore
@@ -31,7 +32,9 @@ def runserver(conf: ConfigParser) -> None:
     try:
         while True:
             zmsg = Bcast(zsub.recv())
-            msg = parse_message(zmsg.packet)
+            msg = common.parse_message(
+                zmsg.proto, zmsg.packet, is_incoming=zmsg.is_incoming
+            )
             log.debug(
                 "IMEI %s from %s at %s: %s",
                 zmsg.imei,
@@ -39,19 +42,24 @@ def runserver(conf: ConfigParser) -> None:
                 datetime.fromtimestamp(zmsg.when).astimezone(tz=timezone.utc),
                 msg,
             )
-            try:
-                lat, lon = qry.lookup(
-                    msg.mcc, msg.mnc, msg.gsm_cells, msg.wifi_aps
-                )
-                resp = Resp(
-                    imei=zmsg.imei,
-                    when=zmsg.when,  # not the current time, but the original!
-                    packet=msg.Out(latitude=lat, longitude=lon).packed,
-                )
-                log.debug("Response for lat=%s, lon=%s: %s", lat, lon, resp)
-                zpush.send(resp.packed)
-            except Exception as e:
-                log.warning("Lookup for %s resulted in %s", msg, e)
+            rect = msg.rectified()
+            log.debug("rectified: %s", rect)
+            if rect.type == "approximate_location":
+                try:
+                    lat, lon = qry.lookup(
+                        rect.mcc, rect.mnc, rect.base_stations, rect.wifi_aps
+                    )
+                    resp = Resp(
+                        imei=zmsg.imei,
+                        when=zmsg.when,  # not the current time, but the original!
+                        packet=msg.Out(latitude=lat, longitude=lon).packed,
+                    )
+                    log.debug(
+                        "Response for lat=%s, lon=%s: %s", lat, lon, resp
+                    )
+                    zpush.send(resp.packed)
+                except Exception as e:
+                    log.warning("Lookup for %s resulted in %s", msg, e)
 
     except KeyboardInterrupt:
         zsub.close()
index ae469a23b6afe416ac9a1cc6f8e9abe25b2ab022..9dae60540f46019957a72121700c6ada5df081de 100644 (file)
@@ -166,3 +166,28 @@ class Resp(_Zmsg):
 
         self.when = when
         self.packet = buffer[24:]
+
+
+class Report(_Zmsg):
+    """Broadcast Zzmq message with "rectified" proto-agnostic json data"""
+
+    KWARGS = (("imei", None), ("payload", ""))
+
+    @property
+    def packed(self) -> bytes:
+        return (
+            pack(
+                "16s",
+                "0000000000000000"
+                if self.imei is None
+                else self.imei.encode(),
+            )
+            + self.payload.encode()
+        )
+
+    def decode(self, buffer: bytes) -> None:
+        imei = buffer[:16]
+        self.imei = (
+            None if imei == b"0000000000000000" else imei.decode().strip("\0")
+        )
+        self.payload = buffer[16:].decode()
index e27eb5f72c985456b925594a30066973b252bb64..236f5daa16a1252f3203e660e1718370148465a5 100755 (executable)
@@ -19,6 +19,7 @@ from enum import Enum
 from inspect import isclass
 from struct import error, pack, unpack
 from time import time
+from types import SimpleNamespace
 from typing import (
     Any,
     Callable,
@@ -363,15 +364,15 @@ class _GPS_POSITIONING(GPS303Pkt):
         ttup = (tup[0] % 100,) + tup[1:6]
         return pack("BBBBBB", *ttup)
 
-    def rectified(self) -> Dict[str, Any]:  # JSON-able dict
-        return {
-            "type": "location",
-            "devtime": str(self.devtime),
-            "speed": self.speed,
-            "direction": self.heading,
-            "latitude": self.latitude,
-            "longitude": self.longitude,
-        }
+    def rectified(self) -> SimpleNamespace:  # JSON-able dict
+        return SimpleNamespace(
+            type="location",
+            devtime=str(self.devtime),
+            speed=self.speed,
+            direction=self.heading,
+            latitude=self.latitude,
+            longitude=self.longitude,
+        )
 
 
 class GPS_POSITIONING(_GPS_POSITIONING):
@@ -489,15 +490,15 @@ class _WIFI_POSITIONING(GPS303Pkt):
             ]
         )
 
-    def rectified(self) -> Dict[str, Any]:  # JSON-able dict
-        return {
-            "type": "approximate_location",
-            "devtime": str(self.devtime),
-            "mcc": self.mcc,
-            "mnc": self.mnc,
-            "base_stations": self.gsm_cells,
-            "wifi_aps": self.wifi_aps,
-        }
+    def rectified(self) -> SimpleNamespace:  # JSON-able dict
+        return SimpleNamespace(
+            type="approximate_location",
+            devtime=str(self.devtime),
+            mcc=self.mcc,
+            mnc=self.mnc,
+            base_stations=self.gsm_cells,
+            wifi_aps=self.wifi_aps,
+        )
 
 
 class WIFI_OFFLINE_POSITIONING(_WIFI_POSITIONING):