]> www.average.org Git - loctrkd.git/blob - loctrkd/termconfig.py
Update changelog for 2.00 release
[loctrkd.git] / loctrkd / termconfig.py
1 """ For when responding to the terminal is not trivial """
2
3 from configparser import ConfigParser, SectionProxy
4 from datetime import datetime, timezone
5 from logging import getLogger
6 from struct import pack
7 from typing import Any, Dict, List, Union
8 import zmq
9
10 from . import common
11 from .zx303proto import *
12 from .zx303proto import STATUS, SETUP, POSITION_UPLOAD_INTERVAL
13 from .zmsg import Bcast, Resp, topic
14
15 log = getLogger("loctrkd/termconfig")
16
17
18 def normconf(section: SectionProxy) -> Dict[str, Any]:
19     result: Dict[str, Any] = {}
20     for key, val in section.items():
21         vals = val.split("\n")
22         if len(vals) > 1 and vals[0] == "":
23             vals = vals[1:]
24         lst: List[Union[str, int]] = []
25         for el in vals:
26             try:
27                 lst.append(int(el, 0))
28             except ValueError:
29                 if el[0] == '"' and el[-1] == '"':
30                     el = el.strip('"').rstrip('"')
31                 lst.append(el)
32         if not (
33             all([isinstance(x, int) for x in lst])
34             or all([isinstance(x, str) for x in lst])
35         ):
36             raise ValueError(
37                 "Values of %s - %s are of different type", key, vals
38             )
39         if len(lst) == 1:
40             result[key] = lst[0]
41         else:
42             result[key] = lst
43     return result
44
45
46 def runserver(conf: ConfigParser) -> None:
47     # Is this https://github.com/zeromq/pyzmq/issues/1627 still not fixed?!
48     zctx = zmq.Context()  # type: ignore
49     zsub = zctx.socket(zmq.SUB)  # type: ignore
50     zsub.connect(conf.get("collector", "publishurl"))
51     for proto in (
52         STATUS.proto_name(),
53         SETUP.proto_name(),
54         POSITION_UPLOAD_INTERVAL.proto_name(),
55     ):
56         zsub.setsockopt(zmq.SUBSCRIBE, topic(proto))
57     zpush = zctx.socket(zmq.PUSH)  # type: ignore
58     zpush.connect(conf.get("collector", "listenurl"))
59
60     try:
61         while True:
62             zmsg = Bcast(zsub.recv())
63             msg = parse_message(zmsg.packet)
64             log.debug(
65                 "IMEI %s from %s at %s: %s",
66                 zmsg.imei,
67                 zmsg.peeraddr,
68                 datetime.fromtimestamp(zmsg.when).astimezone(tz=timezone.utc),
69                 msg,
70             )
71             if msg.RESPOND is not Respond.EXT:
72                 log.error(
73                     "%s does not expect externally provided response", msg
74                 )
75             if zmsg.imei is not None and conf.has_section(zmsg.imei):
76                 termconfig = normconf(conf[zmsg.imei])
77             elif conf.has_section("termconfig"):
78                 termconfig = normconf(conf["termconfig"])
79             else:
80                 termconfig = {}
81             kwargs = {}
82             if isinstance(msg, STATUS):
83                 kwargs = {
84                     "upload_interval": termconfig.get(
85                         "statusintervalminutes", 25
86                     )
87                 }
88             elif isinstance(msg, SETUP):
89                 for key in (
90                     "uploadintervalseconds",
91                     "binaryswitch",
92                     "alarms",
93                     "dndtimeswitch",
94                     "dndtimes",
95                     "gpstimeswitch",
96                     "gpstimestart",
97                     "gpstimestop",
98                     "phonenumbers",
99                 ):
100                     if key in termconfig:
101                         kwargs[key] = termconfig[key]
102             resp = Resp(
103                 imei=zmsg.imei, when=zmsg.when, packet=msg.Out(**kwargs).packed
104             )
105             log.debug("Response: %s", resp)
106             zpush.send(resp.packed)
107
108     except KeyboardInterrupt:
109         zsub.close()
110         zpush.close()
111         zctx.destroy()  # type: ignore
112
113
114 if __name__.endswith("__main__"):
115     runserver(common.init(log))