edgesync 0.3.1__tar.gz → 0.3.3__tar.gz
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.
- {edgesync-0.3.1 → edgesync-0.3.3}/CHANGELOG.md +25 -1
- {edgesync-0.3.1 → edgesync-0.3.3}/PKG-INFO +63 -3
- {edgesync-0.3.1 → edgesync-0.3.3}/README.md +61 -0
- edgesync-0.3.3/VERSION +1 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/docs/getting-started.md +44 -20
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/mqtt.py +2 -9
- {edgesync-0.3.1 → edgesync-0.3.3}/pyproject.toml +1 -3
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_mqtt_transport.py +44 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/uv.lock +2 -7
- edgesync-0.3.1/VERSION +0 -1
- {edgesync-0.3.1 → edgesync-0.3.3}/.github/workflows/ci.yml +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/.github/workflows/release.yml +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/.gitignore +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/CONTRIBUTING.md +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/LICENSE +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/SECURITY.md +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/docs/integrations.md +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/docs/reliability.md +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/docs/storage.md +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/client.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/config.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/exceptions.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/logging.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/delivery.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/message.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/receipt.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/models/stats.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/py.typed +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/queue/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/queue/manager.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/retry/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/retry/backoff.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/retry/policy.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/storage/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/storage/base.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/storage/migrations.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/storage/sqlite.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/base.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/http.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/transports/registry.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/utils/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/utils/clock.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/utils/ids.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/worker/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/worker/lifecycle.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/worker/scheduler.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/edgesync/worker/sync_worker.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/conftest.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/fixtures/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/fixtures/factories.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/fixtures/fake_transport.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_client.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_http_transport.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_sqlite_storage.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/integration/test_worker.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/reliability/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/reliability/test_reliability.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/__init__.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_backoff.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_config.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_models.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_queue_manager.py +0 -0
- {edgesync-0.3.1 → edgesync-0.3.3}/tests/unit/test_retry_policy.py +0 -0
|
@@ -7,6 +7,28 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.3] - 2026-09-13
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- `aiomqtt` is now a required dependency instead of an optional `mqtt` extra, so
|
|
15
|
+
`pip install edgesync` alone is enough to use `MQTTTransport`.
|
|
16
|
+
|
|
17
|
+
## [0.3.2] - 2026-08-24
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- MQTT TLS documentation in `README.md` and `docs/getting-started.md`, covering
|
|
22
|
+
`tls_params`/`port` usage for TLS connections and client-certificate (mutual TLS) auth, plus
|
|
23
|
+
test coverage for the `aiomqtt.Client` construction path (both plaintext and TLS), which
|
|
24
|
+
wasn't previously exercised since existing tests injected a fake client directly.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- `README.md`'s Quickstart now includes a full MQTT usage section (previously it only linked
|
|
29
|
+
out to the getting-started guide), so the MQTT example renders directly on PyPI's project
|
|
30
|
+
page instead of requiring a click-through to GitHub.
|
|
31
|
+
|
|
10
32
|
## [0.3.1] - 2026-08-24
|
|
11
33
|
|
|
12
34
|
### Fixed
|
|
@@ -82,7 +104,9 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
82
104
|
- Crash and restart recovery via expired-lease sweeps, safe across concurrent workers and
|
|
83
105
|
processes sharing the same database file.
|
|
84
106
|
|
|
85
|
-
[Unreleased]: https://github.com/adhuldas/EdgeSync/compare/v0.3.
|
|
107
|
+
[Unreleased]: https://github.com/adhuldas/EdgeSync/compare/v0.3.3...HEAD
|
|
108
|
+
[0.3.3]: https://github.com/adhuldas/EdgeSync/compare/v0.3.2...v0.3.3
|
|
109
|
+
[0.3.2]: https://github.com/adhuldas/EdgeSync/compare/v0.3.1...v0.3.2
|
|
86
110
|
[0.3.1]: https://github.com/adhuldas/EdgeSync/compare/v0.3.0...v0.3.1
|
|
87
111
|
[0.3.0]: https://github.com/adhuldas/EdgeSync/compare/v0.2.1...v0.3.0
|
|
88
112
|
[0.2.1]: https://github.com/adhuldas/EdgeSync/compare/v0.2.0...v0.2.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: edgesync
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Reliable data delivery for unreliable networks.
|
|
5
5
|
Project-URL: Homepage, https://github.com/adhuldas/EdgeSync
|
|
6
6
|
Project-URL: Repository, https://github.com/adhuldas/EdgeSync
|
|
@@ -25,10 +25,9 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
25
25
|
Classifier: Topic :: System :: Distributed Computing
|
|
26
26
|
Classifier: Typing :: Typed
|
|
27
27
|
Requires-Python: >=3.10
|
|
28
|
+
Requires-Dist: aiomqtt<3,>=2.5
|
|
28
29
|
Requires-Dist: aiosqlite>=0.20
|
|
29
30
|
Requires-Dist: httpx>=0.27
|
|
30
|
-
Provides-Extra: mqtt
|
|
31
|
-
Requires-Dist: aiomqtt<3,>=2.5; extra == 'mqtt'
|
|
32
31
|
Description-Content-Type: text/markdown
|
|
33
32
|
|
|
34
33
|
# EdgeSync
|
|
@@ -94,6 +93,67 @@ That's it: `publish()` durably persists the message and returns as soon as it's
|
|
|
94
93
|
background worker delivers it, retrying with exponential backoff on failure, without the
|
|
95
94
|
caller needing to stay connected or wait for the network.
|
|
96
95
|
|
|
96
|
+
## MQTT
|
|
97
|
+
|
|
98
|
+
Publishing to MQTT instead of HTTP is the same pattern with a different transport:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
import asyncio
|
|
102
|
+
from edgesync import EdgeSync
|
|
103
|
+
from edgesync.transports.mqtt import MQTTTransport
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
async def main():
|
|
107
|
+
async with EdgeSync(
|
|
108
|
+
database="edgesync.db",
|
|
109
|
+
destinations={
|
|
110
|
+
"telemetry": MQTTTransport(
|
|
111
|
+
"broker.example.com",
|
|
112
|
+
"devices/device-001/telemetry",
|
|
113
|
+
qos=1,
|
|
114
|
+
username="device-001",
|
|
115
|
+
password="...",
|
|
116
|
+
),
|
|
117
|
+
},
|
|
118
|
+
default_destination="telemetry",
|
|
119
|
+
) as sync:
|
|
120
|
+
await sync.publish({"temperature": 28.5})
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
asyncio.run(main())
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`MQTTTransport` only accepts QoS 1 or 2 — QoS 0 publishes are never acknowledged by the
|
|
127
|
+
broker, so there'd be no way to tell a successful delivery from a lost one, which would break
|
|
128
|
+
EdgeSync's at-least-once guarantee. Unlike `HTTPTransport`, MQTT holds a persistent broker
|
|
129
|
+
connection: `EdgeSync.start()` still won't raise if the broker is unreachable (data keeps
|
|
130
|
+
queuing locally either way), and the transport automatically reconnects on the next delivery
|
|
131
|
+
attempt after a dropped connection or failed publish.
|
|
132
|
+
|
|
133
|
+
**TLS**: by default `MQTTTransport` connects in plaintext on port `1883`. To connect over
|
|
134
|
+
TLS, pass `tls_params` (an `aiomqtt.TLSParameters`) and switch to the broker's TLS port,
|
|
135
|
+
conventionally `8883`:
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
import aiomqtt
|
|
139
|
+
from edgesync.transports.mqtt import MQTTTransport
|
|
140
|
+
|
|
141
|
+
MQTTTransport(
|
|
142
|
+
"broker.example.com",
|
|
143
|
+
"devices/device-001/telemetry",
|
|
144
|
+
port=8883,
|
|
145
|
+
tls_params=aiomqtt.TLSParameters(
|
|
146
|
+
ca_certs="/etc/ssl/certs/ca-certificates.crt",
|
|
147
|
+
),
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`TLSParameters` also accepts `certfile` / `keyfile` for client-certificate (mutual TLS)
|
|
152
|
+
authentication. Omit `tls_params` entirely for an unencrypted connection, e.g. a broker on a
|
|
153
|
+
trusted local network or a local development/test setup. See the
|
|
154
|
+
[MQTT section of the getting-started guide](https://github.com/adhuldas/EdgeSync/blob/main/docs/getting-started.md#mqtt)
|
|
155
|
+
for further detail.
|
|
156
|
+
|
|
97
157
|
## Usage with FastAPI, Flask, and plain asyncio
|
|
98
158
|
|
|
99
159
|
EdgeSync is async-native, so it's most at home in an `asyncio` app or an async framework like
|
|
@@ -61,6 +61,67 @@ That's it: `publish()` durably persists the message and returns as soon as it's
|
|
|
61
61
|
background worker delivers it, retrying with exponential backoff on failure, without the
|
|
62
62
|
caller needing to stay connected or wait for the network.
|
|
63
63
|
|
|
64
|
+
## MQTT
|
|
65
|
+
|
|
66
|
+
Publishing to MQTT instead of HTTP is the same pattern with a different transport:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
import asyncio
|
|
70
|
+
from edgesync import EdgeSync
|
|
71
|
+
from edgesync.transports.mqtt import MQTTTransport
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
async def main():
|
|
75
|
+
async with EdgeSync(
|
|
76
|
+
database="edgesync.db",
|
|
77
|
+
destinations={
|
|
78
|
+
"telemetry": MQTTTransport(
|
|
79
|
+
"broker.example.com",
|
|
80
|
+
"devices/device-001/telemetry",
|
|
81
|
+
qos=1,
|
|
82
|
+
username="device-001",
|
|
83
|
+
password="...",
|
|
84
|
+
),
|
|
85
|
+
},
|
|
86
|
+
default_destination="telemetry",
|
|
87
|
+
) as sync:
|
|
88
|
+
await sync.publish({"temperature": 28.5})
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
asyncio.run(main())
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`MQTTTransport` only accepts QoS 1 or 2 — QoS 0 publishes are never acknowledged by the
|
|
95
|
+
broker, so there'd be no way to tell a successful delivery from a lost one, which would break
|
|
96
|
+
EdgeSync's at-least-once guarantee. Unlike `HTTPTransport`, MQTT holds a persistent broker
|
|
97
|
+
connection: `EdgeSync.start()` still won't raise if the broker is unreachable (data keeps
|
|
98
|
+
queuing locally either way), and the transport automatically reconnects on the next delivery
|
|
99
|
+
attempt after a dropped connection or failed publish.
|
|
100
|
+
|
|
101
|
+
**TLS**: by default `MQTTTransport` connects in plaintext on port `1883`. To connect over
|
|
102
|
+
TLS, pass `tls_params` (an `aiomqtt.TLSParameters`) and switch to the broker's TLS port,
|
|
103
|
+
conventionally `8883`:
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
import aiomqtt
|
|
107
|
+
from edgesync.transports.mqtt import MQTTTransport
|
|
108
|
+
|
|
109
|
+
MQTTTransport(
|
|
110
|
+
"broker.example.com",
|
|
111
|
+
"devices/device-001/telemetry",
|
|
112
|
+
port=8883,
|
|
113
|
+
tls_params=aiomqtt.TLSParameters(
|
|
114
|
+
ca_certs="/etc/ssl/certs/ca-certificates.crt",
|
|
115
|
+
),
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
`TLSParameters` also accepts `certfile` / `keyfile` for client-certificate (mutual TLS)
|
|
120
|
+
authentication. Omit `tls_params` entirely for an unencrypted connection, e.g. a broker on a
|
|
121
|
+
trusted local network or a local development/test setup. See the
|
|
122
|
+
[MQTT section of the getting-started guide](https://github.com/adhuldas/EdgeSync/blob/main/docs/getting-started.md#mqtt)
|
|
123
|
+
for further detail.
|
|
124
|
+
|
|
64
125
|
## Usage with FastAPI, Flask, and plain asyncio
|
|
65
126
|
|
|
66
127
|
EdgeSync is async-native, so it's most at home in an `asyncio` app or an async framework like
|
edgesync-0.3.3/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.3.3
|
|
@@ -126,31 +126,30 @@ than HTTP.
|
|
|
126
126
|
|
|
127
127
|
## MQTT
|
|
128
128
|
|
|
129
|
-
Install the optional extra first:
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
pip install edgesync[mqtt]
|
|
133
|
-
```
|
|
134
|
-
|
|
135
129
|
```python
|
|
130
|
+
import asyncio
|
|
136
131
|
from edgesync import EdgeSync
|
|
137
132
|
from edgesync.transports.mqtt import MQTTTransport
|
|
138
133
|
|
|
139
|
-
sync = EdgeSync(
|
|
140
|
-
database="edgesync.db",
|
|
141
|
-
destinations={
|
|
142
|
-
"telemetry": MQTTTransport(
|
|
143
|
-
"broker.example.com",
|
|
144
|
-
"devices/device-001/telemetry",
|
|
145
|
-
qos=1,
|
|
146
|
-
username="device-001",
|
|
147
|
-
password="...",
|
|
148
|
-
),
|
|
149
|
-
},
|
|
150
|
-
default_destination="telemetry",
|
|
151
|
-
)
|
|
152
134
|
|
|
153
|
-
|
|
135
|
+
async def main():
|
|
136
|
+
async with EdgeSync(
|
|
137
|
+
database="edgesync.db",
|
|
138
|
+
destinations={
|
|
139
|
+
"telemetry": MQTTTransport(
|
|
140
|
+
"broker.example.com",
|
|
141
|
+
"devices/device-001/telemetry",
|
|
142
|
+
qos=1,
|
|
143
|
+
username="device-001",
|
|
144
|
+
password="...",
|
|
145
|
+
),
|
|
146
|
+
},
|
|
147
|
+
default_destination="telemetry",
|
|
148
|
+
) as sync:
|
|
149
|
+
await sync.publish({"temperature": 28.5})
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
asyncio.run(main())
|
|
154
153
|
```
|
|
155
154
|
|
|
156
155
|
`MQTTTransport` only accepts QoS 1 or 2 — QoS 0 publishes are never acknowledged by the
|
|
@@ -160,6 +159,31 @@ connection: `EdgeSync.start()` still won't raise if the broker is unreachable (d
|
|
|
160
159
|
queuing locally either way), and the transport automatically reconnects on the next delivery
|
|
161
160
|
attempt after a dropped connection or failed publish.
|
|
162
161
|
|
|
162
|
+
### TLS
|
|
163
|
+
|
|
164
|
+
By default `MQTTTransport` connects in plaintext on port `1883`. To connect over TLS, pass
|
|
165
|
+
`tls_params` (an `aiomqtt.TLSParameters`, re-exported from the underlying `paho-mqtt` client)
|
|
166
|
+
and switch to the broker's TLS port, conventionally `8883`:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
import aiomqtt
|
|
170
|
+
from edgesync.transports.mqtt import MQTTTransport
|
|
171
|
+
|
|
172
|
+
MQTTTransport(
|
|
173
|
+
"broker.example.com",
|
|
174
|
+
"devices/device-001/telemetry",
|
|
175
|
+
port=8883,
|
|
176
|
+
tls_params=aiomqtt.TLSParameters(
|
|
177
|
+
ca_certs="/etc/ssl/certs/ca-certificates.crt",
|
|
178
|
+
),
|
|
179
|
+
)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`TLSParameters` also accepts `certfile` / `keyfile` for client-certificate (mutual TLS)
|
|
183
|
+
authentication — see [aiomqtt's documentation](https://aiomqtt.bo3hm.com) for the full set of
|
|
184
|
+
options. Omit `tls_params` entirely for an unencrypted connection, e.g. when talking to a
|
|
185
|
+
broker on a trusted local network or in a local development/test setup.
|
|
186
|
+
|
|
163
187
|
## Inspecting the queue
|
|
164
188
|
|
|
165
189
|
```python
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
"""MQTT transport backed by ``aiomqtt``.
|
|
2
2
|
|
|
3
|
-
Requires the optional ``aiomqtt`` dependency: ``pip install edgesync[mqtt]``.
|
|
4
|
-
|
|
5
3
|
Unlike :class:`~edgesync.transports.http.HTTPTransport`, MQTT is a stateful,
|
|
6
4
|
persistent connection rather than a per-request protocol, which shapes two
|
|
7
5
|
design decisions here:
|
|
@@ -22,18 +20,13 @@ from __future__ import annotations
|
|
|
22
20
|
import contextlib
|
|
23
21
|
import json
|
|
24
22
|
|
|
23
|
+
import aiomqtt
|
|
24
|
+
|
|
25
25
|
from edgesync.logging import logger
|
|
26
26
|
from edgesync.models.delivery import DeliveryResult
|
|
27
27
|
from edgesync.models.message import Message
|
|
28
28
|
from edgesync.transports.base import Transport
|
|
29
29
|
|
|
30
|
-
try:
|
|
31
|
-
import aiomqtt
|
|
32
|
-
except ImportError as exc: # pragma: no cover - exercised only without the extra installed
|
|
33
|
-
raise ImportError(
|
|
34
|
-
"MQTTTransport requires the 'aiomqtt' package. Install it with: pip install edgesync[mqtt]"
|
|
35
|
-
) from exc
|
|
36
|
-
|
|
37
30
|
|
|
38
31
|
class MQTTTransport(Transport):
|
|
39
32
|
"""Publish messages as JSON payloads to a fixed MQTT topic.
|
|
@@ -23,11 +23,9 @@ classifiers = [
|
|
|
23
23
|
dependencies = [
|
|
24
24
|
"httpx>=0.27",
|
|
25
25
|
"aiosqlite>=0.20",
|
|
26
|
+
"aiomqtt>=2.5,<3",
|
|
26
27
|
]
|
|
27
28
|
|
|
28
|
-
[project.optional-dependencies]
|
|
29
|
-
mqtt = ["aiomqtt>=2.5,<3"]
|
|
30
|
-
|
|
31
29
|
[project.urls]
|
|
32
30
|
Homepage = "https://github.com/adhuldas/EdgeSync"
|
|
33
31
|
Repository = "https://github.com/adhuldas/EdgeSync"
|
|
@@ -149,3 +149,47 @@ async def test_close_after_failed_start_does_not_disconnect() -> None:
|
|
|
149
149
|
await transport.start()
|
|
150
150
|
await transport.close()
|
|
151
151
|
assert fake.disconnect_calls == 0
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
async def test_start_without_tls_params_constructs_plaintext_client(
|
|
155
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
156
|
+
) -> None:
|
|
157
|
+
captured: dict[str, object] = {}
|
|
158
|
+
|
|
159
|
+
class RecordingClient(FakeMQTTClient):
|
|
160
|
+
def __init__(self, hostname: str, port: int, **kwargs: object) -> None:
|
|
161
|
+
super().__init__()
|
|
162
|
+
captured["hostname"] = hostname
|
|
163
|
+
captured["port"] = port
|
|
164
|
+
captured.update(kwargs)
|
|
165
|
+
|
|
166
|
+
monkeypatch.setattr(aiomqtt, "Client", RecordingClient)
|
|
167
|
+
|
|
168
|
+
transport = MQTTTransport("broker.invalid", "telemetry")
|
|
169
|
+
await transport.start()
|
|
170
|
+
|
|
171
|
+
assert captured["hostname"] == "broker.invalid"
|
|
172
|
+
assert captured["port"] == 1883
|
|
173
|
+
assert captured["tls_params"] is None
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
async def test_start_with_tls_params_constructs_tls_client(
|
|
177
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
178
|
+
) -> None:
|
|
179
|
+
captured: dict[str, object] = {}
|
|
180
|
+
|
|
181
|
+
class RecordingClient(FakeMQTTClient):
|
|
182
|
+
def __init__(self, hostname: str, port: int, **kwargs: object) -> None:
|
|
183
|
+
super().__init__()
|
|
184
|
+
captured["hostname"] = hostname
|
|
185
|
+
captured["port"] = port
|
|
186
|
+
captured.update(kwargs)
|
|
187
|
+
|
|
188
|
+
monkeypatch.setattr(aiomqtt, "Client", RecordingClient)
|
|
189
|
+
|
|
190
|
+
tls_params = aiomqtt.TLSParameters(ca_certs="/etc/ssl/certs/ca-certificates.crt")
|
|
191
|
+
transport = MQTTTransport("broker.invalid", "telemetry", port=8883, tls_params=tls_params)
|
|
192
|
+
await transport.start()
|
|
193
|
+
|
|
194
|
+
assert captured["port"] == 8883
|
|
195
|
+
assert captured["tls_params"] is tls_params
|
|
@@ -270,15 +270,11 @@ toml = [
|
|
|
270
270
|
name = "edgesync"
|
|
271
271
|
source = { editable = "." }
|
|
272
272
|
dependencies = [
|
|
273
|
+
{ name = "aiomqtt" },
|
|
273
274
|
{ name = "aiosqlite" },
|
|
274
275
|
{ name = "httpx" },
|
|
275
276
|
]
|
|
276
277
|
|
|
277
|
-
[package.optional-dependencies]
|
|
278
|
-
mqtt = [
|
|
279
|
-
{ name = "aiomqtt" },
|
|
280
|
-
]
|
|
281
|
-
|
|
282
278
|
[package.dev-dependencies]
|
|
283
279
|
dev = [
|
|
284
280
|
{ name = "mypy" },
|
|
@@ -291,11 +287,10 @@ dev = [
|
|
|
291
287
|
|
|
292
288
|
[package.metadata]
|
|
293
289
|
requires-dist = [
|
|
294
|
-
{ name = "aiomqtt",
|
|
290
|
+
{ name = "aiomqtt", specifier = ">=2.5,<3" },
|
|
295
291
|
{ name = "aiosqlite", specifier = ">=0.20" },
|
|
296
292
|
{ name = "httpx", specifier = ">=0.27" },
|
|
297
293
|
]
|
|
298
|
-
provides-extras = ["mqtt"]
|
|
299
294
|
|
|
300
295
|
[package.metadata.requires-dev]
|
|
301
296
|
dev = [
|
edgesync-0.3.1/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.3.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|