moat-kv 0.71.0__py3-none-any.whl → 0.71.6__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 +29 -29
- 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 +28 -32
- 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 +8 -6
- {moat_kv-0.71.0.dist-info → moat_kv-0.71.6.dist-info}/METADATA +6 -2
- moat_kv-0.71.6.dist-info/RECORD +47 -0
- {moat_kv-0.71.0.dist-info → moat_kv-0.71.6.dist-info}/WHEEL +1 -1
- moat_kv-0.71.6.dist-info/licenses/LICENSE +3 -0
- moat_kv-0.71.6.dist-info/licenses/LICENSE.APACHE2 +202 -0
- moat_kv-0.71.6.dist-info/licenses/LICENSE.MIT +20 -0
- moat_kv-0.71.6.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.6.dist-info}/licenses/LICENSE.txt +0 -0
moat/kv/__init__.py
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
# pylint: disable=W0703,C0103
|
2
2
|
from __future__ import annotations
|
3
|
+
import contextlib
|
3
4
|
|
4
5
|
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
|
5
6
|
|
6
7
|
try:
|
7
|
-
import
|
8
|
-
import pkg_resources # part of setuptools
|
9
|
-
|
10
|
-
with warnings.filterwarnings("ignore"):
|
11
|
-
_version = pkg_resources.require("moat.kv")[0].version
|
12
|
-
del pkg_resources
|
13
|
-
del warnings
|
8
|
+
from importlib.metadata import version
|
14
9
|
|
10
|
+
_version = version("moat.kv")
|
15
11
|
_version_tuple = tuple(int(x) for x in _version.split("."))
|
16
12
|
|
17
13
|
except Exception: # pragma: no cover
|
18
14
|
_version = "0.0.1"
|
19
15
|
_version_tuple = (0, 0, 1)
|
16
|
+
|
17
|
+
with contextlib.suppress(NameError):
|
18
|
+
del version
|
moat/kv/_cfg.yaml
CHANGED
@@ -21,9 +21,9 @@ modules:
|
|
21
21
|
prefix: !P :.moat.kv.code.module
|
22
22
|
runner: # for moat.kv.runner.RunnerRoot
|
23
23
|
# storage for runnable commands
|
24
|
-
prefix: !P :.moat.kv.run
|
24
|
+
prefix: !P :.moat.kv.run
|
25
25
|
# storage for runner states
|
26
|
-
state: !P :.moat.kv.state
|
26
|
+
state: !P :.moat.kv.state
|
27
27
|
|
28
28
|
name: "run"
|
29
29
|
|
@@ -55,6 +55,7 @@ server:
|
|
55
55
|
# default
|
56
56
|
mqtt:
|
57
57
|
uri: "mqtt://localhost:1883"
|
58
|
+
codec: std-msgpack
|
58
59
|
|
59
60
|
# event message path/topic prefix
|
60
61
|
root: !P moat.kv
|
moat/kv/actor/__init__.py
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
This module implements a :class:`asyncactor.Actor` which works on top of
|
3
3
|
a MoaT-KV client.
|
4
4
|
"""
|
5
|
+
|
5
6
|
from __future__ import annotations
|
6
7
|
|
7
8
|
from asyncactor import Actor
|
@@ -71,7 +72,7 @@ class ActorState:
|
|
71
72
|
self.msg = msg
|
72
73
|
|
73
74
|
def __repr__(self):
|
74
|
-
return "
|
75
|
+
return f"<{self.__class__.__name__}:{self.msg!r}>"
|
75
76
|
|
76
77
|
|
77
78
|
class BrokenState(ActorState):
|
moat/kv/actor/deletor.py
CHANGED
@@ -8,9 +8,12 @@ from __future__ import annotations
|
|
8
8
|
import weakref
|
9
9
|
from collections import deque
|
10
10
|
|
11
|
-
import anyio
|
12
11
|
from asyncactor import Actor, PingEvent, TagEvent
|
13
12
|
from asyncactor.backend import get_transport
|
13
|
+
from typing import TYPE_CHECKING
|
14
|
+
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
import anyio
|
14
17
|
|
15
18
|
TAGS = 4
|
16
19
|
|
moat/kv/auth/__init__.py
CHANGED
@@ -61,17 +61,20 @@ The server process is:
|
|
61
61
|
|
62
62
|
from __future__ import annotations
|
63
63
|
|
64
|
-
import io
|
65
64
|
from importlib import import_module
|
66
65
|
|
67
66
|
import jsonschema
|
68
67
|
from moat.util import NotGiven, Path, attrdict, split_arg, yload
|
69
68
|
|
70
|
-
from
|
71
|
-
from
|
72
|
-
from
|
73
|
-
|
74
|
-
from
|
69
|
+
from moat.kv.client import Client, NoData
|
70
|
+
from moat.kv.exceptions import NoAuthModuleError
|
71
|
+
from moat.kv.types import ACLFinder, NullACL
|
72
|
+
import contextlib
|
73
|
+
from typing import TYPE_CHECKING
|
74
|
+
|
75
|
+
if TYPE_CHECKING:
|
76
|
+
from moat.kv.server import ServerClient, StreamCommand
|
77
|
+
from moat.kv.model import Entry
|
75
78
|
|
76
79
|
# Empty schema
|
77
80
|
null_schema = {"type": "object", "additionalProperties": False}
|
@@ -211,7 +214,7 @@ class BaseClientAuth(_AuthLoaded):
|
|
211
214
|
"""
|
212
215
|
Authorizes this record with the server.
|
213
216
|
"""
|
214
|
-
|
217
|
+
with contextlib.suppress(NoData):
|
215
218
|
await client._request(
|
216
219
|
action="auth",
|
217
220
|
typ=self._auth_method,
|
@@ -220,8 +223,6 @@ class BaseClientAuth(_AuthLoaded):
|
|
220
223
|
ident=self.ident,
|
221
224
|
data=self.auth_data(),
|
222
225
|
)
|
223
|
-
except NoData:
|
224
|
-
pass
|
225
226
|
|
226
227
|
def auth_data(self):
|
227
228
|
"""
|
@@ -293,7 +294,7 @@ class BaseClientAuthMaker(_AuthLoaded):
|
|
293
294
|
|
294
295
|
async def send(self, client: Client, _kind="user"):
|
295
296
|
"""Send this user to the server."""
|
296
|
-
|
297
|
+
with contextlib.suppress(NoData):
|
297
298
|
await client._request(
|
298
299
|
"auth_set",
|
299
300
|
iter=False,
|
@@ -303,8 +304,6 @@ class BaseClientAuthMaker(_AuthLoaded):
|
|
303
304
|
chain=self._chain,
|
304
305
|
data=self.send_data(),
|
305
306
|
)
|
306
|
-
except NoData:
|
307
|
-
pass
|
308
307
|
|
309
308
|
def send_data(self):
|
310
309
|
return {}
|
@@ -340,7 +339,7 @@ class BaseServerAuth(_AuthLoaded):
|
|
340
339
|
jsonschema.validate(instance=data.get("data", {}), schema=type(self).schema)
|
341
340
|
|
342
341
|
def aux_conv(self, data: Entry, root: Entry):
|
343
|
-
from
|
342
|
+
from moat.kv.types import ConvNull
|
344
343
|
|
345
344
|
try:
|
346
345
|
data = data["conv"].data["key"]
|
moat/kv/auth/_test.py
CHANGED
@@ -11,7 +11,6 @@ import logging
|
|
11
11
|
|
12
12
|
log = logging.getLogger(__name__)
|
13
13
|
|
14
|
-
from ..client import Client
|
15
14
|
from . import (
|
16
15
|
BaseClientAuth,
|
17
16
|
BaseClientAuthMaker,
|
@@ -20,6 +19,10 @@ from . import (
|
|
20
19
|
null_client_login,
|
21
20
|
null_server_login,
|
22
21
|
)
|
22
|
+
from typing import TYPE_CHECKING
|
23
|
+
|
24
|
+
if TYPE_CHECKING:
|
25
|
+
from moat.kv.client import Client
|
23
26
|
|
24
27
|
|
25
28
|
def load(typ: str, *, make: bool = False, server: bool):
|
moat/kv/auth/password.py
CHANGED
@@ -9,10 +9,8 @@ from __future__ import annotations
|
|
9
9
|
|
10
10
|
import nacl.secret
|
11
11
|
|
12
|
-
from
|
13
|
-
from
|
14
|
-
from ..model import Entry
|
15
|
-
from ..server import StreamCommand
|
12
|
+
from moat.kv.client import Client, NoData
|
13
|
+
from moat.kv.exceptions import AuthFailedError
|
16
14
|
from . import (
|
17
15
|
BaseClientAuth,
|
18
16
|
BaseClientAuthMaker,
|
@@ -21,6 +19,12 @@ from . import (
|
|
21
19
|
null_client_login,
|
22
20
|
null_server_login,
|
23
21
|
)
|
22
|
+
import contextlib
|
23
|
+
from typing import TYPE_CHECKING
|
24
|
+
|
25
|
+
if TYPE_CHECKING:
|
26
|
+
from moat.kv.server import StreamCommand
|
27
|
+
from moat.kv.model import Entry
|
24
28
|
|
25
29
|
|
26
30
|
def load(typ: str, *, make: bool = False, server: bool):
|
@@ -57,6 +61,8 @@ async def pack_pwd(client, password, length):
|
|
57
61
|
async def unpack_pwd(client, password):
|
58
62
|
"""Server side: extract password"""
|
59
63
|
box = nacl.secret.SecretBox(client.dh_key)
|
64
|
+
if isinstance(password, memoryview):
|
65
|
+
password = bytes(password)
|
60
66
|
pwd = box.decrypt(password)
|
61
67
|
return pwd
|
62
68
|
# TODO check with Argon2
|
@@ -164,10 +170,8 @@ class ClientUserMaker(BaseClientAuthMaker):
|
|
164
170
|
# There's no reason to send the password hash back
|
165
171
|
self = cls(_initial=_initial)
|
166
172
|
self._name = m.name
|
167
|
-
|
173
|
+
with contextlib.suppress(AttributeError):
|
168
174
|
self._chain = m.chain
|
169
|
-
except AttributeError:
|
170
|
-
pass
|
171
175
|
return self
|
172
176
|
|
173
177
|
async def send(self, client: Client, _kind="user", **msg): # pylint: disable=unused-argument,arguments-differ
|
moat/kv/backend/mqtt.py
CHANGED
@@ -4,7 +4,6 @@ from contextlib import asynccontextmanager
|
|
4
4
|
|
5
5
|
import anyio
|
6
6
|
from moat.mqtt.client import MQTTClient
|
7
|
-
from moat.mqtt.codecs import NoopCodec
|
8
7
|
from moat.util import NotGiven
|
9
8
|
|
10
9
|
from . import Backend
|
@@ -36,11 +35,11 @@ class MqttBackend(Backend):
|
|
36
35
|
await C.disconnect()
|
37
36
|
|
38
37
|
@asynccontextmanager
|
39
|
-
async def monitor(self, *topic):
|
38
|
+
async def monitor(self, *topic, codec=NotGiven):
|
40
39
|
topic = "/".join(str(x) for x in topic)
|
41
40
|
logger.info("Monitor %s start", topic)
|
42
41
|
try:
|
43
|
-
async with self.client.subscription(topic) as sub:
|
42
|
+
async with self.client.subscription(topic, codec=codec) as sub:
|
44
43
|
|
45
44
|
async def sub_get(sub):
|
46
45
|
async for msg in sub:
|
@@ -55,12 +54,12 @@ class MqttBackend(Backend):
|
|
55
54
|
else:
|
56
55
|
logger.info("Monitor %s end", topic)
|
57
56
|
|
58
|
-
def send(self, *topic, payload): # pylint: disable=invalid-overridden-method
|
57
|
+
def send(self, *topic, payload, **kw): # pylint: disable=invalid-overridden-method
|
59
58
|
"""
|
60
59
|
Send this payload to this topic.
|
61
60
|
"""
|
62
61
|
# client.publish is also async, pass-thru
|
63
|
-
return self.client.publish("/".join(str(x) for x in topic), message=payload)
|
62
|
+
return self.client.publish("/".join(str(x) for x in topic), message=payload, **kw)
|
64
63
|
|
65
64
|
|
66
65
|
@asynccontextmanager
|
moat/kv/client.py
CHANGED
@@ -7,13 +7,13 @@ Main entry point: :func:`open_client`.
|
|
7
7
|
from __future__ import annotations
|
8
8
|
|
9
9
|
import logging
|
10
|
-
import os
|
11
10
|
import socket
|
12
|
-
from contextlib import AsyncExitStack, asynccontextmanager
|
11
|
+
from contextlib import AsyncExitStack, asynccontextmanager, suppress
|
13
12
|
from inspect import iscoroutine
|
14
13
|
|
15
14
|
import anyio
|
16
15
|
from asyncscope import Scope, main_scope, scope
|
16
|
+
from moat.lib.codec import get_codec
|
17
17
|
from moat.util import ( # pylint: disable=no-name-in-module
|
18
18
|
CFG,
|
19
19
|
DelayedRead,
|
@@ -28,11 +28,11 @@ from moat.util import ( # pylint: disable=no-name-in-module
|
|
28
28
|
create_queue,
|
29
29
|
ensure_cfg,
|
30
30
|
gen_ssl,
|
31
|
-
gen_ident,
|
31
|
+
gen_ident,
|
32
|
+
al_lower,
|
32
33
|
num2byte,
|
33
34
|
)
|
34
35
|
|
35
|
-
from .codec import packer, stream_unpacker
|
36
36
|
from .exceptions import (
|
37
37
|
CancelledError,
|
38
38
|
ClientAuthMethodError,
|
@@ -50,13 +50,6 @@ ClosedResourceError = anyio.ClosedResourceError
|
|
50
50
|
__all__ = ["NoData", "ManyData", "open_client", "client_scope", "StreamedRequest"]
|
51
51
|
|
52
52
|
|
53
|
-
class AsyncValueEvent(ValueEvent):
|
54
|
-
def cancel(self):
|
55
|
-
if self.scope is not None:
|
56
|
-
self.scope.cancel()
|
57
|
-
super().set_error(CancelledError())
|
58
|
-
|
59
|
-
|
60
53
|
class NoData(ValueError):
|
61
54
|
"""No reply arrived"""
|
62
55
|
|
@@ -264,10 +257,8 @@ class StreamedRequest:
|
|
264
257
|
except (anyio.BrokenResourceError, anyio.ClosedResourceError, EOFError):
|
265
258
|
pass
|
266
259
|
else:
|
267
|
-
|
260
|
+
with suppress(ServerClosedError):
|
268
261
|
await self.aclose()
|
269
|
-
except ServerClosedError:
|
270
|
-
pass
|
271
262
|
|
272
263
|
async def wait_started(self):
|
273
264
|
await self._started.wait()
|
@@ -281,10 +272,8 @@ class StreamedRequest:
|
|
281
272
|
if self._open:
|
282
273
|
msg = dict(action="stop", task=self.seq)
|
283
274
|
# self._client.logger.debug("SendC %s", msg)
|
284
|
-
|
275
|
+
with suppress(ServerClosedError, anyio.BrokenResourceError):
|
285
276
|
await self._client._request(**msg, _async=True)
|
286
|
-
except (ServerClosedError, anyio.BrokenResourceError):
|
287
|
-
pass
|
288
277
|
# ignore the reply
|
289
278
|
finally:
|
290
279
|
self.qr.close_sender()
|
@@ -301,7 +290,7 @@ class _SingleReply:
|
|
301
290
|
def __init__(self, conn, seq, params):
|
302
291
|
self._conn = conn
|
303
292
|
self.seq = seq
|
304
|
-
self.q =
|
293
|
+
self.q = ValueEvent()
|
305
294
|
self._params = params
|
306
295
|
|
307
296
|
async def set(self, msg):
|
@@ -401,6 +390,7 @@ class Client:
|
|
401
390
|
ensure_cfg("moat.kv")
|
402
391
|
self._cfg = combine_dict(cfg, CFG["kv"], cls=attrdict)
|
403
392
|
self.config = ClientConfig(self)
|
393
|
+
self.codec = get_codec("std-msgpack")
|
404
394
|
|
405
395
|
self._seq = 0
|
406
396
|
self._handlers = {}
|
@@ -484,26 +474,24 @@ class Client:
|
|
484
474
|
raise ServerClosedError("Disconnected")
|
485
475
|
|
486
476
|
try:
|
487
|
-
p =
|
477
|
+
p = self.codec.encode(params)
|
488
478
|
except TypeError as e:
|
489
479
|
raise ValueError(f"Unable to pack: {params!r}") from e
|
490
480
|
await sock.send(p)
|
491
481
|
|
492
482
|
async def _reader(self, *, evt=None):
|
493
483
|
"""Main loop for reading"""
|
494
|
-
unpacker = stream_unpacker()
|
495
|
-
|
496
484
|
with anyio.CancelScope():
|
497
485
|
# XXX store the scope so that the redaer may get cancelled?
|
498
486
|
if evt is not None:
|
499
487
|
await evt.set()
|
500
488
|
try:
|
501
489
|
while True:
|
502
|
-
for msg in
|
490
|
+
for msg in self.codec:
|
503
491
|
# self.logger.debug("Recv %s", msg)
|
504
492
|
try:
|
505
493
|
await self._handle_msg(msg)
|
506
|
-
except ClosedResourceError as exc:
|
494
|
+
except (ClosedResourceError,EOFError) as exc:
|
507
495
|
logger.warning("Reader closed in handler", exc_info=exc)
|
508
496
|
return
|
509
497
|
|
@@ -518,7 +506,7 @@ class Client:
|
|
518
506
|
return # closed by us
|
519
507
|
if len(buf) == 0: # Connection was closed.
|
520
508
|
raise ServerClosedError("Connection closed by peer")
|
521
|
-
|
509
|
+
self.codec.feed(buf)
|
522
510
|
|
523
511
|
except BaseException as exc:
|
524
512
|
logger.warning("Reader died: %r", exc, exc_info=exc)
|
@@ -554,7 +542,7 @@ class Client:
|
|
554
542
|
Any other keywords are forwarded to the server.
|
555
543
|
"""
|
556
544
|
if self._handlers is None:
|
557
|
-
raise ClosedResourceError
|
545
|
+
raise ClosedResourceError
|
558
546
|
if seq is None:
|
559
547
|
act = "action"
|
560
548
|
self._seq += 1
|
@@ -612,7 +600,7 @@ class Client:
|
|
612
600
|
|
613
601
|
async with client._stream("update", path=P("private.storage"),
|
614
602
|
stream=True) as req:
|
615
|
-
with MsgReader("/tmp/msgs.pack") as f:
|
603
|
+
with MsgReader("/tmp/msgs.pack",codec="std-cbor") as f:
|
616
604
|
for msg in f:
|
617
605
|
await req.send(msg)
|
618
606
|
# … or …
|
@@ -647,17 +635,12 @@ class Client:
|
|
647
635
|
yield res
|
648
636
|
except BaseException as exc:
|
649
637
|
if stream:
|
650
|
-
|
638
|
+
with suppress(anyio.ClosedResourceError):
|
651
639
|
await res.send(error=repr(exc))
|
652
|
-
except anyio.ClosedResourceError:
|
653
|
-
pass
|
654
640
|
raise
|
655
641
|
finally:
|
656
|
-
with anyio.fail_after(2, shield=True):
|
657
|
-
|
658
|
-
await res.aclose()
|
659
|
-
except anyio.ClosedResourceError:
|
660
|
-
pass
|
642
|
+
with anyio.fail_after(2, shield=True), suppress(anyio.ClosedResourceError):
|
643
|
+
await res.aclose()
|
661
644
|
|
662
645
|
async def _run_auth(self, auth=None):
|
663
646
|
"""
|
@@ -684,7 +667,7 @@ class Client:
|
|
684
667
|
This async context manager handles the actual TCP connection to
|
685
668
|
the MoaT-KV server.
|
686
669
|
"""
|
687
|
-
hello =
|
670
|
+
hello = ValueEvent()
|
688
671
|
self._handlers[0] = hello
|
689
672
|
|
690
673
|
cfg = self._cfg["conn"]
|
@@ -737,10 +720,8 @@ class Client:
|
|
737
720
|
yield self
|
738
721
|
finally:
|
739
722
|
# Clean up our hacked config
|
740
|
-
|
723
|
+
with suppress(AttributeError):
|
741
724
|
del self._config
|
742
|
-
except AttributeError:
|
743
|
-
pass
|
744
725
|
self.config = ClientConfig(self)
|
745
726
|
finally:
|
746
727
|
self._socket = None
|
@@ -1007,7 +988,7 @@ class Client:
|
|
1007
988
|
"""
|
1008
989
|
return self._stream(action="msg_monitor", topic=topic, raw=raw)
|
1009
990
|
|
1010
|
-
def msg_send(self, topic: tuple[str], data=None, raw: bytes = None):
|
991
|
+
def msg_send(self, topic: tuple[str], data=None, raw: bytes | None = None):
|
1011
992
|
"""
|
1012
993
|
Tunnel a user-tagged message. This sends the message
|
1013
994
|
to all active callers of :meth:`msg_monitor` which use the same topic.
|
moat/kv/code.py
CHANGED
@@ -5,6 +5,7 @@ so that it can be called easily.
|
|
5
5
|
"Code" consists of either Python modules or single procedures.
|
6
6
|
|
7
7
|
"""
|
8
|
+
|
8
9
|
from __future__ import annotations
|
9
10
|
|
10
11
|
import logging
|
@@ -15,6 +16,7 @@ import anyio
|
|
15
16
|
from moat.util import NotGiven, P, make_module, make_proc
|
16
17
|
|
17
18
|
from .obj import ClientEntry, ClientRoot
|
19
|
+
import contextlib
|
18
20
|
|
19
21
|
logger = logging.getLogger(__name__)
|
20
22
|
|
@@ -81,10 +83,8 @@ class ModuleEntry(ClientEntry):
|
|
81
83
|
await super().set_value(value)
|
82
84
|
if value is NotGiven:
|
83
85
|
self._module = None
|
84
|
-
|
86
|
+
with contextlib.suppress(KeyError):
|
85
87
|
del sys.modules[self.name]
|
86
|
-
except KeyError:
|
87
|
-
pass
|
88
88
|
return
|
89
89
|
|
90
90
|
try:
|
moat/kv/command/data.py
CHANGED
@@ -6,6 +6,7 @@ import time
|
|
6
6
|
|
7
7
|
import asyncclick as click
|
8
8
|
from moat.util import MsgReader, NotGiven, P, PathLongener, attr_args, yprint
|
9
|
+
from moat.util.times import ts2iso
|
9
10
|
|
10
11
|
from moat.kv.client import StreamedRequest
|
11
12
|
from moat.kv.data import add_dates, data_get, node_attr
|
@@ -244,8 +245,8 @@ async def monitor(obj, state, only, path_only, add_date, ignore):
|
|
244
245
|
# value has been deleted
|
245
246
|
continue
|
246
247
|
if flushing:
|
247
|
-
r["time"] = time.time()
|
248
|
-
r["_time"] =
|
248
|
+
r["time"] = ts = time.time()
|
249
|
+
r["_time"] = ts2iso(ts)
|
249
250
|
yprint(r, stream=obj.stdout)
|
250
251
|
print("---", file=obj.stdout)
|
251
252
|
if flushing:
|
@@ -258,7 +259,7 @@ async def monitor(obj, state, only, path_only, add_date, ignore):
|
|
258
259
|
@click.pass_obj
|
259
260
|
async def update(obj, infile):
|
260
261
|
"""Send a list of updates to a MoaT-KV subtree"""
|
261
|
-
async with MsgReader(path=infile) as reader:
|
262
|
+
async with MsgReader(path=infile, codec="std-msgpack") as reader:
|
262
263
|
async for msg in reader:
|
263
264
|
if not hasattr(msg, "path"):
|
264
265
|
continue
|
moat/kv/command/dump/__init__.py
CHANGED
@@ -6,19 +6,17 @@ import sys
|
|
6
6
|
from collections.abc import Mapping
|
7
7
|
|
8
8
|
import asyncclick as click
|
9
|
-
from moat.mqtt.codecs import MsgPackCodec
|
10
9
|
from moat.util import (
|
11
|
-
MsgReader,
|
12
10
|
MsgWriter,
|
13
11
|
P,
|
14
12
|
Path,
|
15
|
-
PathLongener,
|
16
13
|
load_subgroup,
|
17
14
|
yload,
|
18
15
|
yprint,
|
19
16
|
)
|
20
17
|
|
21
|
-
from moat.
|
18
|
+
from moat.util.mqtt import unpacker
|
19
|
+
from moat.util.msgpack import StdMsgpack
|
22
20
|
|
23
21
|
|
24
22
|
@load_subgroup(short_help="Local data mangling", sub_pre="dump")
|
@@ -42,7 +40,7 @@ async def init(node, file):
|
|
42
40
|
Using this command, followed by "moat kv server -l <outfile> <node>", is
|
43
41
|
equivalent to running "moat kv server -i 'Initial data' <node>.
|
44
42
|
"""
|
45
|
-
async with MsgWriter(path=file) as f:
|
43
|
+
async with MsgWriter(path=file, codec="std-msgpack") as f:
|
46
44
|
await f(
|
47
45
|
dict(
|
48
46
|
chain=dict(node=node, tick=1, prev=None),
|
@@ -93,29 +91,31 @@ async def msg_(obj, path):
|
|
93
91
|
be = obj.cfg.server.backend
|
94
92
|
kw = obj.cfg.server[be]
|
95
93
|
|
96
|
-
async with
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
v["
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
94
|
+
async with (
|
95
|
+
get_backend(be)(**kw) as conn,
|
96
|
+
conn.monitor(*path) as stream,
|
97
|
+
):
|
98
|
+
async for msg in stream:
|
99
|
+
v = vars(msg)
|
100
|
+
if isinstance(v.get("payload"), (bytearray, bytes)):
|
101
|
+
t = msg.topic
|
102
|
+
v = unpacker(v["payload"])
|
103
|
+
v = _unpacker(v)
|
104
|
+
if v is None:
|
105
|
+
continue
|
106
|
+
if not isinstance(v, Mapping):
|
107
|
+
v = {"_data": v}
|
108
|
+
v["_topic"] = Path.build(t)
|
109
|
+
else:
|
110
|
+
v["_type"] = type(msg).__name__
|
111
|
+
|
112
|
+
v["_timestamp"] = datetime.datetime.now().isoformat(
|
113
|
+
sep=" ",
|
114
|
+
timespec="milliseconds",
|
115
|
+
)
|
116
|
+
|
117
|
+
yprint(v, stream=obj.stdout)
|
118
|
+
print("---", file=obj.stdout)
|
119
119
|
|
120
120
|
|
121
121
|
@cli.command("post")
|
@@ -137,7 +137,7 @@ async def post_(obj, path):
|
|
137
137
|
be = obj.cfg.server.backend
|
138
138
|
kw = obj.cfg.server[be]
|
139
139
|
|
140
|
-
async with get_backend(be)(codec=
|
140
|
+
async with get_backend(be)(codec=StdMsgpack(), **kw) as conn:
|
141
141
|
for d in yload(sys.stdin, multi=True):
|
142
142
|
topic = d.pop("_topic", path)
|
143
143
|
await conn.send(*topic, payload=d)
|
moat/kv/command/internal.py
CHANGED
@@ -6,6 +6,7 @@ from collections.abc import Mapping
|
|
6
6
|
import asyncclick as click
|
7
7
|
from moat.util import P, PathLongener, yprint
|
8
8
|
from range_set import RangeSet
|
9
|
+
import contextlib
|
9
10
|
|
10
11
|
|
11
12
|
@click.group(short_help="Control internal state.") # pylint: disable=undefined-variable
|
@@ -173,10 +174,8 @@ async def dump(obj, path):
|
|
173
174
|
yy = y
|
174
175
|
for p in path:
|
175
176
|
yy = yy.setdefault(p, {})
|
176
|
-
|
177
|
+
with contextlib.suppress(KeyError):
|
177
178
|
yy["_"] = r["value"]
|
178
|
-
except KeyError:
|
179
|
-
pass
|
180
179
|
yprint(y, stream=obj.stdout)
|
181
180
|
|
182
181
|
|
moat/kv/command/job.py
CHANGED
moat/kv/command/type.py
CHANGED
@@ -5,6 +5,7 @@ import json
|
|
5
5
|
|
6
6
|
import asyncclick as click
|
7
7
|
from moat.util import NotGiven, P, Path, PathLongener, yload, yprint
|
8
|
+
import contextlib
|
8
9
|
|
9
10
|
|
10
11
|
@click.group() # pylint: disable=undefined-variable
|
@@ -134,10 +135,8 @@ async def match(obj, path, type_, delete, raw): # pylint: disable=redefined-bui
|
|
134
135
|
yy = y
|
135
136
|
for p in path:
|
136
137
|
yy = yy.setdefault(p, {})
|
137
|
-
|
138
|
+
with contextlib.suppress(KeyError):
|
138
139
|
yy["_"] = r["value"]
|
139
|
-
except KeyError:
|
140
|
-
pass
|
141
140
|
yprint(y, stream=obj.stdout)
|
142
141
|
return
|
143
142
|
|
@@ -194,8 +193,6 @@ async def list(obj, path): # pylint: disable=redefined-builtin
|
|
194
193
|
yy = y
|
195
194
|
for p in path:
|
196
195
|
yy = yy.setdefault(p, {})
|
197
|
-
|
196
|
+
with contextlib.suppress(KeyError):
|
198
197
|
yy["_"] = r["value"]
|
199
|
-
except KeyError:
|
200
|
-
pass
|
201
198
|
yprint(y, stream=obj.stdout)
|