]> 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
 
         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:
         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:
         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):
 
 
 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
         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:
         ...
 
     def enframe(buffer: bytes, imei: Optional[str] = None) -> bytes:
         ...
 
+    class DecodeError(Exception):
+        ...
+
     @staticmethod
     def exposed_protos() -> List[Tuple[str, bool]]:
         ...
     @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
 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")
 
 
 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)
 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"))
     # 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
     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())
     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,
             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,
             )
                 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()
 
     except KeyboardInterrupt:
         zsub.close()
index ae469a23b6afe416ac9a1cc6f8e9abe25b2ab022..9dae60540f46019957a72121700c6ada5df081de 100644 (file)
@@ -166,3 +166,28 @@ class Resp(_Zmsg):
 
         self.when = when
         self.packet = buffer[24:]
 
         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 inspect import isclass
 from struct import error, pack, unpack
 from time import time
+from types import SimpleNamespace
 from typing import (
     Any,
     Callable,
 from typing import (
     Any,
     Callable,
@@ -363,15 +364,15 @@ class _GPS_POSITIONING(GPS303Pkt):
         ttup = (tup[0] % 100,) + tup[1:6]
         return pack("BBBBBB", *ttup)
 
         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):
 
 
 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):
 
 
 class WIFI_OFFLINE_POSITIONING(_WIFI_POSITIONING):