]> www.average.org Git - loctrkd.git/blob - loctrkd/rectifier.py
Convert recitifier to multiprotocol support
[loctrkd.git] / loctrkd / rectifier.py
1 """ Estimate coordinates from WIFI_POSITIONING and send back """
2
3 from configparser import ConfigParser
4 from datetime import datetime, timezone
5 from importlib import import_module
6 from logging import getLogger
7 from os import umask
8 from struct import pack
9 import zmq
10
11 from . import common
12 from .common import CoordReport, HintReport, StatusReport, Report
13 from .zmsg import Bcast, Rept, Resp, topic
14
15 log = getLogger("loctrkd/rectifier")
16
17
18 def runserver(conf: ConfigParser) -> None:
19     qry = import_module("." + conf.get("rectifier", "lookaside"), __package__)
20     qry.init(conf)
21     proto_needanswer = dict(common.exposed_protos())
22     # Is this https://github.com/zeromq/pyzmq/issues/1627 still not fixed?!
23     zctx = zmq.Context()  # type: ignore
24     zsub = zctx.socket(zmq.SUB)  # type: ignore
25     zsub.connect(conf.get("collector", "publishurl"))
26     for proto in proto_needanswer.keys():
27         zsub.setsockopt(zmq.SUBSCRIBE, topic(proto))
28     zpush = zctx.socket(zmq.PUSH)  # type: ignore
29     zpush.connect(conf.get("collector", "listenurl"))
30     zpub = zctx.socket(zmq.PUB)  # type: ignore
31     zpub.connect(conf.get("rectifier", "publishurl"))
32
33     try:
34         while True:
35             zmsg = Bcast(zsub.recv())
36             msg = common.parse_message(
37                 zmsg.proto, zmsg.packet, is_incoming=zmsg.is_incoming
38             )
39             log.debug(
40                 "IMEI %s from %s at %s: %s",
41                 zmsg.imei,
42                 zmsg.peeraddr,
43                 datetime.fromtimestamp(zmsg.when).astimezone(tz=timezone.utc),
44                 msg,
45             )
46             rect: Report = msg.rectified()
47             log.debug("rectified: %s", rect)
48             if isinstance(rect, (CoordReport, StatusReport)):
49                 zpub.send(Rept(imei=zmsg.imei, payload=rect.json).packed)
50             elif isinstance(rect, HintReport):
51                 try:
52                     lat, lon = qry.lookup(
53                         rect.mcc, rect.mnc, rect.gsm_cells, rect.wifi_aps
54                     )
55                     log.debug(
56                         "Approximated lat=%s, lon=%s for %s", lat, lon, rect
57                     )
58                     if proto_needanswer.get(zmsg.proto, False):
59                         resp = Resp(
60                             imei=zmsg.imei,
61                             when=zmsg.when,  # not the current time, but the original!
62                             packet=msg.Out(latitude=lat, longitude=lon).packed,
63                         )
64                         log.debug("Sending reponse %s", resp)
65                         zpush.send(resp.packed)
66                     zpub.send(
67                         Rept(
68                             imei=zmsg.imei,
69                             payload=CoordReport(
70                                 devtime=rect.devtime,
71                                 battery_percentage=rect.battery_percentage,
72                                 accuracy=-1,
73                                 altitude=-1,
74                                 speed=-1,
75                                 direction=-1,
76                                 latitude=lat,
77                                 longitude=lon,
78                             ).json,
79                         ).packed
80                     )
81                 except Exception as e:
82                     log.warning(
83                         "Lookup for %s rectified as %s resulted in %s",
84                         msg,
85                         rect,
86                         e,
87                     )
88
89     except KeyboardInterrupt:
90         zsub.close()
91         zpub.close()
92         zpush.close()
93         zctx.destroy()  # type: ignore
94         qry.shut()
95
96
97 if __name__.endswith("__main__"):
98     runserver(common.init(log))