moat-kv 0.71.0__py3-none-any.whl → 0.71.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- moat/kv/__init__.py +6 -7
- moat/kv/_cfg.yaml +3 -2
- moat/kv/actor/__init__.py +2 -1
- moat/kv/actor/deletor.py +4 -1
- moat/kv/auth/__init__.py +12 -13
- moat/kv/auth/_test.py +4 -1
- moat/kv/auth/password.py +11 -7
- moat/kv/backend/mqtt.py +4 -5
- moat/kv/client.py +20 -39
- moat/kv/code.py +3 -3
- moat/kv/command/data.py +4 -3
- moat/kv/command/dump/__init__.py +36 -34
- moat/kv/command/internal.py +2 -3
- moat/kv/command/job.py +1 -2
- moat/kv/command/type.py +3 -6
- moat/kv/data.py +9 -8
- moat/kv/errors.py +16 -8
- moat/kv/mock/__init__.py +2 -12
- moat/kv/model.py +29 -33
- moat/kv/obj/__init__.py +3 -3
- moat/kv/obj/command.py +3 -3
- moat/kv/runner.py +4 -5
- moat/kv/server.py +106 -126
- moat/kv/types.py +10 -12
- {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/METADATA +6 -2
- moat_kv-0.71.7.dist-info/RECORD +47 -0
- {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/WHEEL +1 -1
- moat_kv-0.71.7.dist-info/licenses/LICENSE +3 -0
- moat_kv-0.71.7.dist-info/licenses/LICENSE.APACHE2 +202 -0
- moat_kv-0.71.7.dist-info/licenses/LICENSE.MIT +20 -0
- moat_kv-0.71.7.dist-info/top_level.txt +1 -0
- build/lib/docs/source/conf.py +0 -201
- build/lib/examples/pathify.py +0 -45
- build/lib/moat/kv/__init__.py +0 -19
- build/lib/moat/kv/_cfg.yaml +0 -93
- build/lib/moat/kv/_main.py +0 -91
- build/lib/moat/kv/actor/__init__.py +0 -98
- build/lib/moat/kv/actor/deletor.py +0 -139
- build/lib/moat/kv/auth/__init__.py +0 -444
- build/lib/moat/kv/auth/_test.py +0 -166
- build/lib/moat/kv/auth/password.py +0 -234
- build/lib/moat/kv/auth/root.py +0 -58
- build/lib/moat/kv/backend/__init__.py +0 -67
- build/lib/moat/kv/backend/mqtt.py +0 -71
- build/lib/moat/kv/client.py +0 -1025
- build/lib/moat/kv/code.py +0 -236
- build/lib/moat/kv/codec.py +0 -11
- build/lib/moat/kv/command/__init__.py +0 -1
- build/lib/moat/kv/command/acl.py +0 -180
- build/lib/moat/kv/command/auth.py +0 -261
- build/lib/moat/kv/command/code.py +0 -293
- build/lib/moat/kv/command/codec.py +0 -186
- build/lib/moat/kv/command/data.py +0 -265
- build/lib/moat/kv/command/dump/__init__.py +0 -143
- build/lib/moat/kv/command/error.py +0 -149
- build/lib/moat/kv/command/internal.py +0 -248
- build/lib/moat/kv/command/job.py +0 -433
- build/lib/moat/kv/command/log.py +0 -53
- build/lib/moat/kv/command/server.py +0 -114
- build/lib/moat/kv/command/type.py +0 -201
- build/lib/moat/kv/config.py +0 -46
- build/lib/moat/kv/data.py +0 -216
- build/lib/moat/kv/errors.py +0 -561
- build/lib/moat/kv/exceptions.py +0 -126
- build/lib/moat/kv/mock/__init__.py +0 -101
- build/lib/moat/kv/mock/mqtt.py +0 -159
- build/lib/moat/kv/mock/tracer.py +0 -63
- build/lib/moat/kv/model.py +0 -1069
- build/lib/moat/kv/obj/__init__.py +0 -646
- build/lib/moat/kv/obj/command.py +0 -241
- build/lib/moat/kv/runner.py +0 -1347
- build/lib/moat/kv/server.py +0 -2809
- build/lib/moat/kv/types.py +0 -513
- ci/rtd-requirements.txt +0 -4
- ci/test-requirements.txt +0 -7
- ci/travis.sh +0 -96
- debian/.gitignore +0 -7
- debian/changelog +0 -1435
- debian/control +0 -43
- debian/moat-kv/usr/lib/python3/dist-packages/docs/source/conf.py +0 -201
- debian/moat-kv/usr/lib/python3/dist-packages/examples/pathify.py +0 -45
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/__init__.py +0 -19
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml +0 -93
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_main.py +0 -91
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/__init__.py +0 -98
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/deletor.py +0 -139
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/__init__.py +0 -444
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/_test.py +0 -166
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/password.py +0 -234
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/root.py +0 -58
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/__init__.py +0 -67
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py +0 -71
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/client.py +0 -1025
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/code.py +0 -236
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/codec.py +0 -11
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/__init__.py +0 -1
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/acl.py +0 -180
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/auth.py +0 -261
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/code.py +0 -293
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/codec.py +0 -186
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/data.py +0 -265
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/dump/__init__.py +0 -143
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/error.py +0 -149
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/internal.py +0 -248
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/job.py +0 -433
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/log.py +0 -53
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/server.py +0 -114
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/type.py +0 -201
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/config.py +0 -46
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/data.py +0 -216
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/errors.py +0 -561
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/exceptions.py +0 -126
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/__init__.py +0 -101
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/mqtt.py +0 -159
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/tracer.py +0 -63
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/model.py +0 -1069
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/__init__.py +0 -646
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/command.py +0 -241
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/runner.py +0 -1347
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/server.py +0 -2809
- debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/types.py +0 -513
- debian/moat-kv.postinst +0 -3
- debian/rules +0 -20
- debian/source/format +0 -1
- debian/watch +0 -4
- docs/Makefile +0 -20
- docs/make.bat +0 -36
- docs/source/TODO.rst +0 -61
- docs/source/_static/.gitkeep +0 -0
- docs/source/acls.rst +0 -80
- docs/source/auth.rst +0 -84
- docs/source/client_protocol.rst +0 -456
- docs/source/code.rst +0 -341
- docs/source/command_line.rst +0 -1187
- docs/source/common_protocol.rst +0 -47
- docs/source/conf.py +0 -201
- docs/source/debugging.rst +0 -70
- docs/source/extend.rst +0 -37
- docs/source/history.rst +0 -36
- docs/source/index.rst +0 -75
- docs/source/model.rst +0 -54
- docs/source/overview.rst +0 -83
- docs/source/related.rst +0 -89
- docs/source/server_protocol.rst +0 -450
- docs/source/startup.rst +0 -31
- docs/source/translator.rst +0 -244
- docs/source/tutorial.rst +0 -711
- docs/source/v3.rst +0 -168
- examples/code/transform.scale.yml +0 -21
- examples/code/transform.switch.yml +0 -82
- examples/code/transform.timeslot.yml +0 -63
- examples/pathify.py +0 -45
- moat/kv/codec.py +0 -11
- moat_kv-0.71.0.dist-info/RECORD +0 -188
- moat_kv-0.71.0.dist-info/top_level.txt +0 -9
- scripts/current +0 -15
- scripts/env +0 -8
- scripts/init +0 -39
- scripts/recover +0 -17
- scripts/rotate +0 -33
- scripts/run +0 -29
- scripts/run-all +0 -10
- scripts/run-any +0 -10
- scripts/run-single +0 -15
- scripts/success +0 -4
- systemd/moat-kv-recover.service +0 -21
- systemd/moat-kv-rotate.service +0 -20
- systemd/moat-kv-rotate.timer +0 -10
- systemd/moat-kv-run-all.service +0 -26
- systemd/moat-kv-run-all@.service +0 -25
- systemd/moat-kv-run-any.service +0 -26
- systemd/moat-kv-run-any@.service +0 -25
- systemd/moat-kv-run-single.service +0 -26
- systemd/moat-kv-run-single@.service +0 -25
- systemd/moat-kv.service +0 -27
- systemd/postinst +0 -7
- systemd/sysusers +0 -3
- {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/licenses/LICENSE.txt +0 -0
moat/kv/server.py
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
# Local server
|
2
2
|
from __future__ import annotations
|
3
3
|
|
4
|
-
import io
|
5
4
|
import os
|
6
5
|
import signal
|
7
6
|
import time
|
7
|
+
from collections.abc import Mapping
|
8
8
|
|
9
9
|
import anyio
|
10
10
|
from anyio.abc import SocketAttribute
|
11
11
|
from asyncscope import scope
|
12
12
|
from moat.util import DelayedRead, DelayedWrite, create_queue, ensure_cfg
|
13
|
+
from moat.lib.codec import get_codec
|
13
14
|
|
14
15
|
try:
|
15
16
|
from contextlib import asynccontextmanager
|
@@ -17,10 +18,9 @@ except ImportError:
|
|
17
18
|
from async_generator import asynccontextmanager
|
18
19
|
|
19
20
|
import logging
|
20
|
-
from collections.abc import Mapping
|
21
21
|
from functools import partial
|
22
22
|
from pprint import pformat
|
23
|
-
from typing import Any
|
23
|
+
from typing import Any, TYPE_CHECKING
|
24
24
|
|
25
25
|
from asyncactor import (
|
26
26
|
Actor,
|
@@ -55,7 +55,6 @@ from . import _version_tuple
|
|
55
55
|
from . import client as moat_kv_client # needs to be mock-able
|
56
56
|
from .actor.deletor import DeleteActor
|
57
57
|
from .backend import get_backend
|
58
|
-
from .codec import packer, stream_unpacker, unpacker
|
59
58
|
from .exceptions import (
|
60
59
|
ACLError,
|
61
60
|
CancelledError,
|
@@ -68,6 +67,10 @@ from .exceptions import (
|
|
68
67
|
)
|
69
68
|
from .model import Node, NodeEvent, NodeSet, UpdateEvent, Watcher
|
70
69
|
from .types import ACLFinder, ACLStepper, ConvNull, NullACL, RootEntry
|
70
|
+
import contextlib
|
71
|
+
|
72
|
+
if TYPE_CHECKING:
|
73
|
+
import io
|
71
74
|
|
72
75
|
Stream = anyio.abc.ByteStream
|
73
76
|
|
@@ -75,9 +78,6 @@ ClosedResourceError = anyio.ClosedResourceError
|
|
75
78
|
|
76
79
|
_client_nr = 0
|
77
80
|
|
78
|
-
SERF_MAXLEN = 450
|
79
|
-
SERF_LEN_DELTA = 15
|
80
|
-
|
81
81
|
|
82
82
|
def max_n(a, b):
|
83
83
|
if a is None:
|
@@ -228,10 +228,8 @@ class StreamCommand:
|
|
228
228
|
await self.send(error=repr(exc))
|
229
229
|
finally:
|
230
230
|
with anyio.move_on_after(2, shield=True):
|
231
|
-
|
231
|
+
with contextlib.suppress(anyio.BrokenResourceError):
|
232
232
|
await self.send(state="end")
|
233
|
-
except anyio.BrokenResourceError:
|
234
|
-
pass
|
235
233
|
|
236
234
|
else:
|
237
235
|
res = await self.run(**kw)
|
@@ -553,62 +551,64 @@ class SCmd_watch(StreamCommand):
|
|
553
551
|
min_depth = msg.get("min_depth", 0)
|
554
552
|
empty = msg.get("empty", False)
|
555
553
|
|
556
|
-
async with
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
await entry.walk(worker, acl=acl, **kv)
|
585
|
-
await self.send(state="uptodate")
|
586
|
-
|
587
|
-
tg.start_soon(orig_state)
|
588
|
-
|
589
|
-
async for m in watcher:
|
590
|
-
ml = len(m.entry.path) - len(msg.path)
|
591
|
-
if ml < min_depth:
|
592
|
-
continue
|
593
|
-
if max_depth >= 0 and ml > max_depth:
|
594
|
-
continue
|
595
|
-
a = acl
|
596
|
-
for p in getattr(m, "path", [])[shorter.depth :]:
|
597
|
-
if not a.allows("e"):
|
598
|
-
break
|
554
|
+
async with (
|
555
|
+
Watcher(entry) as watcher,
|
556
|
+
anyio.create_task_group() as tg,
|
557
|
+
):
|
558
|
+
tock = client.server.tock
|
559
|
+
shorter = PathShortener(entry.path)
|
560
|
+
if msg.get("fetch", False):
|
561
|
+
|
562
|
+
async def orig_state():
|
563
|
+
kv = {"max_depth": max_depth, "min_depth": min_depth}
|
564
|
+
|
565
|
+
async def worker(entry, acl):
|
566
|
+
if entry.data is NotGiven and not empty:
|
567
|
+
return
|
568
|
+
if entry.tock < tock:
|
569
|
+
res = entry.serialize(
|
570
|
+
chop_path=client._chop_path,
|
571
|
+
nchain=nchain,
|
572
|
+
conv=conv,
|
573
|
+
)
|
574
|
+
shorter(res)
|
575
|
+
if not acl.allows("r"):
|
576
|
+
res.pop("value", None)
|
577
|
+
await self.send(**res)
|
578
|
+
|
579
|
+
if not acl.allows("e"):
|
580
|
+
raise StopAsyncIteration
|
599
581
|
if not acl.allows("x"):
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
582
|
+
acl.block("r")
|
583
|
+
|
584
|
+
await entry.walk(worker, acl=acl, **kv)
|
585
|
+
await self.send(state="uptodate")
|
586
|
+
|
587
|
+
tg.start_soon(orig_state)
|
588
|
+
|
589
|
+
async for m in watcher:
|
590
|
+
ml = len(m.entry.path) - len(msg.path)
|
591
|
+
if ml < min_depth:
|
592
|
+
continue
|
593
|
+
if max_depth >= 0 and ml > max_depth:
|
594
|
+
continue
|
595
|
+
a = acl
|
596
|
+
for p in getattr(m, "path", [])[shorter.depth :]:
|
597
|
+
if not a.allows("e"):
|
598
|
+
break
|
599
|
+
if not acl.allows("x"):
|
600
|
+
a.block("r")
|
601
|
+
a = a.step(p)
|
602
|
+
else:
|
603
|
+
res = m.entry.serialize(
|
604
|
+
chop_path=client._chop_path,
|
605
|
+
nchain=nchain,
|
606
|
+
conv=conv,
|
607
|
+
)
|
608
|
+
shorter(res)
|
609
|
+
if not a.allows("r"):
|
610
|
+
res.pop("value", None)
|
611
|
+
await self.send(**res)
|
612
612
|
|
613
613
|
|
614
614
|
class SCmd_msg_monitor(StreamCommand):
|
@@ -621,6 +621,7 @@ class SCmd_msg_monitor(StreamCommand):
|
|
621
621
|
multiline = True
|
622
622
|
|
623
623
|
async def run(self):
|
624
|
+
codec = get_codec("std-msgpack")
|
624
625
|
msg = self.msg
|
625
626
|
raw = msg.get("raw", False)
|
626
627
|
topic = msg.topic
|
@@ -642,7 +643,7 @@ class SCmd_msg_monitor(StreamCommand):
|
|
642
643
|
res["raw"] = resp.payload
|
643
644
|
else:
|
644
645
|
try:
|
645
|
-
res["data"] =
|
646
|
+
res["data"] = codec.decode(resp.payload)
|
646
647
|
except Exception as exc:
|
647
648
|
res["raw"] = resp.payload
|
648
649
|
res["error"] = repr(exc)
|
@@ -716,10 +717,10 @@ class ServerClient:
|
|
716
717
|
if fn is None:
|
717
718
|
fn = StreamCommand(self, msg)
|
718
719
|
if needAuth and not getattr(fn, "noAuth", False):
|
719
|
-
raise NoAuthError
|
720
|
+
raise NoAuthError
|
720
721
|
else:
|
721
722
|
if needAuth and not getattr(fn, "noAuth", False):
|
722
|
-
raise NoAuthError
|
723
|
+
raise NoAuthError
|
723
724
|
fn = partial(self._process, fn, msg)
|
724
725
|
if evt is not None:
|
725
726
|
evt.set()
|
@@ -1069,7 +1070,7 @@ class ServerClient:
|
|
1069
1070
|
assert "data" not in msg
|
1070
1071
|
data = msg.raw
|
1071
1072
|
else:
|
1072
|
-
data =
|
1073
|
+
data = self.codec.encode(msg.data)
|
1073
1074
|
await self.server.backend.send(*topic, payload=data)
|
1074
1075
|
|
1075
1076
|
async def cmd_delete_tree(self, msg):
|
@@ -1173,7 +1174,7 @@ class ServerClient:
|
|
1173
1174
|
if "tock" not in msg:
|
1174
1175
|
msg["tock"] = self.server.tock
|
1175
1176
|
try:
|
1176
|
-
await self.stream.send(
|
1177
|
+
await self.stream.send(self.codec.encode(msg))
|
1177
1178
|
except ClosedResourceError:
|
1178
1179
|
self.logger.info("ERO%d %r", self._client_nr, msg)
|
1179
1180
|
self._send_lock = None
|
@@ -1189,7 +1190,7 @@ class ServerClient:
|
|
1189
1190
|
|
1190
1191
|
async def run(self):
|
1191
1192
|
"""Main loop for this client connection."""
|
1192
|
-
|
1193
|
+
self.codec = get_codec("std-msgpack") # pylint: disable=redefined-outer-name
|
1193
1194
|
|
1194
1195
|
async with anyio.create_task_group() as tg:
|
1195
1196
|
self.tg = tg
|
@@ -1225,7 +1226,7 @@ class ServerClient:
|
|
1225
1226
|
await self.send(msg)
|
1226
1227
|
|
1227
1228
|
while True:
|
1228
|
-
for msg in
|
1229
|
+
for msg in self.codec:
|
1229
1230
|
seq = None
|
1230
1231
|
try:
|
1231
1232
|
seq = msg.seq
|
@@ -1263,7 +1264,7 @@ class ServerClient:
|
|
1263
1264
|
if len(buf) == 0: # Connection was closed.
|
1264
1265
|
self.logger.debug("EOF %d", self._client_nr)
|
1265
1266
|
break
|
1266
|
-
|
1267
|
+
self.codec.feed(buf)
|
1267
1268
|
|
1268
1269
|
tg.cancel_scope.cancel()
|
1269
1270
|
|
@@ -1350,7 +1351,7 @@ class _RecoverControl:
|
|
1350
1351
|
|
1351
1352
|
class Server:
|
1352
1353
|
"""
|
1353
|
-
This is the MoaT-KV server. It manages connections to the
|
1354
|
+
This is the MoaT-KV server. It manages connections to the MQTT server,
|
1354
1355
|
the MoaT-KV clients, and (optionally) logs all changes to a file.
|
1355
1356
|
|
1356
1357
|
Args:
|
@@ -1379,7 +1380,8 @@ class Server:
|
|
1379
1380
|
ports = None
|
1380
1381
|
_tock = 0
|
1381
1382
|
|
1382
|
-
def __init__(self, name: str, cfg: dict = None, init: Any = NotGiven):
|
1383
|
+
def __init__(self, name: str, cfg: dict | None = None, init: Any = NotGiven):
|
1384
|
+
self.codec = get_codec("std-msgpack")
|
1383
1385
|
self.root = RootEntry(self, tock=self.tock)
|
1384
1386
|
from moat.util import CFG
|
1385
1387
|
|
@@ -1408,16 +1410,16 @@ class Server:
|
|
1408
1410
|
# connected clients
|
1409
1411
|
self._clients = set()
|
1410
1412
|
|
1411
|
-
#
|
1412
|
-
self._part_len = SERF_MAXLEN - SERF_LEN_DELTA - len(self.node.name)
|
1413
|
-
self._part_seq = 0
|
1414
|
-
self._part_cache = dict()
|
1415
|
-
|
1413
|
+
# running saver tasks
|
1416
1414
|
self._savers = []
|
1417
1415
|
|
1418
1416
|
# This is here, not in _run_del, because _del_actor needs to be accessible early
|
1419
1417
|
self._del_actor = DeleteActor(self)
|
1420
1418
|
|
1419
|
+
# backwards compat
|
1420
|
+
self._part_cache = dict()
|
1421
|
+
self._part_unpacker = get_codec("std-msgpack").decode
|
1422
|
+
|
1421
1423
|
@property
|
1422
1424
|
def node_cache(self):
|
1423
1425
|
"""
|
@@ -1514,7 +1516,7 @@ class Server:
|
|
1514
1516
|
|
1515
1517
|
async def _set_tock(self):
|
1516
1518
|
if self._actor is not None and self._ready.is_set():
|
1517
|
-
await self._actor.set_value(
|
1519
|
+
await self._actor.set_value([self._tock, self.node.tick])
|
1518
1520
|
|
1519
1521
|
async def del_check(self, value):
|
1520
1522
|
"""
|
@@ -1568,8 +1570,7 @@ class Server:
|
|
1568
1570
|
if "tick" not in msg:
|
1569
1571
|
msg["tick"] = self.node.tick
|
1570
1572
|
self.logger.debug("Send %s: %r", action, msg)
|
1571
|
-
|
1572
|
-
await self.backend.send(*self.cfg.server.root, action, payload=m)
|
1573
|
+
await self.backend.send(*self.cfg.server.root, action, payload=msg)
|
1573
1574
|
|
1574
1575
|
async def watcher(self):
|
1575
1576
|
"""
|
@@ -1832,37 +1833,6 @@ class Server:
|
|
1832
1833
|
self._del_actor.add_deleted(self._delete_also_nodes)
|
1833
1834
|
self._delete_also_nodes = NodeSet()
|
1834
1835
|
|
1835
|
-
def _pack_multiple(self, msg):
|
1836
|
-
""""""
|
1837
|
-
# protect against mistakenly encoded multi-part messages
|
1838
|
-
# TODO use a msgpack extension instead
|
1839
|
-
if isinstance(msg, Mapping):
|
1840
|
-
i = 0
|
1841
|
-
while (f"_p{i}") in msg:
|
1842
|
-
i += 1
|
1843
|
-
j = i
|
1844
|
-
while i:
|
1845
|
-
i -= 1
|
1846
|
-
msg[f"_p{i + 1}"] = msg[f"_p{i}"]
|
1847
|
-
if j:
|
1848
|
-
msg["_p0"] = ""
|
1849
|
-
|
1850
|
-
p = packer(msg)
|
1851
|
-
pl = self._part_len
|
1852
|
-
if len(p) > SERF_MAXLEN:
|
1853
|
-
# Owch. We need to split this thing.
|
1854
|
-
self._part_seq = seq = self._part_seq + 1
|
1855
|
-
i = 0
|
1856
|
-
while i >= 0:
|
1857
|
-
i += 1
|
1858
|
-
px, p = p[:pl], p[pl:]
|
1859
|
-
if not p:
|
1860
|
-
i = -i
|
1861
|
-
px = {"_p0": (self.node.name, seq, i, px)}
|
1862
|
-
yield packer(px)
|
1863
|
-
return
|
1864
|
-
yield p
|
1865
|
-
|
1866
1836
|
def _unpack_multiple(self, msg):
|
1867
1837
|
"""
|
1868
1838
|
Undo the effects of _pack_multiple.
|
@@ -1885,7 +1855,7 @@ class Server:
|
|
1885
1855
|
return None
|
1886
1856
|
p = b"".join(s)
|
1887
1857
|
del self._part_cache[(nn, seq)]
|
1888
|
-
msg =
|
1858
|
+
msg = self._part_unpacker(p)
|
1889
1859
|
msg["_p0"] = ""
|
1890
1860
|
|
1891
1861
|
i = 0
|
@@ -1907,15 +1877,21 @@ class Server:
|
|
1907
1877
|
"""
|
1908
1878
|
cmd = getattr(self, "user_" + action)
|
1909
1879
|
try:
|
1910
|
-
async with self.backend.monitor(
|
1880
|
+
async with self.backend.monitor(
|
1881
|
+
*self.cfg.server.root,
|
1882
|
+
action,
|
1883
|
+
codec=self.codec,
|
1884
|
+
) as stream:
|
1911
1885
|
if delay is not None:
|
1912
1886
|
await delay.wait()
|
1913
1887
|
|
1914
1888
|
async for resp in stream:
|
1915
|
-
msg =
|
1889
|
+
msg = resp.payload
|
1890
|
+
|
1916
1891
|
msg = self._unpack_multiple(msg)
|
1917
1892
|
if not msg: # None, empty, whatever
|
1918
1893
|
continue
|
1894
|
+
|
1919
1895
|
self.logger.debug("Recv %s: %r", action, msg)
|
1920
1896
|
try:
|
1921
1897
|
with anyio.fail_after(15):
|
@@ -2406,8 +2382,8 @@ class Server:
|
|
2406
2382
|
|
2407
2383
|
async def load(
|
2408
2384
|
self,
|
2409
|
-
path: str = None,
|
2410
|
-
stream: io.IOBase = None,
|
2385
|
+
path: str | None = None,
|
2386
|
+
stream: io.IOBase | None = None,
|
2411
2387
|
local: bool = False,
|
2412
2388
|
authoritative: bool = False,
|
2413
2389
|
):
|
@@ -2425,8 +2401,10 @@ class Server:
|
|
2425
2401
|
raise RuntimeError("This server already has data.")
|
2426
2402
|
elif not local and self.node.tick is None:
|
2427
2403
|
raise RuntimeError("This server is not yet operational.")
|
2428
|
-
async with MsgReader(path=path, stream=stream) as rdr:
|
2404
|
+
async with MsgReader(path=path, stream=stream, codec="std-msgpack") as rdr:
|
2429
2405
|
async for m in rdr:
|
2406
|
+
if m is None:
|
2407
|
+
continue
|
2430
2408
|
if "value" in m:
|
2431
2409
|
longer(m)
|
2432
2410
|
if "tock" in m:
|
@@ -2472,15 +2450,15 @@ class Server:
|
|
2472
2450
|
await writer(msg) # XXX legacy
|
2473
2451
|
await self.root.walk(saver, full=full)
|
2474
2452
|
|
2475
|
-
async def save(self, path: str = None, stream=None, full=True):
|
2453
|
+
async def save(self, path: str | None = None, stream=None, full=True):
|
2476
2454
|
"""Save the current state to ``path`` or ``stream``."""
|
2477
2455
|
shorter = PathShortener([])
|
2478
|
-
async with MsgWriter(path=path, stream=stream) as mw:
|
2456
|
+
async with MsgWriter(path=path, stream=stream, codec="std-msgpack") as mw:
|
2479
2457
|
await self._save(mw, shorter, full=full)
|
2480
2458
|
|
2481
2459
|
async def save_stream(
|
2482
2460
|
self,
|
2483
|
-
path: str = None,
|
2461
|
+
path: str | None = None,
|
2484
2462
|
stream: anyio.abc.Stream = None,
|
2485
2463
|
save_state: bool = False,
|
2486
2464
|
done: ValueEvent = None,
|
@@ -2504,7 +2482,7 @@ class Server:
|
|
2504
2482
|
"""
|
2505
2483
|
shorter = PathShortener([])
|
2506
2484
|
|
2507
|
-
async with MsgWriter(path=path, stream=stream) as mw:
|
2485
|
+
async with MsgWriter(path=path, stream=stream, codec="std-msgpack") as mw:
|
2508
2486
|
msg = await self.get_state(nodes=True, known=True, deleted=True)
|
2509
2487
|
# await mw({"info": msg})
|
2510
2488
|
await mw(msg) # XXX legacy
|
@@ -2557,7 +2535,7 @@ class Server:
|
|
2557
2535
|
|
2558
2536
|
async def _saver(
|
2559
2537
|
self,
|
2560
|
-
path: str = None,
|
2538
|
+
path: str | None = None,
|
2561
2539
|
stream=None,
|
2562
2540
|
done: ValueEvent = None,
|
2563
2541
|
save_state=False,
|
@@ -2582,7 +2560,9 @@ class Server:
|
|
2582
2560
|
with anyio.CancelScope(shield=True):
|
2583
2561
|
sd.set()
|
2584
2562
|
|
2585
|
-
async def run_saver(
|
2563
|
+
async def run_saver(
|
2564
|
+
self, path: str | None = None, stream=None, save_state=False, wait: bool = True
|
2565
|
+
):
|
2586
2566
|
"""
|
2587
2567
|
Start a task that continually saves to disk.
|
2588
2568
|
|
moat/kv/types.py
CHANGED
@@ -110,7 +110,7 @@ class MatchEntry(MetaEntry):
|
|
110
110
|
elif isinstance(value.type, str):
|
111
111
|
value.type = P(value.type)
|
112
112
|
elif not isinstance(value.type, (Path, list, tuple)):
|
113
|
-
raise ValueError("Type of
|
113
|
+
raise ValueError(f"Type of {value.type!r} is not a list")
|
114
114
|
try:
|
115
115
|
self.metaroot["type"].follow(value.type, create=False)
|
116
116
|
except KeyError:
|
@@ -277,18 +277,16 @@ class CodecEntry(Entry):
|
|
277
277
|
if self._enc is not None:
|
278
278
|
try:
|
279
279
|
value = self._enc(value, entry=entry, data=self._data, **kv)
|
280
|
-
except TypeError:
|
281
|
-
|
282
|
-
raise
|
280
|
+
except (TypeError,ValueError):
|
281
|
+
pass
|
283
282
|
return value
|
284
283
|
|
285
284
|
def dec_value(self, value, entry=None, **kv):
|
286
285
|
if self._dec is not None:
|
287
286
|
try:
|
288
287
|
value = self._dec(value, entry=entry, data=self._data, **kv)
|
289
|
-
except TypeError:
|
290
|
-
|
291
|
-
raise
|
288
|
+
except (TypeError,ValueError):
|
289
|
+
pass
|
292
290
|
return value
|
293
291
|
|
294
292
|
async def set(self, value):
|
@@ -306,8 +304,9 @@ class CodecEntry(Entry):
|
|
306
304
|
f"failed decoder at {self.path} on {v!r} with {exc!r}",
|
307
305
|
) from exc
|
308
306
|
else:
|
309
|
-
|
310
|
-
|
307
|
+
pass # float, list/tuple, and similar nonsense
|
308
|
+
# if r != w:
|
309
|
+
# raise ValueError(f"Decoding at {self.path}: {v!r} got {r!r}, not {w!r}")
|
311
310
|
|
312
311
|
if value is not None and value.encode is not None:
|
313
312
|
if not value["out"]:
|
@@ -321,8 +320,7 @@ class CodecEntry(Entry):
|
|
321
320
|
f"failed encoder at {self.path} on {v!r} with {exc!r}",
|
322
321
|
) from exc
|
323
322
|
else:
|
324
|
-
|
325
|
-
raise ValueError(f"Encoding at {self.path}: {v!r} got {r!r}, not {w!r}")
|
323
|
+
pass # float, list/tuple, and similar nonsense
|
326
324
|
|
327
325
|
await super().set(value)
|
328
326
|
self._enc = enc
|
@@ -364,7 +362,7 @@ class ConvEntry(MetaEntry):
|
|
364
362
|
if isinstance(value.codec, str):
|
365
363
|
value.codec = P(value.codec)
|
366
364
|
elif not isinstance(value.codec, (Path, list, tuple)):
|
367
|
-
raise ValueError("Codec
|
365
|
+
raise ValueError(f"Codec {value.codec!r} is not a list")
|
368
366
|
try:
|
369
367
|
self.metaroot["codec"].follow(value.codec, create=False)
|
370
368
|
except KeyError:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: moat-kv
|
3
|
-
Version: 0.71.
|
3
|
+
Version: 0.71.7
|
4
4
|
Summary: A distributed no-master key-value store
|
5
5
|
Author-email: Matthias Urlichs <matthias@urlichs.de>
|
6
6
|
Project-URL: homepage, https://m-o-a-t.org
|
@@ -19,18 +19,22 @@ Classifier: Topic :: Home Automation
|
|
19
19
|
Classifier: Topic :: System :: Distributed Computing
|
20
20
|
Requires-Python: >=3.8
|
21
21
|
Description-Content-Type: text/x-rst
|
22
|
+
License-File: LICENSE
|
23
|
+
License-File: LICENSE.APACHE2
|
24
|
+
License-File: LICENSE.MIT
|
22
25
|
License-File: LICENSE.txt
|
23
26
|
Requires-Dist: asyncclick>7.99
|
24
27
|
Requires-Dist: trio>=0.22
|
25
28
|
Requires-Dist: anyio>=4
|
26
29
|
Requires-Dist: range_set>=0.2
|
27
30
|
Requires-Dist: attrs>=22
|
28
|
-
Requires-Dist: asyncactor
|
31
|
+
Requires-Dist: asyncactor~=0.26.3
|
29
32
|
Requires-Dist: asyncscope>=0.10.4
|
30
33
|
Requires-Dist: jsonschema>=2.5
|
31
34
|
Requires-Dist: ruyaml>=0.89
|
32
35
|
Requires-Dist: PyNaCl>=1.3
|
33
36
|
Requires-Dist: moat-lib-diffiehellman~=0.13.4
|
37
|
+
Requires-Dist: moat-link
|
34
38
|
Requires-Dist: psutil
|
35
39
|
Requires-Dist: simpleeval>=0.9.10
|
36
40
|
Requires-Dist: moat-mqtt~=0.42.4
|
@@ -0,0 +1,47 @@
|
|
1
|
+
moat/kv/__init__.py,sha256=an570v034lNp7TNb23T501SM7WNmfeXl2ztGuodG_hg,444
|
2
|
+
moat/kv/_cfg.yaml,sha256=j_rLFRiK1xbj_nzlI1AbzLDhq2pXWrM4M_lr6BH-rSc,2174
|
3
|
+
moat/kv/_main.py,sha256=SgI4ef8AQDOC4N4pLRiyaiSiFIzN-J337WIcuC7DPOY,2234
|
4
|
+
moat/kv/client.py,sha256=qxhhGtfxbcR0MN2dcQzcTga9UBAr9-zRRrMscqeTpVE,34207
|
5
|
+
moat/kv/code.py,sha256=QtXHx09Hh9mxSA8m0z1KAFUEDqR0gpTII5g8MlJ8mbI,6427
|
6
|
+
moat/kv/config.py,sha256=cWJ1m8PRwzzapsin1XSDjRtYJCgNN6g7gA9q48luDV8,1093
|
7
|
+
moat/kv/data.py,sha256=85N2W_pDVRgBn7l9AGdDZHvuHrIPGlbxzgXi_3S0DSI,5924
|
8
|
+
moat/kv/errors.py,sha256=cjX0e184EC10HvQ7UOkWdWmc1A8jPr983IFR8UkaI8U,17089
|
9
|
+
moat/kv/exceptions.py,sha256=4gRsYa6kuBy1qFYiBUYElup_cvOe7QgPQtryHAYphzo,1849
|
10
|
+
moat/kv/model.py,sha256=A7J1Zblk5Wu5zKarD60LwxlLukT-iDtFbTPnQZWz0Kc,33284
|
11
|
+
moat/kv/runner.py,sha256=6vpChgCjiWHAjc2u0bbOOQ8cT5KB-f4uBnQb8MgH9wk,41826
|
12
|
+
moat/kv/server.py,sha256=fwQZNzyJAhqR01d__3hUmEoAD3kgmRfSG0KdESezqpQ,94108
|
13
|
+
moat/kv/types.py,sha256=aCi7_LXzqwruHbEEDJukOjnXNUC2HUaDbgblN8Q05Rc,13998
|
14
|
+
moat/kv/actor/__init__.py,sha256=i560uy9WLE4SmOXWcXKjFKNKZdRR51jOwWg7cSASVRo,2131
|
15
|
+
moat/kv/actor/deletor.py,sha256=F-pb0jHddhmqLp65G7vbZ_QIxXu5ZF0UBzHWKRgN45U,4537
|
16
|
+
moat/kv/auth/__init__.py,sha256=m1x3tyAIxhaF5jSVC-wEJkntBAG2uERvgN0wRTLnp2w,12572
|
17
|
+
moat/kv/auth/_test.py,sha256=k-cHh4m22XuVdXjBN3XAqL5zkH8nKDriEbxH25Tuj10,4404
|
18
|
+
moat/kv/auth/password.py,sha256=wwKrynFPKcJept3IPCWCDLSyTF298NdSBABgCn0htqY,6474
|
19
|
+
moat/kv/auth/root.py,sha256=lW-_hgQp3ZIzAAe4iBl0rdMU-pFuHIC6ObA3rdFXxkk,1303
|
20
|
+
moat/kv/backend/__init__.py,sha256=f5nIOWD2zml2YiaBNXtEOzC7SEGgwDFJMB8YzRISJ0A,1689
|
21
|
+
moat/kv/backend/mqtt.py,sha256=KSerkVN4MHhzjFprZMraTk56Hj0Hx1vev9xfYoKST2A,2009
|
22
|
+
moat/kv/command/__init__.py,sha256=9_8wL9Scv8_Cs8HJyJHGvx1vwXErsuvlsAqNZLcJQR0,8
|
23
|
+
moat/kv/command/acl.py,sha256=wSdlzKBjWIFX3IxCdLcG3ZqjvtX8KPtqe38ibyU2VDo,4665
|
24
|
+
moat/kv/command/auth.py,sha256=vP22ZIBMjRdUxN4_ELKiDgIE5ZqdMxs1ky1WDVUx50M,7149
|
25
|
+
moat/kv/command/code.py,sha256=ycGBoKBB0Gse3Tt9h9WvgiIZVe3Yg-x92RRjfCCCXVQ,8066
|
26
|
+
moat/kv/command/codec.py,sha256=8GqOl-oxWFM2D1Fm9Iheot2AmS_SsOYfqfbbde3qvQY,6028
|
27
|
+
moat/kv/command/data.py,sha256=HcLMMcAnyMBH4iH8X0hZiBgmsnV1yppOlg26zB9R72A,8400
|
28
|
+
moat/kv/command/error.py,sha256=XqHmVJgBGjr6XOozi23wEjiTqPopD1CzkIeR1a3Z_vY,4350
|
29
|
+
moat/kv/command/internal.py,sha256=KnteLPA9SIYk1e2AaN9yWt9r52QvlJCpDEwYcH6hJVI,7404
|
30
|
+
moat/kv/command/job.py,sha256=QIiaK0c08CyB-SMjgoWLqa6N3cXQvds0i_w01Q6Jm5I,13590
|
31
|
+
moat/kv/command/log.py,sha256=ycdtMgiBw2DaCu0yu6tpWKPLlQ33ZZemXsfwZrCzRGg,1350
|
32
|
+
moat/kv/command/server.py,sha256=Hl_6FFq322c5KjJCKxH1nCrxo-h0VEwH4IOMbVeUBN4,3392
|
33
|
+
moat/kv/command/type.py,sha256=bQrbJzVo-KWFC69ywA4EsuE_Gp0IT_YpYrgtU6yaW1g,6214
|
34
|
+
moat/kv/command/dump/__init__.py,sha256=eF7hlFharOShTjoBxU_tyzPB5-HJUZ0XdZTWQfg2JMc,3951
|
35
|
+
moat/kv/mock/__init__.py,sha256=XWqHDWWWbXL61GgIFxxz0ciu2nW2Ba1uKm1J5ZTUuBw,2595
|
36
|
+
moat/kv/mock/mqtt.py,sha256=b9pzbwQBmTX2eSiSgNO7nh2-7l8-0TT8n2GxinQ-1l0,5213
|
37
|
+
moat/kv/mock/tracer.py,sha256=qLEIn9gdlYUypyRYD8O8SbM8ye8XR4xtBl3otP6uNLs,2058
|
38
|
+
moat/kv/obj/__init__.py,sha256=OaQ7PsvvhRhd_H7KUM15nGeApckkCyOv7Xf4llqkzi0,19792
|
39
|
+
moat/kv/obj/command.py,sha256=PzMQOEsXRKjKU3WvFtq1QaPJYBk6oWScKIrA-hAD5vg,7426
|
40
|
+
moat_kv-0.71.7.dist-info/licenses/LICENSE,sha256=ZSyHhIjRRWNh4Iw_hgf9e6WYkqFBA9Fczk_5PIW1zIs,185
|
41
|
+
moat_kv-0.71.7.dist-info/licenses/LICENSE.APACHE2,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
42
|
+
moat_kv-0.71.7.dist-info/licenses/LICENSE.MIT,sha256=Pm2uVV65J4f8gtHUg1Vnf0VMf2Wus40_nnK_mj2vA0s,1046
|
43
|
+
moat_kv-0.71.7.dist-info/licenses/LICENSE.txt,sha256=L5vKJLVOg5t0CEEPpW9-O_0vzbP0PEjEF06tLvnIDuk,541
|
44
|
+
moat_kv-0.71.7.dist-info/METADATA,sha256=lNjt0HBXSSzRYA2HR_Ibl3_Nfk5FmxkueQzChvs8u_k,3376
|
45
|
+
moat_kv-0.71.7.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
46
|
+
moat_kv-0.71.7.dist-info/top_level.txt,sha256=pcs9fl5w5AB5GVi4SvBqIVmFrkRwQkVw_dEvW0Q0cSA,5
|
47
|
+
moat_kv-0.71.7.dist-info/RECORD,,
|