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.
Files changed (178) hide show
  1. moat/kv/__init__.py +6 -7
  2. moat/kv/_cfg.yaml +3 -2
  3. moat/kv/actor/__init__.py +2 -1
  4. moat/kv/actor/deletor.py +4 -1
  5. moat/kv/auth/__init__.py +12 -13
  6. moat/kv/auth/_test.py +4 -1
  7. moat/kv/auth/password.py +11 -7
  8. moat/kv/backend/mqtt.py +4 -5
  9. moat/kv/client.py +20 -39
  10. moat/kv/code.py +3 -3
  11. moat/kv/command/data.py +4 -3
  12. moat/kv/command/dump/__init__.py +36 -34
  13. moat/kv/command/internal.py +2 -3
  14. moat/kv/command/job.py +1 -2
  15. moat/kv/command/type.py +3 -6
  16. moat/kv/data.py +9 -8
  17. moat/kv/errors.py +16 -8
  18. moat/kv/mock/__init__.py +2 -12
  19. moat/kv/model.py +29 -33
  20. moat/kv/obj/__init__.py +3 -3
  21. moat/kv/obj/command.py +3 -3
  22. moat/kv/runner.py +4 -5
  23. moat/kv/server.py +106 -126
  24. moat/kv/types.py +10 -12
  25. {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/METADATA +6 -2
  26. moat_kv-0.71.7.dist-info/RECORD +47 -0
  27. {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/WHEEL +1 -1
  28. moat_kv-0.71.7.dist-info/licenses/LICENSE +3 -0
  29. moat_kv-0.71.7.dist-info/licenses/LICENSE.APACHE2 +202 -0
  30. moat_kv-0.71.7.dist-info/licenses/LICENSE.MIT +20 -0
  31. moat_kv-0.71.7.dist-info/top_level.txt +1 -0
  32. build/lib/docs/source/conf.py +0 -201
  33. build/lib/examples/pathify.py +0 -45
  34. build/lib/moat/kv/__init__.py +0 -19
  35. build/lib/moat/kv/_cfg.yaml +0 -93
  36. build/lib/moat/kv/_main.py +0 -91
  37. build/lib/moat/kv/actor/__init__.py +0 -98
  38. build/lib/moat/kv/actor/deletor.py +0 -139
  39. build/lib/moat/kv/auth/__init__.py +0 -444
  40. build/lib/moat/kv/auth/_test.py +0 -166
  41. build/lib/moat/kv/auth/password.py +0 -234
  42. build/lib/moat/kv/auth/root.py +0 -58
  43. build/lib/moat/kv/backend/__init__.py +0 -67
  44. build/lib/moat/kv/backend/mqtt.py +0 -71
  45. build/lib/moat/kv/client.py +0 -1025
  46. build/lib/moat/kv/code.py +0 -236
  47. build/lib/moat/kv/codec.py +0 -11
  48. build/lib/moat/kv/command/__init__.py +0 -1
  49. build/lib/moat/kv/command/acl.py +0 -180
  50. build/lib/moat/kv/command/auth.py +0 -261
  51. build/lib/moat/kv/command/code.py +0 -293
  52. build/lib/moat/kv/command/codec.py +0 -186
  53. build/lib/moat/kv/command/data.py +0 -265
  54. build/lib/moat/kv/command/dump/__init__.py +0 -143
  55. build/lib/moat/kv/command/error.py +0 -149
  56. build/lib/moat/kv/command/internal.py +0 -248
  57. build/lib/moat/kv/command/job.py +0 -433
  58. build/lib/moat/kv/command/log.py +0 -53
  59. build/lib/moat/kv/command/server.py +0 -114
  60. build/lib/moat/kv/command/type.py +0 -201
  61. build/lib/moat/kv/config.py +0 -46
  62. build/lib/moat/kv/data.py +0 -216
  63. build/lib/moat/kv/errors.py +0 -561
  64. build/lib/moat/kv/exceptions.py +0 -126
  65. build/lib/moat/kv/mock/__init__.py +0 -101
  66. build/lib/moat/kv/mock/mqtt.py +0 -159
  67. build/lib/moat/kv/mock/tracer.py +0 -63
  68. build/lib/moat/kv/model.py +0 -1069
  69. build/lib/moat/kv/obj/__init__.py +0 -646
  70. build/lib/moat/kv/obj/command.py +0 -241
  71. build/lib/moat/kv/runner.py +0 -1347
  72. build/lib/moat/kv/server.py +0 -2809
  73. build/lib/moat/kv/types.py +0 -513
  74. ci/rtd-requirements.txt +0 -4
  75. ci/test-requirements.txt +0 -7
  76. ci/travis.sh +0 -96
  77. debian/.gitignore +0 -7
  78. debian/changelog +0 -1435
  79. debian/control +0 -43
  80. debian/moat-kv/usr/lib/python3/dist-packages/docs/source/conf.py +0 -201
  81. debian/moat-kv/usr/lib/python3/dist-packages/examples/pathify.py +0 -45
  82. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/__init__.py +0 -19
  83. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml +0 -93
  84. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_main.py +0 -91
  85. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/__init__.py +0 -98
  86. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/actor/deletor.py +0 -139
  87. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/__init__.py +0 -444
  88. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/_test.py +0 -166
  89. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/password.py +0 -234
  90. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/auth/root.py +0 -58
  91. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/__init__.py +0 -67
  92. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py +0 -71
  93. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/client.py +0 -1025
  94. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/code.py +0 -236
  95. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/codec.py +0 -11
  96. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/__init__.py +0 -1
  97. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/acl.py +0 -180
  98. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/auth.py +0 -261
  99. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/code.py +0 -293
  100. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/codec.py +0 -186
  101. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/data.py +0 -265
  102. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/dump/__init__.py +0 -143
  103. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/error.py +0 -149
  104. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/internal.py +0 -248
  105. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/job.py +0 -433
  106. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/log.py +0 -53
  107. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/server.py +0 -114
  108. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/command/type.py +0 -201
  109. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/config.py +0 -46
  110. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/data.py +0 -216
  111. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/errors.py +0 -561
  112. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/exceptions.py +0 -126
  113. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/__init__.py +0 -101
  114. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/mqtt.py +0 -159
  115. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/tracer.py +0 -63
  116. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/model.py +0 -1069
  117. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/__init__.py +0 -646
  118. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/obj/command.py +0 -241
  119. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/runner.py +0 -1347
  120. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/server.py +0 -2809
  121. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/types.py +0 -513
  122. debian/moat-kv.postinst +0 -3
  123. debian/rules +0 -20
  124. debian/source/format +0 -1
  125. debian/watch +0 -4
  126. docs/Makefile +0 -20
  127. docs/make.bat +0 -36
  128. docs/source/TODO.rst +0 -61
  129. docs/source/_static/.gitkeep +0 -0
  130. docs/source/acls.rst +0 -80
  131. docs/source/auth.rst +0 -84
  132. docs/source/client_protocol.rst +0 -456
  133. docs/source/code.rst +0 -341
  134. docs/source/command_line.rst +0 -1187
  135. docs/source/common_protocol.rst +0 -47
  136. docs/source/conf.py +0 -201
  137. docs/source/debugging.rst +0 -70
  138. docs/source/extend.rst +0 -37
  139. docs/source/history.rst +0 -36
  140. docs/source/index.rst +0 -75
  141. docs/source/model.rst +0 -54
  142. docs/source/overview.rst +0 -83
  143. docs/source/related.rst +0 -89
  144. docs/source/server_protocol.rst +0 -450
  145. docs/source/startup.rst +0 -31
  146. docs/source/translator.rst +0 -244
  147. docs/source/tutorial.rst +0 -711
  148. docs/source/v3.rst +0 -168
  149. examples/code/transform.scale.yml +0 -21
  150. examples/code/transform.switch.yml +0 -82
  151. examples/code/transform.timeslot.yml +0 -63
  152. examples/pathify.py +0 -45
  153. moat/kv/codec.py +0 -11
  154. moat_kv-0.71.0.dist-info/RECORD +0 -188
  155. moat_kv-0.71.0.dist-info/top_level.txt +0 -9
  156. scripts/current +0 -15
  157. scripts/env +0 -8
  158. scripts/init +0 -39
  159. scripts/recover +0 -17
  160. scripts/rotate +0 -33
  161. scripts/run +0 -29
  162. scripts/run-all +0 -10
  163. scripts/run-any +0 -10
  164. scripts/run-single +0 -15
  165. scripts/success +0 -4
  166. systemd/moat-kv-recover.service +0 -21
  167. systemd/moat-kv-rotate.service +0 -20
  168. systemd/moat-kv-rotate.timer +0 -10
  169. systemd/moat-kv-run-all.service +0 -26
  170. systemd/moat-kv-run-all@.service +0 -25
  171. systemd/moat-kv-run-any.service +0 -26
  172. systemd/moat-kv-run-any@.service +0 -25
  173. systemd/moat-kv-run-single.service +0 -26
  174. systemd/moat-kv-run-single@.service +0 -25
  175. systemd/moat-kv.service +0 -27
  176. systemd/postinst +0 -7
  177. systemd/sysusers +0 -3
  178. {moat_kv-0.71.0.dist-info → moat_kv-0.71.7.dist-info}/licenses/LICENSE.txt +0 -0
@@ -1,166 +0,0 @@
1
- #
2
- """
3
- Test auth method.
4
-
5
- Does not limit anything, allows everything.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import logging
11
-
12
- log = logging.getLogger(__name__)
13
-
14
- from ..client import Client
15
- from . import (
16
- BaseClientAuth,
17
- BaseClientAuthMaker,
18
- BaseServerAuthMaker,
19
- RootServerUser,
20
- null_client_login,
21
- null_server_login,
22
- )
23
-
24
-
25
- def load(typ: str, *, make: bool = False, server: bool):
26
- if typ == "client":
27
- if server:
28
- return null_server_login
29
- else:
30
- return null_client_login
31
- if typ != "user":
32
- raise NotImplementedError("This module only handles users")
33
- if server:
34
- if make:
35
- return ServerUserMaker
36
- else:
37
- return ServerUser
38
- else:
39
- if make:
40
- return ClientUserMaker
41
- else:
42
- return ClientUser
43
-
44
-
45
- class ServerUserMaker(BaseServerAuthMaker):
46
- name = None
47
-
48
- @property
49
- def ident(self):
50
- return self.name
51
-
52
- # Overly-complicated methods of exchanging the user name
53
-
54
- @classmethod
55
- async def recv(cls, cmd, data):
56
- await cmd.send(step="GiveName")
57
- msg = await cmd.recv()
58
- assert msg.step == "HasName"
59
- self = cls()
60
- self.name = msg.name
61
- return self
62
-
63
- async def send(self, cmd):
64
- await cmd.send(step="SendWant")
65
- msg = await cmd.recv()
66
- assert msg.step == "WantName"
67
- await cmd.send(step="SendName", name=self.name, chain=self._chain.serialize(nchain=3))
68
- msg = await cmd.recv()
69
-
70
- # Annoying methods to read+save the user name from/to KV
71
-
72
- @classmethod
73
- def load(cls, data):
74
- self = super().load(data)
75
- self.name = data.name
76
- return self
77
-
78
-
79
- class ServerUser(RootServerUser):
80
- pass
81
-
82
-
83
- class ClientUserMaker(BaseClientAuthMaker):
84
- gen_schema = dict(
85
- type="object",
86
- additionalProperties=False,
87
- properties=dict(name=dict(type="string", minLength=1, pattern="^[a-zA-Z][a-zA-Z0-9_]*$")),
88
- required=["name"],
89
- )
90
- mod_schema = dict(
91
- type="object",
92
- additionalProperties=False,
93
- properties=dict(name=dict(type="string", minLength=1, pattern="^[a-zA-Z][a-zA-Z0-9_]*$")),
94
- # required=[],
95
- )
96
- name = None
97
-
98
- @property
99
- def ident(self):
100
- return self.name
101
-
102
- # Overly-complicated methods of exchanging the user name
103
-
104
- @classmethod
105
- async def recv(cls, client: Client, ident: str, _kind: str = "user", _initial=True):
106
- """Read a record representing a user from the server."""
107
- async with client._stream(
108
- action="auth_get",
109
- typ=cls._auth_method,
110
- kind=_kind,
111
- ident=ident,
112
- stream=True,
113
- nchain=0 if _initial else 2,
114
- ) as s:
115
- m = await s.recv()
116
- assert m.step == "SendWant", m
117
- await s.send(step="WantName")
118
- m = await s.recv()
119
- assert m.step == "SendName", m
120
- assert m.name == ident
121
-
122
- self = cls(name=m.name, _initial=_initial)
123
- self._chain = m.chain
124
- return self
125
-
126
- async def send(self, client: Client, _kind="user"):
127
- """Send a record representing this user to the server."""
128
- async with client._stream(
129
- action="auth_set",
130
- typ=type(self)._auth_method,
131
- kind=_kind,
132
- ident=self.ident,
133
- stream=True,
134
- ) as s:
135
- # we could initially send the ident but don't here, for testing
136
- m = await s.recv()
137
- assert m.step == "GiveName", m
138
- await s.send(step="HasName", name=self.name, chain=self._chain)
139
- m = await s.recv()
140
- assert m.chain.prev is None
141
-
142
- def export(self):
143
- """Return the data required to re-create the user via :meth:`build`."""
144
- return {"name": self.name}
145
-
146
-
147
- class ClientUser(BaseClientAuth):
148
- name = None
149
-
150
- schema = dict(
151
- type="object",
152
- additionalProperties=False,
153
- properties=dict(name=dict(type="string", minLength=1, pattern="^[a-zA-Z][a-zA-Z0-9_]*$")),
154
- required=["name"],
155
- )
156
- _name = None
157
-
158
- @property
159
- def ident(self):
160
- return self.name
161
-
162
- @classmethod
163
- def build(cls, user):
164
- self = super().build(user)
165
- self.name = user["name"]
166
- return self
@@ -1,234 +0,0 @@
1
- #
2
- """
3
- Password-based auth method.
4
-
5
- Does not limit anything, allows everything.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- import nacl.secret
11
-
12
- from ..client import Client, NoData
13
- from ..exceptions import AuthFailedError
14
- from ..model import Entry
15
- from ..server import StreamCommand
16
- from . import (
17
- BaseClientAuth,
18
- BaseClientAuthMaker,
19
- BaseServerAuthMaker,
20
- RootServerUser,
21
- null_client_login,
22
- null_server_login,
23
- )
24
-
25
-
26
- def load(typ: str, *, make: bool = False, server: bool):
27
- if typ == "client":
28
- if server:
29
- return null_server_login
30
- else:
31
- return null_client_login
32
- if typ != "user":
33
- raise NotImplementedError("This module only handles users")
34
- if server:
35
- if make:
36
- return ServerUserMaker
37
- else:
38
- return ServerUser
39
- else:
40
- if make:
41
- return ClientUserMaker
42
- else:
43
- return ClientUser
44
-
45
-
46
- async def pack_pwd(client, password, length):
47
- """Client side: encrypt password"""
48
- secret = await client.dh_secret(length=length)
49
- from hashlib import sha256
50
-
51
- pwd = sha256(password).digest()
52
- box = nacl.secret.SecretBox(secret)
53
- pwd = box.encrypt(pwd)
54
- return pwd
55
-
56
-
57
- async def unpack_pwd(client, password):
58
- """Server side: extract password"""
59
- box = nacl.secret.SecretBox(client.dh_key)
60
- pwd = box.decrypt(password)
61
- return pwd
62
- # TODO check with Argon2
63
-
64
-
65
- class ServerUserMaker(BaseServerAuthMaker):
66
- _name = None
67
- _aux = None
68
- password: str = None
69
-
70
- @property
71
- def ident(self):
72
- return self._name
73
-
74
- @classmethod
75
- async def recv(cls, cmd, data):
76
- self = cls()
77
- self._name = data["ident"]
78
- self._aux = data.get("aux")
79
- pwd = data.get("password")
80
- pwd = await unpack_pwd(cmd.client, pwd)
81
-
82
- # TODO use Argon2 to re-hash this
83
- self.password = pwd
84
- return self
85
-
86
- async def send(self, cmd):
87
- return # nothing to do, we don't share the hash
88
-
89
- @classmethod
90
- def load(cls, data):
91
- self = super().load(data)
92
- self._name = data.path[-1]
93
- return self
94
-
95
- def save(self):
96
- res = super().save()
97
- res["password"] = self.password
98
- return res
99
-
100
-
101
- class ServerUser(RootServerUser):
102
- @classmethod
103
- def load(cls, data: Entry):
104
- """Create a ServerUser object from existing stored data"""
105
- self = super().load(data)
106
- self._name = data.name
107
- return self
108
-
109
- async def auth(self, cmd: StreamCommand, data):
110
- """Verify that @data authenticates this user."""
111
- await super().auth(cmd, data)
112
-
113
- pwd = await unpack_pwd(cmd.client, data.password)
114
- if pwd != self.password: # pylint: disable=no-member
115
- # pylint: disable=no-member
116
- raise AuthFailedError("Password hashes do not match", self._name)
117
-
118
-
119
- class ClientUserMaker(BaseClientAuthMaker):
120
- gen_schema = dict(
121
- type="object",
122
- additionalProperties=True,
123
- properties=dict(
124
- name=dict(type="string", minLength=1, pattern="^[a-zA-Z][a-zA-Z0-9_]*$"),
125
- password=dict(type="string", minLength=5),
126
- ),
127
- required=["name", "password"],
128
- )
129
- mod_schema = dict(
130
- type="object",
131
- additionalProperties=True,
132
- properties=dict(password=dict(type="string", minLength=5)),
133
- # required=[],
134
- )
135
- _name = None
136
- _pass = None
137
- _length = 1024
138
-
139
- @property
140
- def ident(self):
141
- return self._name
142
-
143
- # Overly-complicated methods of exchanging the user name
144
-
145
- @classmethod
146
- def build(cls, user, _initial=True):
147
- self = super().build(user, _initial=_initial)
148
- self._name = user["name"]
149
- if "password" in user:
150
- self._pass = user["password"].encode("utf-8")
151
- return self
152
-
153
- @classmethod
154
- async def recv(cls, client: Client, ident: str, _kind: str = "user", _initial=True):
155
- """Read a record representing a user from the server."""
156
- m = await client._request(
157
- action="auth_get",
158
- typ=cls._auth_method,
159
- kind=_kind,
160
- ident=ident,
161
- nchain=0 if _initial else 2,
162
- )
163
- # just to verify that the user exists
164
- # There's no reason to send the password hash back
165
- self = cls(_initial=_initial)
166
- self._name = m.name
167
- try:
168
- self._chain = m.chain
169
- except AttributeError:
170
- pass
171
- return self
172
-
173
- async def send(self, client: Client, _kind="user", **msg): # pylint: disable=unused-argument,arguments-differ
174
- """Send a record representing this user to the server."""
175
- if self._pass is not None:
176
- msg["password"] = await pack_pwd(client, self._pass, self._length)
177
-
178
- await client._request(
179
- action="auth_set",
180
- ident=self._name,
181
- typ=type(self)._auth_method,
182
- kind=_kind,
183
- chain=self._chain,
184
- **msg,
185
- )
186
-
187
- def export(self):
188
- """Return the data required to re-create the user via :meth:`build`."""
189
- res = super().export()
190
- res["name"] = self._name
191
- return res
192
-
193
-
194
- class ClientUser(BaseClientAuth):
195
- schema = dict(
196
- type="object",
197
- additionalProperties=True,
198
- properties=dict(
199
- name=dict(type="string", minLength=1, pattern="^[a-zA-Z][a-zA-Z0-9_]*$"),
200
- password=dict(type="string", minLength=5),
201
- ),
202
- required=["name", "password"],
203
- )
204
- _name = None
205
- _pass = None
206
- _length = 1024
207
-
208
- @property
209
- def ident(self):
210
- return self._name
211
-
212
- @classmethod
213
- def build(cls, user):
214
- self = super().build(user)
215
- self._name = user["name"]
216
- self._pass = user["password"].encode("utf-8")
217
- return self
218
-
219
- async def auth(self, client: Client, chroot=()):
220
- """
221
- Authorizes this user with the server.
222
- """
223
- try:
224
- pw = await pack_pwd(client, self._pass, self._length)
225
- await client._request(
226
- action="auth",
227
- typ=self._auth_method,
228
- iter=False,
229
- ident=self.ident,
230
- password=pw,
231
- **self.auth_data(),
232
- )
233
- except NoData:
234
- pass
@@ -1,58 +0,0 @@
1
- #
2
- """
3
- Null auth method.
4
-
5
- Does not limit anything, allows everything.
6
- """
7
-
8
- from __future__ import annotations
9
-
10
- from . import (
11
- BaseClientAuth,
12
- BaseClientAuthMaker,
13
- BaseServerAuthMaker,
14
- RootServerUser,
15
- null_client_login,
16
- null_server_login,
17
- )
18
-
19
-
20
- def load(typ: str, *, make: bool = False, server: bool):
21
- if typ == "client":
22
- if server:
23
- return null_server_login
24
- else:
25
- return null_client_login
26
- if typ != "user":
27
- raise NotImplementedError("This module only handles users")
28
- if server:
29
- if make:
30
- return ServerUserMaker
31
- else:
32
- return ServerUser
33
- else:
34
- if make:
35
- return ClientUserMaker
36
- else:
37
- return ClientUser
38
-
39
-
40
- class ServerUserMaker(BaseServerAuthMaker):
41
- schema = {"type": "object", "additionalProperties": False}
42
-
43
-
44
- class ServerUser(RootServerUser):
45
- schema = {"type": "object", "additionalProperties": False}
46
-
47
-
48
- class ClientUserMaker(BaseClientAuthMaker):
49
- gen_schema = {"type": "object", "additionalProperties": False}
50
- mod_schema = {"type": "object", "additionalProperties": False}
51
-
52
- @property
53
- def ident(self):
54
- return "*"
55
-
56
-
57
- class ClientUser(BaseClientAuth):
58
- schema = {"type": "object", "additionalProperties": False}
@@ -1,67 +0,0 @@
1
- from __future__ import annotations
2
- from abc import ABCMeta, abstractmethod
3
- from contextlib import asynccontextmanager
4
-
5
- import anyio
6
-
7
- __all__ = ["get_backend", "Backend"]
8
-
9
-
10
- class Backend(metaclass=ABCMeta):
11
- def __init__(self, tg):
12
- self._tg = tg
13
- self._njobs = 0
14
- self._ended = None
15
-
16
- @abstractmethod
17
- @asynccontextmanager
18
- async def connect(self, *a, **k):
19
- """
20
- This async context manager returns a connection.
21
- """
22
-
23
- async def aclose(self):
24
- """
25
- Force-close the connection.
26
- """
27
- self._tg.cancel_scope.cancel()
28
- if self._njobs > 0:
29
- with anyio.move_on_after(2):
30
- await self._ended.wait()
31
-
32
- async def spawn(self, p, *a, **kw):
33
- async def _run(p, a, kw, *, task_status):
34
- if self._ended is None:
35
- self._ended = anyio.Event()
36
- self._njobs += 1
37
- task_status.started()
38
- try:
39
- return await p(*a, **kw)
40
- finally:
41
- self._njobs -= 1
42
- if not self._njobs:
43
- self._ended.set()
44
- self._ended = None
45
-
46
- return await self._tg.start(_run, p, a, kw)
47
-
48
- @abstractmethod
49
- @asynccontextmanager
50
- async def monitor(self, *topic):
51
- """
52
- Return an async iterator that listens to this topic.
53
- """
54
-
55
- @abstractmethod
56
- async def send(self, *topic, payload):
57
- """
58
- Send this payload to this topic.
59
- """
60
-
61
-
62
- def get_backend(name):
63
- from importlib import import_module
64
-
65
- if "." not in name:
66
- name = "moat.kv.backend." + name
67
- return import_module(name).connect
@@ -1,71 +0,0 @@
1
- from __future__ import annotations
2
- import logging
3
- from contextlib import asynccontextmanager
4
-
5
- import anyio
6
- from moat.mqtt.client import MQTTClient
7
- from moat.mqtt.codecs import NoopCodec
8
- from moat.util import NotGiven
9
-
10
- from . import Backend
11
-
12
- logger = logging.getLogger(__name__)
13
-
14
-
15
- class MqttMessage:
16
- def __init__(self, topic, payload):
17
- self.topic = topic
18
- self.payload = payload
19
-
20
-
21
- class MqttBackend(Backend):
22
- client = None
23
-
24
- @asynccontextmanager
25
- async def connect(self, *a, **kw):
26
- codec = kw.pop("codec", NotGiven)
27
- C = MQTTClient(self._tg, codec=codec)
28
- try:
29
- await C.connect(*a, **kw)
30
- self.client = C
31
- yield self
32
- finally:
33
- self.client = None
34
- with anyio.CancelScope(shield=True):
35
- await self.aclose()
36
- await C.disconnect()
37
-
38
- @asynccontextmanager
39
- async def monitor(self, *topic):
40
- topic = "/".join(str(x) for x in topic)
41
- logger.info("Monitor %s start", topic)
42
- try:
43
- async with self.client.subscription(topic) as sub:
44
-
45
- async def sub_get(sub):
46
- async for msg in sub:
47
- yield MqttMessage(msg.topic.split("/"), msg.data)
48
-
49
- yield sub_get(sub)
50
- except anyio.get_cancelled_exc_class():
51
- raise
52
- except BaseException as exc:
53
- logger.exception("Monitor %s end: %r", topic, exc)
54
- raise
55
- else:
56
- logger.info("Monitor %s end", topic)
57
-
58
- def send(self, *topic, payload): # pylint: disable=invalid-overridden-method
59
- """
60
- Send this payload to this topic.
61
- """
62
- # client.publish is also async, pass-thru
63
- return self.client.publish("/".join(str(x) for x in topic), message=payload)
64
-
65
-
66
- @asynccontextmanager
67
- async def connect(**kw):
68
- async with anyio.create_task_group() as tg:
69
- c = MqttBackend(tg)
70
- async with c.connect(**kw):
71
- yield c