moat-kv 0.70.24__py3-none-any.whl → 0.71.0__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 (74) hide show
  1. build/lib/moat/kv/_cfg.yaml +2 -6
  2. build/lib/moat/kv/backend/mqtt.py +0 -3
  3. ci/rtd-requirements.txt +4 -0
  4. ci/test-requirements.txt +7 -0
  5. ci/travis.sh +96 -0
  6. debian/.gitignore +7 -0
  7. debian/changelog +1435 -0
  8. debian/control +43 -0
  9. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/_cfg.yaml +2 -6
  10. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/mqtt.py +0 -3
  11. debian/moat-kv.postinst +3 -0
  12. debian/rules +20 -0
  13. debian/source/format +1 -0
  14. debian/watch +4 -0
  15. docs/Makefile +20 -0
  16. docs/make.bat +36 -0
  17. docs/source/TODO.rst +61 -0
  18. docs/source/_static/.gitkeep +0 -0
  19. docs/source/acls.rst +80 -0
  20. docs/source/auth.rst +84 -0
  21. docs/source/client_protocol.rst +456 -0
  22. docs/source/code.rst +341 -0
  23. docs/source/command_line.rst +1187 -0
  24. docs/source/common_protocol.rst +47 -0
  25. docs/source/debugging.rst +70 -0
  26. docs/source/extend.rst +37 -0
  27. docs/source/history.rst +36 -0
  28. docs/source/index.rst +75 -0
  29. docs/source/model.rst +54 -0
  30. docs/source/overview.rst +83 -0
  31. docs/source/related.rst +89 -0
  32. docs/source/server_protocol.rst +450 -0
  33. docs/source/startup.rst +31 -0
  34. docs/source/translator.rst +244 -0
  35. docs/source/tutorial.rst +711 -0
  36. docs/source/v3.rst +168 -0
  37. examples/code/transform.scale.yml +21 -0
  38. examples/code/transform.switch.yml +82 -0
  39. examples/code/transform.timeslot.yml +63 -0
  40. moat/kv/_cfg.yaml +2 -6
  41. moat/kv/backend/mqtt.py +0 -3
  42. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/METADATA +2 -5
  43. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/RECORD +68 -17
  44. scripts/current +15 -0
  45. scripts/env +8 -0
  46. scripts/init +39 -0
  47. scripts/recover +17 -0
  48. scripts/rotate +33 -0
  49. scripts/run +29 -0
  50. scripts/run-all +10 -0
  51. scripts/run-any +10 -0
  52. scripts/run-single +15 -0
  53. scripts/success +4 -0
  54. systemd/moat-kv-recover.service +21 -0
  55. systemd/moat-kv-rotate.service +20 -0
  56. systemd/moat-kv-rotate.timer +10 -0
  57. systemd/moat-kv-run-all.service +26 -0
  58. systemd/moat-kv-run-all@.service +25 -0
  59. systemd/moat-kv-run-any.service +26 -0
  60. systemd/moat-kv-run-any@.service +25 -0
  61. systemd/moat-kv-run-single.service +26 -0
  62. systemd/moat-kv-run-single@.service +25 -0
  63. systemd/moat-kv.service +27 -0
  64. systemd/postinst +7 -0
  65. systemd/sysusers +3 -0
  66. build/lib/moat/kv/backend/serf.py +0 -45
  67. build/lib/moat/kv/mock/serf.py +0 -250
  68. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/backend/serf.py +0 -45
  69. debian/moat-kv/usr/lib/python3/dist-packages/moat/kv/mock/serf.py +0 -250
  70. moat/kv/backend/serf.py +0 -45
  71. moat/kv/mock/serf.py +0 -250
  72. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/WHEEL +0 -0
  73. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/licenses/LICENSE.txt +0 -0
  74. {moat_kv-0.70.24.dist-info → moat_kv-0.71.0.dist-info}/top_level.txt +0 -0
scripts/run ADDED
@@ -0,0 +1,29 @@
1
+ #!/bin/bash
2
+ set -ex
3
+
4
+ # This script starts up MoaT-KV.
5
+
6
+ # Normally, starting MoaT-KV on a host where clients don't connect locally is
7
+ # a bad idea. However, on a system that has more than one network namespace
8
+ # you need to use a specific address. So set LOCAL=yes to force starting
9
+ # anyway.
10
+
11
+ if test "$LOCAL" != "yes" && test "$(moat util cfg kv.conn.host)" != "127.0.0.1"; then
12
+ echo "Server is not localhost: not starting."
13
+ exit 42 # mark as succeeded
14
+ fi
15
+
16
+ if test "$MODE" = "master" ; then
17
+ /usr/lib/moat/kv/current "$TEMP"
18
+ fi
19
+
20
+ if test ! -v NAME ; then
21
+ echo "NAME is not set. Exiting." >&2
22
+ exit 1
23
+ fi
24
+
25
+ if test -v TEMP && test -s "$TEMP" ; then
26
+ exec moat -c /etc/moat/moat.cfg kv server -a -l "$TEMP" "$NAME"
27
+ else
28
+ exec moat -c /etc/moat/moat.cfg kv server "$NAME"
29
+ fi
scripts/run-all ADDED
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+ set -ex
3
+
4
+ # This script file starts up a MoaT-KV any-node runner.
5
+
6
+ if test $# = 1 ; then
7
+ exec moat -c /etc/moat/moat.cfg kv job -n - -g "$1" run
8
+ else
9
+ exec moat -c /etc/moat/moat.cfg kv job -n - run
10
+ fi
scripts/run-any ADDED
@@ -0,0 +1,10 @@
1
+ #!/bin/bash
2
+ set -ex
3
+
4
+ # This script file starts up a MoaT-KV any-node runner.
5
+
6
+ if test $# = 1 ; then
7
+ exec moat -c /etc/moat/moat.cfg kv job -g "$1" run
8
+ else
9
+ exec moat -c /etc/moat/moat.cfg kv job run
10
+ fi
scripts/run-single ADDED
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+ set -ex
3
+
4
+ # This script file starts up a MoaT-KV single-node runner.
5
+
6
+ if test ! -v NAME ; then
7
+ echo "NAME is not set. Exiting." >&2
8
+ exit 1
9
+ fi
10
+
11
+ if test $# = 1 ; then
12
+ exec moat -c /etc/moat/moat.cfg kv job -n "$NAME" -g "$1" run
13
+ else
14
+ exec moat -c /etc/moat/moat.cfg kv job -n "$NAME" run
15
+ fi
scripts/success ADDED
@@ -0,0 +1,4 @@
1
+ #!/bin/sh
2
+ set -ex
3
+
4
+ rm -f "$TEMP"
@@ -0,0 +1,21 @@
1
+ [Unit]
2
+ Description=MoaT-KV state recovery
3
+ Conflicts=moat-kv.service
4
+ Conflicts=distkv.service
5
+
6
+ AssertFileNotEmpty=/etc/moat/moat.cfg
7
+
8
+ [Install]
9
+
10
+ [Service]
11
+ Type=oneshot
12
+
13
+ ExecStart=/usr/lib/moat/kv/recover
14
+ ExecStartPost=!/bin/systemctl restart moat-kv.service
15
+
16
+ EnvironmentFile=/usr/lib/moat/kv/env
17
+ EnvironmentFile=-/etc/moat/kv.env
18
+
19
+ User=MoaT-KV
20
+ Group=MoaT
21
+
@@ -0,0 +1,20 @@
1
+ [Unit]
2
+ Description=MoaT-KV log rotate
3
+ Requires=moat-kv.service
4
+ After=moat-kv.service
5
+ Conflicts=distkv-rotate.service
6
+
7
+ ConditionFileNotEmpty=/etc/moat/moat.cfg
8
+ ConditionPathIsDirectory=/var/lib/moat/kv
9
+
10
+ [Install]
11
+
12
+ [Service]
13
+ ExecStart=/usr/lib/moat/kv/rotate
14
+
15
+ EnvironmentFile=/usr/lib/moat/kv/env
16
+ EnvironmentFile=-/etc/moat/kv.env
17
+
18
+ User=MoaT-KV
19
+ Group=MoaT
20
+
@@ -0,0 +1,10 @@
1
+ [Unit]
2
+ Description=The MoaT-KV server state save timer
3
+ Requires=moat-kv.service
4
+
5
+ [Timer]
6
+ OnUnitActiveSec=900
7
+ OnActiveSec=100
8
+
9
+ [Install]
10
+ WantedBy=moat-kv.service
@@ -0,0 +1,26 @@
1
+ [Unit]
2
+ Description=MoaT-KV default all-nodes runner
3
+ After=moat-kv.service
4
+ Requires=moat-kv.service
5
+ Conflicts=distkv-run-all.service
6
+
7
+ ConditionFileNotEmpty=/etc/moat/moat.cfg
8
+
9
+ [Install]
10
+ WantedBy=multi-user.target
11
+
12
+ [Service]
13
+ Type=notify
14
+ ExecStart=/usr/lib/moat/kv/run-all
15
+
16
+ User=MoaT-KV
17
+ Group=MoaT
18
+
19
+ EnvironmentFile=/usr/lib/moat/kv/env
20
+ EnvironmentFile=-/etc/moat/kv.env
21
+
22
+ TimeoutSec=300
23
+ WatchdogSec=10
24
+
25
+ Restart=always
26
+ RestartSec=10
@@ -0,0 +1,25 @@
1
+ [Unit]
2
+ Description=MoaT-KV all-nodes runner for %i
3
+ After=moat-kv.service
4
+ Requires=moat-kv.service
5
+
6
+ ConditionFileNotEmpty=/etc/moat/moat.cfg
7
+
8
+ [Install]
9
+ WantedBy=multi-user.target
10
+
11
+ [Service]
12
+ Type=notify
13
+ ExecStart=/usr/lib/moat/kv/run-all %i
14
+
15
+ User=MoaT-KV
16
+ Group=MoaT
17
+
18
+ EnvironmentFile=/usr/lib/moat/kv/env
19
+ EnvironmentFile=-/etc/moat/kv.env
20
+
21
+ TimeoutSec=300
22
+ WatchdogSec=10
23
+
24
+ Restart=always
25
+ RestartSec=10
@@ -0,0 +1,26 @@
1
+ [Unit]
2
+ Description=MoaT-KV default any-nodes runner
3
+ After=moat-kv.service
4
+ Requires=moat-kv.service
5
+ Conflicts=distkv-run-any.service
6
+
7
+ ConditionFileNotEmpty=/etc/moat/moat.cfg
8
+
9
+ [Install]
10
+ WantedBy=multi-user.target
11
+
12
+ [Service]
13
+ Type=notify
14
+ ExecStart=/usr/lib/moat/kv/run-any
15
+
16
+ User=MoaT-KV
17
+ Group=MoaT
18
+
19
+ EnvironmentFile=/usr/lib/moat/kv/env
20
+ EnvironmentFile=-/etc/moat/kv.env
21
+
22
+ TimeoutSec=300
23
+ WatchdogSec=10
24
+
25
+ Restart=always
26
+ RestartSec=10
@@ -0,0 +1,25 @@
1
+ [Unit]
2
+ Description=MoaT-KV any-nodes runner for %i
3
+ After=moat-kv.service
4
+ Requires=moat-kv.service
5
+
6
+ ConditionFileNotEmpty=/etc/moat/moat.cfg
7
+
8
+ [Install]
9
+ WantedBy=multi-user.target
10
+
11
+ [Service]
12
+ Type=notify
13
+ ExecStart=/usr/lib/moat/kv/run-any %i
14
+
15
+ User=MoaT-KV
16
+ Group=MoaT
17
+
18
+ EnvironmentFile=/usr/lib/moat/kv/env
19
+ EnvironmentFile=-/etc/moat/kv.env
20
+
21
+ TimeoutSec=300
22
+ WatchdogSec=10
23
+
24
+ Restart=always
25
+ RestartSec=10
@@ -0,0 +1,26 @@
1
+ [Unit]
2
+ Description=MoaT-KV default single-node runner
3
+ After=moat-kv.service
4
+ Requires=moat-kv.service
5
+ Conflicts=distkv-run-single.service
6
+
7
+ ConditionFileNotEmpty=/etc/moat/moat.cfg
8
+
9
+ [Install]
10
+ WantedBy=multi-user.target
11
+
12
+ [Service]
13
+ Type=notify
14
+ ExecStart=/usr/lib/moat/kv/run-single
15
+
16
+ User=MoaT-KV
17
+ Group=MoaT
18
+
19
+ EnvironmentFile=/usr/lib/moat/kv/env
20
+ EnvironmentFile=-/etc/moat/kv.env
21
+
22
+ TimeoutSec=300
23
+ WatchdogSec=10
24
+
25
+ Restart=always
26
+ RestartSec=10
@@ -0,0 +1,25 @@
1
+ [Unit]
2
+ Description=MoaT-KV single-node runner for %i
3
+ After=moat-kv.service
4
+ Requires=moat-kv.service
5
+
6
+ ConditionFileNotEmpty=/etc/moat/moat.cfg
7
+
8
+ [Install]
9
+ WantedBy=multi-user.target
10
+
11
+ [Service]
12
+ Type=notify
13
+ ExecStart=/usr/lib/moat/kv/run-single %i
14
+
15
+ User=MoaT-KV
16
+ Group=MoaT
17
+
18
+ EnvironmentFile=/usr/lib/moat/kv/env
19
+ EnvironmentFile=-/etc/moat/kv.env
20
+
21
+ TimeoutSec=300
22
+ WatchdogSec=10
23
+
24
+ Restart=always
25
+ RestartSec=10
@@ -0,0 +1,27 @@
1
+ [Unit]
2
+ Description=MoaT-KV main server
3
+ After=mosquitto.service
4
+ Wants=mosquitto.service
5
+ Conflicts=moat-kv-recover.service
6
+ Conflicts=distkv.service
7
+ OnFailure=moat-kv-recover.service
8
+
9
+ ConditionFileNotEmpty=/etc/moat/moat.cfg
10
+
11
+ [Install]
12
+ WantedBy=multi-user.target
13
+
14
+ [Service]
15
+ Type=notify
16
+ ExecStart=/usr/lib/moat/kv/run
17
+ ExecStartPost=/usr/lib/moat/kv/success
18
+ SuccessExitStatus=42
19
+
20
+ User=MoaT-KV
21
+ Group=MoaT
22
+
23
+ EnvironmentFile=/usr/lib/moat/kv/env
24
+ EnvironmentFile=-/etc/moat/kv.env
25
+
26
+ TimeoutSec=300
27
+ WatchdogSec=10
systemd/postinst ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/sh
2
+
3
+ set -ex
4
+ /usr/lib/moat/kv/init
5
+ systemd-sysusers --no-pager /usr/lib/sysusers.d/moat-kv.conf
6
+ systemctl enable moat-kv.service
7
+ systemctl enable moat-kv-rotate.timer || true # may be masked
systemd/sysusers ADDED
@@ -0,0 +1,3 @@
1
+ g MoaT -
2
+ u MoaT-KV - "MoaT-KV" /var/lib/moat/kv
3
+ m MoaT-KV MoaT
@@ -1,45 +0,0 @@
1
- from __future__ import annotations
2
- from contextlib import asynccontextmanager
3
-
4
- import anyio
5
- import asyncserf
6
-
7
- from . import Backend
8
-
9
- # Simply setting connect=asyncserf.serf_client interferes with mocking
10
- # when testing.
11
-
12
-
13
- class SerfBackend(Backend):
14
- client = None
15
-
16
- @asynccontextmanager
17
- async def connect(self, *a, **k):
18
- async with asyncserf.serf_client(*a, **k) as c:
19
- self.client = c
20
- try:
21
- yield self
22
- finally:
23
- with anyio.CancelScope(shield=True):
24
- await self.aclose()
25
- self.client = None
26
-
27
- def monitor(self, *topic): # pylint: disable=invalid-overridden-method
28
- topic = "user:" + ".".join(topic)
29
- # self.client.stream is also async, pass thru
30
- return self.client.stream(topic)
31
-
32
- def send(self, *topic, payload): # pylint: disable=invalid-overridden-method
33
- """
34
- Send this payload to this topic.
35
- """
36
- # self.client.event is also async, pass thru
37
- return self.client.event(".".join(topic), payload=payload, coalesce=False)
38
-
39
-
40
- @asynccontextmanager
41
- async def connect(*a, **kw):
42
- async with anyio.create_task_group() as tg:
43
- c = SerfBackend(tg)
44
- async with c.connect(*a, **kw):
45
- yield c
@@ -1,250 +0,0 @@
1
- from __future__ import annotations
2
- import copy
3
- import logging
4
- import time
5
- from contextlib import AsyncExitStack, asynccontextmanager
6
- from functools import partial
7
-
8
- import anyio
9
- import attr
10
- from unittest import mock
11
- import trio
12
- from asyncscope import main_scope, scope
13
- from asyncserf.stream import SerfEvent
14
- from moat.util import NotGiven, ValueEvent, attrdict, combine_dict, create_queue
15
-
16
- from moat.kv.codec import unpacker
17
- from moat.kv.mock import S as _S
18
- from moat.kv.server import Server
19
-
20
- logger = logging.getLogger(__name__)
21
-
22
- otm = time.time
23
-
24
- from . import CFG
25
-
26
-
27
- @asynccontextmanager
28
- async def stdtest(n=1, run=True, ssl=False, tocks=20, **kw):
29
- C_OUT = CFG.get("_stdout", NotGiven)
30
- if C_OUT is not NotGiven:
31
- del CFG["_stdout"]
32
- TESTCFG = copy.deepcopy(CFG["kv"])
33
- TESTCFG.server.port = None
34
- TESTCFG.server.backend = "serf"
35
- TESTCFG.root = "test"
36
- if C_OUT is not NotGiven:
37
- CFG["_stdout"] = C_OUT
38
- TESTCFG["_stdout"] = C_OUT
39
-
40
- if ssl:
41
- import ssl
42
-
43
- import trustme
44
-
45
- ca = trustme.CA()
46
- cert = ca.issue_server_cert("127.0.0.1")
47
- server_ctx = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
48
- client_ctx = ssl.create_default_context(purpose=ssl.Purpose.SERVER_AUTH)
49
- ca.configure_trust(client_ctx)
50
- cert.configure_cert(server_ctx)
51
- else:
52
- server_ctx = client_ctx = False
53
-
54
- clock = trio.lowlevel.current_clock()
55
- clock.autojump_threshold = 0.0
56
- # clock.rate = 5
57
-
58
- @attr.s
59
- class S(_S):
60
- splits = attr.ib(factory=set)
61
- serfs = attr.ib(factory=set)
62
-
63
- def split(self, s):
64
- assert s not in self.splits
65
- logger.debug("Split: add %d", s)
66
- self.splits.add(s)
67
-
68
- def join(self, s):
69
- logger.debug("Split: join %d", s)
70
- self.splits.remove(s)
71
-
72
- async def mock_get_host_port(st, host):
73
- i = int(host[host.rindex("_") + 1 :])
74
- s = st.s[i]
75
- await s.is_serving
76
- for host, port, *_ in s.ports:
77
- if host == "::" or host[0] != ":":
78
- return host, port
79
-
80
- def tm():
81
- try:
82
- return trio.current_time()
83
- except RuntimeError:
84
- return otm()
85
-
86
- async def mock_set_tock(self, old):
87
- assert self._tock < tocks, "Test didn't terminate. Limit:" + str(tocks)
88
- await old()
89
-
90
- async with main_scope("moat.kv.test.serf") as scp:
91
- tg = scp._tg
92
- st = S(tg, client_ctx)
93
- async with AsyncExitStack() as ex:
94
- st.ex = ex # pylint: disable=attribute-defined-outside-init
95
- ex.enter_context(mock.patch("time.time", new=tm))
96
- ex.enter_context(mock.patch("time.monotonic", new=tm))
97
- logging._startTime = tm()
98
-
99
- ex.enter_context(
100
- mock.patch("asyncserf.serf_client", new=partial(mock_serf_client, st)),
101
- )
102
-
103
- for i in range(n):
104
- name = "test_" + str(i)
105
- args = kw.get(name, kw.get("args", attrdict()))
106
- args["cfg"] = combine_dict(
107
- args.get("cfg", {}),
108
- {
109
- "kv": {
110
- "conn": {"ssl": client_ctx},
111
- },
112
- "server": {
113
- "bind_default": {
114
- "host": "127.0.0.1",
115
- "port": i + 50120,
116
- "ssl": server_ctx,
117
- },
118
- "serf": {"i": i},
119
- },
120
- },
121
- TESTCFG,
122
- )
123
- s = Server(name, **args)
124
- ex.enter_context(
125
- mock.patch.object(s, "_set_tock", new=partial(mock_set_tock, s, s._set_tock)),
126
- )
127
- ex.enter_context(
128
- mock.patch.object(s, "_get_host_port", new=partial(mock_get_host_port, st)),
129
- )
130
- st.s.append(s)
131
-
132
- async def with_serf(s, *a, **k):
133
- s._scope = scope.get()
134
- return await s._scoped_serve(*a, **k)
135
-
136
- evts = []
137
- for i in range(n):
138
- if kw.get("run_" + str(i), run):
139
- evt = anyio.Event()
140
- await scp.spawn_service(with_serf, st.s[i], ready_evt=evt)
141
- evts.append(evt)
142
- for e in evts:
143
- await e.wait()
144
- try:
145
- yield st
146
- finally:
147
- with anyio.fail_after(2, shield=True):
148
- logger.info("Runtime: %s", clock.current_time())
149
- tg.cancel_scope.cancel()
150
- logger.info("End")
151
- pass # unwinding ex:AsyncExitStack
152
-
153
-
154
- @asynccontextmanager
155
- async def mock_serf_client(master, **cfg):
156
- async with scope.using_scope():
157
- ms = MockServ(master, **cfg)
158
- master.serfs.add(ms)
159
- ms._scope = scope.get() # pylint:disable=attribute-defined-outside-init
160
- try:
161
- yield ms
162
- finally:
163
- master.serfs.remove(ms)
164
- pass # terminating mock_serf_client nursery
165
-
166
-
167
- class MockServ:
168
- def __init__(self, master, **cfg):
169
- self.cfg = cfg
170
- self._tg = scope._tg
171
- self.streams = {}
172
- self._master = master
173
-
174
- def __hash__(self):
175
- return id(self)
176
-
177
- async def spawn(self, fn, *args, **kw):
178
- async def run(evt):
179
- with anyio.CancelScope() as sc:
180
- await evt.set(sc)
181
- await fn(*args, **kw)
182
-
183
- evt = ValueEvent()
184
- self._tg.spawn(run, evt)
185
- return await evt.get()
186
-
187
- async def event(self, name, payload, coalesce=True):
188
- try:
189
- logger.debug("SERF:%s: %r", name, unpacker(payload))
190
- except Exception:
191
- logger.debug("SERF:%s: %r (raw)", name, payload)
192
- assert not coalesce, "'coalesce' must be cleared!"
193
-
194
- i_self = self.cfg.get("i", 0)
195
- for s in list(self._master.serfs):
196
- i_s = s.cfg.get("i", 0)
197
- for x in self._master.splits:
198
- if (i_s < x) != (i_self < x):
199
- break
200
- else:
201
- n = tuple(name.split("."))
202
- while n:
203
- sl = s.streams.get(n, ())
204
- for sn in sl:
205
- await sn.q.put((name, payload))
206
- n = n[:-1]
207
-
208
- def stream(self, typ):
209
- """compat for supporting asyncactor"""
210
- if not typ.startswith("user:"):
211
- raise RuntimeError("not supported")
212
- typ = typ[5:]
213
- return self.serf_mon(typ)
214
-
215
- def serf_mon(self, typ):
216
- if "," in typ:
217
- raise RuntimeError("not supported")
218
- s = MockSerfStream(self, "user:" + typ)
219
- return s
220
-
221
- async def serf_send(self, typ, payload):
222
- """compat for supporting asyncactor"""
223
- return await self.event(typ, payload)
224
-
225
-
226
- class MockSerfStream:
227
- q = None
228
-
229
- def __init__(self, serf, typ):
230
- self.serf = serf
231
- assert typ.startswith("user:")
232
- self.typ = tuple(typ[5:].split("."))
233
-
234
- async def __aenter__(self):
235
- self.q = create_queue(100)
236
- self.serf.streams.setdefault(self.typ, []).append(self)
237
- return self
238
-
239
- async def __aexit__(self, *tb):
240
- self.serf.streams[self.typ].remove(self)
241
- del self.q
242
-
243
- def __aiter__(self):
244
- return self
245
-
246
- async def __anext__(self):
247
- res = await self.q.get()
248
- evt = SerfEvent(self)
249
- evt.topic, evt.payload = res
250
- return evt
@@ -1,45 +0,0 @@
1
- from __future__ import annotations
2
- from contextlib import asynccontextmanager
3
-
4
- import anyio
5
- import asyncserf
6
-
7
- from . import Backend
8
-
9
- # Simply setting connect=asyncserf.serf_client interferes with mocking
10
- # when testing.
11
-
12
-
13
- class SerfBackend(Backend):
14
- client = None
15
-
16
- @asynccontextmanager
17
- async def connect(self, *a, **k):
18
- async with asyncserf.serf_client(*a, **k) as c:
19
- self.client = c
20
- try:
21
- yield self
22
- finally:
23
- with anyio.CancelScope(shield=True):
24
- await self.aclose()
25
- self.client = None
26
-
27
- def monitor(self, *topic): # pylint: disable=invalid-overridden-method
28
- topic = "user:" + ".".join(topic)
29
- # self.client.stream is also async, pass thru
30
- return self.client.stream(topic)
31
-
32
- def send(self, *topic, payload): # pylint: disable=invalid-overridden-method
33
- """
34
- Send this payload to this topic.
35
- """
36
- # self.client.event is also async, pass thru
37
- return self.client.event(".".join(topic), payload=payload, coalesce=False)
38
-
39
-
40
- @asynccontextmanager
41
- async def connect(*a, **kw):
42
- async with anyio.create_task_group() as tg:
43
- c = SerfBackend(tg)
44
- async with c.connect(*a, **kw):
45
- yield c