tollmeshcache 1.0.0__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.
- tollmeshcache-1.0.0/PKG-INFO +319 -0
- tollmeshcache-1.0.0/README.md +274 -0
- tollmeshcache-1.0.0/setup.cfg +4 -0
- tollmeshcache-1.0.0/setup.py +51 -0
- tollmeshcache-1.0.0/tests/__init__.py +1 -0
- tollmeshcache-1.0.0/tests/test_async_client.py +228 -0
- tollmeshcache-1.0.0/tests/test_client.py +312 -0
- tollmeshcache-1.0.0/tollmeshcache/__init__.py +45 -0
- tollmeshcache-1.0.0/tollmeshcache/async_client.py +235 -0
- tollmeshcache-1.0.0/tollmeshcache/client.py +288 -0
- tollmeshcache-1.0.0/tollmeshcache/config.py +65 -0
- tollmeshcache-1.0.0/tollmeshcache/errors.py +154 -0
- tollmeshcache-1.0.0/tollmeshcache/retry.py +154 -0
- tollmeshcache-1.0.0/tollmeshcache.egg-info/PKG-INFO +319 -0
- tollmeshcache-1.0.0/tollmeshcache.egg-info/SOURCES.txt +17 -0
- tollmeshcache-1.0.0/tollmeshcache.egg-info/dependency_links.txt +1 -0
- tollmeshcache-1.0.0/tollmeshcache.egg-info/entry_points.txt +3 -0
- tollmeshcache-1.0.0/tollmeshcache.egg-info/requires.txt +17 -0
- tollmeshcache-1.0.0/tollmeshcache.egg-info/top_level.txt +2 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tollmeshcache
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python SDK for TollMeshCache - Distributed CRDT-based caching
|
|
5
|
+
Home-page: https://github.com/toll-mesh/store
|
|
6
|
+
Author: TollMesh Team
|
|
7
|
+
Author-email: team@tollmesh.io
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
Requires-Dist: requests>=2.28.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-asyncio>=0.20.0; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
26
|
+
Requires-Dist: black>=22.0.0; extra == "dev"
|
|
27
|
+
Requires-Dist: flake8>=4.0.0; extra == "dev"
|
|
28
|
+
Requires-Dist: mypy>=0.990; extra == "dev"
|
|
29
|
+
Provides-Extra: async
|
|
30
|
+
Requires-Dist: httpx>=0.24.0; extra == "async"
|
|
31
|
+
Provides-Extra: grpc
|
|
32
|
+
Requires-Dist: grpcio>=1.50.0; extra == "grpc"
|
|
33
|
+
Requires-Dist: grpcio-tools>=1.50.0; extra == "grpc"
|
|
34
|
+
Requires-Dist: protobuf>=3.20.0; extra == "grpc"
|
|
35
|
+
Dynamic: author
|
|
36
|
+
Dynamic: author-email
|
|
37
|
+
Dynamic: classifier
|
|
38
|
+
Dynamic: description
|
|
39
|
+
Dynamic: description-content-type
|
|
40
|
+
Dynamic: home-page
|
|
41
|
+
Dynamic: provides-extra
|
|
42
|
+
Dynamic: requires-dist
|
|
43
|
+
Dynamic: requires-python
|
|
44
|
+
Dynamic: summary
|
|
45
|
+
|
|
46
|
+
# TollMeshCache Python SDK
|
|
47
|
+
|
|
48
|
+
Complete Python SDK for TollMeshCache - Distributed CRDT-based caching and coordination.
|
|
49
|
+
|
|
50
|
+
## Installation
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install tollmeshcache
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick Start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from tollmeshcache import Client, ClientConfig
|
|
60
|
+
from datetime import timedelta
|
|
61
|
+
|
|
62
|
+
# Initialize client
|
|
63
|
+
config = ClientConfig(host="localhost", port=8080)
|
|
64
|
+
client = Client(config)
|
|
65
|
+
|
|
66
|
+
# Rate limiting
|
|
67
|
+
result = client.consume("user-123", limit=100, window=timedelta(minutes=1))
|
|
68
|
+
if result["ok"]:
|
|
69
|
+
print("Request allowed")
|
|
70
|
+
else:
|
|
71
|
+
print("Rate limited")
|
|
72
|
+
|
|
73
|
+
# Replay protection
|
|
74
|
+
if client.seen("nonce-123", ttl=timedelta(minutes=5))["seen"]:
|
|
75
|
+
print("Replay detected!")
|
|
76
|
+
|
|
77
|
+
# Caching
|
|
78
|
+
client.cache_set("users", "user-123", '{"name": "Alice"}', ttl=timedelta(hours=1))
|
|
79
|
+
value, exists = client.cache_get("users", "user-123")
|
|
80
|
+
|
|
81
|
+
# Health check
|
|
82
|
+
health = client.health()
|
|
83
|
+
print(f"Status: {health['status']}")
|
|
84
|
+
|
|
85
|
+
client.close()
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Features
|
|
89
|
+
|
|
90
|
+
### Rate Limiting
|
|
91
|
+
Distributed rate limiting with automatic convergence across cluster nodes.
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
result = client.consume("api-key", limit=1000, window=timedelta(hours=1))
|
|
95
|
+
if result["ok"]:
|
|
96
|
+
# Process request
|
|
97
|
+
else:
|
|
98
|
+
# Handle rate limit
|
|
99
|
+
print(f"Reset at: {result['reset_at']}")
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Replay Protection
|
|
103
|
+
Prevent replay attacks by tracking seen nonces.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
if client.seen("request-nonce", ttl=timedelta(minutes=5))["seen"]:
|
|
107
|
+
raise Exception("Replay attack detected!")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Distributed Caching
|
|
111
|
+
Store and retrieve values with automatic expiration.
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
# Set
|
|
115
|
+
client.cache_set("namespace", "key", "value", ttl=timedelta(hours=1))
|
|
116
|
+
|
|
117
|
+
# Get
|
|
118
|
+
value, exists = client.cache_get("namespace", "key")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Health & Monitoring
|
|
122
|
+
Check node and cluster status.
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
health = client.health()
|
|
126
|
+
print(f"Status: {health['status']}")
|
|
127
|
+
print(f"Peers: {health['peers']}")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Configuration
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
config = ClientConfig(
|
|
134
|
+
host="localhost", # Server hostname
|
|
135
|
+
port=8080, # Server port
|
|
136
|
+
timeout=5.0, # Request timeout (seconds)
|
|
137
|
+
verify_ssl=True, # Verify SSL certificates
|
|
138
|
+
api_key="secret", # Optional API key
|
|
139
|
+
http_scheme="http", # 'http' or 'https'
|
|
140
|
+
max_retries=3, # Retry attempts
|
|
141
|
+
connection_pool_size=10, # HTTP connection pool size
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Error Handling
|
|
146
|
+
|
|
147
|
+
All operations raise `TollMeshError` on failure:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
from tollmeshcache import TollMeshError, ErrorCode
|
|
151
|
+
|
|
152
|
+
try:
|
|
153
|
+
result = client.consume("key", 100, timedelta(minutes=1))
|
|
154
|
+
except TollMeshError as e:
|
|
155
|
+
if e.is_rate_limited():
|
|
156
|
+
print("Rate limited")
|
|
157
|
+
elif e.is_retryable():
|
|
158
|
+
print("Temporary error - will retry")
|
|
159
|
+
else:
|
|
160
|
+
print(f"Error: {e.message}")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Retry Logic
|
|
164
|
+
|
|
165
|
+
Automatic retry with exponential backoff:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from tollmeshcache import RetryConfig, retry
|
|
169
|
+
|
|
170
|
+
config = RetryConfig(
|
|
171
|
+
max_retries=3,
|
|
172
|
+
base_delay=1.0,
|
|
173
|
+
max_delay=60.0,
|
|
174
|
+
jitter=True,
|
|
175
|
+
backoff_multiplier=2.0,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
@retry(config)
|
|
179
|
+
def risky_operation():
|
|
180
|
+
return client.consume("key", 100, timedelta(minutes=1))
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Context Manager
|
|
184
|
+
|
|
185
|
+
Use as a context manager for automatic cleanup:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
with Client(config) as client:
|
|
189
|
+
result = client.consume("key", 100, timedelta(minutes=1))
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Examples
|
|
193
|
+
|
|
194
|
+
See `examples/` directory:
|
|
195
|
+
- `rate_limiting.py` - Distributed rate limiting
|
|
196
|
+
- `caching.py` - Distributed caching patterns
|
|
197
|
+
- `replay_protection.py` - Replay attack prevention
|
|
198
|
+
|
|
199
|
+
Run examples:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
python examples/rate_limiting.py
|
|
203
|
+
python examples/caching.py
|
|
204
|
+
python examples/replay_protection.py
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Testing
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
pip install -e ".[dev]"
|
|
211
|
+
pytest -v --cov=tollmeshcache
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Run specific tests:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
pytest tests/test_client.py::TestClientConfig -v
|
|
218
|
+
pytest tests/test_client.py::TestConsumeOperation -v
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Performance
|
|
222
|
+
|
|
223
|
+
- **Rate Limiting**: O(1) per operation
|
|
224
|
+
- **Replay Protection**: O(1) per operation
|
|
225
|
+
- **Caching**: O(1) per operation
|
|
226
|
+
- **Connection Pooling**: Automatic with configurable pool size
|
|
227
|
+
- **Retry Logic**: Exponential backoff with jitter
|
|
228
|
+
|
|
229
|
+
## Thread Safety
|
|
230
|
+
|
|
231
|
+
All operations are thread-safe. Safe to use the same client across multiple threads.
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
235
|
+
|
|
236
|
+
def worker(client, key):
|
|
237
|
+
result = client.consume(key, 100, timedelta(minutes=1))
|
|
238
|
+
return result
|
|
239
|
+
|
|
240
|
+
with ThreadPoolExecutor(max_workers=10) as executor:
|
|
241
|
+
futures = [executor.submit(worker, client, f"key-{i}") for i in range(100)]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Async Support
|
|
245
|
+
|
|
246
|
+
For async/await support, use the async client (coming soon):
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
import asyncio
|
|
250
|
+
from tollmeshcache import AsyncClient
|
|
251
|
+
|
|
252
|
+
async def main():
|
|
253
|
+
async with AsyncClient(config) as client:
|
|
254
|
+
result = await client.consume("key", 100, timedelta(minutes=1))
|
|
255
|
+
|
|
256
|
+
asyncio.run(main())
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## Best Practices
|
|
260
|
+
|
|
261
|
+
1. **Reuse Clients**: Create once, reuse across requests
|
|
262
|
+
2. **Handle Errors**: Always handle rate limit and replay errors
|
|
263
|
+
3. **Set TTLs**: Configure appropriate cache TTLs
|
|
264
|
+
4. **Monitor Health**: Periodically check cluster status
|
|
265
|
+
5. **Connection Pooling**: Leverage automatic pooling for performance
|
|
266
|
+
|
|
267
|
+
## API Reference
|
|
268
|
+
|
|
269
|
+
### `Client`
|
|
270
|
+
|
|
271
|
+
Main client class for interacting with TollMeshCache.
|
|
272
|
+
|
|
273
|
+
#### Methods
|
|
274
|
+
|
|
275
|
+
- `consume(key, limit, window) -> ConsumeResult`
|
|
276
|
+
- Check and consume rate limit tokens
|
|
277
|
+
|
|
278
|
+
- `seen(key, ttl) -> SeenResult`
|
|
279
|
+
- Check replay protection
|
|
280
|
+
|
|
281
|
+
- `cache_get(namespace, key) -> (value, exists)`
|
|
282
|
+
- Get value from cache
|
|
283
|
+
|
|
284
|
+
- `cache_set(namespace, key, value, ttl=None) -> None`
|
|
285
|
+
- Set value in cache
|
|
286
|
+
|
|
287
|
+
- `health() -> HealthResponse`
|
|
288
|
+
- Check server health
|
|
289
|
+
|
|
290
|
+
- `get_peers() -> List[Peer]`
|
|
291
|
+
- Get connected peers
|
|
292
|
+
|
|
293
|
+
- `close() -> None`
|
|
294
|
+
- Close client and cleanup
|
|
295
|
+
|
|
296
|
+
### Exceptions
|
|
297
|
+
|
|
298
|
+
- `TollMeshError` - Base exception
|
|
299
|
+
- `RateLimitError` - Rate limit exceeded
|
|
300
|
+
- `ReplayError` - Replay detected
|
|
301
|
+
- `CacheMissError` - Cache miss
|
|
302
|
+
|
|
303
|
+
## Contributing
|
|
304
|
+
|
|
305
|
+
Contributions welcome! Please:
|
|
306
|
+
1. Write tests for new features
|
|
307
|
+
2. Maintain 95%+ test coverage
|
|
308
|
+
3. Follow PEP 8 style guide
|
|
309
|
+
4. Add docstrings to all functions
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
Apache License 2.0
|
|
314
|
+
|
|
315
|
+
## Support
|
|
316
|
+
|
|
317
|
+
- **Documentation**: https://docs.tollmesh.io
|
|
318
|
+
- **Issues**: https://github.com/toll-mesh/store/issues
|
|
319
|
+
- **Discussions**: https://github.com/toll-mesh/store/discussions
|
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# TollMeshCache Python SDK
|
|
2
|
+
|
|
3
|
+
Complete Python SDK for TollMeshCache - Distributed CRDT-based caching and coordination.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install tollmeshcache
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from tollmeshcache import Client, ClientConfig
|
|
15
|
+
from datetime import timedelta
|
|
16
|
+
|
|
17
|
+
# Initialize client
|
|
18
|
+
config = ClientConfig(host="localhost", port=8080)
|
|
19
|
+
client = Client(config)
|
|
20
|
+
|
|
21
|
+
# Rate limiting
|
|
22
|
+
result = client.consume("user-123", limit=100, window=timedelta(minutes=1))
|
|
23
|
+
if result["ok"]:
|
|
24
|
+
print("Request allowed")
|
|
25
|
+
else:
|
|
26
|
+
print("Rate limited")
|
|
27
|
+
|
|
28
|
+
# Replay protection
|
|
29
|
+
if client.seen("nonce-123", ttl=timedelta(minutes=5))["seen"]:
|
|
30
|
+
print("Replay detected!")
|
|
31
|
+
|
|
32
|
+
# Caching
|
|
33
|
+
client.cache_set("users", "user-123", '{"name": "Alice"}', ttl=timedelta(hours=1))
|
|
34
|
+
value, exists = client.cache_get("users", "user-123")
|
|
35
|
+
|
|
36
|
+
# Health check
|
|
37
|
+
health = client.health()
|
|
38
|
+
print(f"Status: {health['status']}")
|
|
39
|
+
|
|
40
|
+
client.close()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
### Rate Limiting
|
|
46
|
+
Distributed rate limiting with automatic convergence across cluster nodes.
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
result = client.consume("api-key", limit=1000, window=timedelta(hours=1))
|
|
50
|
+
if result["ok"]:
|
|
51
|
+
# Process request
|
|
52
|
+
else:
|
|
53
|
+
# Handle rate limit
|
|
54
|
+
print(f"Reset at: {result['reset_at']}")
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Replay Protection
|
|
58
|
+
Prevent replay attacks by tracking seen nonces.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
if client.seen("request-nonce", ttl=timedelta(minutes=5))["seen"]:
|
|
62
|
+
raise Exception("Replay attack detected!")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Distributed Caching
|
|
66
|
+
Store and retrieve values with automatic expiration.
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
# Set
|
|
70
|
+
client.cache_set("namespace", "key", "value", ttl=timedelta(hours=1))
|
|
71
|
+
|
|
72
|
+
# Get
|
|
73
|
+
value, exists = client.cache_get("namespace", "key")
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Health & Monitoring
|
|
77
|
+
Check node and cluster status.
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
health = client.health()
|
|
81
|
+
print(f"Status: {health['status']}")
|
|
82
|
+
print(f"Peers: {health['peers']}")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Configuration
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
config = ClientConfig(
|
|
89
|
+
host="localhost", # Server hostname
|
|
90
|
+
port=8080, # Server port
|
|
91
|
+
timeout=5.0, # Request timeout (seconds)
|
|
92
|
+
verify_ssl=True, # Verify SSL certificates
|
|
93
|
+
api_key="secret", # Optional API key
|
|
94
|
+
http_scheme="http", # 'http' or 'https'
|
|
95
|
+
max_retries=3, # Retry attempts
|
|
96
|
+
connection_pool_size=10, # HTTP connection pool size
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Error Handling
|
|
101
|
+
|
|
102
|
+
All operations raise `TollMeshError` on failure:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
from tollmeshcache import TollMeshError, ErrorCode
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
result = client.consume("key", 100, timedelta(minutes=1))
|
|
109
|
+
except TollMeshError as e:
|
|
110
|
+
if e.is_rate_limited():
|
|
111
|
+
print("Rate limited")
|
|
112
|
+
elif e.is_retryable():
|
|
113
|
+
print("Temporary error - will retry")
|
|
114
|
+
else:
|
|
115
|
+
print(f"Error: {e.message}")
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Retry Logic
|
|
119
|
+
|
|
120
|
+
Automatic retry with exponential backoff:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from tollmeshcache import RetryConfig, retry
|
|
124
|
+
|
|
125
|
+
config = RetryConfig(
|
|
126
|
+
max_retries=3,
|
|
127
|
+
base_delay=1.0,
|
|
128
|
+
max_delay=60.0,
|
|
129
|
+
jitter=True,
|
|
130
|
+
backoff_multiplier=2.0,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
@retry(config)
|
|
134
|
+
def risky_operation():
|
|
135
|
+
return client.consume("key", 100, timedelta(minutes=1))
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Context Manager
|
|
139
|
+
|
|
140
|
+
Use as a context manager for automatic cleanup:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
with Client(config) as client:
|
|
144
|
+
result = client.consume("key", 100, timedelta(minutes=1))
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Examples
|
|
148
|
+
|
|
149
|
+
See `examples/` directory:
|
|
150
|
+
- `rate_limiting.py` - Distributed rate limiting
|
|
151
|
+
- `caching.py` - Distributed caching patterns
|
|
152
|
+
- `replay_protection.py` - Replay attack prevention
|
|
153
|
+
|
|
154
|
+
Run examples:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
python examples/rate_limiting.py
|
|
158
|
+
python examples/caching.py
|
|
159
|
+
python examples/replay_protection.py
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Testing
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
pip install -e ".[dev]"
|
|
166
|
+
pytest -v --cov=tollmeshcache
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Run specific tests:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pytest tests/test_client.py::TestClientConfig -v
|
|
173
|
+
pytest tests/test_client.py::TestConsumeOperation -v
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Performance
|
|
177
|
+
|
|
178
|
+
- **Rate Limiting**: O(1) per operation
|
|
179
|
+
- **Replay Protection**: O(1) per operation
|
|
180
|
+
- **Caching**: O(1) per operation
|
|
181
|
+
- **Connection Pooling**: Automatic with configurable pool size
|
|
182
|
+
- **Retry Logic**: Exponential backoff with jitter
|
|
183
|
+
|
|
184
|
+
## Thread Safety
|
|
185
|
+
|
|
186
|
+
All operations are thread-safe. Safe to use the same client across multiple threads.
|
|
187
|
+
|
|
188
|
+
```python
|
|
189
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
190
|
+
|
|
191
|
+
def worker(client, key):
|
|
192
|
+
result = client.consume(key, 100, timedelta(minutes=1))
|
|
193
|
+
return result
|
|
194
|
+
|
|
195
|
+
with ThreadPoolExecutor(max_workers=10) as executor:
|
|
196
|
+
futures = [executor.submit(worker, client, f"key-{i}") for i in range(100)]
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Async Support
|
|
200
|
+
|
|
201
|
+
For async/await support, use the async client (coming soon):
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
import asyncio
|
|
205
|
+
from tollmeshcache import AsyncClient
|
|
206
|
+
|
|
207
|
+
async def main():
|
|
208
|
+
async with AsyncClient(config) as client:
|
|
209
|
+
result = await client.consume("key", 100, timedelta(minutes=1))
|
|
210
|
+
|
|
211
|
+
asyncio.run(main())
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Best Practices
|
|
215
|
+
|
|
216
|
+
1. **Reuse Clients**: Create once, reuse across requests
|
|
217
|
+
2. **Handle Errors**: Always handle rate limit and replay errors
|
|
218
|
+
3. **Set TTLs**: Configure appropriate cache TTLs
|
|
219
|
+
4. **Monitor Health**: Periodically check cluster status
|
|
220
|
+
5. **Connection Pooling**: Leverage automatic pooling for performance
|
|
221
|
+
|
|
222
|
+
## API Reference
|
|
223
|
+
|
|
224
|
+
### `Client`
|
|
225
|
+
|
|
226
|
+
Main client class for interacting with TollMeshCache.
|
|
227
|
+
|
|
228
|
+
#### Methods
|
|
229
|
+
|
|
230
|
+
- `consume(key, limit, window) -> ConsumeResult`
|
|
231
|
+
- Check and consume rate limit tokens
|
|
232
|
+
|
|
233
|
+
- `seen(key, ttl) -> SeenResult`
|
|
234
|
+
- Check replay protection
|
|
235
|
+
|
|
236
|
+
- `cache_get(namespace, key) -> (value, exists)`
|
|
237
|
+
- Get value from cache
|
|
238
|
+
|
|
239
|
+
- `cache_set(namespace, key, value, ttl=None) -> None`
|
|
240
|
+
- Set value in cache
|
|
241
|
+
|
|
242
|
+
- `health() -> HealthResponse`
|
|
243
|
+
- Check server health
|
|
244
|
+
|
|
245
|
+
- `get_peers() -> List[Peer]`
|
|
246
|
+
- Get connected peers
|
|
247
|
+
|
|
248
|
+
- `close() -> None`
|
|
249
|
+
- Close client and cleanup
|
|
250
|
+
|
|
251
|
+
### Exceptions
|
|
252
|
+
|
|
253
|
+
- `TollMeshError` - Base exception
|
|
254
|
+
- `RateLimitError` - Rate limit exceeded
|
|
255
|
+
- `ReplayError` - Replay detected
|
|
256
|
+
- `CacheMissError` - Cache miss
|
|
257
|
+
|
|
258
|
+
## Contributing
|
|
259
|
+
|
|
260
|
+
Contributions welcome! Please:
|
|
261
|
+
1. Write tests for new features
|
|
262
|
+
2. Maintain 95%+ test coverage
|
|
263
|
+
3. Follow PEP 8 style guide
|
|
264
|
+
4. Add docstrings to all functions
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
Apache License 2.0
|
|
269
|
+
|
|
270
|
+
## Support
|
|
271
|
+
|
|
272
|
+
- **Documentation**: https://docs.tollmesh.io
|
|
273
|
+
- **Issues**: https://github.com/toll-mesh/store/issues
|
|
274
|
+
- **Discussions**: https://github.com/toll-mesh/store/discussions
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r", encoding="utf-8") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name="tollmeshcache",
|
|
8
|
+
version="1.0.0",
|
|
9
|
+
author="TollMesh Team",
|
|
10
|
+
author_email="team@tollmesh.io",
|
|
11
|
+
description="Python SDK for TollMeshCache - Distributed CRDT-based caching",
|
|
12
|
+
long_description=long_description,
|
|
13
|
+
long_description_content_type="text/markdown",
|
|
14
|
+
url="https://github.com/toll-mesh/store",
|
|
15
|
+
packages=find_packages(),
|
|
16
|
+
classifiers=[
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3.8",
|
|
19
|
+
"Programming Language :: Python :: 3.9",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"License :: OSI Approved :: Apache Software License",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
"Development Status :: 5 - Production/Stable",
|
|
26
|
+
"Intended Audience :: Developers",
|
|
27
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
28
|
+
],
|
|
29
|
+
python_requires=">=3.8",
|
|
30
|
+
install_requires=[
|
|
31
|
+
"requests>=2.28.0",
|
|
32
|
+
],
|
|
33
|
+
extras_require={
|
|
34
|
+
"dev": [
|
|
35
|
+
"pytest>=7.0.0",
|
|
36
|
+
"pytest-asyncio>=0.20.0",
|
|
37
|
+
"pytest-cov>=4.0.0",
|
|
38
|
+
"black>=22.0.0",
|
|
39
|
+
"flake8>=4.0.0",
|
|
40
|
+
"mypy>=0.990",
|
|
41
|
+
],
|
|
42
|
+
"async": ["httpx>=0.24.0"],
|
|
43
|
+
"grpc": ["grpcio>=1.50.0", "grpcio-tools>=1.50.0", "protobuf>=3.20.0"],
|
|
44
|
+
},
|
|
45
|
+
entry_points={
|
|
46
|
+
"console_scripts": [
|
|
47
|
+
"tollmesh-init=tollmeshcache.cli:init",
|
|
48
|
+
"tollmesh-config=tollmeshcache.cli:config",
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Test suite for TollMeshCache Python SDK"""
|