meshsocket 0.1.0__tar.gz → 0.1.2__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.
- {meshsocket-0.1.0 → meshsocket-0.1.2}/PKG-INFO +5 -1
- {meshsocket-0.1.0 → meshsocket-0.1.2}/README.md +4 -0
- {meshsocket-0.1.0 → meshsocket-0.1.2}/meshsocket.egg-info/PKG-INFO +5 -1
- {meshsocket-0.1.0 → meshsocket-0.1.2}/pyproject.toml +1 -1
- {meshsocket-0.1.0 → meshsocket-0.1.2}/socketCore.py +41 -2
- {meshsocket-0.1.0 → meshsocket-0.1.2}/LICENSE +0 -0
- {meshsocket-0.1.0 → meshsocket-0.1.2}/meshsocket/__init__.py +0 -0
- {meshsocket-0.1.0 → meshsocket-0.1.2}/meshsocket.egg-info/SOURCES.txt +0 -0
- {meshsocket-0.1.0 → meshsocket-0.1.2}/meshsocket.egg-info/dependency_links.txt +0 -0
- {meshsocket-0.1.0 → meshsocket-0.1.2}/meshsocket.egg-info/requires.txt +0 -0
- {meshsocket-0.1.0 → meshsocket-0.1.2}/meshsocket.egg-info/top_level.txt +0 -0
- {meshsocket-0.1.0 → meshsocket-0.1.2}/setup.cfg +0 -0
- {meshsocket-0.1.0 → meshsocket-0.1.2}/socket_server.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshsocket
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Lightweight WebSocket mesh networking — broadcast, direct routing, and request/response over a simple JSON wire protocol.
|
|
5
5
|
Author: Carter Beaudoin
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,6 +23,10 @@ Dynamic: license-file
|
|
|
23
23
|
|
|
24
24
|
# MeshSocket (Python)
|
|
25
25
|
|
|
26
|
+
[](https://pypi.org/project/meshsocket/)
|
|
27
|
+
[](https://pepy.tech/project/meshsocket)
|
|
28
|
+
[](https://pypi.org/project/meshsocket/)
|
|
29
|
+
|
|
26
30
|
A lightweight WebSocket **mesh networking** library. Nodes connect to a central relay and
|
|
27
31
|
communicate by **broadcast**, **direct routing**, and **request/response** — all over a
|
|
28
32
|
simple JSON wire protocol.
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# MeshSocket (Python)
|
|
2
2
|
|
|
3
|
+
[](https://pypi.org/project/meshsocket/)
|
|
4
|
+
[](https://pepy.tech/project/meshsocket)
|
|
5
|
+
[](https://pypi.org/project/meshsocket/)
|
|
6
|
+
|
|
3
7
|
A lightweight WebSocket **mesh networking** library. Nodes connect to a central relay and
|
|
4
8
|
communicate by **broadcast**, **direct routing**, and **request/response** — all over a
|
|
5
9
|
simple JSON wire protocol.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshsocket
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.2
|
|
4
4
|
Summary: Lightweight WebSocket mesh networking — broadcast, direct routing, and request/response over a simple JSON wire protocol.
|
|
5
5
|
Author: Carter Beaudoin
|
|
6
6
|
License-Expression: MIT
|
|
@@ -23,6 +23,10 @@ Dynamic: license-file
|
|
|
23
23
|
|
|
24
24
|
# MeshSocket (Python)
|
|
25
25
|
|
|
26
|
+
[](https://pypi.org/project/meshsocket/)
|
|
27
|
+
[](https://pepy.tech/project/meshsocket)
|
|
28
|
+
[](https://pypi.org/project/meshsocket/)
|
|
29
|
+
|
|
26
30
|
A lightweight WebSocket **mesh networking** library. Nodes connect to a central relay and
|
|
27
31
|
communicate by **broadcast**, **direct routing**, and **request/response** — all over a
|
|
28
32
|
simple JSON wire protocol.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "meshsocket"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.2"
|
|
8
8
|
description = "Lightweight WebSocket mesh networking — broadcast, direct routing, and request/response over a simple JSON wire protocol."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -110,6 +110,10 @@ class MeshSocket:
|
|
|
110
110
|
|
|
111
111
|
# State
|
|
112
112
|
self.is_running = False
|
|
113
|
+
# Set by stop(reason=...) when the client is being torn down because of a
|
|
114
|
+
# FAULT rather than an ordinary shutdown; surfaced when the supervisor exits.
|
|
115
|
+
self.stopped_reason: Optional[str] = None
|
|
116
|
+
self._maintain_task: Optional[asyncio.Task] = None
|
|
113
117
|
|
|
114
118
|
# Lazy-initialised inside the event loop to avoid DeprecationWarning
|
|
115
119
|
# in Python 3.10+ when constructing outside an async context.
|
|
@@ -202,12 +206,25 @@ class MeshSocket:
|
|
|
202
206
|
raise ValueError("Cannot use start() without a URL.")
|
|
203
207
|
self._start_time = time.time()
|
|
204
208
|
self.is_running = True
|
|
205
|
-
|
|
209
|
+
self.stopped_reason = None
|
|
210
|
+
# Hold the reference: the loop keeps only a weak one, so an unreferenced
|
|
211
|
+
# task can be garbage-collected mid-flight and take the reconnect
|
|
212
|
+
# supervisor down silently.
|
|
213
|
+
self._maintain_task = asyncio.create_task(self._maintain_connection())
|
|
206
214
|
|
|
207
215
|
async def wait_until_ready(self):
|
|
208
216
|
await self.connected_event.wait()
|
|
209
217
|
|
|
210
|
-
async def stop(self):
|
|
218
|
+
async def stop(self, reason: str = None):
|
|
219
|
+
"""Shut the client down for good (the supervisor will NOT reconnect).
|
|
220
|
+
|
|
221
|
+
`reason` marks this as a FAULT rather than an intentional shutdown: it
|
|
222
|
+
is recorded on `stopped_reason` and logged at ERROR when the supervisor
|
|
223
|
+
exits. Callers giving up on a socket should always pass one — a caller
|
|
224
|
+
that reuses the plain shutdown path to mean "fatal error" produces a
|
|
225
|
+
dead client that never reconnects and never says why.
|
|
226
|
+
"""
|
|
227
|
+
self.stopped_reason = reason
|
|
211
228
|
self.is_running = False
|
|
212
229
|
if self.connection:
|
|
213
230
|
await self.connection.close()
|
|
@@ -227,6 +244,28 @@ class MeshSocket:
|
|
|
227
244
|
|
|
228
245
|
# --- INTERNAL CORE ---
|
|
229
246
|
async def _maintain_connection(self):
|
|
247
|
+
try:
|
|
248
|
+
await self._maintain_connection_inner()
|
|
249
|
+
finally:
|
|
250
|
+
# INVARIANT: this supervisor never dies quietly. While it is alive the
|
|
251
|
+
# client reconnects forever; once it exits the client is dead until
|
|
252
|
+
# something calls start() again, so every exit — intentional shutdown,
|
|
253
|
+
# fault, cancellation, or a bug — must leave a line in the log. A
|
|
254
|
+
# silent exit here once cost ~30 h of a "connected" client that was
|
|
255
|
+
# never coming back.
|
|
256
|
+
if self.stopped_reason:
|
|
257
|
+
logging.error(f"{LogColors.FAIL}{self.name} connection supervisor "
|
|
258
|
+
f"STOPPED: {self.stopped_reason} — this client will "
|
|
259
|
+
f"not reconnect until start() is called again"
|
|
260
|
+
f"{LogColors.ENDC}")
|
|
261
|
+
elif self.is_running:
|
|
262
|
+
logging.error(f"{LogColors.FAIL}{self.name} connection supervisor "
|
|
263
|
+
f"exited unexpectedly while still running — this "
|
|
264
|
+
f"client will NOT reconnect{LogColors.ENDC}")
|
|
265
|
+
else:
|
|
266
|
+
logging.info(f"{self.name} connection supervisor stopped (shutdown)")
|
|
267
|
+
|
|
268
|
+
async def _maintain_connection_inner(self):
|
|
230
269
|
retry_delay = 2
|
|
231
270
|
while self.is_running:
|
|
232
271
|
listen_task = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|